How to add custom resolution for HyperV monitor using WinAPI

57 Views Asked by At

I want to add and set custom resolutions (modelines) for a HyperV monitor on an Azure VM

Read the docs and they said ChangeDisplaySettings API should do the trick. Tried it and the following code returns The graphics mode is not supported;

void ChangeScreenResolution(int width, int height) {
    DEVMODE devMode = {};

    WINBOOL result =
        EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode);

    if (result == 0) {
        printf("EnumDisplaySettingsA Falied with code: %d\n", result);
        return;
    }

    DEVMODE *newMode = &devMode;

    newMode->dmPelsWidth = width;
    newMode->dmPelsHeight = height;
    newMode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

    LONG changeDispResult = ChangeDisplaySettingsEx(
        NULL, newMode, NULL, CDS_GLOBAL | CDS_UPDATEREGISTRY | CDS_NORESET, NULL);


    LogChangeDispSettingsReturn(changeDispResult, "ChangeDisplayResolution");

    // According to the docs
    // To change the settings for more than one display at the same
    // time, first call ChangeDisplaySettingsEx for each device
    // individually to update the registry without applying the changes.
    // Then call ChangeDisplaySettingsEx once more, with a NULL device,
    // to apply the changes.
    LONG ret = ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);

    LogChangeDispSettingsReturn(ret, "ChangeScreenResolution Again");
}

Here is the LogChangeDispSettingsReturn function I made for convenience

void LogChangeDispSettingsReturn(LONG ret, char *funcName) {
    printf("%s: ", funcName);

    switch (ret) {
    case DISP_CHANGE_SUCCESSFUL:
        printf("The settings change was successful.\n");
        break;

    case DISP_CHANGE_BADDUALVIEW:
        printf("The settings change was unsuccessful because the "
               "system is DualView capable.\n");
        break;

    case DISP_CHANGE_BADFLAGS:
        printf("An invalid set of flags was passed in.\n");
        break;

    case DISP_CHANGE_BADMODE:
        printf("The graphics mode is not supported.\n");
        break;

    case DISP_CHANGE_BADPARAM:
        printf("An invalid parameter was passed in. This can include "
               "an invalid flag or combination of flags.\n");
        break;

    case DISP_CHANGE_FAILED:
        printf("The display driver failed the specified graphics mode.\n");
        break;

    case DISP_CHANGE_NOTUPDATED:
        printf("Unable to write settings to the registry.\n");
        break;

    case DISP_CHANGE_RESTART:
        printf("The computer must be restarted for the graphics mode "
               "to work.\n");
        break;
    };
}

Also found QueryDisplayConfig and SetDisplayConfig functions and thought about adding modelines to the DISPLAYCONFIG_MODE_INFO *modeInfoArray array returned by QueryDisplayConfig but apparently that's not allowed as I couldn't get it to work.

Also, I am not making these changes via an RDP client so display setting in the GUI are available to me, and hence I'm assuming the APIs should also be available.

Only adding a new mode does not work, if I use my ChangeScreenResolution function to change the resolution to something that I can see in the GUI, then the resolution change works.

0

There are 0 best solutions below