VirtualBox

Changeset 4968 in vbox for trunk


Ignore:
Timestamp:
Sep 21, 2007 5:59:13 PM (17 years ago)
Author:
vboxsync
Message:

Implemented VBoxControl setvideomode command for Windows guest additions.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/VBoxControl/VBoxControl.cpp

    r4071 r4968  
    1616#include <windows.h>
    1717#include <stdio.h>
     18#include <stdarg.h>
     19#include <malloc.h>
    1820
    1921void printHelp()
     
    2729           "VBoxControl   addcustommode <width> <height> <bpp>\n"
    2830           "\n"
    29            "VBoxControl   removecustommode <width> <height> <bpp>\n");
    30 }
    31 
     31           "VBoxControl   removecustommode <width> <height> <bpp>\n"
     32           "\n"
     33           "VBoxControl   setvideomode <width> <height> <bpp> <screen>\n");
     34}
     35
     36#if defined(DEBUG) || defined(LOG_ENABLED)
     37#define dprintf(a) do { int err = GetLastError (); printf a; SetLastError (err); } while (0)
     38#else
     39#define dprintf(a) do {} while (0)
     40#endif /* DEBUG */
     41
     42LONG (WINAPI * gpfnChangeDisplaySettingsEx)(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
     43
     44static unsigned nextAdjacentRectXP (RECTL *paRects, unsigned nRects, unsigned iRect)
     45{
     46    unsigned i;
     47    for (i = 0; i < nRects; i++)
     48    {
     49        if (paRects[iRect].right == paRects[i].left)
     50        {
     51            return i;
     52        }
     53    }
     54    return ~0;
     55}
     56
     57static unsigned nextAdjacentRectXN (RECTL *paRects, unsigned nRects, unsigned iRect)
     58{
     59    unsigned i;
     60    for (i = 0; i < nRects; i++)
     61    {
     62        if (paRects[iRect].left == paRects[i].right)
     63        {
     64            return i;
     65        }
     66    }
     67    return ~0;
     68}
     69
     70static unsigned nextAdjacentRectYP (RECTL *paRects, unsigned nRects, unsigned iRect)
     71{
     72    unsigned i;
     73    for (i = 0; i < nRects; i++)
     74    {
     75        if (paRects[iRect].bottom == paRects[i].top)
     76        {
     77            return i;
     78        }
     79    }
     80    return ~0;
     81}
     82
     83unsigned nextAdjacentRectYN (RECTL *paRects, unsigned nRects, unsigned iRect)
     84{
     85    unsigned i;
     86    for (i = 0; i < nRects; i++)
     87    {
     88        if (paRects[iRect].top == paRects[i].bottom)
     89        {
     90            return i;
     91        }
     92    }
     93    return ~0;
     94}
     95
     96void resizeRect(RECTL *paRects, unsigned nRects, unsigned iPrimary, unsigned iResized, int NewWidth, int NewHeight)
     97{
     98    RECTL *paNewRects = (RECTL *)alloca (sizeof (RECTL) * nRects);
     99    memcpy (paNewRects, paRects, sizeof (RECTL) * nRects);
     100    paNewRects[iResized].right += NewWidth - (paNewRects[iResized].right - paNewRects[iResized].left);
     101    paNewRects[iResized].bottom += NewHeight - (paNewRects[iResized].bottom - paNewRects[iResized].top);
     102   
     103    /* Verify all pairs of originally adjacent rectangles for all 4 directions.
     104     * If the pair has a "good" delta (that is the first rectangle intersects the second)
     105     * at a direction and the second rectangle is not primary one (which can not be moved),
     106     * move the second rectangle to make it adjacent to the first one.
     107     */
     108   
     109    /* X positive. */
     110    unsigned iRect;
     111    for (iRect = 0; iRect < nRects; iRect++)
     112    {
     113        /* Find the next adjacent original rect in x positive direction. */
     114        unsigned iNextRect = nextAdjacentRectXP (paRects, nRects, iRect);
     115        dprintf(("next %d -> %d\n", iRect, iNextRect));
     116       
     117        if (iNextRect == ~0 || iNextRect == iPrimary)
     118        {
     119            continue;
     120        }
     121       
     122        /* Check whether there is an X intesection between these adjacent rects in the new rectangles
     123         * and fix the intersection if delta is "good".
     124         */
     125        int delta = paNewRects[iRect].right - paNewRects[iNextRect].left;
     126       
     127        if (delta > 0)
     128        {
     129            dprintf(("XP intersection right %d left %d, diff %d\n",
     130                     paNewRects[iRect].right, paNewRects[iNextRect].left,
     131                     delta));
     132           
     133            paNewRects[iNextRect].left += delta;
     134            paNewRects[iNextRect].right += delta;
     135        }
     136    }
     137   
     138    /* X negative. */
     139    for (iRect = 0; iRect < nRects; iRect++)
     140    {
     141        /* Find the next adjacent original rect in x negative direction. */
     142        unsigned iNextRect = nextAdjacentRectXN (paRects, nRects, iRect);
     143        dprintf(("next %d -> %d\n", iRect, iNextRect));
     144       
     145        if (iNextRect == ~0 || iNextRect == iPrimary)
     146        {
     147            continue;
     148        }
     149       
     150        /* Check whether there is an X intesection between these adjacent rects in the new rectangles
     151         * and fix the intersection if delta is "good".
     152         */
     153        int delta = paNewRects[iRect].left - paNewRects[iNextRect].right;
     154       
     155        if (delta < 0)
     156        {
     157            dprintf(("XN intersection left %d right %d, diff %d\n",
     158                     paNewRects[iRect].left, paNewRects[iNextRect].right,
     159                     delta));
     160           
     161            paNewRects[iNextRect].left += delta;
     162            paNewRects[iNextRect].right += delta;
     163        }
     164    }
     165   
     166    /* Y positive (in the computer sence, top->down). */
     167    for (iRect = 0; iRect < nRects; iRect++)
     168    {
     169        /* Find the next adjacent original rect in y positive direction. */
     170        unsigned iNextRect = nextAdjacentRectYP (paRects, nRects, iRect);
     171        dprintf(("next %d -> %d\n", iRect, iNextRect));
     172       
     173        if (iNextRect == ~0 || iNextRect == iPrimary)
     174        {
     175            continue;
     176        }
     177       
     178        /* Check whether there is an Y intesection between these adjacent rects in the new rectangles
     179         * and fix the intersection if delta is "good".
     180         */
     181        int delta = paNewRects[iRect].bottom - paNewRects[iNextRect].top;
     182       
     183        if (delta > 0)
     184        {
     185            dprintf(("YP intersection bottom %d top %d, diff %d\n",
     186                     paNewRects[iRect].bottom, paNewRects[iNextRect].top,
     187                     delta));
     188           
     189            paNewRects[iNextRect].top += delta;
     190            paNewRects[iNextRect].bottom += delta;
     191        }
     192    }
     193   
     194    /* Y negative (in the computer sence, down->top). */
     195    for (iRect = 0; iRect < nRects; iRect++)
     196    {
     197        /* Find the next adjacent original rect in x negative direction. */
     198        unsigned iNextRect = nextAdjacentRectYN (paRects, nRects, iRect);
     199        dprintf(("next %d -> %d\n", iRect, iNextRect));
     200       
     201        if (iNextRect == ~0 || iNextRect == iPrimary)
     202        {
     203            continue;
     204        }
     205       
     206        /* Check whether there is an Y intesection between these adjacent rects in the new rectangles
     207         * and fix the intersection if delta is "good".
     208         */
     209        int delta = paNewRects[iRect].top - paNewRects[iNextRect].bottom;
     210       
     211        if (delta < 0)
     212        {
     213            dprintf(("YN intersection top %d bottom %d, diff %d\n",
     214                     paNewRects[iRect].top, paNewRects[iNextRect].bottom,
     215                     delta));
     216           
     217            paNewRects[iNextRect].top += delta;
     218            paNewRects[iNextRect].bottom += delta;
     219        }
     220    }
     221   
     222    memcpy (paRects, paNewRects, sizeof (RECTL) * nRects);
     223    return;
     224}
     225
     226/* Returns TRUE to try again. */
     227static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
     228{
     229    BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
     230   
     231    DISPLAY_DEVICE DisplayDevice;
     232
     233    ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
     234    DisplayDevice.cb = sizeof(DisplayDevice);
     235   
     236    /* Find out how many display devices the system has */
     237    DWORD NumDevices = 0;
     238    DWORD i = 0;
     239    while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
     240    {
     241        dprintf(("[%d] %s\n", i, DisplayDevice.DeviceName));
     242
     243        if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
     244        {
     245            dprintf(("Found primary device. err %d\n", GetLastError ()));
     246            NumDevices++;
     247        }
     248        else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
     249        {
     250           
     251            dprintf(("Found secondary device. err %d\n", GetLastError ()));
     252            NumDevices++;
     253        }
     254       
     255        ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
     256        DisplayDevice.cb = sizeof(DisplayDevice);
     257        i++;
     258    }
     259   
     260    dprintf(("Found total %d devices. err %d\n", NumDevices, GetLastError ()));
     261   
     262    if (NumDevices == 0 || Id >= NumDevices)
     263    {
     264        dprintf(("Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
     265        return FALSE;
     266    }
     267   
     268    DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
     269    DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
     270    RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
     271   
     272    /* Fetch information about current devices and modes. */
     273    DWORD DevNum = 0;
     274    DWORD DevPrimaryNum = 0;
     275   
     276    ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
     277    DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
     278   
     279    i = 0;
     280    while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
     281    {
     282        dprintf(("[%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
     283       
     284        BOOL bFetchDevice = FALSE;
     285
     286        if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
     287        {
     288            dprintf(("Found primary device. err %d\n", GetLastError ()));
     289            DevPrimaryNum = DevNum;
     290            bFetchDevice = TRUE;
     291        }
     292        else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
     293        {
     294           
     295            dprintf(("Found secondary device. err %d\n", GetLastError ()));
     296            bFetchDevice = TRUE;
     297        }
     298       
     299        if (bFetchDevice)
     300        {
     301            if (DevNum >= NumDevices)
     302            {
     303                dprintf(("%d >= %d\n", NumDevices, DevNum));
     304                return FALSE;
     305            }
     306       
     307            paDisplayDevices[DevNum] = DisplayDevice;
     308           
     309            ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
     310            paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
     311            if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
     312                 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
     313            {
     314                dprintf(("EnumDisplaySettings err %d\n", GetLastError ()));
     315                return FALSE;
     316            }
     317           
     318            dprintf(("%dx%d at %d,%d\n",
     319                    paDeviceModes[DevNum].dmPelsWidth,
     320                    paDeviceModes[DevNum].dmPelsHeight,
     321                    paDeviceModes[DevNum].dmPosition.x,
     322                    paDeviceModes[DevNum].dmPosition.y));
     323                   
     324            paRects[DevNum].left   = paDeviceModes[DevNum].dmPosition.x;
     325            paRects[DevNum].top    = paDeviceModes[DevNum].dmPosition.y;
     326            paRects[DevNum].right  = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
     327            paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
     328            DevNum++;
     329        }
     330       
     331        ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
     332        DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
     333        i++;
     334    }
     335   
     336    if (Width == 0)
     337    {
     338        Width = paRects[Id].right - paRects[Id].left;
     339    }
     340
     341    if (Height == 0)
     342    {
     343        Height = paRects[Id].bottom - paRects[Id].top;
     344    }
     345
     346    /* Check whether a mode reset or a change is requested. */
     347    if (   !fModeReset
     348        && paRects[Id].right - paRects[Id].left == Width
     349        && paRects[Id].bottom - paRects[Id].top == Height
     350        && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
     351    {
     352        dprintf(("VBoxDisplayThread : already at desired resolution.\n"));
     353        return FALSE;
     354    }
     355
     356    resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
     357#ifdef dprintf
     358    for (i = 0; i < NumDevices; i++)
     359    {
     360        dprintf(("[%d]: %d,%d %dx%d\n",
     361                i, paRects[i].left, paRects[i].top,
     362                paRects[i].right - paRects[i].left,
     363                paRects[i].bottom - paRects[i].top));
     364    }
     365#endif /* dprintf */
     366   
     367    /* Without this, Windows will not ask the miniport for its
     368     * mode table but uses an internal cache instead.
     369     */
     370    DEVMODE tempDevMode;
     371    ZeroMemory (&tempDevMode, sizeof (tempDevMode));
     372    tempDevMode.dmSize = sizeof(DEVMODE);
     373    EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
     374
     375    /* Assign the new rectangles to displays. */
     376    for (i = 0; i < NumDevices; i++)
     377    {
     378        paDeviceModes[i].dmPosition.x = paRects[i].left;
     379        paDeviceModes[i].dmPosition.y = paRects[i].top;
     380        paDeviceModes[i].dmPelsWidth  = paRects[i].right - paRects[i].left;
     381        paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
     382       
     383        paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH;
     384       
     385        if (   i == Id
     386            && BitsPerPixel != 0)
     387        {
     388            paDeviceModes[i].dmFields |= DM_BITSPERPEL;
     389            paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
     390        }
     391        dprintf(("calling pfnChangeDisplaySettingsEx %x\n", gpfnChangeDisplaySettingsEx));     
     392        gpfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
     393                 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
     394        dprintf(("ChangeDisplaySettings position err %d\n", GetLastError ()));
     395    }
     396   
     397    /* A second call to ChangeDisplaySettings updates the monitor. */
     398    LONG status = ChangeDisplaySettings(NULL, 0);
     399    dprintf(("ChangeDisplaySettings update status %d\n", status));
     400    if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
     401    {
     402        /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
     403        return FALSE;
     404    }
     405
     406    /* Retry the request. */
     407    return TRUE;
     408}
     409
     410void handleSetVideoMode(int argc, char *argv[])
     411{
     412    if (argc != 3 && argc != 4)
     413    {
     414        printf("Error: not enough parameters!\n");
     415        return;
     416    }
     417
     418    DWORD xres = atoi(argv[0]);
     419    DWORD yres = atoi(argv[1]);
     420    DWORD bpp  = atoi(argv[2]);
     421    DWORD scr  = 0;
     422
     423    if (argc == 4)
     424    {
     425        scr = atoi(argv[3]);
     426    }
     427
     428    HMODULE hUser = GetModuleHandle("USER32");
     429
     430    if (hUser)
     431    {
     432        *(uintptr_t *)&gpfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
     433        dprintf(("VBoxService: pChangeDisplaySettingsEx = %p\n", gpfnChangeDisplaySettingsEx));
     434       
     435        if (gpfnChangeDisplaySettingsEx)
     436        {
     437            /* The screen index is 0 based in the ResizeDisplayDevice call. */
     438            scr = scr > 0? scr - 1: 0;
     439           
     440            /* Horizontal resolution must be a multiple of 8, round down. */
     441            xres &= ~0x7;
     442
     443            ResizeDisplayDevice(scr, xres, yres, bpp);
     444        }
     445    }
     446}
    32447
    33448HKEY getVideoKey(bool writable)
     
    365780        handleRemoveCustomMode(argc - 2, &argv[2]);
    366781    }
     782    else if (strcmp(argv[1], "setvideomode") == 0)
     783    {
     784        handleSetVideoMode(argc - 2, &argv[2]);
     785    }
    367786    else
    368787    {
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette