Click here to Skip to main content
15,881,581 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello,

I wish to manually draw what looks like a window caption during the WM_NCPAINT event. I've made some progress, but I can't seem to get the color right. It's not the same as, say, Notepad's caption bar background color, which is RGB(0, 153, 188) - a color I specified a few months back under Settings > Personlization > Colors.

There are a few Win32 #defines that come close, but I suspect that is a coincidence, and I certainly don't want to ask my program to switch to another window first to grab the color of the caption bar.

This is my code. Could you fix it or tell me how to fix it so it gets the right color? Right now the code is filling the client area with the color I've chosen, but that's on purpose. The maximize button I've drawn also looks nothing like "real" (Windows painted) caption menu buttons (iconize/minimize, restore, maximize). Can you help me there aswell? You'd think the DrawCaption function would actually draw the caption like Windows does it.

C++
// WindowsProject2.cpp : Defines the entry point for the application.
//
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#include "framework.h"
#include "WindowsProject2.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINDOWSPROJECT2, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT2));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = /*CS_HREDRAW | CS_VREDRAW*/ CS_DBLCLKS;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT2));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)GetSysColorBrush(COLOR_MENUBAR);
    wcex.lpszMenuName = NULL; // MAKEINTRESOURCEW(IDC_WINDOWSPROJECT2);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable
   
   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_POPUPWINDOW,
      300, 300, 900, 700, nullptr, nullptr, hInstance, nullptr);
   
   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        SetFocus(hWnd);
        CreateWindow(L"BUTTON", L"Click me!", WS_CHILD | WS_VISIBLE, 100, 100, 75, 25, hWnd, 0, 0, 0);
        break;
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    //case WM_PAINT:
    //    {
    //        PAINTSTRUCT ps;
    //        HDC hdc = BeginPaint(hWnd, &ps);
    //        // TODO: Add any drawing code that uses hdc here...
    //        EndPaint(hWnd, &ps);
    //    }
    //    break;
    case WM_NCPAINT:
    {
        PAINTSTRUCT ps;
        HRGN rgn = (HRGN)wParam;
        RECT rect = { 850, 0, 870, 20 };
        RECT rcCap = { 1, -9, 890, 30 };
        RECT rcWin;
        GetWindowRect(hWnd, &rcWin);
        BeginPaint(hWnd, &ps);
        SelectObject(ps.hdc, GetStockObject(BLACK_PEN));
        SelectObject(ps.hdc, GetStockObject(NULL_BRUSH));
        //Rectangle(ps.hdc, 0, 0, rcWin.right, rcWin.bottom);
        //DrawFocusRect(ps.hdc, &rect);
        DrawCaption(hWnd, ps.hdc, &rcCap, DC_ACTIVE | DC_ICON | DC_TEXT | DC_BUTTONS | DC_GRADIENT*0 | DC_SMALLCAP);

        DrawFrameControl(ps.hdc, &rect, DFC_CAPTION, DFCS_CAPTIONMAX | DFCS_HOT | DFCS_FLAT);
        EndPaint(hWnd, &ps);
    }
        break;
    case WM_SIZE:
        InvalidateRect(hWnd, NULL, FALSE);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}


The goal is to create something like Google Chrome, which has complete control over what is drawn in the caption and what happens when you click on it.

I'm running Windows 10. The #pragma on the top is to make post-XP-styled controls, but evidently it has no effect on anything else, including the caption bar.

What I have tried:

1) Looked up GetSysColor and GetSysColorBrush functions on MSDN.
2) Fiddled for hours with my code, trying all the COLOR_* #defines, but in and without GetStockObject.
Posted
Updated 23-Feb-20 10:38am
Comments
Richard MacCutchan 21-Feb-20 10:11am    
What is the reason for using DC_GRADIENT*0? Also, if you are using DrawCaption it will use only the colours as specified in the documentation.
deXo-fan 21-Feb-20 19:50pm    
DC_GRADIENT*0 is just part of the fiddling. Sometimes when I want to see the effect a constant has on a program by omitting it, I simply write constant*0 and when I want to turn it back on I remove the *0. It's alot easier than removing and inserting the entire word. I don't get what you mean by "it will use only the colours".

If I want to know a color, I take a screen shot, paste it into Paint.NET (or something similar) and use their eye dropper / color palate. The color palate gives the RGB settings for the selected color.

Visual Studio's "image editor" also gives RGB settings for the eye dropper.
 
Share this answer
 
v2
I recommend writing what I call an enumerator applet. Here's a screenshot of one I wrote for system colors. I have written several of these but I had done this one yet and your question inspired me. Screenshot at ServImg.com[^]

My point is, write something like this and then you can see what color Notepad is likely to be using.

What I did was I used the CReportCtrl that I found at this site. It is a CListCtrl derivation that allows you to set the colors of the subitems. Then I made an iteration loop that acquired the system color and added a row into the list control.
 
Share this answer
 
Comments
deXo-fan 30-Aug-20 7:59am    
I am very glad my question inspired you! But I don't think either of you got what I really want to do, or maybe I explained it poorly. I can't use the eye dropper tool, because I want my program to use whatever color the OS assigns to, e.g., caption bars. Which means, if it is red when my program is run, then I want my program's caption bar to be red, and if during or after the running of my program the user changes the OS assigned color to, say, green, then I want my program's caption bar to immediately be green. In other words: I want my window to behave like a normal window would; the only difference is I want to draw the caption bar myself instead of having Windows OS draw it. The reason for that is I might want to add a button next to the minimize button (like Chrome has - Chrome has a "new tab" button next to all the tabs while still using whatever color the user asked the OS to give it). And I've been told all of this has to be done in WM_NCPAINT. Just imagine I want to write an empty Window where I have the same level of control over all of it (not just the client area) as Google's programmers have over Chrome. This would include non-client click events, non-client mouseover events, drawing images and all sorts of graphics, etc.

By the way, I'm sorry for waiting until now with answering, but I really appreciate your efforts!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900