简体   繁体   English

WndProc作为班级成员,未能退出

[英]WndProc as a class member, fails to quit

I want to make WndProc a class member function and I found this article , so I tried to apply it to the simplest Win32 program, which does nothing but creating a blank window, the very first step of Win32. 我想让WndProc成为一个类成员函数,我找到了这篇文章 ,所以我试着将它应用到最简单的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;
}

It runs well, but when I close the window the program stays in the message loop and doesn't quit. 它运行良好,但当我关闭窗口时,程序保持在消息循环中并且不会退出。

I found out that WM_DESTROY is not delivered to RealWndProc(), so PostQuitMessage() is not called. 我发现WM_DESTROY没有传递给RealWndProc(),因此没有调用PostQuitMessage()。

If I insert if(WM_DESTROY == message) { PostQuitMessage(0); 如果我插入if(WM_DESTROY == message){PostQuitMessage(0); return 0; 返回0; } right before the last line of StaticWndProc, then the program quits. }右StaticWndProc最后前行,然后程序退出。 But I'm not sure if this is a good way to do it. 但我不确定这是否是一个很好的方法。

How can I make WM_DESTROY consumed by RealWndProc()? 如何使RealWndProc()消耗WM_DESTROY?

Like this is how I did it.. Works just fine.. The only problem I can think of in your code is one of two: 像这样我是怎么做的..工作得很好..我能在你的代码中想到的唯一问题是两个中的一个:

  • You missed the calling convention for the WindowProcedure. 你错过了WindowProcedure的调用约定。
  • You forgot to pass "this" to CreateWindowEx. 你忘了将“this”传递给CreateWindowEx。

And the code: 和代码:

#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();
}

You should catch WM_CLOSE and have it call DestroyWindow() to trigger WM_DESTROY : 你应该捕获WM_CLOSE并让它调用DestroyWindow()来触发WM_DESTROY

case WM_CLOSE:
    DestroyWindow(hWnd);
    break;

Also, your StaticWndProc() method is using the wrong calling convention. 此外,您的StaticWndProc()方法使用错误的调用约定。 It must use the __stdcall calling convention, which is wrapped by WINAPI and CALLBACK macros, eg: 必须使用__stdcall调用约定,该约定由WINAPICALLBACK宏包装,例如:

LRESULT CALLBACK Myclass::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM