Winapi Windows 10上的Win32 API窗口应用程序视网膜高DPI屏幕问题 主题:简单C++基于Win32 API的单窗口应用程序。请参阅下面的代码。 计算机是MacBook Retina,本机安装了Windows 10

Winapi Windows 10上的Win32 API窗口应用程序视网膜高DPI屏幕问题 主题:简单C++基于Win32 API的单窗口应用程序。请参阅下面的代码。 计算机是MacBook Retina,本机安装了Windows 10,winapi,windows-10,retina-display,win32gui,highdpi,Winapi,Windows 10,Retina Display,Win32gui,Highdpi,问题:在鼠标悬停事件中,标题栏(窗口的非客户端区域)中的最小化/最大化/关闭按钮的行为不正确。每个按钮仅在鼠标光标移动时高亮显示,而按钮应一直高亮显示,直到鼠标指针离开按钮区域 问题:问题出在哪里?Win10清单 代码: #include <Windows.h> #include <tchar.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

问题:在鼠标悬停事件中,标题栏(窗口的非客户端区域)中的最小化/最大化/关闭按钮的行为不正确。每个按钮仅在鼠标光标移动时高亮显示,而按钮应一直高亮显示,直到鼠标指针离开按钮区域

问题:问题出在哪里?Win10清单

代码:

#include <Windows.h>
#include <tchar.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR msgGreeting[] = _T("Hello World from MyWindowsApp!");

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        TextOut(hdc, 10, 10, msgGreeting, (int)_tcsclen(msgGreeting));
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }

    return 0;
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // 1. Initialize the application
    // 2. Display the main window
    WNDCLASSEX wndClassWindowMain;
    wndClassWindowMain.cbSize = sizeof(WNDCLASSEX);
    wndClassWindowMain.style = CS_VREDRAW | CS_HREDRAW;
    wndClassWindowMain.lpfnWndProc = WndProc;
    wndClassWindowMain.cbClsExtra = 0;
    wndClassWindowMain.cbWndExtra = 0;
    wndClassWindowMain.hInstance = hInstance;
    wndClassWindowMain.hIcon = LoadIcon(wndClassWindowMain.hInstance, IDI_APPLICATION);
    wndClassWindowMain.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClassWindowMain.hbrBackground = (HBRUSH)(COLOR_WINDOW);
    wndClassWindowMain.lpszMenuName = NULL;
    wndClassWindowMain.lpszClassName = TEXT("MyMainWindowClass");
    wndClassWindowMain.hIconSm = LoadIcon(wndClassWindowMain.hInstance, IDI_APPLICATION);

    if (0 == RegisterClassEx(&wndClassWindowMain))
    {
        MessageBox(NULL
            , _T("Call to RegisterClassEx failed!")
            , _T("MyWindowsApplication")
            , MB_ICONERROR | MB_OK);
        return FALSE;
    }

    HWND hwndWindowMain = CreateWindowEx(WS_EX_APPWINDOW
        , _T("MyMainWindowClass")
        , _T("My Window")
        , WS_OVERLAPPEDWINDOW
        , 100, 100
        , 640, 480
        , NULL
        , NULL
        , hInstance
        , NULL);
    if (NULL == hwndWindowMain)
    {
        MessageBox(NULL
            , _T("Call to CreateWindowEx failed!")
            , _T("MyWindowsApplication")
            , MB_ICONERROR | MB_OK);
        return FALSE;
    }
    ShowWindow(hwndWindowMain, SW_SHOWDEFAULT);
    UpdateWindow(hwndWindowMain);
    // 3. Go to the message retrieval-and-dispatch loop
    MSG msg;
    BOOL bRet;

    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (bRet == -1)
        {
            // handle the error and possibly exit
            return FALSE;
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int)msg.wParam;
}
#包括
#包括
LRESULT回调WndProc(HWND HWND,UINT消息,WPARAM WPARAM,LPARAM LPARAM)
{
PAINTSTRUCT-ps;
HDC-HDC;
TCHAR msgGreeting[]=“来自MyWindowsApp的你好世界!”;
开关(信息)
{
案例WM_油漆:
hdc=开始喷漆(hWnd和ps);
文本输出(hdc,10,10,msgGreeting,(int)tcsclen(msgGreeting));
端漆(hWnd和ps);
打破
案例WM_销毁:
PostQuitMessage(0);
打破
违约:
返回DefWindowProc(hWnd、message、wParam、lParam);
打破
}
返回0;
}
int回调WinMain(HINSTANCE HINSTANCE、HINSTANCE hPrevInstance、LPSTR lpCmdLine、int nCmdShow)
{
//1.初始化应用程序
//2.显示主窗口
WNDCLASSEX wndClassWindowMain;
wndClassWindowMain.cbSize=sizeof(WNDCLASSEX);
wndClassWindowMain.style=CS_VREDRAW | CS_HREDRAW;
wndClassWindowMain.lpfnWndProc=WndProc;
wndClassWindowMain.cbClsExtra=0;
wndClassWindowMain.cbWndExtra=0;
wndClassWindowMain.hInstance=hInstance;
wndClassWindowMain.hIcon=加载图标(wndClassWindowMain.hInstance,IDI_应用程序);
wndClassWindowMain.hCursor=LoadCursor(空,IDC_箭头);
wndClassWindowMain.hbrBackground=(HBRUSH)(彩色窗口);
wndClassWindowMain.lpszMenuame=NULL;
wndClassWindowMain.lpszClassName=文本(“MyMainWindowClass”);
wndClassWindowMain.hIconSm=加载图标(wndClassWindowMain.hInstance,IDI_应用程序);
if(0==RegisterClassEx(&wndClassWindowMain))
{
消息框(空)
,_T(“调用RegisterClassEx失败!”)
,_T(“MyWindowsApplication”)
,MB_i错误| MB_正常);
返回FALSE;
}
HWND hwndWindowMain=CreateWindowEx(WS_EX_APPWINDOW
,_T(“MyMainWindowClass”)
,_T(“我的窗口”)
,WS_重叠窗口
, 100, 100
, 640, 480
无效的
无效的
,hInstance
,空);
如果(NULL==hwndWindowMain)
{
消息框(空)
,\u T(“调用CreateWindowEx失败!”)
,_T(“MyWindowsApplication”)
,MB_i错误| MB_正常);
返回FALSE;
}
ShowWindow(hwndWindowMain、SW_SHOWDEFAULT);
更新窗口(hwndWindowMain);
//3.转到消息检索和调度循环
味精;
布尔布雷特;
while((bRet=GetMessage(&msg,NULL,0,0))!=0)
{
如果(bRet==-1)
{
//处理错误并可能退出
返回FALSE;
}
其他的
{
翻译信息(&msg);
发送消息(&msg);
}
}
返回(int)msg.wParam;
}

