c++winapiwindows-10implementationwindows-11

How to immediately apply DISPLAYCONFIG_SCALING display scaling mode with SetDisplayConfig and DISPLAYCONFIG_PATH_TARGET_INFO


I am currently trying to use SetDisplayConfig from winuser.h to immediately apply a "Preserve aspect ratio" display scaling mode for the active display mode, but I can't seem to get the settings to apply. I've tried many things, but nothing works. Can anybody point me in the right direction to implement this? Any help would be GREATLY appreciated.

Relevant APIs:

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setdisplayconfig

https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_path_info

https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_path_target_info

Article that got me started:

https://learn.microsoft.com/en-us/windows-hardware/drivers/display/scaling-the-desktop-image

I've tried using SetDisplayConfig with QueryDisplayConfig to change DISPLAYCONFIG_PATH_INFO -> DISPLAYCONFIG_PATH_TARGET_INFO.scaling, but it would not apply after calling SetDisplayConfig on the modified scaling value.

UPDATE:

This is what I have so far, but I get ERROR_INVALID_PARAMETER return value for both the QueryDisplayConfig and SetDisplayConfig function calls.

void setDisplayScalingMode(DISPLAYCONFIG_SCALING scalingMode) {
    // Initialize paths and modes.
    UINT32 numPathArrayElements = 0;
    UINT32 numModeInfoArrayElements = 0;
    DISPLAYCONFIG_PATH_INFO* pathArray = new DISPLAYCONFIG_PATH_INFO[numPathArrayElements];
    DISPLAYCONFIG_MODE_INFO* modeInfoArray = new DISPLAYCONFIG_MODE_INFO[numModeInfoArrayElements];

    // Query the active display configuration.
    LONG queryDisplayConfigResult = QueryDisplayConfig(QDC_DATABASE_CURRENT, &numPathArrayElements, pathArray, &numModeInfoArrayElements, modeInfoArray, NULL);

    // Check if the active display configuration was successfully queried, and output an error message if it wasn't.
    if (queryDisplayConfigResult != ERROR_SUCCESS) {
        std::cerr << "Failed to query the display configuration! Error Code: " << queryDisplayConfigResult << std::endl;
    }

    // Set the new display scaling mode for all paths.
    for (UINT32 i = 0; i < numPathArrayElements; ++i) {
        pathArray->targetInfo.scaling = scalingMode;
    }

    // Apply the new display scaling mode.
    LONG setDisplayConfigResult = SetDisplayConfig(numPathArrayElements, pathArray, numModeInfoArrayElements, modeInfoArray, SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG);

    // Check if the new display configuration was successfully applied, and output an error message if it wasn't.
    if (setDisplayConfigResult != ERROR_SUCCESS) {
        std::cerr << "Failed to set the display configuration! Error Code: " << setDisplayConfigResult << std::endl;
    }

    // Clean up allocated memory
    delete[] pathArray;
    delete[] modeInfoArray;
}

Solution

  • I was able to get the display scaling mode values to correctly, and immediately apply once I made the following changes:

     // Point to the current display topology after querying the display configuration.
    DISPLAYCONFIG_TOPOLOGY_ID* currentTopology = new DISPLAYCONFIG_TOPOLOGY_ID;
    
    // Retrieve the size of the buffers that are required to call the QueryDisplayConfig function.
    GetDisplayConfigBufferSizes(QDC_DATABASE_CURRENT, &numPathArrayElements, &numModeInfoArrayElements);
    
    // Initialize the path array and mode info array with the correct buffers to hold the active paths as defined in the
    // persistence database for the currently connected monitors.
    DISPLAYCONFIG_PATH_INFO* pathArray = new DISPLAYCONFIG_PATH_INFO[numPathArrayElements];
    DISPLAYCONFIG_MODE_INFO* modeInfoArray = new DISPLAYCONFIG_MODE_INFO[numModeInfoArrayElements];
    
    // Query the active display configuration.
    LONG queryDisplayConfigResult = QueryDisplayConfig(QDC_DATABASE_CURRENT, &numPathArrayElements, pathArray, 
            &numModeInfoArrayElements, modeInfoArray, currentTopology);
    

    The full implementation is provided in my SetDisplay program. Thank you everybody for pointing me in the right direction!