簡體   English   中英

如何在WinApi C ++包裝器中處理消息

[英]How to handle messages in WinApi C++ wrapper

我正在制作Windows API C ++包裝器。 頭文件如下所示:

#include <windows.h>
#include <exception>
#include <stdexcept>
const int NOID = -1;

class inst {
    struct impinst;  // pimpl idiom
    impinst *imp;

    friend class win;   // win needs to see the private members of inst
                        // (namely, the WNDCLASS)
public:
    inst(const char *, HINSTANCE, int=NOID,
         HICON=LoadIcon(NULL, IDI_APPLICATION));

    ~inst();
};
class win {
    struct impwidget;  // pimpl idiom
    impwidget *imp;
public:
    win(inst &, const char *, int=0, int=0, int=600, int=450);
    void show(int);
    WPARAM msgpump();

    ~win();
};

// These are the object oriented message classes
// handler will be implemented by user of the library
class msg {
public:
    virtual void handler();
};
class movemsg : public msg {
public:
    void handler();
};
class sizemsg : public msg {
public:
    void handler();
};

實施(cpp)文件:

#include "winlib.h"
struct inst::impinst {
    WNDCLASS wc;
    static LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
    {
        return DefWindowProc(hwnd, wm, wp, lp);
    }
    impinst(const char *classname, HINSTANCE hInst, int menuid, HICON hi)
    {
        this->wc.style = 0;
        this->wc.lpfnWndProc = this->winproc;
        this->wc.cbClsExtra = 0;
        this->wc.cbWndExtra = 0;
        this->wc.hInstance = hInst;
        this->wc.hIcon = hi;
        this->wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        this->wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
        this->wc.lpszMenuName = (menuid == NOID) ?
                                NULL : MAKEINTRESOURCE(menuid);
        this->wc.lpszClassName = classname;

        if (!RegisterClass(&this->wc))
            throw "Could not construct window instance";
    }
};
inst::inst(const char *classname, HINSTANCE hInst, int menuid, HICON hi)
{
    this->imp = new impinst(classname, hInst, menuid, hi);
}
inst::~inst()
{
    delete this->imp;
}


struct win::impwidget {
    HWND hwnd;

    impwidget(inst &i, const char *text, int x, int y, int width, int height)
    {
        this->hwnd = CreateWindow(i.imp->wc.lpszClassName, text,
                                  WS_OVERLAPPEDWINDOW, x, y, width, height,
                                  NULL, NULL, i.imp->wc.hInstance, NULL);
        if (this->hwnd == NULL)
            throw "Could not create window";
    }
};
win::win(inst &i, const char *text, int x, int y, int width, int height)
{
    this->imp = new impwidget(i, text, x, y, width, height);
}
void win::show(int cmdshow)
{
    ShowWindow(this->imp->hwnd, cmdshow);
    UpdateWindow(this->imp->hwnd);
}
WPARAM win::msgpump()
{
    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
win::~win()
{
    delete this->imp;
}

不過,我有一個問題:如何將所有消息處理程序函數傳遞給我的inst類,以便可以在winproc函數中實現它們? 現在,它是空的(只是調用DefWindowProc ),但是我需要它以某種方式獲取handler功能的所有用戶提供的實現,並將它們傳遞給winproc進行處理。 我該怎么辦? 我是否需要將指針傳遞給msg類?

編輯:

我的問題是不同的,因為我的問題是問什么要傳遞給lpParam的參數CreateWindow ,而不是如何像其他的問題。

將數據傳遞到winproc回調有點winproc ,但是如果您注意到CreateWindow的文檔,則有一個lpParam參數,可用於將數據傳遞到WM_CREATEWM_NCCREATE事件。

因此,您可以執行以下操作:

MyData* my_data = ...;
this->hwnd = CreateWindow(i.imp->wc.lpszClassName, text,
                          WS_OVERLAPPEDWINDOW, x, y, width, height,
                          NULL, NULL, i.imp->wc.hInstance,
                          my_data /* passed to WM_NCCREATE: */);

然后在winproc ,當您收到WM_NCCREATE消息時,我們可以使用SetWindowLongPtr將其關聯到窗口句柄,如下所示:

static LRESULT CALLBACK winproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_NCCREATE)
    {
        MyData* my_data = (MyData*)(LPCREATESTRUCT(lParam)->lpCreateParams);
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)my_data);
    }
    ...
}

對於其他事件,您可以使用以下方法檢索該數據:

LONG_PTR lpUserData = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (lpUserData)
{
     MyData* my_data = (MyData*)(lpUserData);
     // do stuff with `my_data`
}

它非常winproc回,因此很容易包裝它,並可能在傳遞my_data的回調之上創建自己的winproc方法(或者my_data可以是指向類的指針,您可以通過該方法調用方法)。 還要確保在銷毀窗口本身之前,銷毀my_data的指針。

這種回旋特性是必需的,因為在調用SetWindowLongPtr之前,我們必須首先確保成功創建了窗口。 最直接的操作是在WM_NCCREATE事件中,我們通過CreateWindow傳遞數據。 然后,我們可以檢索該數據並調用SetWindowLongPtr ,並在后續事件中通過GetWindowLongPtr訪問它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM