WndProc 作为类成员,无法退出
Posted
技术标签:
【中文标题】WndProc 作为类成员,无法退出【英文标题】:WndProc as a class member, fails to quit 【发布时间】:2014-03-15 19:59:27 【问题描述】:我想让 WndProc 成为一个类成员函数,我找到了this article,所以我尝试将它应用到最简单的 Win32 程序中,它只是创建一个空白窗口,这是 Win32 的第一步。
int Myclass::Start(HINSTANCE hInstance, int nCmdShow)
if (FAILED(InitWindow(hInstance, nCmdShow)))
return 0;
MSG msg = 0 ;
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
return (int)msg.wParam;;
LRESULT Myclass::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
Myclass* pThis = nullptr;
if (message == WM_NCCREATE)
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<Myclass*>(lpcs->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
else
pThis = reinterpret_cast<Myclass*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if(pThis)
return pThis->RealWndProc(hWnd, message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
LRESULT Myclass::RealWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
PAINTSTRUCT ps;
HDC hdc;
switch (message)
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
它运行良好,但是当我关闭窗口时,程序停留在消息循环中并且不会退出。
我发现WM_DESTROY没有传递给RealWndProc(),所以没有调用PostQuitMessage()。
如果我插入 if(WM_DESTROY == message) PostQuitMessage(0);返回0; 在 StaticWndProc 的最后一行之前,然后程序退出。但我不确定这是否是一个好方法。
如何让 RealWndProc() 使用 WM_DESTROY?
【问题讨论】:
【参考方案1】:我就是这样做的.. 工作得很好.. 我能在你的代码中想到的唯一问题是两个之一:
您错过了 WindowProcedure 的调用约定。 您忘记将“this”传递给 CreateWindowEx。还有代码:
#include <windows.h>
class Window
public:
Window(LPCTSTR Title, LPCTSTR Class, DWORD dwStyleEx = 0, DWORD dwStyle = WS_OVERLAPPEDWINDOW,
POINT Location = CW_USEDEFAULT, CW_USEDEFAULT, int Width = CW_USEDEFAULT,
int Height = CW_USEDEFAULT, HWND Parent = HWND_DESKTOP, HMENU Menu = nullptr);
int Loop();
private:
HWND WindowHandle;
static LRESULT __stdcall WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
LRESULT RealWindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);
;
Window::Window(LPCTSTR Title, LPCTSTR Class, DWORD dwStyleEx, DWORD dwStyle, POINT Location, int Width, int Height, HWND Parent, HMENU Menu)
WNDCLASSEX WndClass =
sizeof(WNDCLASSEX), CS_DBLCLKS, Window::WindowProcedure,
0, 0, GetModuleHandle(nullptr), LoadIcon(nullptr, IDI_APPLICATION),
LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_BACKGROUND),
nullptr, Class, LoadIcon(nullptr, IDI_APPLICATION)
;
if(RegisterClassEx(&WndClass))
WindowHandle = CreateWindowEx(dwStyleEx, Class, Title, dwStyle, Location.x, Location.y, Width, Height, Parent, Menu, GetModuleHandle(nullptr), this);
LRESULT __stdcall Window::WindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
Window* Data = nullptr;
switch(Msg)
case WM_NCCREATE:
CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
Data = static_cast<Window*>(pCreate->lpCreateParams);
SetWindowLongPtr(Hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(Data));
break;
default:
Data = reinterpret_cast<Window*>(GetWindowLongPtr(Hwnd, GWLP_USERDATA));
break;
return Data ? Data->RealWindowProcedure(Hwnd, Msg, wParam, lParam) : DefWindowProc(Hwnd, Msg, wParam, lParam);
LRESULT Window::RealWindowProcedure(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
switch(Msg)
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(Hwnd, Msg, wParam, lParam);
return 0;
int Window::Loop()
MSG Messages = nullptr;
ShowWindow(WindowHandle, SW_SHOW);
while(GetMessage(&Messages, nullptr, 0, 0))
TranslateMessage(&Messages);
DispatchMessage(&Messages);
return Messages.wParam;
int main()
Window w("TItle", "Class");
return w.Loop();
【讨论】:
你是对的!将“this”传递给 CreatWindow 解决了这个问题!我认为 InitWindow() 是微不足道的,所以我省略了它,但我错了。我刚刚发现那篇文章中甚至提到了它......哦,我的......(叹气)非常感谢!【参考方案2】:你应该抓住WM_CLOSE
并让它调用DestroyWindow()
来触发WM_DESTROY
:
case WM_CLOSE:
DestroyWindow(hWnd);
break;
另外,您的 StaticWndProc()
方法使用了错误的调用约定。它必须使用__stdcall
调用约定,由WINAPI
和CALLBACK
宏包装,例如:
LRESULT CALLBACK Myclass::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
【讨论】:
据我所知,你所说的 WM_CLOSE 是由 DefWindowProc 完成的,不是吗?对于调用约定,我在头文件中写了“CALLBACK”,但我没有提到它,所以这是我的错误。 :)以上是关于WndProc 作为类成员,无法退出的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 boost::tokenizer 作为 C++ 类成员?