3

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.

CPlusSharp
  • 881
  • 5
  • 15
  • 1
    Not having a documented way to find this out is pretty core about COM. You may well discover a stub, surely not what you'd like to find. – Hans Passant May 06 '14 at 22:10

2 Answers2

3

Yirkha's answer is in good standing and I have two notes to add:

  1. 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.

  2. 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.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
2

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.

Yirkha
  • 12,737
  • 5
  • 38
  • 53
  • That would only work for a in-process COM object. An out-of-process COM object runs in another process and the local process uses a proxy to communicate with the other process. So the vtable of the COM object would point to memory within the local process that does not match any DLLs in the local process's modules list, or at least certainly will not be the original module of the actual COM object. – Remy Lebeau May 06 '14 at 22:12
  • True, good point - it would show only the creator of the marshalling object, or maybe nothing at all, as the virtual tables are probably created dynamically on the heap in that case. – Yirkha May 06 '14 at 22:19
  • This seems to work for DirectShow COM-Filters, I don't know about other proxy/stub scenarios. Thanks. – CPlusSharp May 06 '14 at 22:45
  • 1
    DShow filters are all inprocess, so the trick looks good. And of course, filters all implement `IPersist`, so registry lookup option is still there as an alternate route. – Roman R. May 07 '14 at 06:17
  • I've used the registry lookup, but as we are also having filters loaded without registration in [GraphStudioNext](https://code.google.com/p/graph-studio-next/), this trick is needed. – CPlusSharp May 07 '14 at 09:00
  • For COM interfaces implemented in scripted languages, the vtable would definitely be on the heap, and I suspect the same applies to .Net languages. – MSalters May 07 '14 at 09:29