我正在制作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
回调有点麻烦,但是如果您注意到CreateWindow
的文档,则可以使用lpParam
参数将数据传递到WM_CREATE
或WM_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`
}
这是一个非常so回的操作,因此可以很方便地包装它,并可以在传递
winproc
的回调函数的顶部制作自己的my_data
方法(或者my_data
可以是指向类的指针,您可以通过该方法调用方法)。还要确保my_data
的指针不会在窗口本身被破坏之前被破坏。这种回旋特性是必需的,因为在调用
SetWindowLongPtr
之前,我们必须首先确保成功创建了窗口。最直接的操作是在WM_NCCREATE
事件中,我们通过CreateWindow
传递数据。然后,我们可以检索该数据并调用SetWindowLongPtr
,并在后续事件中通过GetWindowLongPtr
访问它。关于c++ - 如何在WinApi C++包装器中处理消息,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33857409/