def ShowInfo(spec): if not spec: tlbSpec = selecttlb.SelectTlb(excludeFlags=selecttlb.FLAG_HIDDEN) if tlbSpec is None: return try: tlb = pythoncom.LoadRegTypeLib(tlbSpec.clsid, tlbSpec.major, tlbSpec.minor, tlbSpec.lcid) except pythoncom.com_error: # May be badly registered. sys.stderr.write( "Warning - could not load registered typelib '%s'\n" % (tlbSpec.clsid)) tlb = None infos = [(tlb, tlbSpec)] else: infos = GetTypeLibsForSpec(spec) for (tlb, tlbSpec) in infos: desc = tlbSpec.desc if desc is None: if tlb is None: desc = "<Could not load typelib %s>" % (tlbSpec.dll) else: desc = tlb.GetDocumentation(-1)[0] print(desc) print(" %s, lcid=%s, major=%s, minor=%s" % (tlbSpec.clsid, tlbSpec.lcid, tlbSpec.major, tlbSpec.minor)) print( " >>> # Use these commands in Python code to auto generate .py support" ) print(" >>> from win32com.client import gencache") print(" >>> gencache.EnsureModule('%s', %s, %s, %s)" % (tlbSpec.clsid, tlbSpec.lcid, tlbSpec.major, tlbSpec.minor))
def GenerateChildFromTypeLibSpec(child, typelibInfo, verboseLevel = None, progressInstance = None, bUnicodeToString=None): assert bUnicodeToString is None, "this is deprecated and will go away" if verboseLevel is None: verboseLevel = 0 # By default, we use no gui, and no verbose level for the children. if type(typelibInfo)==type(()): typelibCLSID, lcid, major, minor = typelibInfo tlb = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid) else: tlb = typelibInfo tla = typelibInfo.GetLibAttr() typelibCLSID = tla[0] lcid = tla[1] major = tla[3] minor = tla[4] spec = selecttlb.TypelibSpec(typelibCLSID, lcid, major, minor) spec.FromTypelib(tlb, str(typelibCLSID)) typelibs = [(tlb, spec)] if progressInstance is None: progressInstance = SimpleProgress(verboseLevel) progress = progressInstance for typelib, info in typelibs: dir_name = gencache.GetGeneratedFileName(info.clsid, info.lcid, info.major, info.minor) dir_path_name = os.path.join(gencache.GetGeneratePath(), dir_name) progress.LogBeginGenerate(dir_path_name) gen = genpy.Generator(typelib, info.dll, progress) gen.generate_child(child, dir_path_name) progress.SetDescription("Importing module") __import__("win32com.gen_py." + dir_name + "." + child) progress.Close()
def GetTypeLibsForSpec(arg): """Given an argument on the command line (either a file name, library description, or ProgID of an object) return a list of actual typelibs to use. """ typelibs = [] try: try: tlb = pythoncom.LoadTypeLib(arg) spec = selecttlb.TypelibSpec(None, 0, 0, 0) spec.FromTypelib(tlb, arg) typelibs.append((tlb, spec)) except pythoncom.com_error: # See if it is a description tlbs = selecttlb.FindTlbsWithDescription(arg) if len(tlbs) == 0: # Maybe it is the name of a COM object? try: ob = Dispatch(arg) # and if so, it must support typelib info tlb, index = ob._oleobj_.GetTypeInfo( ).GetContainingTypeLib() spec = selecttlb.TypelibSpec(None, 0, 0, 0) spec.FromTypelib(tlb) tlbs.append(spec) except pythoncom.com_error: pass if len(tlbs) == 0: print("Could not locate a type library matching '%s'" % (arg)) for spec in tlbs: # Version numbers not always reliable if enumerated from registry. # (as some libs use hex, other's dont. Both examples from MS, of course.) if spec.dll is None: tlb = pythoncom.LoadRegTypeLib(spec.clsid, spec.major, spec.minor, spec.lcid) else: tlb = pythoncom.LoadTypeLib(spec.dll) # We have a typelib, but it may not be exactly what we specified # (due to automatic version matching of COM). So we query what we really have! attr = tlb.GetLibAttr() spec.major = attr[3] spec.minor = attr[4] spec.lcid = attr[1] typelibs.append((tlb, spec)) return typelibs except pythoncom.com_error: t, v, tb = sys.exc_info() sys.stderr.write("Unable to load type library from '%s' - %s\n" % (arg, v)) tb = None # Storing tb in a local is a cycle! sys.exit(1)
def _build_typeinfos_(self): # Can only ever be one for now. tlb_guid = getattr(self._obj_, '_typelib_guid_', None) if tlb_guid is None: return [] tlb_major, tlb_minor = getattr(self._obj_, '_typelib_version_', (1, 0)) tlb = pythoncom.LoadRegTypeLib(tlb_guid, tlb_major, tlb_minor) typecomp = tlb.GetTypeComp() # Not 100% sure what semantics we should use for the default interface. # Look for the first name in _com_interfaces_ that exists in the typelib. for iname in self._obj_._com_interfaces_: try: type_info, type_comp = typecomp.BindType(iname) if type_info is not None: return [type_info] except pythoncom.com_error: pass return []
def BuildOleItems(clsid): tlbs = selecttlb.EnumTlbs() tlbs = {tlb.clsid: tlb for tlb in tlbs} tlbSpec = tlbs.get(clsid) if tlbSpec is None: return {} raise LookupError('KHOpenAPI Module not found') if tlbSpec.dll is None: tlb = pythoncom.LoadRegTypeLib(tlbSpec.clsid, int(tlbSpec.major, 16), int(tlbSpec.minor, 16), tlbSpec.lcid) else: tlb = pythoncom.LoadTypeLib(tlbSpec.dll) gen = genpy.Generator(tlb, tlbSpec.dll, None, bBuildHidden=1) oleItems, _enumItems, _recordItems, _vtableItems = gen.BuildOleItemsFromType() oleItems = {str(clsId): oleItem for clsId, oleItem in oleItems.items()} return oleItems
def RegisterInterfaces(typelibGUID, lcid, major, minor, interface_names=None): ret = [] # return a list of (dispid, funcname for our policy's benefit # First see if we have makepy support. If so, we can probably satisfy the request without loading the typelib. try: mod = gencache.GetModuleForTypelib(typelibGUID, lcid, major, minor) except ImportError: mod = None if mod is None: import win32com.client.build # Load up the typelib and build (but don't cache) it now tlb = pythoncom.LoadRegTypeLib(typelibGUID, major, minor, lcid) typecomp_lib = tlb.GetTypeComp() if interface_names is None: interface_names = [] for i in range(tlb.GetTypeInfoCount()): info = tlb.GetTypeInfo(i) doc = tlb.GetDocumentation(i) attr = info.GetTypeAttr() if attr.typekind == pythoncom.TKIND_INTERFACE or \ (attr.typekind == pythoncom.TKIND_DISPATCH and attr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL): interface_names.append(doc[0]) for name in interface_names: type_info, type_comp = typecomp_lib.BindType(name, ) # Not sure why we don't get an exception here - BindType's C # impl looks correct.. if type_info is None: raise ValueError("The interface '%s' can not be located" % (name, )) # If we got back a Dispatch interface, convert to the real interface. attr = type_info.GetTypeAttr() if attr.typekind == pythoncom.TKIND_DISPATCH: refhtype = type_info.GetRefTypeOfImplType(-1) type_info = type_info.GetRefTypeInfo(refhtype) attr = type_info.GetTypeAttr() item = win32com.client.build.VTableItem( type_info, attr, type_info.GetDocumentation(-1)) _doCreateVTable(item.clsid, item.python_name, item.bIsDispatch, item.vtableFuncs) for info in item.vtableFuncs: names, dispid, desc = info invkind = desc[4] ret.append((dispid, invkind, names[0])) else: # Cool - can used cached info. if not interface_names: interface_names = list(mod.VTablesToClassMap.values()) for name in interface_names: try: iid = mod.NamesToIIDMap[name] except KeyError: raise ValueError( "Interface '%s' does not exist in this cached typelib" % (name, )) # print "Processing interface", name sub_mod = gencache.GetModuleForCLSID(iid) is_dispatch = getattr(sub_mod, name + "_vtables_dispatch_", None) method_defs = getattr(sub_mod, name + "_vtables_", None) if is_dispatch is None or method_defs is None: raise ValueError("Interface '%s' is IDispatch only" % (name, )) # And create the univgw defn _doCreateVTable(iid, name, is_dispatch, method_defs) for info in method_defs: names, dispid, desc = info invkind = desc[4] ret.append((dispid, invkind, names[0])) return ret
def EnsureModule( typelibCLSID, lcid, major, minor, progressInstance=None, bValidateFile=not is_readonly, bForDemand=bForDemandDefault, bBuildHidden=1, ): """Ensure Python support is loaded for a type library, generating if necessary. Given the IID, LCID and version information for a type library, check and if necessary (re)generate, then import the necessary support files. If we regenerate the file, there is no way to totally snuff out all instances of the old module in Python, and thus we will regenerate the file more than necessary, unless makepy/genpy is modified accordingly. Returns the Python module. No exceptions are caught during the generate process. Params typelibCLSID -- IID of the type library. major -- Integer major version. minor -- Integer minor version lcid -- Integer LCID for the library. progressInstance -- Instance to use as progress indicator, or None to use the GUI progress bar. bValidateFile -- Whether or not to perform cache validation or not bForDemand -- Should a complete generation happen now, or on demand? bBuildHidden -- Should hidden members/attributes etc be generated? """ bReloadNeeded = 0 try: try: module = GetModuleForTypelib(typelibCLSID, lcid, major, minor) except ImportError: # If we get an ImportError # We may still find a valid cache file under a different MinorVersion # # (which windows will search out for us) # print "Loading reg typelib", typelibCLSID, major, minor, lcid module = None try: tlbAttr = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr() # if the above line doesn't throw a pythoncom.com_error, check if # it is actually a different lib than we requested, and if so, suck it in if tlbAttr[1] != lcid or tlbAttr[4] != minor: # print "Trying 2nd minor #", tlbAttr[1], tlbAttr[3], tlbAttr[4] try: module = GetModuleForTypelib(typelibCLSID, tlbAttr[1], tlbAttr[3], tlbAttr[4]) except ImportError: # We don't have a module, but we do have a better minor # version - remember that. minor = tlbAttr[4] # else module remains None except pythoncom.com_error: # couldn't load any typelib - mod remains None pass if module is not None and bValidateFile: assert not is_readonly, "Can't validate in a read-only gencache" try: typLibPath = pythoncom.QueryPathOfRegTypeLib( typelibCLSID, major, minor, lcid) # windows seems to add an extra \0 (via the underlying BSTR) # The mainwin toolkit does not add this erroneous \0 if typLibPath[-1] == "\0": typLibPath = typLibPath[:-1] suf = getattr(os.path, "supports_unicode_filenames", 0) if not suf: # can't pass unicode filenames directly - convert try: typLibPath = typLibPath.encode( sys.getfilesystemencoding()) except AttributeError: # no sys.getfilesystemencoding typLibPath = str(typLibPath) tlbAttributes = pythoncom.LoadRegTypeLib( typelibCLSID, major, minor, lcid).GetLibAttr() except pythoncom.com_error: # We have a module, but no type lib - we should still # run with what we have though - the typelib may not be # deployed here. bValidateFile = 0 if module is not None and bValidateFile: assert not is_readonly, "Can't validate in a read-only gencache" filePathPrefix = "%s\\%s" % ( GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor), ) filePath = filePathPrefix + ".py" filePathPyc = filePathPrefix + ".py" if __debug__: filePathPyc = filePathPyc + "c" else: filePathPyc = filePathPyc + "o" # Verify that type library is up to date. # If we have a differing MinorVersion or genpy has bumped versions, update the file from . import genpy if (module.MinorVersion != tlbAttributes[4] or genpy.makepy_version != module.makepy_version): # print "Version skew: %d, %d" % (module.MinorVersion, tlbAttributes[4]) # try to erase the bad file from the cache try: os.unlink(filePath) except os.error: pass try: os.unlink(filePathPyc) except os.error: pass if os.path.isdir(filePathPrefix): import shutil shutil.rmtree(filePathPrefix) minor = tlbAttributes[4] module = None bReloadNeeded = 1 else: minor = module.MinorVersion filePathPrefix = "%s\\%s" % ( GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor), ) filePath = filePathPrefix + ".py" filePathPyc = filePathPrefix + ".pyc" # print "Trying py stat: ", filePath fModTimeSet = 0 try: pyModTime = os.stat(filePath)[8] fModTimeSet = 1 except os.error as e: # If .py file fails, try .pyc file # print "Trying pyc stat", filePathPyc try: pyModTime = os.stat(filePathPyc)[8] fModTimeSet = 1 except os.error as e: pass # print "Trying stat typelib", pyModTime # print str(typLibPath) typLibModTime = os.stat(typLibPath)[8] if fModTimeSet and (typLibModTime > pyModTime): bReloadNeeded = 1 module = None except (ImportError, os.error): module = None if module is None: # We need to build an item. If we are in a read-only cache, we # can't/don't want to do this - so before giving up, check for # a different minor version in our cache - according to COM, this is OK if is_readonly: key = str(typelibCLSID), lcid, major, minor # If we have been asked before, get last result. try: return versionRedirectMap[key] except KeyError: pass # Find other candidates. items = [] for desc in GetGeneratedInfos(): if key[0] == desc[0] and key[1] == desc[1] and key[2] == desc[ 2]: items.append(desc) if items: # Items are all identical, except for last tuple element # We want the latest minor version we have - so just sort and grab last items.sort() new_minor = items[-1][3] ret = GetModuleForTypelib(typelibCLSID, lcid, major, new_minor) else: ret = None # remember and return versionRedirectMap[key] = ret return ret # print "Rebuilding: ", major, minor module = MakeModuleForTypelib( typelibCLSID, lcid, major, minor, progressInstance, bForDemand=bForDemand, bBuildHidden=bBuildHidden, ) # If we replaced something, reload it if bReloadNeeded: module = reload(module) AddModuleToCache(typelibCLSID, lcid, major, minor) return module
def GenerateFromTypeLibSpec(typelibInfo, file = None, verboseLevel = None, progressInstance = None, bUnicodeToString=None, bForDemand = bForDemandDefault, bBuildHidden = 1): assert bUnicodeToString is None, "this is deprecated and will go away" if verboseLevel is None: verboseLevel = 0 # By default, we use no gui and no verbose level! if bForDemand and file is not None: raise RuntimeError("You can only perform a demand-build when the output goes to the gen_py directory") if isinstance(typelibInfo, tuple): # Tuple typelibCLSID, lcid, major, minor = typelibInfo tlb = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid) spec = selecttlb.TypelibSpec(typelibCLSID, lcid, major, minor) spec.FromTypelib(tlb, str(typelibCLSID)) typelibs = [(tlb, spec)] elif isinstance(typelibInfo, selecttlb.TypelibSpec): if typelibInfo.dll is None: # Version numbers not always reliable if enumerated from registry. tlb = pythoncom.LoadRegTypeLib(typelibInfo.clsid, typelibInfo.major, typelibInfo.minor, typelibInfo.lcid) else: tlb = pythoncom.LoadTypeLib(typelibInfo.dll) typelibs = [(tlb, typelibInfo)] elif hasattr(typelibInfo, "GetLibAttr"): # A real typelib object! # Could also use isinstance(typelibInfo, PyITypeLib) instead, but PyITypeLib is not directly exposed by pythoncom. # pythoncom.TypeIIDs[pythoncom.IID_ITypeLib] seems to work tla = typelibInfo.GetLibAttr() guid = tla[0] lcid = tla[1] major = tla[3] minor = tla[4] spec = selecttlb.TypelibSpec(guid, lcid, major, minor) typelibs = [(typelibInfo, spec)] else: typelibs = GetTypeLibsForSpec(typelibInfo) if progressInstance is None: progressInstance = SimpleProgress(verboseLevel) progress = progressInstance bToGenDir = (file is None) for typelib, info in typelibs: gen = genpy.Generator(typelib, info.dll, progress, bBuildHidden=bBuildHidden) if file is None: this_name = gencache.GetGeneratedFileName(info.clsid, info.lcid, info.major, info.minor) full_name = os.path.join(gencache.GetGeneratePath(), this_name) if bForDemand: try: os.unlink(full_name + ".py") except os.error: pass try: os.unlink(full_name + ".pyc") except os.error: pass try: os.unlink(full_name + ".pyo") except os.error: pass if not os.path.isdir(full_name): os.mkdir(full_name) outputName = os.path.join(full_name, "__init__.py") else: outputName = full_name + ".py" fileUse = gen.open_writer(outputName) progress.LogBeginGenerate(outputName) else: fileUse = file worked = False try: gen.generate(fileUse, bForDemand) worked = True finally: if file is None: gen.finish_writer(outputName, fileUse, worked) if bToGenDir: progress.SetDescription("Importing module") gencache.AddModuleToCache(info.clsid, info.lcid, info.major, info.minor) progress.Close()
def EnsureModule(typelibCLSID, lcid, major, minor, progressInstance=None, bValidateFile=1, bForDemand=bForDemandDefault, bBuildHidden=1): """Ensure Python support is loaded for a type library, generating if necessary. Given the IID, LCID and version information for a type library, check and if necessary (re)generate, then import the necessary support files. If we regenerate the file, there is no way to totally snuff out all instances of the old module in Python, and thus we will regenerate the file more than necessary, unless makepy/genpy is modified accordingly. Returns the Python module. No exceptions are caught during the generate process. Params typelibCLSID -- IID of the type library. major -- Integer major version. minor -- Integer minor version lcid -- Integer LCID for the library. progressInstance -- Instance to use as progress indicator, or None to use the GUI progress bar. bValidateFile -- Whether or not to perform cache validation or not bForDemand -- Should a complete generation happen now, or on demand? bBuildHidden -- Should hidden members/attributes etc be generated? """ bReloadNeeded = 0 try: try: #print "Try specified typelib" module = GetModuleForTypelib(typelibCLSID, lcid, major, minor) #print module except ImportError: # If we get an ImportError # We may still find a valid cache file under a different MinorVersion # #print "Loading reg typelib" tlbAttr = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr() # if the above line doesn't throw a pythoncom.com_error # Let's suck it in #print "Trying 2nd minor #", tlbAttr[1], tlbAttr[3], tlbAttr[4] try: module = GetModuleForTypelib(typelibCLSID, tlbAttr[1], tlbAttr[3], tlbAttr[4]) except ImportError: module = None minor = tlbAttr[4] if module is not None and bValidateFile: try: typLibPath = pythoncom.QueryPathOfRegTypeLib( typelibCLSID, major, minor, lcid) tlbAttributes = pythoncom.LoadRegTypeLib( typelibCLSID, major, minor, lcid).GetLibAttr() except pythoncom.com_error: # We have a module, but no type lib - we should still # run with what we have though - the typelib may not be # deployed here. bValidateFile = 0 if module is not None and bValidateFile: filePathPrefix = "%s\\%s" % (GetGeneratePath(), GetGeneratedFileName( typelibCLSID, lcid, major, minor)) filePath = filePathPrefix + ".py" filePathPyc = filePathPrefix + ".py" if __debug__: filePathPyc = filePathPyc + "c" else: filePathPyc = filePathPyc + "o" # Verify that type library is up to date. #print "Grabbing typelib" # If the following doesn't throw an exception, then we have a valid type library typLibPath = pythoncom.QueryPathOfRegTypeLib( typelibCLSID, major, minor, lcid) tlbAttributes = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr() #print "Grabbed typelib: ", tlbAttributes[3], tlbAttributes[4] ##print module.MinorVersion # If we have a differing MinorVersion or genpy has bumped versions, update the file import genpy if module.MinorVersion != tlbAttributes[ 4] or genpy.makepy_version != module.makepy_version: #print "Version skew: %d, %d" % (module.MinorVersion, tlbAttributes[4]) # try to erase the bad file from the cache try: os.unlink(filePath) except os.error: pass try: os.unlink(filePathPyc) except os.error: pass if os.path.isdir(filePathPrefix): import shutil shutil.rmtree(filePathPrefix) minor = tlbAttributes[4] module = None bReloadNeeded = 1 else: minor = module.MinorVersion filePathPrefix = "%s\\%s" % ( GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor)) filePath = filePathPrefix + ".py" filePathPyc = filePathPrefix + ".pyc" #print "Trying py stat: ", filePath fModTimeSet = 0 try: pyModTime = os.stat(filePath)[8] fModTimeSet = 1 except os.error, e: # If .py file fails, try .pyc file #print "Trying pyc stat", filePathPyc try: pyModTime = os.stat(filePathPyc)[8] fModTimeSet = 1 except os.error, e: pass #print "Trying stat typelib", pyModTime #print str(typLibPath) typLibModTime = os.stat(str(typLibPath[:-1]))[8] if fModTimeSet and (typLibModTime > pyModTime): bReloadNeeded = 1 module = None
def GenerateFromTypeLibSpec(typelibInfo, file = None, verboseLevel = None, progressInstance = None, bUnicodeToString=NeedUnicodeConversions, bForDemand = bForDemandDefault, bBuildHidden = 1): if verboseLevel is None: verboseLevel = 0 # By default, we use no gui and no verbose level! if bForDemand and file is not None: raise RuntimeError, "You can only perform a demand-build when the output goes to the gen_py directory" if type(typelibInfo)==type(()): # Tuple typelibCLSID, lcid, major, minor = typelibInfo tlb = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid) spec = selecttlb.TypelibSpec(typelibCLSID, lcid, major, minor) spec.FromTypelib(tlb, str(typelibCLSID)) typelibs = [(tlb, spec)] elif type(typelibInfo)==types.InstanceType: if typelibInfo.dll is None: # Version numbers not always reliable if enumerated from registry. tlb = pythoncom.LoadRegTypeLib(typelibInfo.clsid, typelibInfo.major, typelibInfo.minor, typelibInfo.lcid) else: tlb = pythoncom.LoadTypeLib(typelibInfo.dll) typelibs = [(tlb, typelibInfo)] elif hasattr(typelibInfo, "GetLibAttr"): # A real typelib object! tla = typelibInfo.GetLibAttr() guid = tla[0] lcid = tla[1] major = tla[3] minor = tla[4] spec = selecttlb.TypelibSpec(guid, lcid, major, minor) typelibs = [(typelibInfo, spec)] else: typelibs = GetTypeLibsForSpec(typelibInfo) if progressInstance is None: progressInstance = SimpleProgress(verboseLevel) progress = progressInstance bToGenDir = (file is None) for typelib, info in typelibs: if file is None: this_name = gencache.GetGeneratedFileName(info.clsid, info.lcid, info.major, info.minor) full_name = os.path.join(gencache.GetGeneratePath(), this_name) if bForDemand: try: os.unlink(full_name + ".py") except os.error: pass try: os.unlink(full_name + ".pyc") except os.error: pass try: os.unlink(full_name + ".pyo") except os.error: pass if not os.path.isdir(full_name): os.mkdir(full_name) outputName = os.path.join(full_name, "__init__.py") else: outputName = full_name + ".py" # generate to a temp file (so errors don't leave a 1/2 # generated file) and one which can handle unicode! try: os.unlink(outputName) except os.error: pass encoding = 'mbcs' # could make this a param. fileUse = codecs.open(outputName + ".temp", "wt", encoding) progress.LogBeginGenerate(outputName) else: fileUse = file gen = genpy.Generator(typelib, info.dll, progress, bUnicodeToString=bUnicodeToString, bBuildHidden=bBuildHidden) gen.generate(fileUse, bForDemand) if file is None: fileUse.close() os.rename(outputName + ".temp", outputName) if bToGenDir: progress.SetDescription("Importing module") gencache.AddModuleToCache(info.clsid, info.lcid, info.major, info.minor) progress.Close()