【问题标题】:How to load COM object with custom interface from dll in python?如何从 python 中的 dll 加载具有自定义接口的 COM 对象?
【发布时间】:2017-11-25 04:36:41
【问题描述】:

大家好。 任务是使用从 dll 加载的 COM 对象(禁止使用 regsvr32)。该对象还公开了我将来需要的 DirectShow 接口。

然后我尝试使用来自this link 的示例获取模块,但遇到了一个问题:pythoncom 不了解 DirectShow 接口(例如 IBaseFilter)。 from this post 我的印象是 pythoncom 不支持自定义 COM 接口,但那是在 2008 年,也许现在情况发生了变化?

代码是

# -*- coding: utf-8 -*-
import ctypes, inspect, os, pythoncom, sys
from comtypes import client
from ctypes import OleDLL, c_long, byref
from uuid import UUID

#dshow is a module with DirectShow constants, etc
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"path_to_dshow_module")))
if cmd_subfolder not in sys.path:
    sys.path.insert(0, cmd_subfolder)
import dshow

#that way comtypes gets to know about DirectShow interfaces
qedit = client.GetModule("qedit.dll") 
dll_path = os.path.join(cmd_subfolder, "../my_path/my_dshow_filter.ax") #specifying path to dll
iid_interface = dshow.CLSID_IUnknown
iid_ibasefilter = dshow.CLSID_IBaseFilter
clsid_class = UUID(dshow.CLSID_my_filter).bytes_le
iclassfactory = UUID(str(pythoncom.IID_IClassFactory)).bytes_le
com_classfactory = c_long(0)

my_dll = ctypes.oledll.LoadLibrary(dll_path)
#getting com_classfactory pointer to an adress of IClassFactory within loaded dll
hr = my_dll.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory))
#creating class factory from adress using pythoncom
MyFactory = pythoncom.ObjectFromAddress(com_classfactory.value, pythoncom.IID_IClassFactory)
#creating COM object using IClassFactory::CreateInstance, using IUnknown as a default interface
dmx_interface = MyFactory.CreateInstance(None, iid_interface)
# I could've tried to use IBaseFilter directly, 
# but pythoncom knows nothing about DirectShow interfaces!
# dmx = dmx_interface.QueryInterface(str(qedit.IBaseFilter._iid_)) #that yields an error
dmx = dmx_interface.QueryInterface(iid_ibasefilter) #that yields the same error

我得到的错误是TypeError: There is no interface object registered that supports this IID,这是可以理解的。

所以,comtypes 知道这些接口!但不幸的是,我找不到使用 comtypes 甚至 ctypes 从 dll 加载 COM 对象的方法。

我已经处理这个问题好几天了,非常感谢您的建议。

【问题讨论】:

    标签: python com directshow


    【解决方案1】:

    最后,我做了一些指针操作,但我做到了。

    我已从 comtypes.server 导入类 IClassFactory 并为其获取了一个指针(指针 №1)。之后,我在我加载的 dll 中获得了一个指向 IClassFactory 对象的 c_long 指针(指针 №2)。最后,我将指针№2的值赋给了指针№1。

    from comtypes.server import IClassFactory
    #same code as it was before
    dll_path = os.path.join(cmd_subfolder, "../my_path/my_dshow_filter.ax")
    clsid_class = UUID(dshow.CLSID_my_filter).bytes_le
    #that may be replaced with other IID_IClassFactory definition
    #so no pythoncom is required at all
    iclassfactory = UUID(str(pythoncom.IID_IClassFactory)).bytes_le 
    com_classfactory = c_long(0)
    my_dll = ctypes.oledll.LoadLibrary(dll)
    hr = my_dll.DllGetClassObject(clsid_class, iclassfactory, byref(com_classfactory))
    ptr_icf = POINTER(IClassFactory)(com_classfactory.value) #pointer to IClassFactory
    #and there we'll have a pointer to IUknown of the filter inside the dll
    filter = ptr_icf.CreateInstance() 
    dec = filter.QueryInterface(qedit.IBaseFilter) 
    filter_graph.AddFilter(dec, "dec")
    #Voila!
    

    因此,这项工作可以在不使用任何 pythoncom 的情况下完成,这对我来说是一个很大的优势(因为之前的所有工作都是通过 comtypes 模块完成的)

    【讨论】:

    • 您目前知道直接从 ctypes 执行此操作的方法吗?具体来说,我正在尝试加载IFileOperation
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 2011-02-12
    相关资源
    最近更新 更多