win32 - 内部.dll对话框

时间:2015-08-26 13:55:55

标签: c++ winapi dll dialog

我想要一个创建.dll,它会显示一些对话框。

在我的.dll中我有这段代码:

HWND hDlg = CreateDialogParam(NULL, MAKEINTRESOURCE(IDD_RANKING_DIALOG), NULL, msgProc, NULL);
if (!hDlg)  {
    ShowError(GetLastErrorAsString().c_str());
    return false;
}

ShowError调用消息框,GetLastErrorAsString()只调用标准GetLastError并转换为字符串。
我有这个输出:

  

在图像文件中找不到指定的资源类型。

然后我有一个标准的win32 Window应用程序,我调用方法,调用上面提到的代码。

DialogTest test;
test.showDialog(); // calls functionality from .dll

我做错了什么?我是否需要将资源文件链接到.dll?

我正在使用Visual Studio 2010,并且在我的资源文件(.rc)中指定了dialog

2 个答案:

答案 0 :(得分:6)

错误代码和消息是准确的:在您指示系统寻找它的地方找不到资源:用于启动进程的可执行映像,而不是您的DLL。记录了该行为(请参阅CreateDialogParam):

  

hInstance [in,optional]

     

键入: HINSTANCE

     

包含对话框模板的模块句柄。如果此参数为NULL,则使用当前可执行文件。

由于您的DLL中存储了对话框模板,因此您必须传递标识DLL的HINSTANCE。有很多方法可以获得正确的值,但是传递NULLGetModuleHandle(NULL)将无效。这两个都将模块句柄返回到启动进程的可执行映像(而不是您的DLL)。

简单的解决方案:选择传递到DllMain hInstance 并将其存储在全局变量中供以后使用。

HINSTANCE g_hInst = NULL;

BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) {
    switch ( fdwReason ) {
    case DLL_PROCESS_ATTACH:
        g_hInst = hinstDLL;
        break;
    default:
        break;
    }
    return TRUE;
}

强大的解决方案:此解决方案可以在任何地方,DLL,EXE或静态LIB中使用。只有缺点:它依赖于微软链接器的无证功能。不过不用担心,它不会无声地失败。

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

HINST_THISMODULE将始终保持正确的值,无论其在何处使用。 1)

同样可以使用官方接口(GetModuleHandleEx)来实现。以下解决方案也可以从EXE,DLL或静态LIB中使用,只要您确保编译并将该函数链接到相应的模块中:

HMODULE GetCurrentModuleHandle() {
    HMODULE hModule = NULL;
    GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
                       (LPCTSTR)GetCurrentModuleHandle,
                       &hModule );

    return hModule;
}

这会返回HMODULE,而不是HINSTANCE。但这不是问题,因为它们与 2)是相同的。

<小时/> 1)来自Accessing the current module's HINSTANCE from a static library

2) What is the difference between HINSTANCE and HMODULE?

答案 1 :(得分:2)

您指定NULL作为CreateDialogParam的第一个参数。如果要从Win32 Window Application加载对话框资源文件,则应使用此文件:

HWND hDlg = CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_RANKING_DIALOG), NULL, msgProc, NULL);

但是,如果要从DLL本身加载它,则应该使用DLL的DllMain入口点函数将第一个参数替换为HINSTANCE参数。