1

我正在尝试通过遵循一些教程来学习 win32 API。
(虽然,我做了非常小的调整来创建一个无边框的固定窗口。)

但是,我最简单的窗口应用程序正在退出一些随机代码。
我不知道为什么它没有以代码“0”退出。

有关更多信息,我使用的是 Visual Studio 2012 Pro。
源代码的文件扩展名为 .c,编译器设置可能是默认设置。
我将该项目创建为一个空的 win32 应用程序(不是控制台)。

请,一些帮助将不胜感激。
谢谢你。

#include <Windows.h>
#include <windowsx.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int __stdcall WinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPSTR lpCmdLine,
                      INT nCmdShow) {
    HWND hWnd;
    WNDCLASSEX wcex;
    MSG msg;

    ZeroMemory(&wcex, sizeof(WNDCLASSEX));

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc  = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"WindowClass1";
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(
            NULL,
            L"Failed to register window!",
            L"ERROR",
            MB_OK | MB_ICONEXCLAMATION);
        return EXIT_FAILURE;
    }

    hWnd = CreateWindowEx(
        0,
        L"WindowClass1",
        L"Application",
        WS_POPUP,
        0, 0,
        GetSystemMetrics(SM_CXSCREEN),
        GetSystemMetrics(SM_CYSCREEN),
        NULL, NULL, hInstance, NULL);


    if (hWnd == NULL)
    {
        MessageBox(
            NULL,
            L"Failed to create window!",
            L"ERROR",
            MB_OK |  MB_ICONEXCLAMATION);
        return EXIT_FAILURE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    while (GetMessage(&msg, hWnd, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }

    return 0;
}
4

2 回答 2

3

在您的程序中,GetMessage实际上是返回-1这是一个错误条件。您的消息循环在GetMessage返回值 <=0 时终止,因此它在GetMessage返回 -1 时终止。

现在,因为最终调用GetMessage失败并出现错误,所以 的值msg.wParam没有明确定义。您不应将其作为退出代码返回。您应该只msg.wParam在最终调用返回 0 时作为退出代码返回。这一切都在文档GetMessage中明确说明。

如果您将消息循环更改为如下所示,您可以看到所有这些:

while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        return GetLastError();
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}

return msg.wParam;

在我的机器上,bRet == -1选择了路线,错误代码是 1400。这是ERROR_INVALID_WINDOW_HANDLE. 我不太清楚你的应用为什么会这样,但我很满意我已经回答了你关于退出代码的问题!

于 2012-12-03T21:37:20.870 回答
2

除了用空白窗口覆盖整个屏幕,需要使用 ALT-F4 退出您的应用程序之外,一切看起来都不错,除了一件事:

GetMessage,尽管声称返回“BOOL”,但实际上返回 int:成功时返回一些正值,接收到 WM_QUIT 时返回 0,出错时返回 -1。出于这个原因,微软从 GetMessage(和其他函数)返回“ BOOL plus a lil' something something ”的政策是愚蠢和危险的,他们应该为此受到鞭笞。

如果 GetMessage 返回 -1 则 msg 的内容可能有效也可能无效;换句话说,wParam 可能为零,也可能为零potato。这可能会转化为您看到的“随机”退出代码。

我建议这样的事情:

int nRet;

do
{
    nRet = GetMessage(&msg, hWnd, 0, 0);

    if(nRet == -1)
        return GetLastError();

    if(nRet != 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
} while(nRet != 0);

return msg.wParam;
于 2012-12-03T22:11:25.923 回答