0

我以前练习过winapi应用程序,但从来没有遇到过这个问题。

我尝试制作一个自定义 WindowProc 来覆盖 WM_QUIT/WM_CLOSE/WM_DESTROY 消息的默认行为以不执行任何操作,但是当我按下 ALT 时窗口仍然关闭!

这是整个代码:

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
    const LPCSTR className = "Class name";
    WNDCLASS wc = {};
    wc.style = 0;
    wc.lpfnWndProc = DefWindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(nullptr);
    wc.hIcon = nullptr;
    wc.hCursor = nullptr;
    wc.hbrBackground = nullptr;
    wc.lpszMenuName = nullptr;
    wc.lpszClassName = className;

    RegisterClass(&wc);
    HWND window = CreateWindow(className, "Title", WS_OVERLAPPEDWINDOW, 200, 200, 600, 400, nullptr, nullptr, nullptr, nullptr);

    ShowWindow(window, SW_SHOW);

    MSG msg = {};

    while (msg.wParam != WM_QUIT)
    {
        while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return msg.wParam;
}

我相信当我按下 ALT 时窗口不应该关闭,但确实如此。

4

2 回答 2

4

您正在将message字段与wParam字段混合:

while (msg.wParam != WM_QUIT)

当您按下 ALT 时,窗口会收到一条WM_KEYDOWN消息,该消息wParam是虚拟键码。WM_QUIT碰巧 ALT 具有与(0x12)的常量相同的 VK 代码。

此外,您还在WM_QUIT退出前进行翻译和调度。您可以通过使用适当的检查进行单级缩进来处理这两种情况:

while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) && msg.message != WM_QUIT)

正如评论中所指出的,这更干净GetMessage

while (GetMessage(&msg, nullptr, 0, 0) > 0)
于 2019-10-19T17:58:05.867 回答
3

您的代码存在一些问题。

首先,您应该使用GetMessage()而不是PeekMessage(). 根本区别在于它PeekMessage()是非阻塞的,因此您的程序将使用 100% 的 CPU 来运行该循环。

此外,由于内部循环可能会或可能不会连续遍历多条消息,因此像您正在做的那样检查外部循环上的内容将是命中或未命中,并且不会检查所有消息。您应该检查内部循环中的每条消息。

但在这种情况下,没有必要,因为如果窗口关闭,这个循环就会结束。你做的这个检查是没有意义的。

您的代码还有其他一些不一致之处,wc.hInstance应该是hInstance您作为参数收到的WinMain(). 无需使用 API 去寻找这些信息。

CreateWindow()应该hInstance再次接收,因为它是倒数第二个参数,而不是nullptr.

最后,正如克里斯的回答所指出的那样,您应该寻找消息类型 inmsg.message而不是 in msg.wParam

除此之外,这里没有做“自定义 WindowProc”的地方。如果你想做一个自定义的 WndProc 那么你应该设置wc.lpfnWndProc为你自己的函数而不是DefWindowProc,你可以在那里为你的 Window 定义自定义行为。

例如:

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
    case WM_DESTROY:
        // do nothing
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

请注意,无需测试WM_QUIT,因为此消息仅在您的应用程序调用PostQuitMessage().

于 2019-10-19T18:09:27.217 回答