如何在钩子程序中将复选框绘制到消息框上?

How to draw checkbox onto message box in hook procedure?

我正在 Win32 中制作自定义消息框 api。因此,我按照 here 中的教程创建了挂钩过程和其他东西。

我成功更改了按钮文本,但是,当我在消息框上绘制一个复选框并按下其中一个消息框按钮时,该复选框被绘制到主 window !

我的代码:

typedef void (*mbxdraw)(HWND);
static HHOOK hMsgHk;        // internal linkage; local to this file
static mbxdraw drawproc;    // internal linkage

LRESULT CALLBACK CBTProc(int nCode, WPARAM wp, LPARAM lp)
{
    HWND hwndMsgbx;
    if (nCode < 0)
        return CallNextHookEx(hMsgHk, nCode, wp, lp);
    switch (nCode) {
    case HCBT_ACTIVATE:
        // obtain the message box handle
        hwndMsgbx = (HWND) wp;
        drawproc(hwndMsgbx);    // calls function pointer
        return 0;
    }
    return CallNextHookEx(hMsgHk, nCode, wp, lp);
}

int msgbox(HWND hOwner, char *text, char *cap, UINT flags, mbxdraw md)
{
    int ret;

    hMsgHk = SetWindowsHookEx(WH_CBT, CBTProc, NULL, GetCurrentThreadId());

    drawproc = md;

    ret = MessageBox(hOwner, text, cap, flags);

    UnhookWindowsHookEx(hMsgHk);
    return ret;
}

在我传递的函数中(main.cpp):

void draw(HWND hMsg)
{
    // this is the checkbox: 
    CreateWindow("BUTTON", "Check", WS_CHILD | WS_VISIBLE | BS_CHECKBOX,
                 10, 70, 65, 10, hMsg, (HMENU) CHKID, GetModuleHandle(NULL), NULL);
    SetWindowText(GetDlgItem(hMsg, IDYES), "Save Changes");
}

只要我按下消息框上的两个按钮之一,复选框就会绘制到主 window 上。它甚至使用完全相同的 X 和 Y 坐标以及相同的宽度、高度和文本绘制。

我以为我获取消息框句柄的方法不对,但我看到消息框句柄的地址不等于主句柄window。

我传递函数指针而不是仅仅编写代码的原因是,当它真正起作用时,我会把它放在一个 c++ 包装器中 class。

如果我在这个简单的程序中测试它,它就会工作:

#include <windows.h>
#include <stdio.h>

#pragma comment(lib,"user32.lib")

#define CHKID 100

typedef void (*mbxdraw)(HWND);
static HHOOK hMsgHk;        // internal linkage; local to this file
static mbxdraw drawproc;    // internal linkage

LRESULT CALLBACK CBTProc(int nCode, WPARAM wp, LPARAM lp)
{
    HWND hwndMsgbx;
    if (nCode < 0)
        return CallNextHookEx(hMsgHk, nCode, wp, lp);
    switch (nCode) {
    case HCBT_ACTIVATE:
        // obtain the message box handle
        hwndMsgbx = (HWND) wp;
        drawproc(hwndMsgbx);    // calls function pointer
        return 0;
    }
    return CallNextHookEx(hMsgHk, nCode, wp, lp);
}

void draw(HWND hMsg)
{
    // this is the checkbox: 
    CreateWindow("BUTTON", "Check", WS_CHILD | WS_VISIBLE | BS_CHECKBOX,
                 10, 70, 65, 10, hMsg, (HMENU) CHKID, GetModuleHandle(NULL), NULL);
    SetWindowText(GetDlgItem(hMsg, IDYES), "Save Changes");
}

int msgbox(HWND hOwner, char *text, char *cap, UINT flags, mbxdraw md)
{
    int ret;

    hMsgHk = SetWindowsHookEx(WH_CBT, CBTProc, NULL, GetCurrentThreadId());

    drawproc = md;

    ret = MessageBox(hOwner, text, cap, flags);

    UnhookWindowsHookEx(hMsgHk);
    return ret;
}

int main(int argc, char *argv[])
{

    msgbox(NULL, "The quick brown fox jumps over the lazy dog", "The brown fox", MB_YESNO, draw);
    Sleep(2000);
    return 0;
}

也许您在删除挂钩之前在同一个线程中创建了其他一些 window?

您的代码体现了错误的方法。你想制作一个带有复选框的本地消息对话框。 TaskDialogIndirect 就是为此目的而提供的。

您的方法,即使您修复了它,它也无法适应未来 Windows 版本中实现的变化。使用提供的系统 API.