C++ 如何正确绘制简单的非客户区(4像素红色边框)?

C++ 如何正确绘制简单的非客户区(4像素红色边框)?,c++,winapi,nonclient-area,C++,Winapi,Nonclient Area,我正在尝试绘制一个自定义绘制的非客户端区域,而不是默认的主题边框(Windows10) 我处理了WM\u NCCALCSIZE以将非客户端区域的大小调整为每侧4个像素,然后处理了WM\u NCPAINT以绘制红色边框 我的自定义绘制在应用程序首次显示时成功,但在应用程序调整大小或最小化并还原时无法重新绘制,尽管在调整大小或恢复窗口时调用了WM\u NCCALCSIZE和WM\u NCPAINT #pragma comment(lib, "UxTheme") #include <window

我正在尝试绘制一个自定义绘制的非客户端区域,而不是默认的主题边框(Windows10)

我处理了
WM\u NCCALCSIZE
以将非客户端区域的大小调整为每侧4个像素,然后处理了
WM\u NCPAINT
以绘制红色边框

我的自定义绘制在应用程序首次显示时成功,但在应用程序调整大小或最小化并还原时无法重新绘制,尽管在调整大小或恢复窗口时调用了
WM\u NCCALCSIZE
WM\u NCPAINT

#pragma comment(lib, "UxTheme")
#include <windows.h>
#include <uxtheme.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = (HICON) LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = CreateSolidBrush(RGB(0,128,0));
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = "window";
    wcex.hIconSm = NULL;

    RegisterClassEx(&wcex);

    HWND hWnd = CreateWindowEx(
        WS_EX_COMPOSITED,
        "window",
        NULL,
        WS_OVERLAPPEDWINDOW,
        100,
        100,
        600,
        400,
        NULL,
        NULL,
        hInstance, 
        NULL); 

    ShowWindow(hWnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return static_cast<int>(msg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
        case WM_CREATE:
            SetWindowTheme(hWnd, L"", L"");
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_NCCALCSIZE:
        {
            RECT rect;
            GetWindowRect(hWnd, &rect);
            LPNCCALCSIZE_PARAMS ncParams = (LPNCCALCSIZE_PARAMS) lParam;
            ncParams->rgrc[0].top = rect.top + 4;
            ncParams->rgrc[0].left = rect.left + 4;
            ncParams->rgrc[0].bottom = rect.bottom - 4;
            ncParams->rgrc[0].right = rect.right - 4;
            return 0;
        }
        case WM_NCPAINT:
        {
            RECT rect;
            GetWindowRect(hWnd, &rect);
            HDC dc = GetDCEx(hWnd, (HRGN) wParam, DCX_WINDOW | DCX_CACHE | DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
            HPEN pen = CreatePen(PS_INSIDEFRAME, 4, RGB(255, 0, 0));
            HGDIOBJ old = SelectObject(dc, pen);
            int width = rect.right - rect.left;
            int height = rect.bottom - rect.top;
            Rectangle(dc, 0, 0, width, height);
            SelectObject(dc, old);
            DeleteObject(pen);
            ReleaseDC(hWnd, dc);
            return 0;
        }
        case WM_NCACTIVATE:
            RedrawWindow(hWnd, NULL, NULL, RDW_UPDATENOW);
            return 0;
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
#pragma注释(lib,“UxTheme”)
#包括
#包括
LRESULT回调WndProc(HWND、UINT、WPARAM、LPARAM);
int WINAPI WinMain(HINSTANCE HINSTANCE、HINSTANCE HPPreInstance、LPSTR lpCmdLine、int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=NULL;
wcex.hCursor=(HICON)LoadCursor(空,IDC_箭头);
wcex.hbrBackground=CreateSolidBrush(RGB(0128,0));
wcex.lpszMenuName=NULL;
wcex.lpszClassName=“窗口”;
wcex.hIconSm=NULL;
注册类别(&wcex);
HWND HWND=CreateWindowEx(
WS_EX_合成,
“窗口”,
无效的
WS_重叠窗口,
100,
100,
600,
400,
无效的
无效的
hInstance,
无效);
显示窗口(hWnd、nCmdShow);
味精;
while(GetMessage(&msg,NULL,0,0)){
翻译信息(&msg);
发送消息(&msg);
}
返回静态_cast(msg.wParam);
}
LRESULT回调WndProc(HWND HWND、UINT uMsg、WPARAM WPARAM、LPARAM LPARAM)
{
开关(uMsg){
案例WM_创建:
设置窗口主题(hWnd,L“”,L“”);
返回0;
案例WM_销毁:
PostQuitMessage(0);
返回0;
案例WM_NCCALCSIZE:
{
RECT-RECT;
GetWindowRect(hWnd和&rect);
LPNCCALCSIZE_参数ncParams=(LPNCCALCSIZE_参数)lParam;
ncParams->rgrc[0]。top=rect.top+4;
ncParams->rgrc[0]。left=rect.left+4;
ncParams->rgrc[0]。bottom=rect.bottom-4;
ncParams->rgrc[0]。right=rect.right-4;
返回0;
}
案例WM_NCPAINT:
{
RECT-RECT;
GetWindowRect(hWnd和&rect);
HDC dc=GetDCEx(hWnd,(HRGN)wParam,DCX_窗口| DCX_缓存| DCX_交叉点rgn | DCX_锁窗口更新);
HPEN pen=CreatePen(PS_INSIDEFRAME,4,RGB(255,0,0));
HGDIOBJ old=选择对象(直流、笔);
int width=rect.right-rect.left;
int height=rect.bottom-rect.top;
矩形(dc、0、0、宽度、高度);
选择对象(dc,旧);
删除对象(笔);
释放dc(hWnd,dc);
返回0;
}
案例WM_n激活:
重画窗口(hWnd、NULL、NULL、RDW_UPDATENOW);
返回0;
打破
}
返回DefWindowProc(hWnd、uMsg、wParam、lParam);
}

WM\u NCPAINT
消息的
wParam
有时返回1而不是区域的句柄(
HRGN
)。在这种情况下,必须使用
CreateRectRgn
函数创建
HRGN

#pragma comment(lib, "UxTheme")
#include <windows.h>
#include <uxtheme.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = (HICON) LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = CreateSolidBrush(RGB(0,128,0));
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = "window";
    wcex.hIconSm = NULL;

    RegisterClassEx(&wcex);

    HWND hWnd = CreateWindowEx(
        NULL,
        "window",
        NULL,
        WS_OVERLAPPEDWINDOW,
        100,
        100,
        600,
        400,
        NULL,
        NULL,
        hInstance, 
        NULL); 

    ShowWindow(hWnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return static_cast<int>(msg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
        case WM_CREATE:
            SetWindowTheme(hWnd, L"", L"");
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        case WM_NCCALCSIZE:
        {
            LPNCCALCSIZE_PARAMS ncParams = (LPNCCALCSIZE_PARAMS) lParam;
            ncParams->rgrc[0].top += 4;
            ncParams->rgrc[0].left += 4;
            ncParams->rgrc[0].bottom -= 4;
            ncParams->rgrc[0].right -= 4;
            return 0;
        }
        case WM_NCPAINT:
        {
            RECT rect;
            GetWindowRect(hWnd, &rect);
            HRGN region = NULL;
            if (wParam == NULLREGION) {
                region = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
            } else {
                HRGN copy = CreateRectRgn(0, 0, 0, 0);
                if (CombineRgn(copy, (HRGN) wParam, NULL, RGN_COPY)) {
                    region = copy;
                } else {
                    DeleteObject(copy);
                }
            }
            HDC dc = GetDCEx(hWnd, region, DCX_WINDOW | DCX_CACHE | DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
            if (!dc && region) {
                DeleteObject(region);
            }
            HPEN pen = CreatePen(PS_INSIDEFRAME, 4, RGB(255, 0, 0));
            HGDIOBJ old = SelectObject(dc, pen);
            int width = rect.right - rect.left;
            int height = rect.bottom - rect.top;
            Rectangle(dc, 0, 0, width, height);
            SelectObject(dc, old);
            ReleaseDC(hWnd, dc);
            DeleteObject(pen);
            return 0;
        }
        case WM_NCACTIVATE:
            RedrawWindow(hWnd, NULL, NULL, RDW_UPDATENOW);
            return 0;
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
#pragma注释(lib,“UxTheme”)
#包括
#包括
LRESULT回调WndProc(HWND、UINT、WPARAM、LPARAM);
int WINAPI WinMain(HINSTANCE HINSTANCE、HINSTANCE HPPreInstance、LPSTR lpCmdLine、int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=NULL;
wcex.hCursor=(HICON)LoadCursor(空,IDC_箭头);
wcex.hbrBackground=CreateSolidBrush(RGB(0128,0));
wcex.lpszMenuName=NULL;
wcex.lpszClassName=“窗口”;
wcex.hIconSm=NULL;
注册类别(&wcex);
HWND HWND=CreateWindowEx(
无效的
“窗口”,
无效的
WS_重叠窗口,
100,
100,
600,
400,
无效的
无效的
hInstance,
无效);
显示窗口(hWnd、nCmdShow);
味精;
while(GetMessage(&msg,NULL,0,0)){
翻译信息(&msg);
发送消息(&msg);
}
返回静态_cast(msg.wParam);
}
LRESULT回调WndProc(HWND HWND、UINT uMsg、WPARAM WPARAM、LPARAM LPARAM)
{
开关(uMsg){
案例WM_创建:
设置窗口主题(hWnd,L“”,L“”);
返回0;
案例WM_销毁:
PostQuitMessage(0);
返回0;
案例WM_NCCALCSIZE:
{
LPNCCALCSIZE_参数ncParams=(LPNCCALCSIZE_参数)lParam;
ncParams->rgrc[0]。顶部+=4;
ncParams->rgrc[0]。左+=4;
ncParams->rgrc[0]。底部-=4;
ncParams->rgrc[0]。右-=4;
返回0;
}
案例WM_NCPAINT:
{
RECT-RECT;
GetWindowRect(hWnd和&rect);
HRGN区域=空;
if(wParam==NULLREGION){
region=CreateRectRgn(rect.left、rect.top、rect.right、rect.bottom);
}否则{
HRGN copy=CreateRectRgn(0,0,0,0);
if(CombineRgn(复制,(HRGN)wParam,NULL,RGN_复制)){
区域=复制;
}否则{
删除对象(副本);
}
}
HDC dc=GetDCEx(hWnd,region,DCX_窗口| DCX_缓存| DCX_INTERSECTRGN | DCX_锁窗口更新);
如果(!dc&&区域){
删除对象(区域);
}
HPEN pen=CreatePen(PS_INSIDEFRAME,4,RGB(255,0,0));
HGDIOBJ old=选择对象(直流、笔);
int wid