Win32 C++ Trouble Replacing DWM Extended Frame

k combs 6 Reputation points
2021-04-20T00:18:04.787+00:00

EDIT: If this question is not in the right place, feel free to move. I'm not sure I posted this in the right place.

Hi there! First time using this website, so I'm sorry if I don't format the code right or if I make a silly mistake. But I am working on a nonstandard caption and border for my application. My end goal is to replace the standard caption and border, completely. I was following a tutorial on MSDN about DWM (https://learn.microsoft.com/en-us/windows/win32/dwm/customframe), but they never mention how to (properly) draw the border.

From my research, people say to use WM_PAINT to draw the caption and border, yet there's my problem. The only that happens is Windows will draw my caption and frame OVER its own caption and border. I can draw anything perfectly fine in the "nonclient" area, but windows keep's the original frame underneath, and the color of my own caption and frame is altered by what's underneath (dark grey makes my green system color turn a lighter green). I cannot get Window's to stop drawing it's own border underneath my own unless I override the WM_NCPAINT message. Is this behavior suppose to happen?

I am using a Layered Window (I heard it's good on performance), is that what's causing the problem? The Layered Window doesn't have the jittery buffer junk that non-layered windows have, so I'm not sure what's going on.

How would I prevent this awkward behavior? Everything I've tried so far as only made the caption and borders disappear or become... "unintelligible" to say the least. I'm worried about overriding WM_NCPAINT because I've heard that it's not the "right way" to do a custom frame, and I've tried overriding that message before. But it really just obliterates the entire nonclient window, and I cannot get stuff to draw properly (transparent, looks like a phantom of Windows 7 Aero).

Thanks again for any help! And here is the code I have so far (the margins are correct: the window is supposed to resemble windows 7 and 8.1/8).

Here is what I mean:

89283-untitled.png

Here is my code so far:

#include <dwmapi.h>  
#include <Uxtheme.h>  
#include <vssym32.h>  
#include <windowsx.h>  
  
#pragma comment(lib, "uxtheme.lib")  
#pragma comment(lib, "dwmapi.lib")  
  
#include <defs.h>  
  
#define FRAMEWIDTH      8  
#define CAPTIONHEIGHT   27  
  
#define RECTRIGHT(v)  v.right  
#define RECTBOTTOM(v) v.bottom  
#define RECTLEFT(v)   v.left  
#define RECTTOP(v)    v.top  
#define RECTSIZE1(v)  (RECTRIGHT(v) - RECTLEFT(v))  
#define RECTSIZE2(v)  (RECTBOTTOM(v) - RECTTOP(v))  
  
#ifdef __cplusplus  
extern "C"  
{  
#endif  
  
HINSTANCE hDesktopApp;  
TCHAR lpszTitle[] = TEXT("wordproc");  
TCHAR lpszWindowClass[] = TEXT("DesktopApp");  
  
VOID NewDesktopApp(HINSTANCE hInstance);  
      
#define SDK_HGDI_SOLID_BRUSH_SIZE   8  
#define SDK_HGDI_PEN_SIZE           8  
  
HBRUSH  hFrameBrushPtr  [SDK_HGDI_SOLID_BRUSH_SIZE];  
HPEN    hFramePenPtr    [SDK_HGDI_PEN_SIZE];  
  
#define HWND_HT_FRAME_BA0   HTTOPLEFT  
#define HWND_HT_FRAME_BA1   HTLEFT  
#define HWND_HT_FRAME_BA2   HTBOTTOMLEFT          
#define HWND_HT_FRAME_BA3   HTBOTTOM          
#define HWND_HT_FRAME_BA4   HTBOTTOMRIGHT     
#define HWND_HT_FRAME_BA5   HTRIGHT       
#define HWND_HT_FRAME_BA6   HTTOPRIGHT    
#define HWND_HT_FRAME_BA7   HTTOP  
#define HWND_HT_NULL        HTNOWHERE  
#define HWND_HT_FRAME_BA8   HWND_HT_NULL  
#define HWND_HT_CAPTION     HTCAPTION  
#define HWND_HT_CLIENT      HTCLIENT  
#define HWND_HT_MAXBUTTON   HTMINBUTTON  
#define HWND_HT_MAXBUTTON   HTMAXBUTTON  
#define HWND_HT_CLOSE       HTCLOSE  
static  
LRESULT WINAPI PaintNonClientArea(HWND hWnd, HRGN hNCregion)  
{  
    LONG_PTR    lRet    = (LONG_PTR)0;  
    RECT        rNCRect;  
    PAINTSTRUCT ps;  
    HDC         hDC;  
    HDC         hMemDC;             // <- might go unused, but here in case needed  
    HANDLE      oldBrush;  
    HANDLE      oldPen;  
      
    hDC = BeginPaint(hWnd, &ps);  
    FillRect(hDC, &ps.rcPaint, reinterpret_cast<HBRUSH>(hFrameBrushPtr[0]));  
  
    BOOL bRet;  
    bRet = EndPaint(hWnd, &ps);  
    if (bRet == FALSE)  
    {  
        // error.  
    }  
  
    return (LONG_PTR)1;  
}  
  
static  
LRESULT SetHWNDInfoForDWM(HWND hWnd)  
{  
    const MARGINS margins =  
    {  
        8,  
        8,  
        28,  
        8  
    };  
  
    HRESULT hr = DwmExtendFrameIntoClientArea(hWnd, &margins);  
    if (!SUCCEEDED(hr))  
    {  
        return (LONG_PTR)0;  
    }  
  
    DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED;  
    hr = DwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, (void*)&ncrp, sizeof(DWMNCRENDERINGPOLICY));  
    if (!SUCCEEDED(hr))  
    {  
        return (LONG_PTR)0;  
    }  
  
    BOOL bDrawNC = TRUE;  
    hr = DwmSetWindowAttribute(hWnd, DWMWA_ALLOW_NCPAINT, (void*)&bDrawNC, sizeof(BOOL));  
    if (!SUCCEEDED(hr))  
    {  
        return (LONG_PTR)0;  
    }  
  
    return (LONG_PTR)1;  
}  
  
static  
LRESULT HitTest(HWND hWnd, WPARAM wParam, LPARAM lParam)  
{  
    bool fOnResizeBorder = false;  
    BOOL bRet;  
    LONG_PTR lRet = (LONG_PTR)0;  
             
    RECT rcWindow =   
    {  
        0,  
        0,  
        0,  
        0  
    };  
    bRet = GetWindowRect(hWnd, &rcWindow);  
    if (bRet == FALSE)  
    {  
    }  
  
    DWORD dwExStyle = (DWORD)(WS_EX_LAYERED);  
    DWORD dwStyle = ((DWORD)(WS_VISIBLE | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_DLGFRAME | WS_THICKFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS));  
  
    RECT rcNCregion =   
    {  
        0,  
        0,  
        0,  
        0  
    };  
    bRet = AdjustWindowRectEx(&rcNCregion, dwStyle & ~WS_CAPTION, FALSE, dwExStyle);  
    if (bRet == FALSE)  
    {  
    }  
  
    INT dwRow = 1;  
    INT dwCol = 1;  
  
    POINT pt;  
    pt.x = LOWORD(lParam);  
    pt.y = HIWORD(lParam);  
  
    if (pt.y >= rcWindow.top && pt.y < rcWindow.top + CAPTIONHEIGHT)  
    {  
        if (pt.y < (rcWindow.top - rcNCregion.top))  
        {  
            dwRow = 0;  
        }  
        else  
        {  
            return HTCAPTION;  
        }  
    }  
  
    if (pt.y < rcWindow.bottom && pt.y >= rcWindow.bottom - FRAMEWIDTH)  
    {  
        dwRow = 2;  
    }  
  
    if (pt.x >= rcWindow.left && pt.x < rcWindow.left + FRAMEWIDTH)  
    {  
        dwCol = 0;  
    }  
      
    if (pt.x < rcWindow.right && pt.x >= rcWindow.right - FRAMEWIDTH)  
    {  
        dwCol = 2;  
    }  
      
    static LONG_PTR larrHitTest[3][3] =  
    {  
        { HWND_HT_FRAME_BA0, HWND_HT_FRAME_BA7, HWND_HT_FRAME_BA6 },  
        { HWND_HT_FRAME_BA1, HWND_HT_FRAME_BA8, HWND_HT_FRAME_BA5 },  
        { HWND_HT_FRAME_BA2, HWND_HT_FRAME_BA3, HWND_HT_FRAME_BA4 }  
    };  
  
    return larrHitTest[dwRow][dwCol];  
}  
  
static  
LRESULT WINAPI RecalcNonClientArea(LPARAM lParam)  
{  
    LONG_PTR            lRet        = (LONG_PTR)0;  
    NCCALCSIZE_PARAMS*  lpParams    = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);  
  
    RECTLEFT  (lpParams->rgrc[0]) = RECTLEFT  (lpParams->rgrc[0]) + 0;  
    RECTTOP   (lpParams->rgrc[0]) = RECTTOP   (lpParams->rgrc[0]) + 0;  
    RECTBOTTOM(lpParams->rgrc[0]) = RECTBOTTOM(lpParams->rgrc[0]) - 0;  
    RECTRIGHT (lpParams->rgrc[0]) = RECTRIGHT (lpParams->rgrc[0]) - 0;  
  
    lRet = ((LONG_PTR)(WVR_VALIDRECTS));  
  
    return lRet;  
}  
  
BOOL WINAPI InitializeResources(VOID)  
{  
    BOOL bRet = FALSE;  
  
    // initialize solid-color paint brushes  
    hFrameBrushPtr[0] = reinterpret_cast<HBRUSH>(CreateSolidBrush(RGB( 52,  52, 52)));  // color: Non-client Window Frame Border  
    hFrameBrushPtr[1] = reinterpret_cast<HBRUSH>(CreateSolidBrush(RGB(203,  94, 72)));  // color: HTCLOSE color   
    hFrameBrushPtr[2] = reinterpret_cast<HBRUSH>(CreateSolidBrush(RGB( 68,  68, 68)));  // color: HTMINBUTTON and HTMAXBUTTON  
  
    // initialize solid-color pens  
    hFramePenPtr[0] = reinterpret_cast<HPEN>(CreatePen(PS_SOLID, 1, RGB( 47,  47,  47)));  
    hFramePenPtr[1] = reinterpret_cast<HPEN>(CreatePen(PS_SOLID, 1, RGB(286, 186, 186)));  
    hFramePenPtr[2] = reinterpret_cast<HPEN>(CreatePen(PS_SOLID, 1, RGB(145, 145, 145)));  
    hFramePenPtr[3] = reinterpret_cast<HPEN>(CreatePen(PS_SOLID, 1, RGB( 42,  42,  42)));  
  
    return bRet;  
}  
  
LRESULT CALLBACK DwmWndProc(bool* pfCallDWP, HWND message, UINT uMsg, WPARAM wParam, LPARAM lParam);  
LRESULT CALLBACK AppWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);  
  
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
{  
    LONG_PTR lRet = (LONG_PTR)0;  
    bool fCallDWP = true;  
    BOOL fDwmEnabled = FALSE;  
  
    HRESULT hr = DwmIsCompositionEnabled(&fDwmEnabled);  
    if (!SUCCEEDED(hr))  
    {  
        MessageBox  
            (  
            nullptr,   
            __TEXT  
                (  
  
                "Call to function \"HRESULT DwmIsCompositionEnabled\" returned an unexpected error."  
                "\n\n"  
                "Resolve: The Desktop Window Manager (DWM) is required for this application. Please ensure that composition is enabled on your operating"  
                "system, and try again."  
                ),  
            __TEXT  
                (  
                "Desktop Window Manager"  
                ),  
            MB_OK  
            );  
        abort();  
    }  
    else  
    {  
        lRet = DwmWndProc(&fCallDWP, hWnd, message, wParam, lParam);  
    }  
  
    if (fCallDWP)  
    {  
        lRet = AppWndProc(hWnd, message, wParam, lParam);  
    }  
  
    return lRet;  
}  
  
