win32 - .dll 内的对话框

Posted

技术标签:

【中文标题】win32 - .dll 内的对话框【英文标题】:win32 - Dialog inside .dll 【发布时间】:2015-08-26 13:55:55 【问题描述】:

我想创建一个.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

【问题讨论】:

您正在将NULL 中的hInstance 参数传递给CreateDialogParam()。这意味着对话框资源将在加载了您的 DLL 的可执行文件中查找,而不是在 DLL 本身中查找。您应该传递与您的 DLL 关联的 HINSTANCE 我尝试过使用 GetModuleHandle(0) 而不是 NULL,但它没有帮助。那么如何获取dll的HINSTANCE。 它作为第一个参数传递给您的DllMain() 好的,如果我没有 DLLMain()?因为我的 .dll 是从 Java 代码调用的。他们在 java 中使用 System.LoadLibrary()。这是否会导致运行我的 DllMain() 然后我可以将 hInstance 保存到全局变量并用它创建对话框? 与资源错误无关,ShowError(GetLastErrorAsString().c_str()); 是一个等待发生的错误。我假设GetLastErrorAsString 返回std::wstringstd::string。这是暂时的,一旦c_str() 返回,它就会超出范围。然后你将一个悬空指针传递给ShowError 【参考方案1】:

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

hInstance [输入,可选]

类型: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。唯一的缺点:它依赖于 Microsoft 链接器的未记录功能。不过不用担心,它不会默默地失败。

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?

【讨论】:

谢谢,所有解决方案看起来都是正确的,但我尝试了这个,它可以工作。【参考方案2】:

您将 NULL 指定为 CreateDialogParam 的第一个参数。如果你想从 Win32 窗口应用程序加载对话框资源文件,你应该改用这个:

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

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

【讨论】:

不,GetModuleHandle(NULL) 返回与当前可执行文件关联的模块,而不是 DLL。 @FrédéricHamidi 感谢您指出这一点,我相信我已经纠正了答案 可以,但不需要调用GetModuleHandle()。如果您想从当前可执行文件的模块加载资源,您可以简单地将NULL 传递给CreateDialogParam() That's historical baggage, and not necessarily good practice. @EdwardClements 这两个陈述都是正确的。这是仍然有效的历史包袱。旋转电话的工作方式与此相同,但您可能不应该在新办公楼中安装旋转电话。

以上是关于win32 - .dll 内的对话框的主要内容,如果未能解决你的问题,请参考以下文章

WIN32对话框抛出异常[重复]

安装迅雷提示;损坏的图像,导致迅雷无法安装。弹出的对话框显示是:COMCTL32.dll没有被指定在windows运行

从 DLL 创建和加载对话框

Win10下装 VC6.0单步调试报((OLE32.DLL): 0xC0000005: Access Violation)

Linux网卡以及防火墙配置方法

如何用VS2010编写动态链接库DLL