Получить DLL-файл для COM-объекта без использования CLSID и реестра в C++
Можно ли получить DLL-имя файла для загруженного COM-объекта без использования CLSID и поиска в реестре?
у меня есть IUnknown
или в моем случае IBaseFilter
указатель интерфейса и теперь я хочу получить DLL-имя файла, который создал этот COM-объект. Можно ли использовать адрес точки объекта для обратного просмотра загруженного модуля, в котором он был создан? А потом получить HMODULE
использовать его в GetModuleFileName
,
2 ответа
Естественно, используя только некоторые хаки. Сам объект находится в куче, которая является общей, но вы могли видеть, где находится его виртуальная таблица - он должен быть почти всегда в разделе данных только для чтения двоичного файла создателя.
Итак, загрузите первый указатель в объекте, так как там находятся указатели виртуальных таблиц в Windows COM ABI:
IBaseFilter* pFilter = ...;
char* vtbl = *reinterpret_cast<char**>(pFilter);
Тогда я изначально предложил сделать цирк с EnumProcessModules()
например, здесь, позвоните GetModuleInformation()
на каждом модуле и проверьте, если vtbl
указатель попадает в его диапазоны памяти. Тупой я забыл про VirtualQueryEx()
так что лучше сделай, как Роман описал в своем ответе.
Конечно, все это может работать только для внутрипроцессных COM-объектов и там, где не задействованы прокси-серверы. Я предполагаю, что это все еще может быть полезным в вашем случае DirectShow, хотя.
Также смотрите комментарий об использовании IPersist::GetClassId()
и поиск в реестре, он должен применяться к большинству фильтров DirectShow.
У Йиркхи хороший ответ, и у меня есть два примечания:
Фильтры DirectShow обычно являются COM-объектами старой школы C++ с таблицей виртуальных методов, находящейся в сегменте кода, без прокси-кода-заглушки, пока мы находимся внутри одного процесса. То есть, хаки разрешения модуля из указателя интерфейса работают хорошо.
Есть более легкая замена
EnumProcessModules
/GetModuleInformation
пройтись по списку модулей.VirtualQueryEx
может найти базовый адрес DLL напрямую:
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)))
{
PS Это то, что мы также делаем как в DirectShowSpy здесь, так и в GraphStudioNext.