LRESULT CALLBACK DwmWndProc(bool* pfCallDWP, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
{  
    bool fCallDWP = true;  
    LONG_PTR lRet = (LONG_PTR)0;  
          
    /*++  
  
  
  
    --*/  
    if (message == WM_DESTROY)  
    {  
        PostQuitMessage(EXIT_SUCCESS);  
        fCallDWP = true;  
    }  
  
    /*++  
  
  
  
    --*/  
    if (message == WM_CLOSE)  
    {  
        unsigned int i;  
        for (i = 0; i < (unsigned int)SDK_HGDI_SOLID_BRUSH_SIZE; i++)  
        {  
            DeleteBrush(hFrameBrushPtr[(unsigned int)i]);  
            DeletePen(hFramePenPtr[(unsigned int)i]);  
        }  
  
        DestroyWindow(hWnd);  
        fCallDWP = true;  
    }  
  
    /*++  
  
      
      
    --*/  
    if ((message == WM_NCHITTEST) && (lRet == 0))  
    {  
        lRet = (LONG_PTR)HitTest(hWnd, wParam, lParam);  
        if (lRet == HTNOWHERE)  
        {  
            fCallDWP = true;  
        }  
        else  
        {  
            fCallDWP = false;  
        }  
    }  
  
    /*++  
  
  
  
    --*/  
    if ((message == WM_NCCALCSIZE) && (wParam == TRUE))  
    {  
        lRet = (LONG_PTR)RecalcNonClientArea(lParam);  
        fCallDWP = false;  
    }  
  
    /*++  
  
  
  
    --*/  
    if (message == WM_CREATE)  
    {  
        lRet = SetHWNDInfoForDWM(hWnd);  
      
        BOOL bRet;  
        bRet = InitializeResources();  
        if (bRet == FALSE)  
        {  
        }  
  
        fCallDWP = true;  
    }  
  
    /*++  
  
  
  
    --*/  
    if (message == WM_ACTIVATE)  
    {  
        SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOOWNERZORDER);  
        fCallDWP = true;  
    }  
  
    /*++  
  
  
  
    --*/  
    if (message == WM_PAINT)  
    {  
        lRet = (LONG_PTR)PaintNonClientArea(hWnd, (HRGN)wParam);  
        fCallDWP = true;  
    }  
  
    *pfCallDWP = fCallDWP;  
  
    return lRet;  
}  
  
