使用类成员作为 WNDPROC/DLGPROC 有或没有全局
我将继续对此进行总结,如何使用属于类成员的对话过程?我正在创建一个窗口包装类,但是 CreateDialogParam
需要一个全局对话框过程,所以我尝试了这个解决方法:
I'll go ahead and give a summary to this, how can I use a dialog procedure that is a member of a class? I am creating a window wrapper class, but CreateDialogParam
needs a global dialog procedure, so I tried this workaround:
我对这个话题做了一些搜索.我正在创建一个 Dialog
类,我将其子类化以创建一个 CMainWnd
然后实例化它.在 Dialog
类中,我有一个成员函数定义为 INT_PTR CALLBACK Dialog::cb_proc(HWND,UINT,WPARAM,LPARAM)
.现在,我知道 windows 必须有一个全局函数作为回调过程.
I have done a bit of searching on this topic. I am making a Dialog
class which I am subclassing to make a CMainWnd
and then instantiating that. In the Dialog
class I have a member function defined as INT_PTR CALLBACK Dialog::cb_proc(HWND,UINT,WPARAM,LPARAM)
. Now, I know that windows must have a global function as a callback procedure.
所以我做了一个 std::map
映射以将对话框窗口句柄与其 Dialog 类指针相关联.
So I made a std::map<HWND,Dialog*> DlgProcs
map to associate the dialogs window handle with its Dialog class pointer.
还有一个 INT_PTR CALLBACK DlgMainProc(HWND,UINT,WPARAM,LPARAM)
,所以我可以将它传递给 CreateDialogParam()
.在 DlgMainProc(...)
的主体中,我搜索地图以使用 hWnd
参数来查找 Dialog*
并返回其 cb_proc(..)
成员.
And a INT_PTR CALLBACK DlgMainProc(HWND,UINT,WPARAM,LPARAM)
so I could pass that to CreateDialogParam()
. In the body of DlgMainProc(...)
I search the map for using the hWnd
parameter to find the Dialog*
and return its cb_proc(..)
member.
我的问题是没有处理任何消息,这是因为我的 Dialog
类中的成员过程从未被调用.即使我将 MessageBox()
放在 DlgMainProc
中的 if (DlgProcs.find(hWnd) != DlgProcs.end()) {
> 语句,消息框会一遍又一遍地显示,直到我不得不从 Visual Studio 2008 中止程序.这告诉我它正在我的地图中找到 hWnd
.奇怪的是,如果我在之后将它放在 else
语句中,它也会这样做,这自相矛盾地告诉我它没有在地图中找到 hWnd
.
My problem is that none of the messages get processed, this is because the member procedure in my Dialog
class never gets called. Even though when I put a MessageBox()
in DlgMainProc
inside a if (DlgProcs.find(hWnd) != DlgProcs.end()) {
statement, the messagebox is displayed, over and over again until I have to abort the program from Visual Studio 2008. Which tells me that it is finding the hWnd
in my map. The weird thing is it also does this if I put it in the else
statement after that, which contradictingly tells me it is NOT finding the hWnd
in the map.
如果我在 cb_proc
成员函数中放置一个消息框,它根本不会显示.但在此期间,我从未遇到任何编译器、链接器或运行时错误.当我从中删除消息框时(为了不必中止程序,它只是出于调试目的)程序运行但没有消息得到处理,X 按钮不会关闭程序,按钮点击什么也不做.
If I put a messagebox in the cb_proc
member function it does not get displayed at all. But during this I never get any compiler, linker, or runtime errors. When I remove the messagebox from it (as to not have to abort the program, it was just for debugging purposes) the program runs but no messages get processed, the X button does not close the program, button clicks do nothing.
这是 PasteBin 代码:http://pastebin.com/GsGUBpZU顺便说一句,我对此进行子类化没有问题,我的窗口创建得很好,只是没有处理消息,cb_proc
只是从未被调用.
Here is the PasteBin code: http://pastebin.com/GsGUBpZU
Btw, I have no problem subclassing this, my window is created fine, just no messages are processed, cb_proc
just never gets called.
这是代码的相关部分
map<HWND,Dialog*> g_DlgProcs;
INT_PTR CALLBACK g_MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (g_DlgProcs.find(hWnd) != g_DlgProcs.end()) {
Alert("blah"); // Gets executed repeatedly
return g_DlgProcs[hWnd]->cb_proc(hWnd, msg, wParam, lParam);
} else {
Alert("blah"); // Removing the above alert, this gets
// executed repeatedly, erm, as well.. O.o strange
return FALSE;
}
}
Dialog::Dialog(int id, HWND parent /* = HWND_DESKTOP */) {
_id = id;
_parent = parent;
// Tried this before CreateDialogParam
g_DlgProcs.insert(make_pair(_handle, this));
_handle = CreateDialogParam(
(HINSTANCE)GetModuleHandle(NULL),
MAKEINTRESOURCE(id), _parent,
(DLGPROC)g_MainDlgProc, NULL
);
// Then tried it after CreateDialogParam
g_DlgProcs.insert(make_pair(_handle, this));
}
INT_PTR CALLBACK Dialog::cb_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
Alert("blah"); // Never gets executed
bool handled = true;
switch (msg)
{
case WM_INITDIALOG:
OnInitialize();
break;
case WM_COMMAND:
if (HIWORD(wParam) == 0 || HIWORD(wParam) == 1) {
OnMenuCommand((HIWORD(wParam) == 1), (int)LOWORD(wParam));
} else {
OnCtrlCommand((int)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam);
}
break;
case WM_NOTIFY:
{
LPNMHDR head = (LPNMHDR)lParam;
OnNotification(head->code, head->idFrom, head->hwndFrom);
}
break;
case WM_CLOSE:
OnClose(); // DestroyWindow(_handle)
break;
case WM_DESTROY:
OnDestroy(); // PostQuitMessage(0)
default:
handled = ProcessMsg(msg, wParam, lParam);
}
// Convert bool to Windows BOOL enum
return ((handled == true) ? TRUE : FALSE);
}
<小时>
有人知道为什么它永远不会被调用吗?或者只是指导我使用另一种方法将成员函数用作 DLGPROC?
Does anybody know why it never gets called? Or maybe just guide me to another way to use a member function as a DLGPROC?
推荐答案
我试过你的代码,它奏效了:cb_proc
被调用.您将错过在 CreateDialogParam
返回之前发送的任何消息(例如 WM_INITDIALOG
).
I tried your code and it worked: cb_proc
gets called. You will miss any messages (e.g. WM_INITDIALOG
) that get sent before CreateDialogParam
returns.
您可以通过将窗口句柄和对象添加到 g_MainDlgProc
中的地图来解决后一个问题.如果你收到一个未知窗口的消息,你就知道它属于你正在创建的窗口;将对象放在全局中,您可以将句柄/对象添加到地图中.
You can fix the latter problem by adding the window handle and the object to the map in g_MainDlgProc
. If you get a message for an unknown window, you know it belongs to the window you're creating; put the object in a global and you can add the handle/object to the map.
相关文章