Как мне получить HMODULE для исполняемого в данный момент кода?

У меня есть статическая библиотека, которая может быть связана либо в .exe или .dll, Во время выполнения я хочу, чтобы только мои библиотечные функции получили HMODULE для чего бы то ни было статический код библиотеки был связан с.

В настоящее время я использую следующий трюк (вдохновленный этим форумом):

const HMODULE GetCurrentModule()
{
    MEMORY_BASIC_INFORMATION mbi = {0};
    ::VirtualQuery( GetCurrentModule, &mbi, sizeof(mbi) );

    return reinterpret_cast<HMODULE>(mbi.AllocationBase);
}

Есть ли лучший способ сделать это, который не выглядит таким хакерским?

(Примечание: цель этого состоит в том, чтобы загрузить некоторые ресурсы Win32, к которым, как я знаю, мои пользователи будут подключены одновременно с моей статической библиотекой.)

4 ответа

Решение
HMODULE GetCurrentModule()
{ // NB: XP+ solution!
  HMODULE hModule = NULL;
  GetModuleHandleEx(
    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    (LPCTSTR)GetCurrentModule,
    &hModule);

  return hModule;
}

__ImageBase является сгенерированным компоновщиком символом, который является заголовком DOS модуля (только MSVC). Из этого вы можете привести его адрес к HINSTANCE или же HMODULE, Так что это удобнее, чем проходить через API.

Так что вам просто нужно сделать это:

EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)

От http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx

Я бы посмотрел на GetModuleHandleEx() используя флаг GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, Похоже, вы можете изменить свой GetCurrentModule() называть эту рутину вместо VirtualQuery()и передать адрес GetCurrentModule() как lpModuleName аргумент.

ETA:

const HMODULE GetCurrentModule()
{
    DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS;
    HMODULE hm = 0;
    ::GetModuleHandleEx( flags, reinterpret_cast<LPCTSTR>( GetCurrentModule ), &hm );   
    return hm;
}

Я не пробовал это, но я думаю, что это будет делать то, что вы хотите.

#if _MSC_VER >= 1300  // for VC 7.0 
#ifndef _delayimp_h 
extern "C" IMAGE_DOS_HEADER __ImageBase; 
#endif
#endif
... 
HMODULE module() 
{ 
#if _MSC_VER < 1300  // earlier than .NET compiler (VC 6.0) 
    MEMORY_BASIC_INFORMATION mbi; 
    static int address; 
    ;::VirtualQuery(&address, &mbi, sizeof(mbi)); 
    return reinterpret_cast(mbi.AllocationBase); 
#else  // VC 7.0 
    // from ATL 7.0 sources 
  return reinterpret_cast(&__ImageBase); 
#endif 
} 

Подробнее здесь https://www.apriorit.com/dev-blog/74-hmodule-hinstance-handle-from-static-library-in-c

HMODULE - это HINSTANCE - базовый адрес модуля. Итак, я посмотрю, как это работает. Но если все, что вам нужно, это HMODULE исполняемого файла, почему бы не перечислить все HMODULE в процессе (EnumProcessModules). У одного из них ваш.lib будет связан.

Ограничение, которое я вижу, состоит в том, что вы понятия не имеете, из какой DLL или EXE происходит ваш.lib. Возможно, вы захотите сравнить HMODULE (базовые адреса) с _ReturnAddress, который вы получаете из вашего.lib. Ваш.lib будет принадлежать к старшей HMODLUE меньше, чем ваш _ReturnAddress

Другие вопросы по тегам