链接按钮和窗口类

时间:2012-02-24 22:26:39

标签: c++ windows winapi inheritance wrapper

我正在开发自己的个性化winapi包装器。我想要的语法是这样的:

// #define wndproc(name) void name (Window & hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
// #define buttonproc(name) void name (Button & hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

wndproc (rightClick) { //evaluates to function to handle window message
    ::msg ("You right clicked the window. Closing window...");
    hwnd.close(); //close() is implemented in my Window class
}

buttonproc (buttonClick) { //same thing basically
    ::msg ("You clicked this button. I'm going to hide the other one...");

    //if text on this button is "One button", find the one belonging to parent
    //with the text "Other button" and hide it, or vice-versa
    hwnd.text == "One button"
    ? hwnd.parent().button ("Other button").hide();
    : hwnd.parent().button ("One button").hide();
}

int main() {
    Window win; //create default window
    win.addmsg (WM_LBUTTONDOWN, rightClick); //look for l-click message and call that

    Button b1 (win, "One button", 100, 100, 50, 20, buttonClick); //parent, coords, size, clicked
    Button b2 (win, "Other button", 200, 100, 50, 20, buttonClick);  

    return messageLoop(); //should be self-explanatory
}  

问题是,在wndproc中,hwndWindow &而在buttonprochwndButton &。我或许可以说:

msgproc (Window, rightClick){...} 
msgproc (Button, buttonClick){...}

问题在于我必须调用这些程序并赋予它们正确的hwnd。我的主窗口过程在我的Window类中实现。它获得了四个正常的参数。如果我需要将WM_COMMAND消息传递给右键按钮,我想给它相应的Button对象。

目前的方式,我将指针传递给WindowButton的超类。当然,它会创建复杂的代码,例如:

((Window *)hwnd)->operator()() //get HWND of the Window

无论如何,它似乎并没有那么好用。不幸的是,我现在想到的唯一方法就是保留每个Button创建的列表并将其拉出来。我甚至可以将此扩展到所有可能的收件人。

这样做的好处是我的Button类有一个静态窗口过程,只要找到WM_COMMAND消息就会调用该过程。我没有添加其他控件,但它的设计目的是通过检查现有的id并在创建按钮时调用您指定的过程(如果匹配)。问题是,完成此操作后,还会调用添加WM_COMMAND处理程序的任何其他内容(如复选框)。

我在考虑在每个HWND孩子及其相应对象的Window中保留一个列表。通过这种方式,我可以在Button等每个类中修改额外的过程,这将导致进行大量额外处理,并将proc [i] ((BaseWindow *)hwnd, msg, wParam, lParam)替换为proc [i] (control [loword(wParam)], msg, wParam, lParam) WM_COMMAND使用lParam查看它是否为控件。

似乎我错过了一些大事。我可能会开始实现这个,然后遇到一个重大问题。有没有更好的方法来做所有这些?

当我在它的时候,有没有办法让control()函数返回正确的对象类型(Button,Checkbox ...),具体取决于它找到哪个id来对应而不是只是一系列不同的对象(我很确定我已经看到了一种方法)?

1 个答案:

答案 0 :(得分:1)

问题是如何处理传递给父级而不是按钮类(或其他)的WM_COMMAND消息。

最简单的解决方法是向窗口基类添加WM_COMMAND处理程序,以将消息转发给生成它的控件。然后,该消息将在控件的类中处理。

WM_COMMAND处理程序中的代码可能如下所示:

if (lParam != 0)
{
    // lParam non zero so this is a control notification.
    if ((HWND)lParam == hWnd)
    {
        // The message has arrived at its destination
        return OnNotify(HIWORD(wParam), LOWORD(wParam));
    }
    else
    {
        // Reflect the message back to the control.
        return SendMessage((HWND)lParam, WM_COMMAND, wParam, lParam);
    }
}

我最初误解了这个问题。以下描述了将消息路由到对象的几种方法:

MFC方式

每个窗口都使用相同的窗口过程。您有一个从HWND到窗口对象的全局映射。 (地图实际上是每个线程,但在大多数应用程序中这是不必要的。)当消息到达时,您查找对象并将消息发送给它。如果Button派生自Window,则每类处理非常容易。

一个轻微的复杂情况是,如果要捕获在创建窗口时生成的消息,则需要在全局窗口过程中将窗口添加到地图中。

ATL方式

每个窗口都有自己的窗口过程(也可能是它自己的类,以便最初设置窗口过程变得容易;我忘了)。窗口过程是生成的存根,它加载指向对象*的指针并跳转到基类的窗口过程(这是一个非静态成员函数)。 (为了简单起见,存根应该跳转到基类中的非虚拟wndproc,它调用“真正的”虚拟wndproc。)除了改变HWND映射到对象的方式之外,这在其他方面基本上与MFC模型。

*在x86上,存根在跳转到wndproc之前将对象指针放在ECX中。这也适用于x64(虽然我不知道它是否像这样工作)但是对象指针会覆盖HWND(因此基类非虚拟wndproc不会有HWND参数)。