2

Good day, everyone. The task is to work with COM object loaded from dll (regsvr32 usage is forbidden). Also that object exposes DirectShow interfaces that I'll need in a future.

Then I'm trying to get a module using examples from this link, I'm running into a problem: pythoncom doesn't know a thing about DirectShow interfaces (IBaseFilter for instance). And from this post I get an impression that pythoncom doesnt' support custom COM interfaces, but that was in 2008, maybe things have changed now?

The code is

# -*- 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

The error I get is TypeError: There is no interface object registered that supports this IID, which is understandable.

So, comtypes knows about that intefaces! But unfortunately, I can't find a way to load COM object from dll using comtypes or even ctypes.

I've been working with that issue for several days now and I would really appreciate words of advice.

1 Answers1

2

In the end, it took some pointers manipulations but I did it.

I've imported class IClassFactory from comtypes.server and acquired a pointer for it (pointer №1). After that I've obtained a c_long pointer to IClassFactory object inside the dll that I loaded (pointer №2). At last, I've assigned the value of pointer №2 to pointer №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!

So, the job may be done without any use of pythoncom, which is a great advantage to me (seeing as all the previous work is done via comtypes module)

  • Do you currently know of a way to do it directly from ctypes? Specifically I'm trying to load [IFileOperation](https://stackoverflow.com/questions/62065891/how-to-use-ifileoperation-from-ctypes) – Jay Jun 05 '20 at 14:32