链接按钮和窗口类
我正在开发我自己的个性化 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 处理程序的任何其他内容(例如复选框)也将被调用。
我正在考虑在 Window
中保留每个 HWND 子项及其相应对象的列表。这样我就可以取消每个类中的额外过程,例如 Button
,这将导致发生大量额外处理,并替换 proc [i] ((BaseWindow *)hwnd, msg, wParam, lParam)
与类似 proc [i] (control [loword(wParam)], msg, wParam, lParam)
的内容WM_COMMAND
,使用lParam
来查看它是否是一个控件。
看来我错过了一些大事。我很可能会开始实施这个,然后遇到一个大问题。有没有更好的方法来完成这一切?
当我这样做时,有没有一种方法可以创建一个 control()
函数,根据它找到的 id 对应的对象类型返回正确的对象类型(按钮、复选框...)而不仅仅是一组不同的对象(我很确定我已经找到了一种方法)?
I'm working on my own personalized winapi wrapper. My desired syntax is such:
// #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
}
The thing is, in wndproc
, hwnd
is a Window &
and in buttonproc
, hwnd
is a Button &
. I might be able to get away with saying:
msgproc (Window, rightClick){...}
msgproc (Button, buttonClick){...}
The problem is in the fact that I have to call these procedures and give them the right hwnd
. My main window procedure is implemented in my Window
class. It gets the four normal arguments. If I need to pass on a WM_COMMAND
message to the right button procedure, I'd like to give it the corresponding Button
object.
The way it is currently, I pass a pointer to the superclass of both Window
and Button
. Of course it creates convoluted code such as:
((Window *)hwnd)->operator()() //get HWND of the Window
It doesn't seem to really work that well anyways. Unfortunately, the only way I can think of at the moment to do so is to keep a list of every Button
created and pull the right one out. I could even extend this to all possible recipients.
The advantage to doing it this way is that my Button
class has a static window procedure that is called any time a WM_COMMAND
message is found. I haven't added other controls, but it is designed to work by checking the id with existing ones and calling the procedure you specify when you create the button if it's a match. The thing is, when this is done, any other things (like a checkbox) that add the WM_COMMAND
handler will be called as well.
I was thinking of keeping a list in Window
of every HWND child and its corresponding object. This way I can just nuke the extra procedures in every class like the Button
, which will cause a lot of extra processing to occur, and replace proc [i] ((BaseWindow *)hwnd, msg, wParam, lParam)
with something like proc [i] (control [loword(wParam)], msg, wParam, lParam)
for WM_COMMAND
, using lParam
to see whether it's a control.
It seems like I'm missing something big though. Chances are I'll start to implement this and then run into a major problem. Is there a better way to do all of this?
While I'm at it, is there a way to make a control()
function that returns the correct object type (Button, Checkbox...) depending on which one it finds the id to correspond to instead of just an array of varying objects (which I'm pretty sure I've seen a way to do)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是如何处理传递给父类而不是按钮类(或其他类)的 WM_COMMAND 消息。
最简单的修复方法是将 WM_COMMAND 处理程序添加到窗口基类,以将消息转发到生成它的控件。然后该消息将在控件的类中进行处理。
WM_COMMAND 处理程序中的代码可能如下所示:
我最初误解了这个问题。下面描述了将消息路由到对象的几种方法:
MFC 方式
每个窗口都使用相同的窗口过程。您有一个从 HWND 到窗口对象的全局映射。 (该映射实际上是每个线程的,但在大多数应用程序中这是不必要的。)当消息到达时,您查找对象并将消息分派给它。如果
Button
派生自Window
那么就很容易进行每个类的处理。一个稍微复杂的问题是,如果您想捕获创建窗口时生成的消息,您需要将窗口添加到全局窗口过程中的映射中。
ATL方式
每个窗口都有自己的窗口过程(也可能有自己的类,以便于最初设置窗口过程;我忘记了)。窗口过程是一个生成的存根,它加载指向对象*的指针并跳转到基类的窗口过程(这是一个非静态成员函数)。 (为了简单起见,存根应该跳转到基类中的非虚拟 wndproc,它调用“真正的”虚拟 wndproc。)除了更改 HWND 映射到对象的方式之外,在其他方面,这与MFC 模型。
*在 x86 上,存根在跳转到 wndproc 之前将对象指针放入 ECX 中。这也适用于 x64(尽管我不知道它是否确实像这样工作),但对象指针会覆盖 HWND(因此基类非虚拟 wndproc 不会有 HWND 参数)。
The question was how to handle WM_COMMAND messages which get delivered to the parent rather than the button class (or whatever).
The simplest fix is to add a WM_COMMAND handler to the window base class to forward the message to the control that generated it. The message will then get handled in the control's class.
The code in the WM_COMMAND handler might look something like this:
I originally misunderstood the question. The following describes a couple of ways of routing messages to objects:
The MFC way
Every window uses the same window procedure. You have a global map from HWND to window object. (The map is actually per-thread, but in most apps this is unnecessary.) When a message arrives you look up the object and dispatch the message to it. If
Button
derives fromWindow
then it's very easy to do per-class processing.One slight complication is that if you want to capture messages generated while the window is being created you need to add the window to your map in the global window procedure.
The ATL way
Every window has its own window procedure (possibly its own class too, to make it easy to set the window procedure initially; I forget). The window procedure is a generated stub that loads up a pointer to the object* and jumps to the base class's window procedure (which is a non-static member function). (To keep it simple, the stub should jump to a non-virtual wndproc in the base class which calls the "real" virtual wndproc.) Apart from changing the way HWNDs map to objects this is, in other respects, basically the same as the MFC model.
*On x86 the stub puts the object pointer in ECX before jumping to the wndproc. This would also work on x64 (though I don't know if it does work like this) but the object pointer would overwrite the HWND (so the base class non-virtual wndproc wouldn't have an HWND parameter).