GetModuleHandle (NULL) против hInstance

При программировании с использованием Windows API я всегда делал глобальную переменную HINSTANCE from WinMain. Если я хочу сделать кнопку ОК, я бы сделал это так (с учетом глобальной HINSTANCE g_hInstance):

return CreateWindow("BUTTON", "OK", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, 10, 10, 100, 30, exampleParentWindow, EXAMPLECHILDID, g_hInstance, NULL);

но в последнее время я видел, что дескриптор экземпляра определяется без необходимости передавать его в качестве параметра или забивать глобальное пространство имен, используя вызов GetModuleHandle(NULL) *. Итак, приведенный выше пример будет выглядеть так:

return CreateWindow("BUTTON", "OK", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, 10, 10, 100, 30, exampleParentWindow, EXAMPLECHILDID, GetModuleHandle(NULL), NULL);

* Если ваш компилятор поддерживает его, вы можете написать GetModuleHandle(nullptr), и оператор будет иметь тот же результат.

Какое преимущество (если есть) вызова GetModuleHandle(NULL) для явного указания дескриптора экземпляра?

Fine Print: Я знаю, что у этого есть ответ, но он не был сформулирован как его собственный вопрос в StackOverflow.

Ответ 1

В EXE это не имеет никакого значения. hInstance из WinMain() и GetModuleHandle(NULL) оба ссылаются на одно и то же HINSTANCE (модуль файла .exe). Но это имеет значение, если вы вместо этого создаете окна внутри DLL, так как вам нужно использовать hInstance DLL, но GetModuleHandle(NULL) все равно вернет HINSTANCE EXE- HINSTANCE который загрузил DLL.

Ответ 2

HMODULE WINAPI GetModuleHandle( _In_opt_  LPCTSTR lpModuleName );

Отдайте дескриптор модуля имени модуля. Если вы передаете NULL, вы получите дескриптор модуля EXE, который в настоящее время запущен. Если вы конкретно называете имя модуля, вы получаете дескриптор модуля этой DLL, который сопоставляется с адресным пространством процесса. Использование заключается в том, что когда вы пытаетесь вызвать функцию, экспортируемую DLL, или пытаетесь использовать шаблон диалога со стороны dll. В это время, если вы используете возвращаемую форму HMODULE GetMoudleHandle (NULL), ваш код не будет работать.

Ответ 3

Одна потенциальная выгода, которую вы получаете от использования GetModuleHandle (NULL) по сравнению с прямым использованием WinMain HINSTANCE, связана с архитектурой. Если вы хотите предоставить независимую от платформы систему, которая работает на linux/windows/что угодно, у вас может быть слой, который выполняет зависящие от платформы переводы. В этом случае вы не хотите, чтобы зависимые от платформы объекты, такие как HINSTANCE, отображались в основном коде приложения. Итак, чтобы обойти эту зависимость от платформы, я поместил GetModuleHandle (NULL) в конструктор класса, зависящего от платформы, который имеет тот же эффект, что и прямое использование WinMain HINSTANCE, но абстрагирует эту специфическую функциональность от основной базы кода.

Ответ 4

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

HMODULE getThisModuleHandle()
{
    //Returns module handle where this function is running in: EXE or DLL
    HMODULE hModule = NULL;
    ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 
        GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 
        (LPCTSTR)getThisModuleHandle, &hModule);

    return hModule;
}