def FindOutgoingInterface(source): """XXX Describe the strategy that is used...""" # If the COM object implements IProvideClassInfo2, it is easy to # find the default outgoing interface. try: pci = source.QueryInterface(comtypes.typeinfo.IProvideClassInfo2) guid = pci.GetGUID(1) except comtypes.COMError: pass else: # another try: block needed? try: interface = comtypes.com_interface_registry[str(guid)] except KeyError: tinfo = pci.GetClassInfo() tlib, index = tinfo.GetContainingTypeLib() GetModule(tlib) interface = comtypes.com_interface_registry[str(guid)] logger.debug("%s using sinkinterface %s", source, interface) return interface # If we can find the CLSID of the COM object, we can look for a # registered outgoing interface (__clsid has been set by # comtypes.client): clsid = source.__dict__.get('__clsid') try: interface = comtypes.com_coclass_registry[clsid]._outgoing_interfaces_[ 0] except KeyError: pass else: logger.debug("%s using sinkinterface from clsid %s", source, interface) return interface ## interface = find_single_connection_interface(source) ## if interface: ## return interface raise TypeError("cannot determine source interface")
def GetBestInterface(punk): """Try to QueryInterface a COM pointer to the 'most useful' interface. Get type information for the provided object, either via IDispatch.GetTypeInfo(), or via IProvideClassInfo.GetClassInfo(). Generate a wrapper module for the typelib, and QI for the interface found. """ if not punk: # NULL COM pointer return punk # or should we return None? # find the typelib and the interface name logger.debug("GetBestInterface(%s)", punk) try: try: pci = punk.QueryInterface(comtypes.typeinfo.IProvideClassInfo) logger.debug("Does implement IProvideClassInfo") except comtypes.COMError: # Some COM objects support IProvideClassInfo2, but not IProvideClassInfo. # These objects are broken, but we support them anyway. logger.debug( "Does NOT implement IProvideClassInfo, trying IProvideClassInfo2" ) pci = punk.QueryInterface(comtypes.typeinfo.IProvideClassInfo2) logger.debug("Does implement IProvideClassInfo2") tinfo = pci.GetClassInfo() # TypeInfo for the CoClass # find the interface marked as default ta = tinfo.GetTypeAttr() for index in range(ta.cImplTypes): if tinfo.GetImplTypeFlags(index) == 1: break else: if ta.cImplTypes != 1: # Hm, should we use dynamic now? raise TypeError("No default interface found") # Only one interface implemented, use that (even if # not marked as default). index = 0 href = tinfo.GetRefTypeOfImplType(index) tinfo = tinfo.GetRefTypeInfo(href) except comtypes.COMError: logger.debug("Does NOT implement IProvideClassInfo/IProvideClassInfo2") try: pdisp = punk.QueryInterface(comtypes.automation.IDispatch) except comtypes.COMError: logger.debug("No Dispatch interface: %s", punk) return punk try: tinfo = pdisp.GetTypeInfo(0) except comtypes.COMError: pdisp = comtypes.client.dynamic.Dispatch(pdisp) logger.debug("IDispatch.GetTypeInfo(0) failed: %s" % pdisp) return pdisp typeattr = tinfo.GetTypeAttr() logger.debug("Default interface is %s", typeattr.guid) try: punk.QueryInterface(comtypes.IUnknown, typeattr.guid) except comtypes.COMError: logger.debug( "Does not implement default interface, returning dynamic object") return comtypes.client.dynamic.Dispatch(punk) itf_name = tinfo.GetDocumentation(-1)[0] # interface name tlib = tinfo.GetContainingTypeLib()[0] # typelib # import the wrapper, generating it on demand mod = GetModule(tlib) # Python interface class interface = getattr(mod, itf_name) logger.debug("Implements default interface from typeinfo %s", interface) # QI for this interface # XXX # What to do if this fails? # In the following example the engine.Eval() call returns # such an object. # # engine = CreateObject("MsScriptControl.ScriptControl") # engine.Language = "JScript" # engine.Eval("[1, 2, 3]") # # Could the above code, as an optimization, check that QI works, # *before* generating the wrapper module? result = punk.QueryInterface(interface) logger.debug("Final result is %s", result) return result
pdisp = comtypes.client.dynamic.Dispatch(pdisp) logger.info("IDispatch.GetTypeInfo(0) failed: %s" % pdisp) return pdisp typeattr = tinfo.GetTypeAttr() logger.info("Default interface is %s", typeattr.guid) try: punk.QueryInterface(comtypes.IUnknown, typeattr.guid) except comtypes.COMError, details: logger.info("Does not implement default interface, returning dynamic object") return comtypes.client.dynamic.Dispatch(punk) itf_name = tinfo.GetDocumentation(-1)[0] # interface name tlib = tinfo.GetContainingTypeLib()[0] # typelib # import the wrapper, generating it on demand mod = GetModule(tlib) # Python interface class interface = getattr(mod, itf_name) logger.info("Implements default interface from typeinfo %s", interface) # QI for this interface # XXX # What to do if this fails? # In the following example the engine.Eval() call returns # such an object. # # engine = CreateObject("MsScriptControl.ScriptControl") # engine.Language = "JScript" # engine.Eval("[1, 2, 3]") # # Could the above code, as an optimization, check that QI works, # *before* generating the wrapper module?