问题
Is it possible to get the DLL-filename for a loaded COM-Object without using the CLSID and a registry lookup?
I have an IUnknown
or in my case an IBaseFilter
interface pointer and now I want to get the DLL-filename who created this COM-Object. Can I use the object point adress to reverse lookup the loaded module where it was created? And then get the HMODULE
to use it in GetModuleFileName
.
回答1:
Only using some hacks, naturally. The object itself is on the heap, which is shared, but you could see where the its virtual table resides - it should be almost universally in the read-only data section of the creator's binary.
So load the first pointer in the object, as that's where virtual table pointers reside in Windows COM ABI:
IBaseFilter* pFilter = ...;
char* vtbl = *reinterpret_cast<char**>(pFilter);
Then I originally suggested to do some circus with EnumProcessModules()
like e.g. here, call GetModuleInformation()
on each module and check if the vtbl
pointer falls into its memory ranges. Stupid me, I forgot about VirtualQueryEx()
, so better do it as Roman described in his answer.
Of course, all this can work only for in-process COM objects and where there are no proxies involved. I assume it can still be useful in your DirectShow case though.
Also see the comment about using IPersist::GetClassId()
and registry lookup, it should apply nicely to most DirectShow filters.
回答2:
Yirkha's answer is in good standing and I have two notes to add:
DirectShow filters are typically old school C++ COM objects with virtual method table residing in code segment, with no proxy/stub code as long as we are inside single process. That is, the hacks of resolving module from interface pointer do work well.
There is an easier replacement for
EnumProcessModules
/GetModuleInformation
walk along module list.VirtualQueryEx
can locate the base address of the DLL directly:
const VOID* pvVirtualTable = *((const VOID**) pBaseFilter);
MEMORY_BASIC_INFORMATION Information;
if(VirtualQueryEx(GetCurrentProcess(), pvVirtualTable, &Information,
sizeof Information))
{
TCHAR pszPath[MAX_PATH] = { 0 };
if(GetModuleFileName((HMODULE) Information.AllocationBase, pszPath,
_countof(pszPath)))
{
P.S. This is something we also do in both DirectShowSpy here , and also in GraphStudioNext.
来源:https://stackoverflow.com/questions/23505194/get-the-dll-file-for-a-com-object-without-using-clsid-and-registry-in-c