1

I need a window featuring no title bar, none of the control boxes, no system menu, and no frames (all that functionality is provided with separate controls).

I suspect that this should be possible to do with CreateWindowExA's window styles argument dwStyle and possibly lpWindowName, as described here: https://learn.microsoft.com/en-us/windows/desktop/winmsg/window-styles

This is how the arguments look like originally:

HWND hwnd = CreateWindowEx(
    0,                              // Optional window styles.
    CLASS_NAME,                     // Window class.
    L"",                            // No window name (title text).
    WS_OVERLAPPEDWINDOW,            // Window style.

    // Size and position.
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

    NULL,       // Parent window.
    NULL,       // Menu.
    hInstance,  // Instance handle.
    NULL        // Additional application data.
);

However, in dwStyle, the normal window style WS_OVERLAPPEDWINDOW is defined as

WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX

with WS_OVERLAPPED being 0x00000000L.

Simply providing 0 and omitting the rest doesn't work, as also the documentation implies: "The window is an overlapped window. An overlapped window has a title bar and a border."

(The funny thing is, I am perfectly able to do this task in VB.NET (and even in VB6) by setting the ControlBox property to False and then by removing the titlebar using Text = "", so I strongly suspect that when possible in VB...)

How would I do my task in C++?


Just in case the WindowProc is needed in order to process a different message, here it is in its minimalistic version:

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

        case WM_PAINT:
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
            EndPaint(hwnd, &ps);
            return 0;

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

(Compiling with VS 2017.)

  • 5
    WS_POPUP may work for you. https://learn.microsoft.com/en-us/windows/desktop/winmsg/window-styles – Retired Ninja Sep 20 '18 at 13:28
  • @RetiredNinja, unfortunately, it doesn't. Probably I should also show my WindowProc, in case I do not catch a needed message. Updating this now. –  Sep 20 '18 at 13:38
  • As @RetiredNinja pointed out, the decoration for a borderless/frameless window should be `WS_POPUP`. If I remind correctly, the default windows class generated by VS2017 set the background color to `(COLOR_WINDOW + 1)`, and you are painting a rect with color `(COLOR_WINDOW + 1)`... – Ayak973 Sep 20 '18 at 14:13
  • Use the Spy++ utility to see what style flags are used, mapping of the style flags is not very intuitive after 32 years. VB.NET uses style = WS_CLIPCHILDREN | WS_TABSTOP, exstyle = WS_EX_APPWINDOW | WS_EX_CONTROLPARENT and a NULL for the window text. Or in other words, it is WS_CLIPCHILDREN that actually helps to avoid WS_OVERLAPPED :) Why WS_POPUP produces an invisible window is not intuitive to me, it is not CW_USEDEFAULT. – Hans Passant Sep 20 '18 at 14:18
  • 3
    `WS_POPUP` normally works. It doesn't work in your case, because you still have `CW_USEDEFAULT` arguments, which are only valid for overlapped windows. _"if CW_USEDEFAULT is specified for a pop-up or child window, nWidth and nHeight are set to zero."_ – zett42 Sep 20 '18 at 14:18
  • 1
    [Another technique](https://stackoverflow.com/q/43818022/7571258), which removes the border but keeps the drop shadow. – zett42 Sep 20 '18 at 14:21
  • @zett42, thanks. When I replace position and size with, say, 100, 100 and 100, 100, it works like intended. If you bother to transform your comment into an answer, I'd gladly accept it as the solution. –  Sep 21 '18 at 02:32

1 Answers1

0

The non-client area of a top-level window can be removed by using only the WS_POPUP style:

HWND hwnd = CreateWindowEx(
    0,                              // Optional window styles.
    CLASS_NAME,                     // Window class.
    L"",                            // No window name (title text).
    WS_POPUP,                       // Window style.

    // Size and position.
    100, 100, 400, 300,

    NULL,       // Parent window.
    NULL,       // Menu.
    hInstance,  // Instance handle.
    NULL        // Additional application data.
);

Note that CW_USEDEFAULT for size and position is only valid for overlapped windows. For popup windows you have to be explicit.

Depending on your use case, the technique described by this answer might be better suitable. Using the DWM API, it allows you to remove the non-client area, but keep the drop shadow to make the window stand out better from the background.

zett42
  • 25,437
  • 3
  • 35
  • 72