You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在DLL中注册窗口类以提供给EXE程序使用?

在DLL中注册窗口类并让EXE调用的实现方案

关于“注册窗口类的模块必须是创建该窗口的模块”的解释

这句话的核心不是“只有注册类的DLL才能创建窗口”,而是创建窗口时必须传入与注册该窗口类时完全相同的hInstance(即DLL的实例句柄)。系统通过「窗口类名 + hInstance」的组合来唯一识别窗口类,只要EXE能拿到这个hInstance,就能正常创建该类的窗口。

具体实现步骤

1. 在DLL中保存实例句柄

在DllMain中接收并保存DLL的实例句柄(仅做存储操作,避免在DllMain中执行复杂逻辑):

HINSTANCE g_hDllInst = NULL;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        g_hDllInst = hModule; // 保存DLL实例句柄
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

2. 在DLL中实现窗口过程并导出注册函数

编写窗口过程函数,再实现一个导出函数用于注册窗口类(不要在DllMain中注册,防止触发系统锁问题):

// DLL内部的窗口过程
LRESULT CALLBACK DllWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
}

// 导出的注册窗口类函数
__declspec(dllexport) BOOL RegisterDllWindowClass()
{
    WNDCLASSEX wc = {0};
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = DllWndProc; // 绑定DLL中的窗口过程
    wc.hInstance     = g_hDllInst; // 必须使用DLL的实例句柄
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = L"DllCustomWindowClass"; // 唯一类名

    return RegisterClassEx(&wc) != 0;
}

3. EXE中加载DLL并创建窗口

EXE加载DLL后,先调用注册函数,再传入DLL的实例句柄创建窗口:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // 加载目标DLL
    HMODULE hDll = LoadLibrary(L"YourDllFile.dll");
    if (!hDll) return 1;

    // 获取DLL导出的注册函数
    typedef BOOL(*PFN_REGISTER_CLASS)();
    PFN_REGISTER_CLASS pfnRegister = (PFN_REGISTER_CLASS)GetProcAddress(hDll, "RegisterDllWindowClass");
    if (!pfnRegister || !pfnRegister())
    {
        FreeLibrary(hDll);
        return 1;
    }

    // 创建窗口:关键是传入DLL的实例句柄hDll作为CreateWindowEx的hInstance参数
    HWND hWnd = CreateWindowEx(
        0,
        L"DllCustomWindowClass", // 用DLL注册的类名
        L"EXE Created Window from DLL Class",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
        NULL, NULL, hDll, // 此处必须传DLL的句柄
        NULL);

    if (!hWnd)
    {
        FreeLibrary(hDll);
        return 1;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    FreeLibrary(hDll);
    return (int)msg.wParam;
}

关键注意事项

  • 不要在DllMain中注册窗口类:DllMain运行时系统处于锁定状态,执行注册类这类操作可能导致死锁或异常。
  • 窗口过程必须在DLL中:系统调用窗口过程时需要找到对应的代码段,因此窗口过程必须属于DLL的代码空间。
  • 类名要唯一:避免与EXE或其他DLL的窗口类名冲突,建议使用带有DLL标识的前缀。

内容的提问来源于stack exchange,提问作者Plastic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:40:23