Search code examples
windowswinapiexit-code

Why does changing the window class name affect the exit code of a Win32 program?


Why does closing the created window result in an exit code of 134 (0x86) in the reproducible code example below?

What I also found, is that changing the const wchar_t CLASS_NAME[] variable results in a different exit code. Increasing the class name with 1 character, increases the exit code with 2, it seems.

What I would expect from this code, is an exit code of 0, right? What is causing this?

#include <Windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ int nShowCmd) {
    const wchar_t CLASS_NAME[] = L"AFEWCHARACTERS";

    WNDCLASSW wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClassW(&wc);

    HWND hwnd = CreateWindowExW(
        0,
        CLASS_NAME,
        L"Window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        nullptr,
        nullptr,
        hInstance,
        nullptr
    );

    if (hwnd != nullptr) {
        ShowWindow(hwnd, nShowCmd);
    }

    MSG msg{};
    while (GetMessageW(&msg, nullptr, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

Solution

  • Your code exhibits undefined behavior, as your wWinMain() function is missing a required return statement after its message loop finishes:

        MSG msg{};
        while (GetMessageW(&msg, nullptr, 0, 0) > 0) {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    
        return 0; // or msg.wParam // <-- ADD THIS!
    }
    

    The return value of wWinMain() is used to set the calling process's exit code upon a graceful exit (ie, if ExitProcess()/TerminateProcess() has not been called beforehand, and an uncaught exception has not been thrown). Per the GetExitCodeProcess() documentation:

    This function returns immediately. If the process has not terminated and the function succeeds, the status returned is STILL_ACTIVE (a macro for STATUS_PENDING (minwinbase.h)). If the process has terminated and the function succeeds, the status returned is one of the following values:

    • The exit value specified in the ExitProcess() or TerminateProcess() function.
    • The return value from the main() or WinMain() function of the process.
    • The exception value for an unhandled exception that caused the process to terminate.

    Only main() (which is defined by the C/C++ standards, and thus has special handling) is allowed to omit a return statement, in which case its return value will be 0 implicitly. Any other function with a non-void return type requires an explicit return, otherwise its return value will be indeterminate.