Win32:更多“面向对象”窗口消息处理系统 [英] Win32: More "object oriented" window message handling system

查看:259
本文介绍了Win32:更多“面向对象”窗口消息处理系统的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Win32 API中,一个窗口具有指向处理其消息的WndProc函数的用户定义版本的指针。

In Win32 API a window has the pointer to a user defined version of WndProc function that handling its messages.

有一些方法来覆盖这种低级机制有一个像MFC消息映射等解决方案。

There are some ways to cover this low-level mechanism with a solution like MFC message map and so on.

在我的小应用程序中,我正在寻找一种方法来封装这个低级的东西与面向对象的解决方案。

In my very little app I'm looking for a way to encapsulate this low-level thing with a object oriented solution.

我试图用HWND键和MyWindowClass项创建一个C ++映射,当我创建一个MyClass对象时,我向映射添加了一个对,然后查找对于由HWN的MyWindowClass对象。但问题出在CreateWindowEx之后,调用Win32内部发送一个WM_CREATE消息到刚刚创建的窗口,所以我不能在这个消息之前添加在地图中的对,并且不能通过将WM_CREATE传递给对象实例化WndProc。

I tried to create a C++ map with HWND key and "MyWindowClass" item and when I created an object of the MyClass I added a pair to the map and then looking for the MyWindowClass object by HWN. But the problem is after CreateWindowEx called Win32 internally send a WM_CREATE message to the just created window so I can't add pair in the map before this message and can't control WM_CREATE through passing it to the object instanced WndProc.

代码是:

#ifndef NOTIFYWINDOW_H
#define NOTIFYWINDOW_H

#include "Bacn.h"

class NotifyWindow
{
private:

    HWND m_hWnd;

    Gdiplus::Graphics* m_graphics;

protected:

    static std::map<HWND, NotifyWindow*> s_NotifyWindows;

    static LRESULT CALLBACK s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    static void s_WndMessageLoop();

    LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);

    void Initialize();

    void OnPaint();

    void OnCreate();

public: 

    NotifyWindow();

    ~NotifyWindow();
};

#endif //NOTIFYWINDOW_H



And its implementation:

#include "NotifyWindow.h"

using namespace Gdiplus;
using namespace std;

map<HWND*, NotifyWindow> NotifyWindow::s_NotifyWindows;

LRESULT CALLBACK NotifyWindow::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    map<HWND, NotifyWindow*>::iterator search = s_NotifyWindows.find(hWnd);
    if (search != s_NotifyWindows.end())
    {
        search->second->WndProc(uMsg, wParam, lParam);
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);   
}

void NotifyWindow::s_WndMessageLoop()
{

}

