我正在开发自己的个性化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
中,hwnd
是Window &
而在buttonproc
,hwnd
是Button &
。我或许可以说:
msgproc (Window, rightClick){...}
msgproc (Button, buttonClick){...}
问题在于我必须调用这些程序并赋予它们正确的hwnd
。我的主窗口过程在我的Window
类中实现。它获得了四个正常的参数。如果我需要将WM_COMMAND
消息传递给右键按钮,我想给它相应的Button
对象。
目前的方式,我将指针传递给Window
和Button
的超类。当然,它会创建复杂的代码,例如:
((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来对应而不是只是一系列不同的对象(我很确定我已经看到了一种方法)?
答案 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参数)。