在运行时创建事件处理程序而不使用 WndProc win32 c++ 我尝试了什么?编辑:来自answer的实施示例:

如何解决在运行时创建事件处理程序而不使用 WndProc win32 c++ 我尝试了什么?编辑:来自answer的实施示例:

在使用 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",212,...
}

但我想创建或删除事件处理程序,而不是在运行时使用 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,LParaM lParam)
{
    //Draw some buttons to see whether event WM_CREATE called or not
    HWND button4 = CreateWindow(L"button",(HMENU)1002,NULL);
    HWND button2 = CreateWindow(L"button",L"button2",46,(HMENU)1003,NULL);
    HWND button1 = CreateWindow(L"button",L"button1",(HMENU)1004,NULL);
    return 0;
}

LRESULT handleClose(HWND hWnd,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,LParaM lParam)
{
    auto handler = messageHandlers.find(msg);
    if (handler != messageHandlers.end()) return handler->second(hWnd,msg,lParam);
    return DefWindowProc(hWnd,lParam);
}

BOOL InitInstance(HINSTANCE hInstance,int nCmdshow){
    AddHandler();
    //DelHandler();
    ...

解决方法

消息 ID 只是一个无符号整数,所以它并没有什么特别之处。尽管巨型 switch 语句是处理消息的一种常用方法,但如果您愿意,您可以做完全不同的事情。为了支持处理程序的动态插入/删除,一种可能性是使用 std::unordered_map:

// a message handler receives the normal parameters:
using msgHandler = LRESULT(*)(HWND,UINT,WPARAM,LPARAM);

// a map from message numbers to the handler functions:
std::unordered_map<UINT,msgHandler> messageHandlers;

// A couple of message handler functions:
LRESULT handleCreate(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {
    // ...
}

LRESULT handleDraw(HWND hWnd,LPARAM lParam) {
   // ...
}

// register them to handle the appropriate messages:
messageHandlers[WM_CREATE] = handleCreate;
messageHandlers[WM_PAINT] = handleDraw;

// and then our (now really tiny) window proc that uses those:
LRESULT CALLBACK WndProc(HWND hWnd,LPARAM lParam)
{
    auto handler = messageHandlers.find(msg);
    if (handler != messageHandlers.end())
        return handler->second(hWnd,msg,wParam,lParam);
    return DefWindowProc(hWnd,lParam);
}

由于我们只是在 std::unordered_map 中存储指向函数的指针,因此添加、查找或删除处理程序都只是使用在 std::unodered_map 中添加、查找或删除某些内容的正常操作(例如,messageHandlers.erase(WM_CREATE); 从地图中删除 WM_CREATE 处理程序)。

如果您想对此进行更详细的说明,您可以创建特定类型来处理不同的消息,因此(例如)在其 lParam 中没有收到任何有意义的消息的人根本不会收到 { {1}},而另一个接收两个“混合”在一起的东西,一个在 lParam 的低字中,另一个在 lParam 的高字中可以将它们分成两部分单独的参数。但这还有很多工作要做。

您可能还想查找 WindowsX.h,这是 Microsoft 在 SDK 中提供(或至少用于提供)的标头,它处理映射有点像我上面概述的(后一个版本,其中每个处理程序接收参数表示它接收的逻辑数据,而不是用于编码该数据的 lParamWPARAM

,

您可以像这样动态处理消息:

typedef void (*FHANDLE)();
std::vector<FHANDLE> handles;

void AddHandler(FHANDLE handle)
{
    handles.push_back(handle);
}
void DelHandler(FHANDLE handle)
{
    auto it = std::find(handles.begin(),handles.end(),handle);
    handles.erase(it);
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        for (int i = 0; i < handles.size(); i++)
        {
            handles[i]();
        }
        break;
    ...
    }
}

并添加/删除句柄:

void myclick1()
{
    MessageBox(0,L"test1",L"message",0);
}
void myclick2()
{
    MessageBox(0,L"test2",0);
}

BOOL InitInstance(HINSTANCE hInstance,int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable
   AddHandler(myclick1);
   AddHandler(myclick2);
   //DelHandler(myclick2);
   HWND hWnd = CreateWindowW(szWindowClass,szTitle,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,nullptr,hInstance,nullptr);
   ...
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?