LRESULT CALLBACK AppWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
{  
    LONG_PTR lRet = (LONG_PTR)0;  
  
    switch (message)  
    {  
    case WM_CREATE:  
        {  
            break;  
        }  
    case WM_COMMAND:  
        {  
            break;  
        }  
    case WM_PAINT:  
        {  
            break;  
        }  
    default:  
        return DefWindowProc(hWnd, message, wParam, lParam);  
    }  
  
    return lRet;  
}  
  
extern  
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)  
{  
    try  
    {  
        NewDesktopApp(hInstance);  
    }  
    catch (std::exception& const e)  
    {  
        abort();  
    }  
  
    static MSG msg;  
  
    BOOL bRet;  
    while ((bRet = GetMessage(&msg, nullptr, 0, 0)) == TRUE)  
    {  
        if (bRet == FALSE)  
        {  
            // error.  
        }  
        else  
        {  
            TranslateMessage  
            (  
                &msg  
            );  
            DispatchMessage  
            (  
                &msg  
            );  
        }  
    }  
  
    return (INT)msg.wParam;  
}  
  
static  
ATOM MyRegisterClass(HINSTANCE hInstance)  
{  
    WNDCLASSEX wcex;  
    ZeroMemory(&wcex, sizeof(WNDCLASSEX));  
  
    wcex.cbSize         = sizeof(WNDCLASSEX);  
    wcex.hbrBackground  = NULL;  
    wcex.cbClsExtra     = 0;  
    wcex.cbWndExtra     = 0;  
    wcex.style          = 0;  
    wcex.hInstance      = hInstance;  
    wcex.lpfnWndProc    = WndProc;  
    wcex.hIcon          = LoadIcon  (wcex.hInstance, IDI_APPLICATION);  
    wcex.hCursor        = LoadCursor(wcex.hInstance, IDC_ARROW);  
    wcex.hIconSm        = LoadIcon  (wcex.hInstance, IDI_APPLICATION);  
    wcex.lpszClassName  = lpszWindowClass;  
    wcex.lpszMenuName   = NULL;  
  
    return RegisterClassEx(&wcex);  
}  
  
