不同机器上的 Winapi 缩放

Winapi scaling in different machines

几周来我一直在尝试使用 winapi(无 MFC)设计一个小界面,但有一个问题我无法解决。我的 window 的创建是以像素为单位指定的,但是我的控件的大小是以逻辑单位为单位的。

我认为解决方案是在为 window 创建字体时使用 MulDiv 函数:

#include <windows.h>

LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
    switch(msg) {
        case WM_CLOSE:
            DestroyWindow(hwnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

const char * g_szClassName = "SampleWindow";


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    //Let's register our window class
    WNDCLASSEX wc;
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = wndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(RGB(240,240,240));
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = NULL;

    if(!RegisterClassEx(&wc)) {
        return 0;
    }

    DWORD dwStyle=( (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)&~WS_MAXIMIZEBOX);
    RECT rect;
    rect.left = rect.top = 0;
    rect.right = 300;
    rect.bottom = 100;
    ::AdjustWindowRect(&rect, dwStyle, false);

    HWND mWindow = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "Sample Window",
        dwStyle,
        CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top,// (x,y,width,height)
        NULL, NULL, hInstance, NULL);

    if(mWindow == NULL) {
        return 0;
    }

    HDC hdc = GetDC(mWindow);

    NONCLIENTMETRICS ncm;
    ncm.cbSize = sizeof(NONCLIENTMETRICS);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
    ncm.lfMessageFont.lfWidth = 0;
    ncm.lfMessageFont.lfHeight = -MulDiv(16, GetDeviceCaps(hdc, LOGPIXELSY), 72);
    HFONT normalFont = CreateFontIndirect(&ncm.lfMessageFont);

    HWND someText = CreateWindow( "Static", "This text will scale badly", 
        WS_VISIBLE | WS_CHILD | SS_LEFT,  // Styles 
        10, 10, 500, 30, // (x, y, width, height)
        mWindow, (HMENU) NULL, hInstance, NULL);

    SendMessage(someText, WM_SETFONT, (WPARAM) normalFont, MAKELPARAM(TRUE, 0));

    ShowWindow(mWindow, SW_SHOW);
    UpdateWindow(mWindow);

    //Run the window
    MSG Msg;
    while(GetMessage(&Msg, NULL, 0, 0) > 0) {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    DeleteObject(normalFont);
    ReleaseDC(hdc);
}

通常我使用 MSVC2010 编译代码,但这个最小的示例是使用 gcc 7.2.0(MinGW 64 位)编译的。这在我的电脑上有效,也可以使用 windows 10 的缩放设置。但是,我注意到在某些电脑上文本看起来更大。我只是无法获得带有控件的 window 来保持 window 与所有测试机器上的元素之间的比率。我的应用程序不支持 DPI,因此每个元素都应该以相同的方式缩放,但每个编辑和静态控件似乎都违反了我要求的 16pt 字体。

使用 winapi 获得保持比率 window 的正确方法是什么?

这是一个发生的例子。正确的图片是它在我的机器上的样子(改变缩放比例确实缩放了整个 window,并且它保留了字体和 window 之间的比例),右边是一台戴尔电脑 运行 相同的程序(更改缩放参数不会修改任何内容,整个 window 得到缩放但文本看起来仍然很糟糕)。

谢谢。

请勿在不支持 DPI 的应用程序中自行调整文本大小。

要么让 OS 处理所有调整,要么将您的应用程序显示为 DPI 感知并自行计算尺寸变化。

现在,这并不意味着您应该在非感知应用程序中对大小进行硬编码。最好的办法是 use SystemParametersInfo to query for the user's preferred font size,就像您已经为字体所做的那样。不要应用基于 LOGPIXELSXLOGPIXELSY 的调整。