如何在python中从dll加载带有自定义接口的COM对象?

时间:2017-06-22 04:36:26

标签: python com directshow

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

然后我试图使用this link中的示例来获取模块,我遇到了一个问题:pythoncom不知道有关DirectShow接口的事情(例如IBaseFilter)。 from this post我得到的印象是pythoncom不支持自定义COM接口,但那是在2008年,现在情况可能已经改变了?

代码是

bytesDecode

我得到的错误是# -*- 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 ,这是可以理解的。

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

我已经在这个问题上工作了好几天了,我真的很感激你的建议。

1 个答案:

答案 0 :(得分:0)

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

我从 comtypes.server 导入了类 IClassFactory 并获取了一个指针(指针№1)。之后,我在我加载的dll(指针№2)中获得了一个指向 IClassFactory 对象的c_long指针。最后,我将指针№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 模块完成的)