def WriteVTableMap(self, generator): stream = generator.file print >> stream, "%s_vtables_dispatch_ = %d" % (self.python_name, self.bIsDispatch) print >> stream, "%s_vtables_ = [" % (self.python_name, ) for v in self.vtableFuncs: names, dispid, desc = v arg_desc = desc[2] arg_reprs = [] # more hoops so we don't generate huge lines. item_num = 0 print >> stream, "\t((", for name in names: print >> stream, repr(name), ",", item_num = item_num + 1 if item_num % 5 == 0: print >> stream, "\n\t\t\t", print >> stream, "), %d, (%r, %r, [" % (dispid, desc[0], desc[1]), for arg in arg_desc: item_num = item_num + 1 if item_num % 5 == 0: print >> stream, "\n\t\t\t", defval = build.MakeDefaultArgRepr(arg) if arg[3] is None: arg3_repr = None else: arg3_repr = repr(arg[3]) print >> stream, repr((arg[0], arg[1], defval, arg3_repr)), ",", print >> stream, "],", for d in desc[3:]: print >> stream, repr(d), ",", print >> stream, "))," print >> stream, "]" print >> stream
def MakeDefaultArgsForPropertyPut(argsDesc): ret = [] for desc in argsDesc[1:]: default = build.MakeDefaultArgRepr(desc) if default is None: break ret.append(default) return tuple(ret)
def WriteClassBody(self, generator): stream = generator.file # Write in alpha order. names = list(self.mapFuncs.keys()) names.sort() specialItems = { "count": None, "item": None, "value": None, "_newenum": None } # If found, will end up with (entry, invoke_tupe) itemCount = None for name in names: entry = self.mapFuncs[name] # skip [restricted] methods, unless it is the # enumerator (which, being part of the "system", # we know about and can use) dispid = entry.desc[0] if entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED and \ dispid != pythoncom.DISPID_NEWENUM: continue # If not accessible via IDispatch, then we can't use it here. if entry.desc[3] != pythoncom.FUNC_DISPATCH: continue if dispid == pythoncom.DISPID_VALUE: lkey = "value" elif dispid == pythoncom.DISPID_NEWENUM: specialItems["_newenum"] = (entry, entry.desc[4], None) continue # Dont build this one now! else: lkey = name.lower() if lkey in specialItems and specialItems[ lkey] is None: # remember if a special one. specialItems[lkey] = (entry, entry.desc[4], None) if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, '\t# Result is of type ' + entry.GetResultName( ) if entry.wasProperty: print >> stream, '\t# The method %s is actually a property, but must be used as a method to correctly pass the arguments' % name ret = self.MakeFuncMethod(entry, build.MakePublicAttributeName(name)) for line in ret: print >> stream, line print >> stream, "\t_prop_map_get_ = {" names = self.propMap.keys() names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: resultName = entry.GetResultName() if resultName: print >> stream, "\t\t# Property '%s' is an object of type '%s'" % ( key, resultName) lkey = key.lower() details = entry.desc resultDesc = details[2] argDesc = () mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0] == pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0] == pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[ lkey] is None: # remember if a special one. specialItems[lkey] = (entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0] == pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % ( build.MakePublicAttributeName(key), mapEntry) names = self.propMapGet.keys() names.sort() for key in names: entry = self.propMapGet[key] if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, "\t\t# Method '%s' returns object of type '%s'" % ( key, entry.GetResultName()) details = entry.desc lkey = key.lower() argDesc = details[2] resultDesc = details[8] mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0] == pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0] == pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[ lkey] is None: # remember if a special one. specialItems[lkey] = (entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0] == pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % ( build.MakePublicAttributeName(key), mapEntry) print >> stream, "\t}" print >> stream, "\t_prop_map_put_ = {" # These are "Invoke" args names = list(self.propMap.keys()) names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: lkey = key.lower() details = entry.desc # If default arg is None, write an empty tuple defArgDesc = build.MakeDefaultArgRepr(details[2]) if defArgDesc is None: defArgDesc = "" else: defArgDesc = defArgDesc + "," print >> stream, '\t\t"%s" : ((%s, LCID, %d, 0),(%s)),' % ( build.MakePublicAttributeName(key), details[0], pythoncom.DISPATCH_PROPERTYPUT, defArgDesc) names = list(self.propMapPut.keys()) names.sort() for key in names: entry = self.propMapPut[key] if generator.bBuildHidden or not entry.hidden: details = entry.desc defArgDesc = MakeDefaultArgsForPropertyPut(details[2]) print >> stream, '\t\t"%s": ((%s, LCID, %d, 0),%s),' % ( build.MakePublicAttributeName(key), details[0], details[4], defArgDesc) print >> stream, "\t}" if specialItems["value"]: entry, invoketype, propArgs = specialItems["value"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry, '__call__') else: typename = "property" ret = [ "\tdef __call__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs ] print >> stream, "\t# Default %s for this class is '%s'" % ( typename, entry.names[0]) for line in ret: print >> stream, line if sys.version_info > (3, 0): print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__call__(*args))" else: print >> stream, "\tdef __unicode__(self, *args):" print >> stream, "\t\ttry:" print >> stream, "\t\t\treturn unicode(self.__call__(*args))" print >> stream, "\t\texcept pythoncom.com_error:" print >> stream, "\t\t\treturn repr(self)" print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__unicode__(*args))" print >> stream, "\tdef __int__(self, *args):" print >> stream, "\t\treturn int(self.__call__(*args))" if specialItems["_newenum"]: enumEntry, invoketype, propArgs = specialItems["_newenum"] resultCLSID = enumEntry.GetResultCLSIDStr() # If we dont have a good CLSID for the enum result, assume it is the same as the Item() method. if resultCLSID == "None" and "Item" in self.mapFuncs: resultCLSID = self.mapFuncs["Item"].GetResultCLSIDStr() # "Native" Python iterator support print >> stream, '\tdef __iter__(self):' print >> stream, '\t\t"Return a Python iterator for this object"' print >> stream, '\t\tob = self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),())' % ( pythoncom.DISPID_NEWENUM, enumEntry.desc[4]) print >> stream, '\t\treturn win32com.client.util.Iterator(ob, %s)' % resultCLSID # And 'old style' iterator support - magically used to simulate iterators # before Python grew them print >> stream, '\tdef _NewEnum(self):' print >> stream, '\t\t"Create an enumerator from this object"' print >> stream, '\t\treturn win32com.client.util.WrapEnum(self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),()),%s)' % ( pythoncom.DISPID_NEWENUM, enumEntry.desc[4], resultCLSID) print >> stream, '\tdef __getitem__(self, index):' print >> stream, '\t\t"Allow this class to be accessed as a collection"' print >> stream, "\t\tif '_enum_' not in self.__dict__:" print >> stream, "\t\t\tself.__dict__['_enum_'] = self._NewEnum()" print >> stream, "\t\treturn self._enum_.__getitem__(index)" else: # Not an Enumerator, but may be an "Item/Count" based collection if specialItems["item"]: entry, invoketype, propArgs = specialItems["item"] print >> stream, '\t#This class has Item property/method which may take args - allow indexed access' print >> stream, '\tdef __getitem__(self, item):' print >> stream, '\t\treturn self._get_good_object_(self._oleobj_.Invoke(*(%d, LCID, %d, 1, item)), "Item")' % ( entry.desc[0], invoketype) if specialItems["count"]: entry, invoketype, propArgs = specialItems["count"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry, '__len__') else: typename = "property" ret = [ "\tdef __len__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs ] print >> stream, "\t#This class has Count() %s - allow len(ob) to provide this" % ( typename) for line in ret: print >> stream, line # Also include a __nonzero__ print >> stream, "\t#This class has a __len__ - this is needed so 'if object:' always returns TRUE." print >> stream, "\tdef __nonzero__(self):" print >> stream, "\t\treturn True"
def WriteClassBody(self, generator): stream = generator.file # Write in alpha order. names = list(self.mapFuncs.keys()) names.sort() specialItems = {"count":None, "item":None,"value":None,"_newenum":None} # If found, will end up with (entry, invoke_tupe) itemCount = None for name in names: entry=self.mapFuncs[name] # skip [restricted] methods, unless it is the # enumerator (which, being part of the "system", # we know about and can use) dispid = entry.desc[0] if entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED and \ dispid != pythoncom.DISPID_NEWENUM: continue # If not accessible via IDispatch, then we can't use it here. if entry.desc[3] != pythoncom.FUNC_DISPATCH: continue if dispid==pythoncom.DISPID_VALUE: lkey = "value" elif dispid==pythoncom.DISPID_NEWENUM: specialItems["_newenum"] = (entry, entry.desc[4], None) continue # Dont build this one now! else: lkey = name.lower() if lkey in specialItems and specialItems[lkey] is None: # remember if a special one. specialItems[lkey] = (entry, entry.desc[4], None) if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, '\t# Result is of type ' + entry.GetResultName() if entry.wasProperty: print >> stream, '\t# The method %s is actually a property, but must be used as a method to correctly pass the arguments' % name ret = self.MakeFuncMethod(entry,build.MakePublicAttributeName(name)) for line in ret: print >> stream, line print >> stream, "\t_prop_map_get_ = {" names = self.propMap.keys(); names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: resultName = entry.GetResultName() if resultName: print >> stream, "\t\t# Property '%s' is an object of type '%s'" % (key, resultName) lkey = key.lower() details = entry.desc resultDesc = details[2] argDesc = () mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0]==pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0]==pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[lkey] is None: # remember if a special one. specialItems[lkey] = (entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0]==pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % (build.MakePublicAttributeName(key), mapEntry) names = self.propMapGet.keys(); names.sort() for key in names: entry = self.propMapGet[key] if generator.bBuildHidden or not entry.hidden: if entry.GetResultName(): print >> stream, "\t\t# Method '%s' returns object of type '%s'" % (key, entry.GetResultName()) details = entry.desc lkey = key.lower() argDesc = details[2] resultDesc = details[8] mapEntry = MakeMapLineEntry(details[0], pythoncom.DISPATCH_PROPERTYGET, resultDesc, argDesc, key, entry.GetResultCLSIDStr()) if entry.desc[0]==pythoncom.DISPID_VALUE: lkey = "value" elif entry.desc[0]==pythoncom.DISPID_NEWENUM: lkey = "_newenum" else: lkey = key.lower() if lkey in specialItems and specialItems[lkey] is None: # remember if a special one. specialItems[lkey]=(entry, pythoncom.DISPATCH_PROPERTYGET, mapEntry) # All special methods, except _newenum, are written # "normally". This is a mess! if entry.desc[0]==pythoncom.DISPID_NEWENUM: continue print >> stream, '\t\t"%s": %s,' % (build.MakePublicAttributeName(key), mapEntry) print >> stream, "\t}" print >> stream, "\t_prop_map_put_ = {" # These are "Invoke" args names = list(self.propMap.keys()); names.sort() for key in names: entry = self.propMap[key] if generator.bBuildHidden or not entry.hidden: lkey=key.lower() details = entry.desc # If default arg is None, write an empty tuple defArgDesc = build.MakeDefaultArgRepr(details[2]) if defArgDesc is None: defArgDesc = "" else: defArgDesc = defArgDesc + "," print >> stream, '\t\t"%s" : ((%s, LCID, %d, 0),(%s)),' % (build.MakePublicAttributeName(key), details[0], pythoncom.DISPATCH_PROPERTYPUT, defArgDesc) names = list(self.propMapPut.keys()); names.sort() for key in names: entry = self.propMapPut[key] if generator.bBuildHidden or not entry.hidden: details = entry.desc defArgDesc = MakeDefaultArgsForPropertyPut(details[2]) print >> stream, '\t\t"%s": ((%s, LCID, %d, 0),%s),' % (build.MakePublicAttributeName(key), details[0], details[4], defArgDesc) print >> stream, "\t}" if specialItems["value"]: entry, invoketype, propArgs = specialItems["value"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry,'__call__') else: typename = "property" ret = [ "\tdef __call__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs] print >> stream, "\t# Default %s for this class is '%s'" % (typename, entry.names[0]) for line in ret: print >> stream, line if sys.version_info > (3,0): print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__call__(*args))" else: print >> stream, "\tdef __unicode__(self, *args):" print >> stream, "\t\ttry:" print >> stream, "\t\t\treturn unicode(self.__call__(*args))" print >> stream, "\t\texcept pythoncom.com_error:" print >> stream, "\t\t\treturn repr(self)" print >> stream, "\tdef __str__(self, *args):" print >> stream, "\t\treturn str(self.__unicode__(*args))" print >> stream, "\tdef __int__(self, *args):" print >> stream, "\t\treturn int(self.__call__(*args))" # _NewEnum (DISPID_NEWENUM) does not appear in typelib for many office objects, # but it can still be retrieved at runtime, so always create __iter__. # Also, some of those same objects use 1-based indexing, causing the old-style # __getitem__ iteration to fail for index 0 where the dynamic iteration succeeds. if specialItems["_newenum"]: enumEntry, invoketype, propArgs = specialItems["_newenum"] invkind = enumEntry.desc[4] # ??? Wouldn't this be the resultCLSID for the iterator itself, rather than the resultCLSID # for the result of each Next() call, which is what it's used for ??? resultCLSID = enumEntry.GetResultCLSIDStr() else: invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET resultCLSID = "None" # If we dont have a good CLSID for the enum result, assume it is the same as the Item() method. if resultCLSID == "None" and "Item" in self.mapFuncs: resultCLSID = self.mapFuncs["Item"].GetResultCLSIDStr() print >> stream, '\tdef __iter__(self):' print >> stream, '\t\t"Return a Python iterator for this object"' print >> stream, '\t\ttry:' print >> stream, '\t\t\tob = self._oleobj_.InvokeTypes(%d,LCID,%d,(13, 10),())' % (pythoncom.DISPID_NEWENUM, invkind) print >> stream, '\t\texcept pythoncom.error:' print >> stream, '\t\t\traise TypeError("This object does not support enumeration")' # Iterator is wrapped as PyIEnumVariant, and each result of __next__ is Dispatch'ed if necessary print >> stream, '\t\treturn win32com.client.util.Iterator(ob, %s)' %resultCLSID if specialItems["item"]: entry, invoketype, propArgs = specialItems["item"] resultCLSID = entry.GetResultCLSIDStr() print >> stream, '\t#This class has Item property/method which allows indexed access with the object[key] syntax.' print >> stream, '\t#Some objects will accept a string or other type of key in addition to integers.' print >> stream, '\t#Note that many Office objects do not use zero-based indexing.' print >> stream, '\tdef __getitem__(self, key):' print >> stream, '\t\treturn self._get_good_object_(self._oleobj_.Invoke(*(%d, LCID, %d, 1, key)), "Item", %s)' \ % (entry.desc[0], invoketype, resultCLSID) if specialItems["count"]: entry, invoketype, propArgs = specialItems["count"] if propArgs is None: typename = "method" ret = self.MakeFuncMethod(entry,'__len__') else: typename = "property" ret = [ "\tdef __len__(self):\n\t\treturn self._ApplyTypes_(*%s)" % propArgs] print >> stream, "\t#This class has Count() %s - allow len(ob) to provide this" % (typename) for line in ret: print >> stream, line # Also include a __nonzero__ print >> stream, "\t#This class has a __len__ - this is needed so 'if object:' always returns TRUE." print >> stream, "\tdef __nonzero__(self):" print >> stream, "\t\treturn True"