LRESULT NotifyWindow::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        OnCreate();
        break;
    case WM_PAINT:
        OnPaint();
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_SIZE:
        break;
    case WM_SETFOCUS:
        break;
    case WM_KILLFOCUS:
        break;
    case WM_MOUSEMOVE:
        break;
    default:
        return DefWindowProc(m_hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

void NotifyWindow::Initialize()
{
    WNDCLASSEX wc;

    const wchar_t *className = L"BacnNotifyWindowClass";
    const wchar_t *windowName = L"BacnNotifyWindow";

    HINSTANCE hInstance = GetModuleHandle(NULL);

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpszClassName = className;
    wc.lpfnWndProc = NotifyWindow::s_WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = NULL;
    wc.hIconSm = NULL;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;

    RegisterClassEx(&wc);

    DWORD dwExtStyle = WS_EX_TOPMOST;
    DWORD dwStyle = WS_POPUP | WS_SYSMENU;  

    m_hWnd = CreateWindowEx(
        dwExtStyle,
        className,
        windowName,
        dwStyle,
        300,
        300,
        100,
        100,
        NULL,
        NULL,
        hInstance,
        NULL);  

    s_NotifyWindows.insert(pair<HWND, NotifyWindow*>(m_hWnd, this));

    ShowWindow(m_hWnd, SW_SHOW);
}

NotifyWindow::NotifyWindow()
{
    Initialize();   
}

NotifyWindow::~NotifyWindow()
{

}

void NotifyWindow::OnPaint()
{

}

void NotifyWindow::OnCreate()
{

}


推荐答案

建议:make WndProc 你的窗口基类。请求Windows为每个足够大以存储指针的窗口实例分配额外的内存(使用 cbWndExtra )。当创建一个窗口时,使用 SetWindowLongPtr 将一个指向你的窗口类对象的指针放入到与每个窗口实例相关联的额外内存中。在 static sWndProc 中,使用 GetWindowLongPtr 检索此指针,并调用您的窗口基类函数 virtual WndProc 。在我看来,它比拥有一个专门用于调度 WndProc 调用的额外地图对象更简洁。

Suggestion: make WndProc virtual in your window base class. Request Windows to allocate extra memory for each window instance big enough to store a pointer (use cbWndExtra). When creating a window, put a pointer to your windows class object into this extra memory associated with each window instance using SetWindowLongPtr. In your static sWndProc, retrieve this pointer using GetWindowLongPtr and call your window base class function virtual WndProc. In my opinion, it's more neat way than having a whole extra map object dedicated to dispatching WndProc calls.

编辑:另外,你意识到,在你的代码中,你试图注册Windows窗口类,每次创建一个窗口类的对象?如果你只创建一个窗口,这是技术上很好,我猜,但即使那么它是容易出错的设计。 Windows窗口类应该只注册一次,而不是每次使用此Windows窗口类创建一个窗口。

Plus, you do realize, in your code you are trying to register Windows window class every time you create an object of your window class? If you create just one window this is technically fine, I guess, but even then it's error-prone design. Windows window class should be registered just once, not every time you create a window with this Windows window class.

编辑:此外,在您的代码中,如果您不处理您的 WndProc 中的Windows消息,您的代码将调用 DefWindowProc 两次此消息:第一次在成员函数 switch 子句,第二次在 static sWndProc 中。 DefWindowProc 不应在同一封邮件上调用两次。

Also, in your code, if you are not processing Windows message in your WndProc, you code will call DefWindowProc twice for this message: first time in member function within switch clause, second time in static sWndProc. DefWindowProc shouldn't be called twice on the same message.

编辑:对不起,我错过了您的实际问题不知为什么,我认为你的帖子是关于设计,不是关于 WM_CREATE 。要处理 WM_NCCREATE WM_NCCALCSIZE WM_CREATE 统一的方式,可以在调用 CreateWindowEx 中设置 lpParam ,再次指向您的窗口类的对象。此参数将作为 CREATESTRUCT 的成员传递给 static sWndProc ,其中 WM_NCCREATE WM_CREATE 。您可以在 static sWndProc 中处理 WM_NCCREATE (要发送的第一条消息),获取此指针指向您的对象,使用 SetWindowLongPtr 将其放入窗口实例额外的内存,然后使用它调用成员函数 WndProc 如果你从它的构造函数中调用 CreateWindowEx ,那么请注意调用不完全创建的Windows类的对象。这样,您就不必担心程序中任何其他位置的低级Windows消息分派。当然,你仍然需要你的成员函数 WndProc 来调度消息到实际的函数调用。

Sorry, I missed your actual question before somehow, I thought your post was about design, not about WM_CREATE. In order to process WM_NCCREATE, WM_NCCALCSIZE or WM_CREATE in a uniform way, you can set lpParam in call to CreateWindowEx to, again, pointer to the object of your window class. This parameter will be passed to your static sWndProc as a member of CREATESTRUCT with WM_NCCREATE and WM_CREATE. You can process, say, WM_NCCREATE (first message to be sent) inside static sWndProc, get this pointer to your object, use SetWindowLongPtr to put it into window instance extra memory, and then use it to call member function WndProc (just be careful about calling not fully created object of your windows class, if you call CreateWindowEx from its constructor). This way, you don't need to worry about "low-level" Windows message dispatching anywhere else in your program. You, of course, will still need your member function WndProc to dispatch messages to actual function calls.

这篇关于Win32:更多“面向对象”窗口消息处理系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