Search code examples
cwindowswinapiwindowcl

Winapi Window in c not responding


I've been trying to make a simple window using WinAPI, it compiles and links with some warnings, when I open the program the window shows up, but when I try to interact with it, a windows warning sound is played and it doesn't allow me to use the window, not even close it, I have to use task manager.

To compile it I'm using Microsoft's "cl.exe" with the command line:

cl /c window.c

and the warnings are:

window.c(39): warning C4133: 'function': incompatible types, from 'LPSTR' to 'HINSTANCE'
window.c(40): warning C4133: 'function': incompatible types, from 'LPSTR' to 'HINSTANCE'
window.c(41): warning C4047: '=': 'HBRUSH' differs in levels of indirection from 'int'

To link I use crinkler with the commandline:

crinkler /NODEFAULTLIB /ENTRY:main /SUSBYSTEM:WINDOWS /TINYHEADER /TINYIMPORT /OUT:c.exe window.obj kernel32.lib user32.lib

and the warning is:

: warning LNK: Entry point not at start of section, jump necessary

The code I'm using is:

#include <windows.h>

#define WINDOW_STYLE        WS_VISIBLE+WS_OVERLAPPEDWINDOW-WS_THICKFRAME-WS_MAXIMIZE
#define WINDOW_WIDTH        640
#define WINDOW_HEIGHT       480

static const char* window_name = "My Window";
RECT window_rect = {0, 0, WINDOW_HEIGHT, WINDOW_WIDTH};

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

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

int main()
{
    int ret = 0;
    HMODULE instance = GetModuleHandleA(NULL);

    AdjustWindowRect(&window_rect, WINDOW_STYLE, FALSE);

    WNDCLASSEXA window_class;
    window_class.cbSize = 48;
    window_class.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW;
    window_class.lpfnWndProc = WindowProc;
    window_class.cbClsExtra = 0;
    window_class.cbWndExtra = 0;
    window_class.hInstance = instance;
    window_class.hIcon = LoadIconA(IDI_APPLICATION, 0);
    window_class.hCursor = LoadCursorA(IDI_APPLICATION, 0);
    window_class.hbrBackground = COLOR_WINDOW;
    window_class.lpszMenuName = 0;
    window_class.lpszClassName = window_name;
    window_class.hIconSm = 0;

    if (RegisterClassExA(&window_class)) {

        HWND window = CreateWindowExA(
            0,
            window_name,
            window_name,
            WINDOW_STYLE,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            window_rect.right - window_rect.left,
            window_rect.bottom - window_rect.top,
            0,
            0,
            instance,
            NULL);

        ShowWindow(window, SW_SHOW);
        UpdateWindow(window);

        MSG msg;

        while(1)
        {
            if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
                if (msg.message == WM_QUIT) {
                    ExitProcess(0);
                    break;
                } else {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
        }
    } else {
        ret = 1;
    }

    ExitProcess(0);

    return ret;
}

Does anybody know how to fix it? Thanks.


Solution

  • The following line doesn't do what you think it does:

    #define WINDOW_STYLE WS_VISIBLE+WS_OVERLAPPEDWINDOW-WS_THICKFRAME-WS_MAXIMIZE
    

    While somewhat common, and occasionally even producing the correct value, it is a very brittle way to implement bit manipulations. In this particular case, the expression expands to:

    0x10000000L + 0x00CF0000L - 0x00040000L - 0x01000000L
    

    This produces the value 0xFFCB0000L1 (due to accidentally using WS_MAXIMIZE instead of WS_MAXIMIZEBOX). This translates to a window with the following styles:

    • WS_POPUP
    • WS_CHILD (note, that this is already mutually exclusive with WS_POPUP)
    • WS_ICONIC
    • WS_VISIBLE
    • WS_DISABLED
    • ...

    As documented:

    WS_DISABLED: The window is initially disabled. A disabled window cannot receive input from the user. To change this after a window has been created, use the EnableWindow function.

    That explains why you cannot interact with your window. The fix is simple: Use bitwise operators for bit manipulations instead of arithmetic operators:

    #define WINDOW_STYLE (WS_VISIBLE | WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZE)
    

    1 Leaving the fact, that the behavior for signed overflow is undefined aside.