解决方案:

#include <Windows.h>
#include <tchar.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR msgGreeting[] = _T("Hello World from MyWindowsApp!");

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        TextOut(hdc, 10, 10, msgGreeting, (int)_tcsclen(msgGreeting));
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }

    return 0;
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // 1. Initialize the application
    // 2. Display the main window
    WNDCLASSEX wndClassWindowMain;
    wndClassWindowMain.cbSize = sizeof(WNDCLASSEX);
    wndClassWindowMain.style = CS_VREDRAW | CS_HREDRAW;
    wndClassWindowMain.lpfnWndProc = WndProc;
    wndClassWindowMain.cbClsExtra = 0;
    wndClassWindowMain.cbWndExtra = 0;
    wndClassWindowMain.hInstance = hInstance;
    wndClassWindowMain.hIcon = LoadIcon(wndClassWindowMain.hInstance, IDI_APPLICATION);
    wndClassWindowMain.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClassWindowMain.hbrBackground = (HBRUSH)(COLOR_WINDOW);
    wndClassWindowMain.lpszMenuName = NULL;
    wndClassWindowMain.lpszClassName = TEXT("MyMainWindowClass");
    wndClassWindowMain.hIconSm = LoadIcon(wndClassWindowMain.hInstance, IDI_APPLICATION);

    if (0 == RegisterClassEx(&wndClassWindowMain))
    {
        MessageBox(NULL
            , _T("Call to RegisterClassEx failed!")
            , _T("MyWindowsApplication")
            , MB_ICONERROR | MB_OK);
        return FALSE;
    }

    HWND hwndWindowMain = CreateWindowEx(WS_EX_APPWINDOW
        , _T("MyMainWindowClass")
        , _T("My Window")
        , WS_OVERLAPPEDWINDOW
        , 100, 100
        , 640, 480
        , NULL
        , NULL
        , hInstance
        , NULL);
    if (NULL == hwndWindowMain)
    {
        MessageBox(NULL
            , _T("Call to CreateWindowEx failed!")
            , _T("MyWindowsApplication")
            , MB_ICONERROR | MB_OK);
        return FALSE;
    }
    ShowWindow(hwndWindowMain, SW_SHOWDEFAULT);
    UpdateWindow(hwndWindowMain);
    // 3. Go to the message retrieval-and-dispatch loop
    MSG msg;
    BOOL bRet;

    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (bRet == -1)
        {
            // handle the error and possibly exit
            return FALSE;
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int)msg.wParam;
}
问题在于上面示例中的应用程序的DPI(每英寸点数)感知。要使本机C++/Win32 API代码与不同屏幕(包括4K和Retina)兼容,需要执行以下步骤:

  • 包括适当的标题
    #包括
  • 告诉链接器编译的函数代码在哪里
    #pragma comment(lib,“Shcore.lib”)
  • 最后在
    WinMain
    中添加以下调用
    SetProcessDpiAwareness(PROCESS\u PER\u MONITOR\u DPI\u AWARE)
  • 现在在视网膜上,我看到我的应用程序窗口适当缩放。最小化/最大化/关闭按钮按预期工作


    进一步阅读如下:

    解决方案:

    #include <Windows.h>
    #include <tchar.h>
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
        TCHAR msgGreeting[] = _T("Hello World from MyWindowsApp!");
    
        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            TextOut(hdc, 10, 10, msgGreeting, (int)_tcsclen(msgGreeting));
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
            break;
        }
    
        return 0;
    }
    
    int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        // 1. Initialize the application
        // 2. Display the main window
        WNDCLASSEX wndClassWindowMain;
        wndClassWindowMain.cbSize = sizeof(WNDCLASSEX);
        wndClassWindowMain.style = CS_VREDRAW | CS_HREDRAW;
        wndClassWindowMain.lpfnWndProc = WndProc;
        wndClassWindowMain.cbClsExtra = 0;
        wndClassWindowMain.cbWndExtra = 0;
        wndClassWindowMain.hInstance = hInstance;
        wndClassWindowMain.hIcon = LoadIcon(wndClassWindowMain.hInstance, IDI_APPLICATION);
        wndClassWindowMain.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndClassWindowMain.hbrBackground = (HBRUSH)(COLOR_WINDOW);
        wndClassWindowMain.lpszMenuName = NULL;
        wndClassWindowMain.lpszClassName = TEXT("MyMainWindowClass");
        wndClassWindowMain.hIconSm = LoadIcon(wndClassWindowMain.hInstance, IDI_APPLICATION);
    
        if (0 == RegisterClassEx(&wndClassWindowMain))
        {
            MessageBox(NULL
                , _T("Call to RegisterClassEx failed!")
                , _T("MyWindowsApplication")
                , MB_ICONERROR | MB_OK);
            return FALSE;
        }
    
        HWND hwndWindowMain = CreateWindowEx(WS_EX_APPWINDOW
            , _T("MyMainWindowClass")
            , _T("My Window")
            , WS_OVERLAPPEDWINDOW
            , 100, 100
            , 640, 480
            , NULL
            , NULL
            , hInstance
            , NULL);
        if (NULL == hwndWindowMain)
        {
            MessageBox(NULL
                , _T("Call to CreateWindowEx failed!")
                , _T("MyWindowsApplication")
                , MB_ICONERROR | MB_OK);
            return FALSE;
        }
        ShowWindow(hwndWindowMain, SW_SHOWDEFAULT);
        UpdateWindow(hwndWindowMain);
        // 3. Go to the message retrieval-and-dispatch loop
        MSG msg;
        BOOL bRet;
    
        while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
        {
            if (bRet == -1)
            {
                // handle the error and possibly exit
                return FALSE;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        return (int)msg.wParam;
    }
    
    问题在于上面示例中的应用程序的DPI(每英寸点数)感知。要使本机C++/Win32 API代码与不同屏幕(包括4K和Retina)兼容,需要执行以下步骤:

  • 包括适当的标题
    #包括
  • 告诉链接器编译的函数代码在哪里
    #pragma comment(lib,“Shcore.lib”)
  • 最后在
    WinMain
    中添加以下调用
    SetProcessDpiAwareness(PROCESS\u PER\u MONITOR\u DPI\u AWARE)
  • 现在在视网膜上,我看到我的应用程序窗口适当缩放。最小化/最大化/关闭按钮按预期工作


    <> P>进一步阅读如下:

    C和C++是不同的语言。请使用相关的标签。@ KayLUM对于这个案例没有区别,因为情况是关于平台而不是语言。@ KayLUM,我展示的代码是C++,但是很容易移植到C和C++程序员使用的WiAPI中,所以有两个标签将有助于目标受众找到这个线程。顺便说一句,我已经找到了解决办法。请欣赏.KayLUM:代码是有效的C和有效C++。它不是有效的Pascal、Delphi、Rust、Go或Python。为什么通过C++任意选择C来限制可发现性的范围,反之亦然?这将如何使这个问答更容易被发现?你对此有令人信服的答案吗?语言与问题无关。这是一个关于winapi的问题。最好给它贴上这样的标签。一个知道WiAPI的Delphi程序员也可以作为C或C++程序员来回答。C和C++是不同的语言。请使用相关的标签。@ KayLUM在这种情况下没有区别,因为情况是关于平台而不是语言。@ KayLUM,我展示的代码是C++,但是很容易移植到C和C++程序员使用的C.WiAPI,所以两个标签都会有。