static  
VOID NewDesktopApp(HINSTANCE hInstance)  
{  
    hDesktopApp = hInstance;  
    if (MyRegisterClass(hDesktopApp) == (ATOM)0)  
    {  
        MessageBox(nullptr, __TEXT("Failed to register window class \"DesktopApp\"!"), __TEXT("wordproc"), MB_OK);  
        throw std::exception  
        (  
        );  
    }  
  
    DWORD dwExStyle = (DWORD)(WS_EX_LAYERED);  
    DWORD dwStyle = ((DWORD)(WS_VISIBLE | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_DLGFRAME | WS_THICKFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS));  
    RECT r =  
    {  
        0,  
        0,  
        1480,  
        680  
    };  
    AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle);  
    HWND hWnd = CreateWindowEx  
    (  
        dwExStyle,  
        lpszWindowClass,  
        lpszTitle,  
        dwStyle,  
        CW_USEDEFAULT,  
        CW_USEDEFAULT,  
        CW_USEDEFAULT,  
        CW_USEDEFAULT,  
        //((INT)RECTSIZE1(r)),  
        //((INT)RECTSIZE2(r)),  
        nullptr,  
        nullptr,  
        hDesktopApp,  
        nullptr  
    );  
    if (!hWnd)  
    {  
        MessageBox(nullptr, __TEXT("Failed to create window of class type \"DesktopApp\"!"), __TEXT("wordproc"), MB_OK);  
        throw std::exception  
        (  
        );  
    }  
  
    SetLayeredWindowAttributes(hWnd, NULL, 255, LWA_ALPHA);  
    //UpdateLayeredWindow()  
  
    ShowWindow(hWnd, SW_NORMAL);  
    UpdateWindow(hWnd);  
}  
  
#ifdef __cplusplus  
}  
#endif  
Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,412 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,519 questions
{count} vote