我想要一个创建.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
。
答案 0 :(得分:6)
错误代码和消息是准确的:在您指示系统寻找它的地方找不到资源:用于启动进程的可执行映像,而不是您的DLL。记录了该行为(请参阅CreateDialogParam):
hInstance [in,optional]
键入: HINSTANCE
包含对话框模板的模块句柄。如果此参数为NULL,则使用当前可执行文件。
由于您的DLL中存储了对话框模板,因此您必须传递标识DLL的HINSTANCE
。有很多方法可以获得正确的值,但是传递NULL
或GetModuleHandle(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 :(得分:2)
您指定NULL作为CreateDialogParam
的第一个参数。如果要从Win32 Window Application加载对话框资源文件,则应使用此文件:
HWND hDlg = CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_RANKING_DIALOG), NULL, msgProc, NULL);
但是,如果要从DLL本身加载它,则应该使用DLL的DllMain入口点函数将第一个参数替换为HINSTANCE参数。