Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x 从Python访问COM方法_Python 3.x_Com - Fatal编程技术网

Python 3.x 从Python访问COM方法

Python 3.x 从Python访问COM方法,python-3.x,com,Python 3.x,Com,我有一个旧的Windows DLL,没有源代码,它实现了一个实用函数表。几年前,计划将其转换为COM对象,以便实现IUnknown接口。要使用此DLL,有一个头文件(简化): 但没有为IFunctions接口定义CLSID。最终,头文件中的接口定义不符合COM标准 从C++中,DLL可以加载 CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, clsid, ptr); 使用“ptr”中的一些指针算法,我找到了Function1()等的地址。由于它工

我有一个旧的Windows DLL,没有源代码,它实现了一个实用函数表。几年前,计划将其转换为COM对象,以便实现IUnknown接口。要使用此DLL,有一个头文件(简化):

但没有为IFunctions接口定义CLSID。最终,头文件中的接口定义不符合COM标准

从C++中,DLL可以加载

CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, clsid, ptr);
使用“ptr”中的一些指针算法,我找到了Function1()等的地址。由于它工作,没有完成完整的COM实现,因此我无法查询IFunctions接口,因为该接口不是COM接口。在Windows注册表中,我只找到对象的CLSID和DLL在ProcServer32中的引用

我在Python方面没有太多的经验,但我需要使用Python中的这个DLL,可能使用ctypes和comtypes。我可以使用(注册表中的CLSID)加载DLL

我知道在COM对象function1()的VTable中,address正好位于QueryInterface()、AddRef()、Release()之后,但我找不到实现如下类的解决方案:

class DllFunction:
    # not necessary, but for completeness ...
    def QueryInterface(self, interface, iid=None):
        return unk.QueryInterface(comtypes.IUnknown)
    def AddRef(slef):
        return unk.AddRef()
    def Release(self):
        return unk.Release()
    # Functions I actually need to call from Python
    def Function1(self, p1, p2):
        # what to do ??
    def Function2(self, p1):
    # etc.

我想在Python中实现这个解决方案,试图避免在C++中扩展模块的开发。


感谢您的帮助。

感谢您提供了一些提示。实际上我无法修复DLL,因为我没有源代码。在C++中封装它是一种选择,但是在C中开发一个Python模块听起来更好。 我的计划是只使用Python,可能没有额外的模块,所以我设法只使用ctypes来解决这个问题。下面的代码显示了解决方案。它可以工作,但需要一些改进(错误检查等)


我希望这个例子对某些人有用。它可以用来封装COM对象而不使用CAMType,而对我来说,它可以解释cType是如何工作的。

似乎不太可能,您最好是修复DLL,或者在C++中制作一个包装器,它可以提供一个完整的COM接口。因为它是日语,请使用谷歌翻译等进行阅读。看起来很累人:/I我特别坚持,即使是“标准”win api com函数,也有必要用Python完成所有这些吗?
unk = CreateObject('{11111111-2222-3333-4444-555555555555}', clsctx=comtypes.CLSCTX_INPROC_SERVER)
class DllFunction:
    # not necessary, but for completeness ...
    def QueryInterface(self, interface, iid=None):
        return unk.QueryInterface(comtypes.IUnknown)
    def AddRef(slef):
        return unk.AddRef()
    def Release(self):
        return unk.Release()
    # Functions I actually need to call from Python
    def Function1(self, p1, p2):
        # what to do ??
    def Function2(self, p1):
    # etc.
'''
    Simple example of how to use the DLL from Python on Win32.

    We need only ctypes.
'''
import ctypes
from ctypes import *
'''
    We need a class to mirror GUID structure
'''
class GUID(Structure):
    _fields_ = [("Data1", c_ulong),
                ("Data2", c_ushort),
                ("Data3", c_ushort),
                ("Data4", c_ubyte * 8)]

if __name__ == "__main__":
    '''
        COM APIs to activate/deactivate COM environment and load the COM object
    '''
    ole32=WinDLL('Ole32.dll')
    CoInitialize = ole32.CoInitialize
    CoUninitialize = ole32.CoUninitialize
    CoCreateInstance = ole32.CoCreateInstance
    '''
        COM environment initialization
    '''
    rc = CoInitialize(None)
    '''
        To use CoCreate Instance in C (not C++):
            void * driver = NULL;
            rc = CoCreateInstance(&IID_Driver,      // CLSID of the COM object
                           0,                       // no aggregation
                           CLSCTX_INPROC_SERVER,    // CLSCTX_INPROC_SERVER = 1
                           &IID_Driver,             // CLSID of the required interface
                           (void**)&driver);        // result
        In Python it is:
    '''
    clsid = GUID(0x11111111, 0x2222, 0x3333, 
               (0x44, 0x44, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55))
    drv = c_void_p(None)
    rc = CoCreateInstance(byref(clsid), 0, 1, byref(clsid), byref(drv))
    '''
        Pointers manipulation. Short form:
        function = cast( c_void_p( cast(drv, POINTER(c_void_p))[0] ), POINTER(c_void_p))
    '''
    VTable = cast(drv, POINTER(c_void_p))
    wk = c_void_p(VTable[0])
    function = cast(wk, POINTER(c_void_p))
    #print('VTbale address: ', hex(VTable[0]))
    #print('QueryInterface address: ', hex(function[0]))
    #print('AddRef address: ', hex(function[1]))
    #print('Release address: ', hex(function[2]))
    '''
        To define functions from their addresses we first need to define their WINFUNCTYPE.
        In C we call QueryInterface:
            HRESULT rc = driver->lpVtbl->QueryInterface(driver, &IID_IUnknown, (void**)&iUnk);
        So we need a long (HRESULT) return value and three pointers. It would be better to be
        more accurate in pointer types, but ... it works!
        We can use whatever names we want for function types and functions
    '''
    QueryInterfaceType = WINFUNCTYPE(c_long, c_void_p, c_void_p, c_void_p)
    QueryInterface = QueryInterfaceType(function[0])
    AddRefType = WINFUNCTYPE(c_ulong, c_void_p)
    AddRef = AddRefType(function[1])
    ReleaseType = WINFUNCTYPE(c_ulong, c_void_p)
    Release = ReleaseType(function[2])
    '''
        The same for other functions, but library functions do not want 'this':
            long rc = driver->lpVtbl->init(0);
    '''
    doThisType = WINFUNCTYPE(c_long, c_void_p)
    doThis=doThisType(function[3])

    getNameType = WINFUNCTYPE(c_int, c_char_p)
    getName = getNameType(function[4])
    getName.restype = None      # to have None since function is void

    getVersionType = WINFUNCTYPE(c_long)
    getVersion = getVersionType(function[5])

    getMessageType = WINFUNCTYPE(c_int, c_char_p)
    getMessage = getMessageType(function[6])
    getMessage.restype = None       # to have None since function is void
    '''
        Now we can use functions in plain Python
    '''
    rc = doThis(0)
    print(rc)

    name = create_string_buffer(128)
    rc = getName(name)
    print(rc)
    print(name.value)

    ver = getVersion()
    print(ver)

    msg = create_string_buffer(256)
    rc = getMessage(msg)
    print(rc)
    print(msg.value)
    '''
        Unload DLL and reset COM environment
    '''
    rc = Release(drv)
    rc = CoUninitialize()

    print("Done!")