如何使用python中的dll自定义界面加载COM对象?
问题描述:
美好的一天,每个人。 该任务是使用从dll加载的COM对象(禁止使用regsvr32)。此外,该对象还提供了将来需要的DirectShow接口。如何使用python中的dll自定义界面加载COM对象?
然后我试图从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知道该接口!但不幸的是,我找不到一种方法来从DLL加载COM对象使用comtypes或甚至ctypes。
我一直在处理这个问题好几天了,我真的很感激建议的话。
答
最后,它采取了一些指针操作,但我做到了。
我已经导入类的IClassFactory从comtypes.server和取得的指针,它(指针№1)。之后,我已经获得了一个c_long指针,它指向我加载的dll(指针№2)内的对象IClassFactory。最后,我将指针№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模块完成)
来完成