How can I change Windows 10 Display Scaling Programmatically using C#

前端 未结 6 2044
野的像风
野的像风 2020-11-28 11:39

I\'m trying to find a way to change the Display Scaling in Windows 10 Programmatically using C#.

Let me also say that, I\'m not trying to create a application that a

6条回答
  •  粉色の甜心
    2020-11-28 11:52

    If system wide DPI scaling is to be changed (System DPI scaling - scaling of primary monitor in case of multi monitor setup or there is only a single monitor), rather than per monitor DPI scaling, SystemParametersInfo() can be used.

    This API has an undocumented parameter which achieves this : SPI_SETLOGICALDPIOVERRIDE

    From Microsoft doc:

    SPI_SETLOGICALDPIOVERRIDE   Do not use. 
    0x009F
    

    Usage :

    SystemParametersInfo(SPI_SETLOGICALDPIOVERRIDE, relativeIndex, (LPVOID)0, 1);
    

    To figure out what value to use for relativeIndex variable above, you have to understand how OS expects DPI scaling values to be specified (explained here).

    In brief, relativeIndex tells how many steps above, or below the recommended DPI scaling value you want to go. For eg. if recommended DPI scaling value is 125%, and you want to set 150% as scaling, relativeIndex will be 1 (one step over 125%), or if you want to set 100%, relativeIndex will be -1 (one step below 125%).

    All steps may not be of same size.

    100,125,150,175,200,225,250,300,350, 400, 450, 500
    

    Till 250% the steps increase in units of 25%, and after than in units of 50%.

    Thus, you must first get the value of recommended DPI scaling, for which same API can be used, with SPI_GETLOGICALDPIOVERRIDE parameter.

    SystemParametersInfo(SPI_GETLOGICALDPIOVERRIDE, 0, (LPVOID)&dpi, 1);
    

    The value returned in dpi variable above is also to be understood in a special way. The value will be negative, and its magnitude will indicated the index of DPI scaling percentage in the list above.

    So if this API returns -1, the recommended DPI scaling value will be 125%.

    Sample code:

    #include 
    #include 
    
    using namespace std;
    
    
    static const UINT32 DpiVals[] = { 100,125,150,175,200,225,250,300,350, 400, 450, 500 };
    
    /*Get default DPI scaling percentage.
    The OS recommented value.
    */
    int GetRecommendedDPIScaling()
    {
        int dpi = 0;
        auto retval = SystemParametersInfo(SPI_GETLOGICALDPIOVERRIDE, 0, (LPVOID)&dpi, 1);
    
        if (retval != 0)
        {
            int currDPI = DpiVals[dpi * -1];
            return currDPI;
        }
    
        return -1;
    }
    
    void SetDpiScaling(int percentScaleToSet)
    {
        int recommendedDpiScale = GetRecommendedDPIScaling();
    
        if (recommendedDpiScale > 0)
        {
            int index = 0, recIndex = 0, setIndex = 0 ;
            for (const auto& scale : DpiVals)
            {
                if (recommendedDpiScale == scale)
                {
                    recIndex = index;
                }
                if (percentScaleToSet == scale)
                {
                    setIndex = index;
                }
                index++;
            }
            
            int relativeIndex = setIndex - recIndex;
            SystemParametersInfo(SPI_SETLOGICALDPIOVERRIDE, relativeIndex, (LPVOID)0, 1);
        }
    }
    
    int main()
    {
        for (;;)
        {
            int n = 0, dpiToSet = 0;
            cout << R"(
                1. Show Recommended DPI
                2. Set DPI
                Anything else to exit
    )";
            cin >> n;
            switch (n)
            {
            case 1:
                cout << "recommened scaling: " << GetRecommendedDPIScaling() << "%" << endl;
                break;
            case 2:
                cout << "enter scaling to set in percentage" << endl;
                cin >> dpiToSet;
                SetDpiScaling(dpiToSet);
                break;
            default:
                exit(0);
                break;
            }
        }
        return 0;
    }
    

    Source code: https://github.com/lihas/windows-DPI-scaling-sample.

    Here is a sample run.

    Pros and cons
    With respect to my earlier approaches (https://stackoverflow.com/a/58066736/981766, https://stackoverflow.com/a/57397039/981766)

    Pros

    1. This is a very simple API. Hence when you only have to change DPI scaling of primary monitor in a multi monitor setup, or if there is only a single monitor, prefer this approach.

    Cons

    1. Cannot set DPI scaling of non primary monitors on a multi monitor setup.
    2. Doesn't return currently applied DPI scaling (though you can use other OS API for it)
    3. Doesn't give you max, min possible DPI scaling values. Though if you try to set outside this range, OS doesn't allow it, and will use nearest allowed.

    References

    1. https://social.msdn.microsoft.com/Forums/vstudio/en-US/3259c521-b3ed-4121-97da-70a08fb8bb19/change-setting?forum=windowsgeneraldevelopmentissues (slightly inaccurate)
    2. How to set Windows scale and layout with python code
    3. https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa?redirectedfrom=MSDN
    4. https://github.com/lihas/windows-DPI-scaling-sample

提交回复
热议问题