Accessing unregistered COM objects from python via a registered TLB

前端 未结 3 925
悲&欢浪女
悲&欢浪女 2020-12-13 11:14

I have three pieces of code that i\'m working with at the moment:

  • A closed source application (Main.exe)
  • A closed source VB COM object implemented as
相关标签:
3条回答
  • 2020-12-13 11:38

    What I did to access Free Download Manager's type library was the following:

    import pythoncom, win32com.client
    
    fdm = pythoncom.LoadTypeLib('fdm.tlb')
    downloads_stat = None
    
    for index in xrange(0, fdm.GetTypeInfoCount()):
        type_name = fdm.GetDocumentation(index)[0]
    
        if type_name == 'FDMDownloadsStat':
            type_iid = fdm.GetTypeInfo(index).GetTypeAttr().iid
            downloads_stat = win32com.client.Dispatch(type_iid)
            break
    
    downloads_stat.BuildListOfDownloads(True, True)
    print downloads_stat.Download(0).Url
    

    The code above will print the URL of the first download.

    0 讨论(0)
  • 2020-12-13 11:47

    Here is a method I devised to load a COM object from a DLL. It was based on a lot of reading about COM, etc. I'm not 100% sure about the last lines, specifically d=. I think that only works if IID_Dispatch is passed in (which you can see if the default param).

    In addition, I believe this code leaks - for one, the DLL is never unloaded (use ctypes.windll.kernel32.FreeLibraryW) and I believe the COM ref counts for the initial class factory are off by one, and thus never get released. But still, this works for my application.

    import pythoncom
    import win32com.client
    def CreateInstanceFromDll(dll, clsid_class, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None, dwClsContext=pythoncom.CLSCTX_SERVER):
        from uuid import UUID
        from ctypes import OleDLL, c_long, byref
        e = OleDLL(dll)
        clsid_class = UUID(clsid_class).bytes_le
        iclassfactory = UUID(str(pythoncom.IID_IClassFactory)).bytes_le
        com_classfactory = c_long(0)
        hr = e.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory))
        MyFactory = pythoncom.ObjectFromAddress(com_classfactory.value, pythoncom.IID_IClassFactory)
        i = MyFactory.CreateInstance(pUnkOuter, iid_interface)
        d = win32com.client.__WrapDispatch(i)
        return d
    
    0 讨论(0)
  • 2020-12-13 11:49

    For a useful utility module that wraps the object-from-DLL case, as well as others, see https://gist.github.com/4219140

    __all__ = (
        ####### Class Objects
    
        #CoGetClassObject - Normal, not wrapped
        'CoDllGetClassObject', #Get ClassObject from a DLL file
    
        ####### ClassFactory::CreateInstance Wrappers
    
        'CoCreateInstanceFromFactory', #Create an object via IClassFactory::CreateInstance
        'CoCreateInstanceFromFactoryLicenced', #Create a licenced object via IClassFactory2::CreateInstanceLic
    
        ###### Util
    
        'CoReleaseObject', #Calls Release() on a COM object
    
        ###### Main Utility Methods
    
        #'CoCreateInstance', #Not wrapped, normal call
        'CoCreateInstanceLicenced', #CoCreateInstance, but with a licence key
    
        ###### Hacky DLL methods for reg-free COM without Activation Contexts, manifests, etc
        'CoCreateInstanceFromDll', #Given a dll, a clsid, and an iid, create an object
        'CoCreateInstanceFromDllLicenced', #Given a dll, a clsid, an iid, and a license key, create an object
    )
    
    IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}"
    
    from uuid import UUID
    from ctypes import OleDLL, WinDLL, c_ulong, byref, WINFUNCTYPE, POINTER, c_char_p, c_void_p
    from ctypes.wintypes import HRESULT
    import pythoncom
    import win32com.client
    
    import logging
    log = logging.getLogger(__name__)
    
    
    def _raw_guid(guid):
        """Given a string GUID, or a pythoncom IID, return the GUID laid out in memory suitable for passing to ctypes"""
        return UUID(str(guid)).bytes_le
    
    proto_icf2_base = WINFUNCTYPE(HRESULT,
        c_ulong,
        c_ulong,
        c_char_p,
        c_ulong,
        POINTER(c_ulong),
    )
    IClassFactory2__CreateInstanceLic = proto_icf2_base(7, 'CreateInstanceLic', (
        (1, 'pUnkOuter'),
        (1 | 4, 'pUnkReserved'),
        (1, 'riid'),
        (1, 'bstrKey'),
        (2, 'ppvObj'),
        ), _raw_guid(IID_IClassFactory2))
    
    #--------------------------------
    #--------------------------------
    
    def _pc_wrap(iptr, resultCLSID=None):
        #return win32com.client.__WrapDispatch(iptr)
        log.debug("_pc_wrap: %s, %s"%(iptr, resultCLSID))
        disp = win32com.client.Dispatch(iptr, resultCLSID=resultCLSID)
        log.debug("_pc_wrap: %s (%s)", disp.__class__.__name__, disp)
        return disp
    
    def CoCreateInstanceFromFactory(factory_ptr, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None):
        """Given a factory_ptr whose interface is IClassFactory, create the instance of clsid_class with the specified interface"""
        ClassFactory = pythoncom.ObjectFromAddress(factory_ptr.value, pythoncom.IID_IClassFactory)
        i = ClassFactory.CreateInstance(pUnkOuter, iid_interface)
        return i
    
    def CoCreateInstanceFromFactoryLicenced(factory_ptr, key, iid_interface=pythoncom.IID_IDispatch, pUnkOuter=None):
        """Given a factory_ptr whose interface is IClassFactory2, create the instance of clsid_class with the specified interface"""
        requested_iid = _raw_guid(iid_interface)
    
        ole_aut = WinDLL("OleAut32.dll")
        key_bstr = ole_aut.SysAllocString(unicode(key))
        try:
            obj = IClassFactory2__CreateInstanceLic(factory_ptr, pUnkOuter or 0, c_char_p(requested_iid), key_bstr)
            disp_obj = pythoncom.ObjectFromAddress(obj, iid_interface)
            return disp_obj
        finally:
            if key_bstr:
                ole_aut.SysFreeString(key_bstr)
    
    #----------------------------------
    
    def CoReleaseObject(obj_ptr):
        """Calls Release() on a COM object. obj_ptr should be a c_void_p"""
        if not obj_ptr:
            return
        IUnknown__Release = WINFUNCTYPE(HRESULT)(2, 'Release', (), pythoncom.IID_IUnknown)
        IUnknown__Release(obj_ptr)
    
    #-----------------------------------
    
    def CoCreateInstanceLicenced(clsid_class, key, pythoncom_iid_interface=pythoncom.IID_IDispatch, dwClsContext=pythoncom.CLSCTX_SERVER, pythoncom_wrapdisp=True, wrapas=None):
        """Uses IClassFactory2::CreateInstanceLic to create a COM object given a licence key."""
        IID_IClassFactory2 = "{B196B28F-BAB4-101A-B69C-00AA00341D07}"
        ole = OleDLL("Ole32.dll")
        clsid_class_raw = _raw_guid(clsid_class)
        iclassfactory2 = _raw_guid(IID_IClassFactory2)
        com_classfactory = c_void_p(0)
    
        ole.CoGetClassObject(clsid_class_raw, dwClsContext, None, iclassfactory2, byref(com_classfactory))
        try:
            iptr = CoCreateInstanceFromFactoryLicenced(
                    factory_ptr = com_classfactory,
                    key=key,
                    iid_interface=pythoncom_iid_interface,
                    pUnkOuter=None,
            )
            if pythoncom_wrapdisp:
                return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
            return iptr
        finally:
            if com_classfactory:
                CoReleaseObject(com_classfactory)
    
    #-----------------------------------------------------------
    #DLLs
    
    def CoDllGetClassObject(dll_filename, clsid_class, iid_factory=pythoncom.IID_IClassFactory):
        """Given a DLL filename and a desired class, return the factory for that class (as a c_void_p)"""
        dll = OleDLL(dll_filename)
        clsid_class = _raw_guid(clsid_class)
        iclassfactory = _raw_guid(iid_factory)
        com_classfactory = c_void_p(0)
        dll.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory))
        return com_classfactory
    
    def CoCreateInstanceFromDll(dll, clsid_class, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None):
        iclassfactory_ptr = CoDllGetClassObject(dll, clsid_class)
        try:
            iptr = CoCreateInstanceFromFactory(iclassfactory_ptr, iid_interface)
            if pythoncom_wrapdisp:
                return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
            return iptr
        finally:
            CoReleaseObject(iclassfactory_ptr)
    
    def CoCreateInstanceFromDllLicenced(dll, clsid_class, key, iid_interface=pythoncom.IID_IDispatch, pythoncom_wrapdisp=True, wrapas=None):
        iclassfactory2_ptr = CoDllGetClassObject(dll, clsid_class, iid_factory=IID_IClassFactory2)
        try:
            iptr = CoCreateInstanceFromFactoryLicenced(iclassfactory2_ptr, key, iid_interface)
            if pythoncom_wrapdisp:
                return _pc_wrap(iptr, resultCLSID=wrapas or clsid_class)
            return iptr
        finally:
            CoReleaseObject(iclassfactory2_ptr)
    
    0 讨论(0)
提交回复
热议问题