【问题标题】:WM_DESTROY not called inside wrapped WndProcWM_DESTROY 未在包装的 WndProc 内调用
【发布时间】:2017-12-29 22:49:55
【问题描述】:

我采用了您在那里找到的典型解决方案,以便使用WNDPROC 作为对象方法,但看起来WM_DESTROY 消息没有发送到对象窗口自己的WNDPROC 并且程序确实关闭窗口后不退出。

我的窗口类看起来像这样(删除了不相关的代码):

class MyWindow : MyApp
{
public:
    MyWindow();
    void Create(void);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
private:
    HWND _hWnd;
};

void MyWindow::Create()
{
    // Here I register my class and call CreateWindowEx
    // Everything works fine so far

    // Part of the code where I assign the static WNDPROC
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = MyApp::WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = this->Instance;
    wcex.hIcon = LoadIcon(this->Instance, MAKEINTRESOURCE(32512));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = "MyWindowClass";
    wcex.hIconSm = LoadIcon(this->Instance, MAKEINTRESOURCE(32512));

    RegisterClassExW(&wcex);

    this->_hWnd = CreateWindowExW(
        WS_EX_TOOLWINDOW | WS_EX_TOOLWINDOW,
        wcex.lpszClassName,
        "Window Title",
        WS_POPUP,
        10, 10,
        600, 400,
        nullptr, 
        nullptr, 
        this->Instance,
        nullptr
    );

    ShowWindow(this->_hWnd, SW_SHOW);
    UpdateWindow(this->_hWnd);
}

LRESULT CALLBACK MyWindow::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        // If I place a MessageBox here, it shows up
    }
    break;
    case WM_DESTROY:
        // It never gets to this point

        // Decrease windows count
        this->WindowsCount--;

        PostQuitMessage(0);
        break;
    break;
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    return 0;
}

现在是一个包含静态 WNDPROC 的类,它是在创建时分配的

class MyApp
{
public:
    static HINSTANCE Instance;
    static int WindowsCount;

    MyApp();
    static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
};

和实施

LRESULT CALLBACK MyApp::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // Window object
    MyWindow* myWindow = NULL;

    if (msg == WM_CREATE) {
        myWindow = reinterpret_cast<MyWindow *>(((LPCREATESTRUCT)lParam)->lpCreateParams);
        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)myWindow);
    }
    else {
        myWindow = reinterpret_cast<MyWindow *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
    }

    // If window not identified, identify now
    if (myWindow) {
        return myWindow->WndProc(hWnd, msg, wParam, lParam);
    }

    // Call window object's processor
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

WM_CLOSE 消息也未被捕获。我真的不明白为什么这些消息没有传递出去

【问题讨论】:

  • MyApp::WndProc 中第一个 if 语句的逻辑是错误的。
  • 对不起,谢谢。无论如何,这不是原因。问题依旧
  • 这个窗口是对话框吗? 关闭窗口后 - 可能只是窗口被隐藏但没有被破坏?
  • 这是一个用WS_EX_TOOLWINDOWWS_POPUP创建的窗口。但是即使我把它改成WS_OVERLAPPEDWINDOWWS_EX_APPWINDOW,结果都是一样的
  • 代码中也没有WM_CLOSE 的句柄。无论如何-当您真正按下关闭按钮时-您会收到此消息。如果窗口被破坏 - 你得到wm_destroy。所以你的消息处理程序有问题

标签: c++ winapi window wrapper wndproc


【解决方案1】:

您将CreateWindowEx()lpParam 参数设置为nullptr,因此myWindowMyApp::WndProc() 中始终为nullptr,因此永远不会调用MyWindow::WndProc()。您需要传递this 而不是nullptr

在调用 ShowWindow()/UpdateWindow() 之前,您也没有进行任何错误检查以确保 RegisterClassExW()CreateWindowEx() 成功。

另外,请考虑使用SetWindowSubclass() 而不是(Get|Set)WindowLongPtr(GWLP_USERDATA)。请参阅 MSDN 上的 Subclassing Controls,以及 Safer Subclassing 上 Raymond Chen 的博客文章。

【讨论】:

  • 谢谢。我认为SetWindowSubclass() 仅适用于子窗口/控件,不适用于主窗口。我会改成这样的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
  • 2011-12-08
  • 2016-05-16
  • 1970-01-01
  • 2017-09-08
  • 2020-05-13
相关资源
最近更新 更多