1

いくつかのチュートリアルに従って、win32APIを学習しようとしています。
(ただし、フチなしの固定ウィンドウを作成するために非常に小さな調整を行いました。)

ただし、私の最も単純なウィンドウアプリケーションは、ランダムなコードで終了します。
コード「0」で終了しない理由がわかりません。

詳細については、Visual Studio2012Proを使用しています。
ソースコードのファイル拡張子は.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を使用してアプリを終了する必要がありますが、次の1つを除いて見栄えがよくなります。

GetMessageは、「BOOL」を返すと主張しているにもかかわらず、実際にはintを返します。成功した場合は正の値、WM_QUITを受信した場合は0、エラーの場合は-1を返します。GetMessage(およびその他の関数)から「 BOOLplus a lil'somethingsomething」を返すというMicrosoftのポリシーは、この理由で愚かで危険であり、鞭打ちする必要があります。

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 に答える