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

时间:2015-08-02 14:23:42

标签: c winapi messagebox

我正在Win32 api中创建一个自定义消息框。所以,我按照here的教程创建了钩子程序和事物。

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

我的代码:

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");
}

只要按下消息框中的两个按钮之一,复选框就会被绘制到主窗口上。它甚至可以使用相同的X坐标和Y坐标以及相同的宽度,高度和文本进行绘制。

我想也许我正在以错误的方式获取消息框句柄,但是我看到消息框句柄的地址不等于主窗口的句柄。

我传递函数指针而不仅仅是编写代码的原因是因为稍后,当它实际工作时,我会把它放在一个c ++包装类中。

2 个答案:

答案 0 :(得分:1)

您的代码体现了错误的方法。您想要使用复选框创建本机消息对话框。 TaskDialogIndirect是为此目的而提供的。

您的方法,即使您修复它,它对未来Windows版本中的实现更改也不健壮。使用系统提供的API。

答案 1 :(得分:0)

如果我在这个简单的程序中测试它,它就有效:

#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;
}

也许你在删除钩子之前在同一个线程中创建了一些其他窗口?