【发布时间】:2021-01-05 05:10:22
【问题描述】:
在使用 C# 时,之前很容易在运行时创建事件处理程序,例如:
Button button1 = new button1();
button1.click += Button_Click(); //Create handler
button1.click -= Button_Click(); //Remove handler
public void Button_Click()
{
//Button clicked
}
但在 win32 中,我遇到了必须处理所有事件的 WndProc 回调。我想为特定消息创建一个处理程序并将其附加到特定的 void。
目前,我正在使用 WndProc 来捕获 WM_CREATE 消息并绘制控件:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
Draw(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void Draw(HWND hWnd)
{
HWND button4 = CreateWindow(L"button", L"button4", WS_CHILD | WS_VISIBLE , 329, 118, 112, 67, hWnd, (HMENU)1001, hInst, NULL);
HWND button3 = CreateWindow(L"button", L"button3", WS_CHILD | WS_VISIBLE , 212, 118, 112, 67,
...
}
但我想创建或删除事件处理程序,而不是在运行时使用 WndProc,例如:
AddHandler WM_CREATE , Draw(hWnd);
DelHandler WM_CREATE , Draw(hWnd);
我尝试了什么?
SetWindowsHookEx 的问题在于它像 WndProc 一样处理整个消息。我不想要一个处理整个窗口消息并跳过其中一些消息的处理程序。这可能会导致性能或内存泄漏问题。
编辑:来自answer的实现示例:
#include <unordered_map>
using msgHandler = LRESULT(*)(HWND, UINT, WPARAM, LPARAM);
std::unordered_map<UINT, msgHandler> messageHandlers;
LRESULT handleCreate(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
//Draw some buttons to see whether event WM_CREATE called or not
HWND button4 = CreateWindow(L"button", L"button4", WS_CHILD | WS_VISIBLE, 329, 118, 112, 67, hWnd, (HMENU)1001, hInst, NULL);
HWND button3 = CreateWindow(L"button", L"button3", WS_CHILD | WS_VISIBLE, 212, 118, 112, 67, hWnd, (HMENU)1002, hInst, NULL);
HWND button2 = CreateWindow(L"button", L"button2", WS_CHILD | WS_VISIBLE, 329, 46, 112, 67, hWnd, (HMENU)1003, hInst, NULL);
HWND button1 = CreateWindow(L"button", L"button1", WS_CHILD | WS_VISIBLE, 212, 46, 112, 67, hWnd, (HMENU)1004, hInst, NULL);
return 0;
}
LRESULT handleClose(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
//Quit form
PostQuitMessage(0);
return 0;
}
void AddHandler()
{
messageHandlers[WM_CREATE] = handleCreate;
messageHandlers[WM_DESTROY] = handleClose;
}
void DelHandler()
{
messageHandlers.erase(WM_CREATE);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
auto handler = messageHandlers.find(msg);
if (handler != messageHandlers.end()) return handler->second(hWnd, msg, wParam, lParam);
return DefWindowProc(hWnd, msg, wParam, lParam);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){
AddHandler();
//DelHandler();
...
【问题讨论】:
-
一种选择是编写自己的 WndProc,它保存一个处理程序表以及它们注册的消息。另一种方法是编写一个 WndProc,为每条消息引发一个事件,并让每个人都注册他们想要处理的事件。
-
我需要尝试注册特定消息的第一个选项。你能指导我更多吗?
-
在此示例中,c# 事件处理程序是在编译时创建的。
//Create handler和//Remove handler和错误。 -
也许“原始”win32 不是您所需要的。 C/C++/Native Windows 编程还有其他选项。例如,您可以尝试 MFC docs.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications 它更接近 .NET 事件,或者至少研究它以获取信息。
-
This answer 填写选项1的详细信息。
标签: c++ winapi wndproc setwindowshookex