VirtualBox

Changeset 10797

Show
Ignore:
Timestamp:
07/22/08 10:12:42 (3 months ago)
Author:
vboxsync
Message:

Guest properties: initial commit of new interface

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Config.kmk

    r10773 r10797  
    320320endif 
    321321# Enable the host/guest information service (aka guest properties). 
    322 VBOX_WITH_INFO_SVC = 1 
     322VBOX_WITH_GUEST_PROPS = 1 
    323323# Enable performance API. 
    324324VBOX_WITH_RESOURCE_USAGE_API = 1 
  • trunk/include/VBox/HostServices/GuestPropertySvc.h

    r10003 r10797  
    11/** @file 
    2  * Shared information services
     2 * Guest property service
    33 * Common header for host service and guest clients. 
    44 */ 
     
    2020 */ 
    2121 
    22 #ifndef ___VBox_HostService_VBoxSharedInfoSvc_h 
    23 #define ___VBox_HostService_VBoxSharedInfoSvc_h 
     22#ifndef ___VBox_HostService_GuestPropertyService_h 
     23#define ___VBox_HostService_GuestPropertyService_h 
    2424 
    2525#include <VBox/types.h> 
     
    2828 
    2929/** Everything defined in this file lives in this namespace. */ 
    30 namespace svcInfo
     30namespace guestProp
    3131 
    3232/* 
     
    3535enum eHostFn 
    3636{ 
    37     /** Pass the address of the console object from Main to the service */ 
     37    /** Pass the address of the cfgm node used by the service as a database. */ 
    3838    SET_CFGM_NODE = 1, 
    3939    /**  
     
    6060enum eGuestFn 
    6161{ 
    62     /** Get the value attached to a configuration property key */ 
    63     GET_CONFIG_KEY = 1, 
    64     /** Set the value attached to a configuration property key */ 
    65     SET_CONFIG_KEY = 2, 
    66     /** Remove the value attached to a configuration property key */ 
    67     DEL_CONFIG_KEY = 3 
     62    /** Get a guest property */ 
     63    GET_PROP = 1, 
     64    /** Set a guest property */ 
     65    SET_PROP = 2, 
     66    /** Set just the value of a guest property */ 
     67    SET_PROP_VALUE = 3, 
     68    /** Delete a guest property */ 
     69    DEL_PROP = 4, 
     70    /** Enumerate guest properties */ 
     71    ENUM_PROPS = 5 
    6872}; 
    6973 
     
    7276/** Helper macro for the length of the prefix VBOX_SHARED_INFO_KEY_PREFIX */ 
    7377#define VBOX_SHARED_INFO_PREFIX_LEN          (sizeof(VBOX_SHARED_INFO_KEY_PREFIX) - 1) 
    74 /** Maximum length for extra data keys used by the get and set key value functions */ 
    75 enum { KEY_MAX_LEN = 64 }; 
     78/** Maximum length for property names */ 
     79enum { MAX_NAME_LEN = 64 }; 
     80/** Maximum length for property values */ 
     81enum { MAX_VALUE_LEN = 128 }; 
    7682/** Maximum length for extra data key values used by the get and set key value functions */ 
    77 enum { KEY_MAX_VALUE_LEN = 128 }; 
    78 /** Maximum number of extra data keys per guest */ 
    79 enum { KEY_MAX_KEYS = 256 }; 
     83enum { MAX_FLAGS_LEN = 128 }; 
     84/** Maximum number of properties per guest */ 
     85enum { MAX_KEYS = 256 }; 
    8086 
    8187/** 
     
    8389 */ 
    8490#pragma pack (1) 
    85 /** The guest is requesting the value of a configuration key */ 
    86 typedef struct _GetConfigKe
    87 { 
    88     VBoxGuestHGCMCallInfo hdr; 
    89  
    90     /** 
    91      * The key to look up (IN pointer) 
     91/** The guest is requesting the value of a property */ 
     92typedef struct _GetPropert
     93{ 
     94    VBoxGuestHGCMCallInfo hdr; 
     95 
     96    /** 
     97     * The property name (IN pointer) 
    9298     * This must fit to a number of criteria, namely 
    93      *  - Only ASCII characters with no spaces 
    94      *  - Less than or equal to VBOX_SHARED_INFO_KEY_MAX_LEN bytes in length 
    95      *  - Zero terminated 
    96      */ 
    97     HGCMFunctionParameter key; 
    98  
    99     /** 
    100      * The value of the key (OUT pointer) 
     99     *  - Only Utf8 strings are allowed 
     100     *  - Less than or equal to MAX_NAME_LEN bytes in length 
     101     *  - Zero terminated 
     102     */ 
     103    HGCMFunctionParameter name; 
     104 
     105    /** 
     106     * The returned string data will be placed here.  (OUT pointer) 
     107     * This call returns two null-terminated strings which will be placed one 
     108     * after another: value and flags. 
     109     */ 
     110    HGCMFunctionParameter buffer; 
     111 
     112    /** 
     113     * The property timestamp.  (OUT uint64_t) 
     114     */ 
     115 
     116    HGCMFunctionParameter timestamp; 
     117 
     118    /** 
     119     * If the buffer provided was large enough this will contain the size of 
     120     * the returned data.  Otherwise it will contain the size of the buffer 
     121     * needed to hold the data and VERR_BUFFER_OVERFLOW will be returned. 
     122     * (OUT uint32_t) 
     123     */ 
     124    HGCMFunctionParameter size; 
     125} GetProperty; 
     126 
     127/** The guest is requesting to change a property */ 
     128typedef struct _SetProperty 
     129
     130    VBoxGuestHGCMCallInfo hdr; 
     131 
     132    /** 
     133     * The property key.  (IN pointer) 
     134     * This must fit to a number of criteria, namely 
     135     *  - Only Utf8 strings are allowed 
     136     *  - Less than or equal to MAX_NAME_LEN bytes in length 
     137     *  - Zero terminated 
     138     */ 
     139    HGCMFunctionParameter name; 
     140 
     141    /** 
     142     * The value of the property (IN pointer) 
     143     * Criteria as for the key parameter, but with length less than or equal to 
     144     * MAX_VALUE_LEN.   
    101145     */ 
    102146    HGCMFunctionParameter value; 
    103147 
    104148    /** 
    105      * The size of the value.  If this is greater than the size of the array 
    106      * supplied in the second parameter then no data was transferred and th
    107      * call must be repeated.  If it is zero then no value was found. 
    108      * (OUT uint32_t) 
    109      */ 
    110     HGCMFunctionParameter size
    111 } GetConfigKey; 
    112  
    113 /** The guest is requesting to change the value of a configuration key */ 
    114 typedef struct _SetConfigKey 
    115 { 
    116     VBoxGuestHGCMCallInfo hdr; 
    117  
    118     /** 
    119      * The key to change up.  This must fit to a number of criteria, namely 
    120      * - Only ASCII characters with no spaces 
    121      *  - Less than or equal to VBOX_SHARED_INFO_KEY_MAX_LEN bytes in length 
    122      *  - Zero terminated 
    123      */ 
    124     HGCMFunctionParameter key; 
    125  
    126     /** 
    127     * The value of the key (IN pointer) 
    128      * Criteria as for the key parameter, but with length less that or equal to 
    129      * VBOX_SHARED_INFO_KEY_MAX_VALUE_LEN.  A null pointer causes the value to 
    130      * be removed from the database. 
     149     * The property flags (IN pointer) 
     150     * This is a comma-separated list of the format flag=valu
     151     * The length must be less than or equal to MAX_FLAGS_LEN and only 
     152     * known flag names and values will be accepted. 
     153     */ 
     154    HGCMFunctionParameter flags
     155} SetProperty; 
     156 
     157/** The guest is requesting to change the value of a property */ 
     158typedef struct _SetPropertyValue 
     159{ 
     160    VBoxGuestHGCMCallInfo hdr; 
     161 
     162    /** 
     163     * The property key.  (IN pointer) 
     164     * This must fit to a number of criteria, namely 
     165     *  - Only Utf8 strings are allowed 
     166     *  - Less than or equal to MAX_NAME_LEN bytes in length 
     167     *  - Zero terminated 
     168    */ 
     169    HGCMFunctionParameter name; 
     170 
     171    /** 
     172     * The value of the property (IN pointer) 
     173     * Criteria as for the key parameter, but with length less than or equal to 
     174     * MAX_VALUE_LEN.   
    131175     */ 
    132176    HGCMFunctionParameter value; 
    133 } SetConfigKey; 
    134  
    135 /** The guest is requesting to remove a configuration key */ 
    136 typedef struct _DelConfigKey 
    137 
    138     VBoxGuestHGCMCallInfo hdr; 
    139  
    140     /** 
    141      * The key to change up.  This must fit to a number of criteria, namely 
    142      *  - Only ASCII characters with no spaces 
    143      *  - Less than or equal to VBOX_SHARED_INFO_KEY_MAX_LEN bytes in length 
    144      *  - Zero terminated 
    145      */ 
    146     HGCMFunctionParameter key; 
    147 } DelConfigKey; 
     177} SetPropertyValue; 
     178 
     179/** The guest is requesting to remove a property */ 
     180typedef struct _DelProperty 
     181
     182    VBoxGuestHGCMCallInfo hdr; 
     183 
     184    /** 
     185     * The property name.  This must fit to a number of criteria, namely 
     186     *  - Only Utf8 strings are allowed 
     187     *  - Less than or equal to MAX_NAME_LEN bytes in length 
     188     *  - Zero terminated 
     189     */ 
     190    HGCMFunctionParameter name; 
     191} DelProperty; 
     192 
     193/** The guest is requesting to enumerate properties */ 
     194typedef struct _EnumProperties 
     195
     196    VBoxGuestHGCMCallInfo hdr; 
     197 
     198    /** 
     199     * Null-separated array of patterns to match the properties against. 
     200     * (IN pointer) 
     201     * If no patterns are given then return all. 
     202     */ 
     203    HGCMFunctionParameter patterns; 
     204    /** 
     205     * Null-separated array of strings in which the properties are returned. 
     206     * (OUT pointer) 
     207     * The number of strings in the array is always a multiple of four, 
     208     * and in sequences of name, value, timestamp (hexadecimal string) and the 
     209     * flags as a comma-separated list in the format "name=value" 
     210     */ 
     211    HGCMFunctionParameter strings; 
     212} EnumProperties; 
    148213#pragma pack () 
    149214 
    150 } /* namespace svcInfo */ 
    151  
    152 #endif  /* ___VBox_HostService_VBoxSharedInfoSvc_h defined */ 
     215} /* namespace guestProp */ 
     216 
     217#endif  /* ___VBox_HostService_GuestPropertySvc_h defined */ 
  • trunk/include/VBox/VBoxGuest.h

    r10651 r10797  
    15281528/** @}  */ 
    15291529 
    1530 #ifdef VBOX_WITH_INFO_SVC 
    1531 /** @name Information Services 
     1530#ifdef VBOX_WITH_GUEST_PROPS 
     1531/** @name Guest properties 
    15321532 * @{ */ 
    1533 VBGLR3DECL(int)     VbglR3InfoSvcConnect(uint32_t *pu32ClientId); 
    1534 VBGLR3DECL(int)     VbglR3InfoSvcDisconnect(uint32_t u32ClientId); 
    1535 VBGLR3DECL(int)     VbglR3InfoSvcWriteKey(uint32_t u32ClientId, char *pszKey, char *pszValue); 
    1536 VBGLR3DECL(int)     VbglR3InfoSvcReadKey(uint32_t u32ClientId, char *pszKey, char *pszValue, uint32_t cbValue, uint32_t *pcbActual); 
     1533VBGLR3DECL(int)     VbglR3GuestPropConnect(uint32_t *pu32ClientId); 
     1534VBGLR3DECL(int)     VbglR3GuestPropDisconnect(uint32_t u32ClientId); 
     1535VBGLR3DECL(int)     VbglR3GuestPropWrite(uint32_t u32ClientId, char *pszName, char *pszValue, char *pszFlags); 
     1536VBGLR3DECL(int)     VbglR3GuestPropWriteValue(uint32_t u32ClientId, char *pszName, char *pszValue); 
     1537VBGLR3DECL(int)     VbglR3GuestPropRead(uint32_t u32ClientId, const char *pszName, void *pvBuf, uint32_t cbBuf, char **ppszValue, uint64_t *pu64Timestamp, char **ppszFlags, uint32_t *pcbBufActual); 
     1538VBGLR3DECL(int)     VbglR3GuestPropReadValue(uint32_t ClientId, const char *pszName, char *pszValue, uint32_t cchValue, uint32_t *pcchValueActual); 
     1539VBGLR3DECL(int)     VbglR3GuestPropReadValueAlloc(uint32_t u32ClientId, const char *pszName, char **ppszValue); 
     1540VBGLR3DECL(void)    VbglR3GuestPropReadValueFree(char *pszValue); 
    15371541/** @}  */ 
    1538 #endif /* VBOX_WITH_INFO_SVC defined */ 
     1542#endif /* VBOX_WITH_GUEST_PROPS defined */ 
    15391543 
    15401544 
  • trunk/src/VBox/Additions/WINNT/Makefile.kmk

    r10129 r10797  
    3434include $(PATH_SUB_CURRENT)/VBoxTray/Makefile.kmk 
    3535include $(PATH_SUB_CURRENT)/VBoxGINA/Makefile.kmk 
    36 include $(PATH_SUB_CURRENT)/VBoxControl/Makefile.kmk 
    3736include $(PATH_SUB_CURRENT)/VBoxHook/Makefile.kmk 
    3837ifndef VBOX_OSE 
  • trunk/src/VBox/Additions/common/Makefile.kmk

    r10130 r10797  
    3030# Include sub-makefile. 
    3131include $(PATH_SUB_CURRENT)/VBoxGuestLib/Makefile.kmk 
    32 if1of ($(KBUILD_TARGET), freebsd linux os2 solaris) 
    3332include $(PATH_SUB_CURRENT)/VBoxControl/Makefile.kmk 
    34 endif 
    3533if1of ($(KBUILD_TARGET), freebsd os2 solaris) 
    3634include $(PATH_SUB_CURRENT)/VBoxGuest/Makefile.kmk 
  • trunk/src/VBox/Additions/common/VBoxControl/Makefile.kmk

    r10127 r10797  
    3333PROGRAMS += VBoxControl 
    3434VBoxControl_TEMPLATE = VBOXGUESTR3EXE 
    35 ifdef VBOX_WITH_INFO_SVC 
    36  VBoxControl_DEFS += VBOX_HGCM VBOX_WITH_INFO_SVC 
     35ifeq ($(KBUILD_TARGET),win) 
     36 ifdef VBOX_SIGN_ADDITIONS # (See the main Windows Additions makefile.) 
     37  VBoxControl_NOINST  = true 
     38 endif 
    3739endif 
     40VBoxControl_DEFS     += \ 
     41        $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS VBOX_HGCM,) 
    3842VBoxControl_SOURCES = \ 
    3943        VBoxControl.cpp \ 
    4044        VBoxControlSVN.cpp 
     45VBoxControl_SOURCES.win = \ 
     46        VBoxControl.rc 
    4147VBoxControl_LIBS = \ 
    4248        $(VBOX_LIB_IPRT_GUEST_R3) \ 
  • trunk/src/VBox/Additions/common/VBoxControl/VBoxControl.cpp

    r10236 r10797  
    2525*   Header Files                                                               * 
    2626*******************************************************************************/ 
    27 #include <iprt/thread.h> 
     27#include <iprt/mem.h> 
    2828#include <iprt/string.h> 
    2929#include <iprt/stream.h> 
    3030#include <iprt/path.h> 
    3131#include <iprt/initterm.h> 
     32#include <VBox/log.h> 
    3233#include <VBox/VBoxGuest.h> 
    3334#include <VBox/version.h> 
    34 #ifdef VBOX_WITH_INFO_SVC 
    35 # include <VBox/HostServices/VBoxInfoSvc.h> 
     35#ifdef RT_OS_WINDOWS 
     36# include <windows.h> 
     37# include <malloc.h>  /* for alloca */ 
     38#endif 
     39#ifdef VBOX_WITH_GUEST_PROPS 
     40# include <VBox/HostServices/GuestPropertySvc.h> 
    3641#endif 
    3742#include "VBoxControl.h" 
     
    5762static void doUsage(char const *line, char const *name = "", char const *command = "") 
    5863{ 
    59     RTPrintf("%s %-*s%s", name, 30 - strlen(name), command, line); 
     64    RTPrintf("%s %-*s%s", name, 32 - strlen(name), command, line); 
    6065} 
    6166 
     
    6368enum g_eUsage 
    6469{ 
    65 #ifdef VBOX_WITH_INFO_SVC 
     70#ifdef RT_OS_WINDOWS 
     71    GET_VIDEO_ACCEL, 
     72    SET_VIDEO_ACCEL, 
     73    LIST_CUST_MODES, 
     74    ADD_CUST_MODE, 
     75    REMOVE_CUST_MODE, 
     76    SET_VIDEO_MODE, 
     77#endif 
     78#ifdef VBOX_WITH_GUEST_PROPS 
    6679    GET_GUEST_PROP, 
    6780    SET_GUEST_PROP, 
     
    7386{ 
    7487    RTPrintf("Usage:\n\n"); 
    75     RTPrintf("%s [-v|--version]    print version number and exit\n", g_pszProgName); 
    76     RTPrintf("%s --nologo ...      suppress the logo\n\n", g_pszProgName); 
    77  
    78 #ifdef VBOX_WITH_INFO_SVC 
     88    RTPrintf("%s [-v|--version]       print version number and exit\n", g_pszProgName); 
     89    RTPrintf("%s --nologo ...         suppress the logo\n\n", g_pszProgName); 
     90 
     91#ifdef RT_OS_WINDOWS 
     92    if ((GET_VIDEO_ACCEL == eWhich) || (USAGE_ALL == eWhich)) 
     93        doUsage("\n", g_pszProgName, "getvideoacceleration"); 
     94    if ((SET_VIDEO_ACCEL == eWhich) || (USAGE_ALL == eWhich)) 
     95        doUsage("<on|off>\n", g_pszProgName, "setvideoacceleration"); 
     96    if ((LIST_CUST_MODES == eWhich) || (USAGE_ALL == eWhich)) 
     97        doUsage("\n", g_pszProgName, "listcustommodes"); 
     98    if ((ADD_CUST_MODE == eWhich) || (USAGE_ALL == eWhich)) 
     99        doUsage("<width> <height> <bpp>\n", g_pszProgName, "addcustommode"); 
     100    if ((REMOVE_CUST_MODE == eWhich) || (USAGE_ALL == eWhich)) 
     101        doUsage("<width> <height> <bpp>\n", g_pszProgName, "removecustommode"); 
     102    if ((SET_VIDEO_MODE == eWhich) || (USAGE_ALL == eWhich)) 
     103        doUsage("<width> <height> <bpp> <screen>\n", g_pszProgName, "setvideomode"); 
     104#endif 
     105#ifdef VBOX_WITH_GUEST_PROPS 
    79106    if ((GET_GUEST_PROP == eWhich) || (USAGE_ALL == eWhich)) 
    80         doUsage("<key>\n", g_pszProgName, "getguestproperty"); 
     107        doUsage("<name>\n", g_pszProgName, "getguestproperty"); 
    81108    if ((SET_GUEST_PROP == eWhich) || (USAGE_ALL == eWhich)) 
    82         doUsage("<key> [<value>] (no value deletes key)\n", g_pszProgName, "setguestproperty"); 
     109        doUsage("<name> [<value>] (no value deletes property)\n", g_pszProgName, "setguestproperty"); 
    83110#endif 
    84111} 
     
    101128} 
    102129 
    103 #ifdef VBOX_WITH_INFO_SVC 
     130#ifdef RT_OS_WINDOWS 
     131 
     132LONG (WINAPI * gpfnChangeDisplaySettingsEx)(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam); 
     133 
     134static unsigned nextAdjacentRectXP (RECTL *paRects, unsigned nRects, unsigned iRect) 
     135
     136    unsigned i; 
     137    for (i = 0; i < nRects; i++) 
     138    { 
     139        if (paRects[iRect].right == paRects[i].left) 
     140        { 
     141            return i; 
     142        } 
     143    } 
     144    return ~0; 
     145
     146 
     147static unsigned nextAdjacentRectXN (RECTL *paRects, unsigned nRects, unsigned iRect) 
     148
     149    unsigned i; 
     150    for (i = 0; i < nRects; i++) 
     151    { 
     152        if (paRects[iRect].left == paRects[i].right) 
     153        { 
     154            return i; 
     155        } 
     156    } 
     157    return ~0; 
     158
     159 
     160static unsigned nextAdjacentRectYP (RECTL *paRects, unsigned nRects, unsigned iRect) 
     161
     162    unsigned i; 
     163    for (i = 0; i < nRects; i++) 
     164    { 
     165        if (paRects[iRect].bottom == paRects[i].top) 
     166        { 
     167            return i; 
     168        } 
     169    } 
     170    return ~0; 
     171
     172 
     173unsigned nextAdjacentRectYN (RECTL *paRects, unsigned nRects, unsigned iRect) 
     174
     175    unsigned i; 
     176    for (i = 0; i < nRects; i++) 
     177    { 
     178        if (paRects[iRect].top == paRects[i].bottom) 
     179        { 
     180            return i; 
     181        } 
     182    } 
     183    return ~0; 
     184
     185 
     186void resizeRect(RECTL *paRects, unsigned nRects, unsigned iPrimary, unsigned iResized, int NewWidth, int NewHeight) 
     187
     188    RECTL *paNewRects = (RECTL *)alloca (sizeof (RECTL) * nRects); 
     189    memcpy (paNewRects, paRects, sizeof (RECTL) * nRects); 
     190    paNewRects[iResized].right += NewWidth - (paNewRects[iResized].right - paNewRects[iResized].left); 
     191    paNewRects[iResized].bottom += NewHeight - (paNewRects[iResized].bottom - paNewRects[iResized].top); 
     192     
     193    /* Verify all pairs of originally adjacent rectangles for all 4 directions.  
     194     * If the pair has a "good" delta (that is the first rectangle intersects the second) 
     195     * at a direction and the second rectangle is not primary one (which can not be moved), 
     196     * move the second rectangle to make it adjacent to the first one. 
     197     */ 
     198     
     199    /* X positive. */ 
     200    unsigned iRect; 
     201    for (iRect = 0; iRect < nRects; iRect++) 
     202    { 
     203        /* Find the next adjacent original rect in x positive direction. */ 
     204        unsigned iNextRect = nextAdjacentRectXP (paRects, nRects, iRect); 
     205        Log(("next %d -> %d\n", iRect, iNextRect)); 
     206         
     207        if (iNextRect == ~0 || iNextRect == iPrimary) 
     208        { 
     209            continue; 
     210        } 
     211         
     212        /* Check whether there is an X intesection between these adjacent rects in the new rectangles 
     213         * and fix the intersection if delta is "good". 
     214         */ 
     215        int delta = paNewRects[iRect].right - paNewRects[iNextRect].left; 
     216         
     217        if (delta > 0) 
     218        { 
     219            Log(("XP intersection right %d left %d, diff %d\n", 
     220                     paNewRects[iRect].right, paNewRects[iNextRect].left, 
     221                     delta)); 
     222             
     223            paNewRects[iNextRect].left += delta; 
     224            paNewRects[iNextRect].right += delta; 
     225        } 
     226    } 
     227     
     228    /* X negative. */ 
     229    for (iRect = 0; iRect < nRects; iRect++) 
     230    { 
     231        /* Find the next adjacent original rect in x negative direction. */ 
     232        unsigned iNextRect = nextAdjacentRectXN (paRects, nRects, iRect); 
     233        Log(("next %d -> %d\n", iRect, iNextRect)); 
     234         
     235        if (iNextRect == ~0 || iNextRect == iPrimary) 
     236        { 
     237            continue; 
     238        } 
     239         
     240        /* Check whether there is an X intesection between these adjacent rects in the new rectangles 
     241         * and fix the intersection if delta is "good". 
     242         */ 
     243        int delta = paNewRects[iRect].left - paNewRects[iNextRect].right; 
     244         
     245        if (delta < 0) 
     246        { 
     247            Log(("XN intersection left %d right %d, diff %d\n", 
     248                     paNewRects[iRect].left, paNewRects[iNextRect].right, 
     249                     delta)); 
     250             
     251            paNewRects[iNextRect].left += delta; 
     252            paNewRects[iNextRect].right += delta; 
     253        } 
     254    } 
     255     
     256    /* Y positive (in the computer sence, top->down). */ 
     257    for (iRect = 0; iRect < nRects; iRect++) 
     258    { 
     259        /* Find the next adjacent original rect in y positive direction. */ 
     260        unsigned iNextRect = nextAdjacentRectYP (paRects, nRects, iRect); 
     261        Log(("next %d -> %d\n", iRect, iNextRect)); 
     262         
     263        if (iNextRect == ~0 || iNextRect == iPrimary) 
     264        { 
     265            continue; 
     266        } 
     267         
     268        /* Check whether there is an Y intesection between these adjacent rects in the new rectangles 
     269         * and fix the intersection if delta is "good". 
     270         */ 
     271        int delta = paNewRects[iRect].bottom - paNewRects[iNextRect].top; 
     272         
     273        if (delta > 0) 
     274        { 
     275            Log(("YP intersection bottom %d top %d, diff %d\n", 
     276                     paNewRects[iRect].bottom, paNewRects[iNextRect].top, 
     277                     delta)); 
     278             
     279            paNewRects[iNextRect].top += delta; 
     280            paNewRects[iNextRect].bottom += delta; 
     281        } 
     282    } 
     283     
     284    /* Y negative (in the computer sence, down->top). */ 
     285    for (iRect = 0; iRect < nRects; iRect++) 
     286    { 
     287        /* Find the next adjacent original rect in x negative direction. */ 
     288        unsigned iNextRect = nextAdjacentRectYN (paRects, nRects, iRect); 
     289        Log(("next %d -> %d\n", iRect, iNextRect)); 
     290         
     291        if (iNextRect == ~0 || iNextRect == iPrimary) 
     292        { 
     293            continue; 
     294        } 
     295         
     296        /* Check whether there is an Y intesection between these adjacent rects in the new rectangles 
     297         * and fix the intersection if delta is "good". 
     298         */ 
     299        int delta = paNewRects[iRect].top - paNewRects[iNextRect].bottom; 
     300         
     301        if (delta < 0) 
     302        { 
     303            Log(("YN intersection top %d bottom %d, diff %d\n", 
     304                     paNewRects[iRect].top, paNewRects[iNextRect].bottom, 
     305                     delta)); 
     306             
     307            paNewRects[iNextRect].top += delta; 
     308            paNewRects[iNextRect].bottom += delta; 
     309        } 
     310    } 
     311     
     312    memcpy (paRects, paNewRects, sizeof (RECTL) * nRects); 
     313    return; 
     314
     315 
     316/* Returns TRUE to try again. */ 
     317static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel) 
     318
     319    BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0); 
     320     
     321    DISPLAY_DEVICE DisplayDevice; 
     322 
     323    ZeroMemory(&DisplayDevice, sizeof(DisplayDevice)); 
     324    DisplayDevice.cb = sizeof(DisplayDevice); 
     325     
     326    /* Find out how many display devices the system has */ 
     327    DWORD NumDevices = 0; 
     328    DWORD i = 0; 
     329    while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0)) 
     330    {  
     331        Log(("[%d] %s\n", i, DisplayDevice.DeviceName)); 
     332 
     333        if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) 
     334        { 
     335            Log(("Found primary device. err %d\n", GetLastError ())); 
     336            NumDevices++; 
     337        } 
     338        else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) 
     339        { 
     340             
     341            Log(("Found secondary device. err %d\n", GetLastError ())); 
     342            NumDevices++; 
     343        } 
     344         
     345        ZeroMemory(&DisplayDevice, sizeof(DisplayDevice)); 
     346        DisplayDevice.cb = sizeof(DisplayDevice); 
     347        i++; 
     348    } 
     349     
     350    Log(("Found total %d devices. err %d\n", NumDevices, GetLastError ())); 
     351     
     352    if (NumDevices == 0 || Id >= NumDevices) 
     353    { 
     354        Log(("Requested identifier %d is invalid. err %d\n", Id, GetLastError ())); 
     355        return FALSE; 
     356    } 
     357     
     358    DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices); 
     359    DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices); 
     360    RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices); 
     361     
     362    /* Fetch information about current devices and modes. */ 
     363    DWORD DevNum = 0; 
     364    DWORD DevPrimaryNum = 0; 
     365     
     366    ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE)); 
     367    DisplayDevice.cb = sizeof(DISPLAY_DEVICE); 
     368     
     369    i = 0; 
     370    while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0)) 
     371    {  
     372        Log(("[%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName)); 
     373         
     374        BOOL bFetchDevice = FALSE; 
     375 
     376        if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) 
     377        { 
     378            Log(("Found primary device. err %d\n", GetLastError ())); 
     379            DevPrimaryNum = DevNum; 
     380            bFetchDevice = TRUE; 
     381        } 
     382        else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) 
     383        { 
     384             
     385            Log(("Found secondary device. err %d\n", GetLastError ())); 
     386            bFetchDevice = TRUE; 
     387        } 
     388         
     389        if (bFetchDevice) 
     390        { 
     391            if (DevNum >= NumDevices) 
     392            { 
     393                Log(("%d >= %d\n", NumDevices, DevNum)); 
     394                return FALSE; 
     395            } 
     396         
     397            paDisplayDevices[DevNum] = DisplayDevice; 
     398             
     399            ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE)); 
     400            paDeviceModes[DevNum].dmSize = sizeof(DEVMODE); 
     401            if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName, 
     402                 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum])) 
     403            { 
     404                Log(("EnumDisplaySettings err %d\n", GetLastError ())); 
     405                return FALSE; 
     406            } 
     407             
     408            Log(("%dx%d at %d,%d\n", 
     409                    paDeviceModes[DevNum].dmPelsWidth, 
     410                    paDeviceModes[DevNum].dmPelsHeight, 
     411                    paDeviceModes[DevNum].dmPosition.x, 
     412                    paDeviceModes[DevNum].dmPosition.y)); 
     413                     
     414            paRects[DevNum].left   = paDeviceModes[DevNum].dmPosition.x; 
     415            paRects[DevNum].top    = paDeviceModes[DevNum].dmPosition.y; 
     416            paRects[DevNum].right  = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth; 
     417            paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight; 
     418            DevNum++; 
     419        } 
     420         
     421        ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE)); 
     422        DisplayDevice.cb = sizeof(DISPLAY_DEVICE); 
     423        i++; 
     424    } 
     425     
     426    if (Width == 0) 
     427    { 
     428        Width = paRects[Id].right - paRects[Id].left; 
     429    } 
     430 
     431    if (Height == 0) 
     432    { 
     433        Height = paRects[Id].bottom - paRects[Id].top; 
     434    } 
     435 
     436    /* Check whether a mode reset or a change is requested. */ 
     437    if (   !fModeReset 
     438        && paRects[Id].right - paRects[Id].left == Width 
     439        && paRects[Id].bottom - paRects[Id].top == Height 
     440        && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel) 
     441    { 
     442        Log(("VBoxDisplayThread : already at desired resolution.\n")); 
     443        return FALSE; 
     444    } 
     445 
     446    resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height); 
     447#ifdef Log 
     448    for (i = 0; i < NumDevices; i++) 
     449    { 
     450        Log(("[%d]: %d,%d %dx%d\n", 
     451                i, paRects[i].left, paRects[i].top, 
     452                paRects[i].right - paRects[i].left, 
     453                paRects[i].bottom - paRects[i].top)); 
     454    } 
     455#endif /* Log */ 
     456     
     457    /* Without this, Windows will not ask the miniport for its 
     458     * mode table but uses an internal cache instead. 
     459     */ 
     460    DEVMODE tempDevMode; 
     461    ZeroMemory (&tempDevMode, sizeof (tempDevMode)); 
     462    tempDevMode.dmSize = sizeof(DEVMODE); 
     463    EnumDisplaySettings(NULL, 0xffffff, &tempDevMode); 
     464 
     465    /* Assign the new rectangles to displays. */ 
     466    for (i = 0; i < NumDevices; i++) 
     467    { 
     468        paDeviceModes[i].dmPosition.x = paRects[i].left; 
     469        paDeviceModes[i].dmPosition.y = paRects[i].top; 
     470        paDeviceModes[i].dmPelsWidth  = paRects[i].right - paRects[i].left; 
     471        paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top; 
     472         
     473        paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH; 
     474         
     475        if (   i == Id 
     476            && BitsPerPixel != 0) 
     477        { 
     478            paDeviceModes[i].dmFields |= DM_BITSPERPEL; 
     479            paDeviceModes[i].dmBitsPerPel = BitsPerPixel; 
     480        } 
     481        Log(("calling pfnChangeDisplaySettingsEx %x\n", gpfnChangeDisplaySettingsEx));      
     482        gpfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,  
     483                 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);  
     484        Log(("ChangeDisplaySettings position err %d\n", GetLastError ())); 
     485    } 
     486     
     487    /* A second call to ChangeDisplaySettings updates the monitor. */ 
     488    LONG status = ChangeDisplaySettings(NULL, 0);  
     489    Log(("ChangeDisplaySettings update status %d\n", status)); 
     490    if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE) 
     491    { 
     492        /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */ 
     493        return FALSE; 
     494    } 
     495 
     496    /* Retry the request. */ 
     497    return TRUE; 
     498
     499 
     500int handleSetVideoMode(int argc, char *argv[]) 
     501
     502    if (argc != 3 && argc != 4) 
     503    { 
     504        usage(SET_VIDEO_MODE); 
     505        return 1; 
     506    } 
     507 
     508    DWORD xres = atoi(argv[0]); 
     509    DWORD yres = atoi(argv[1]); 
     510    DWORD bpp  = atoi(argv[2]); 
     511    DWORD scr  = 0; 
     512 
     513    if (argc == 4) 
     514    { 
     515        scr = atoi(argv[3]); 
     516    } 
     517 
     518    HMODULE hUser = GetModuleHandle("USER32"); 
     519 
     520    if (hUser) 
     521    { 
     522        *(uintptr_t *)&gpfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA"); 
     523        Log(("VBoxService: pChangeDisplaySettingsEx = %p\n", gpfnChangeDisplaySettingsEx)); 
     524         
     525        if (gpfnChangeDisplaySettingsEx) 
     526        { 
     527            /* The screen index is 0 based in the ResizeDisplayDevice call. */ 
     528            scr = scr > 0? scr - 1: 0; 
     529             
     530            /* Horizontal resolution must be a multiple of 8, round down. */ 
     531            xres &= ~0x7; 
     532 
     533            ResizeDisplayDevice(scr, xres, yres, bpp); 
     534        } 
     535    } 
     536    return 0; 
     537
     538 
     539HKEY getVideoKey(bool writable) 
     540
     541    HKEY hkeyDeviceMap = 0; 
     542    HKEY hkeyVideo = 0; 
     543    LONG status; 
     544 
     545    status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkeyDeviceMap); 
     546    if ((status != ERROR_SUCCESS) || !hkeyDeviceMap) 
     547    { 
     548        VBoxControlError("Error opening video device map registry key!\n"); 
     549        return 0; 
     550    } 
     551    char szVideoLocation[256]; 
     552    DWORD dwKeyType; 
     553    szVideoLocation[0] = 0; 
     554    DWORD len = sizeof(szVideoLocation); 
     555    status = RegQueryValueExA(hkeyDeviceMap, "\\Device\\Video0", NULL, &dwKeyType, (LPBYTE)szVideoLocation, &len); 
     556    /* 
     557     * This value will start with a weird value: \REGISTRY\Machine 
     558     * Make sure this is true. 
     559     */ 
     560    if (   (status == ERROR_SUCCESS) 
     561        && (dwKeyType == REG_SZ) 
     562        && (_strnicmp(szVideoLocation, "\\REGISTRY\\Machine", 17) == 0)) 
     563    { 
     564        /* open that branch */ 
     565        status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, &szVideoLocation[18], 0, KEY_READ | (writable ? KEY_WRITE : 0), &hkeyVideo); 
     566    } 
     567    else 
     568    { 
     569        VBoxControlError("Error opening registry key '%s'\n", &szVideoLocation[18]); 
     570    } 
     571    RegCloseKey(hkeyDeviceMap); 
     572    return hkeyVideo; 
     573
     574 
     575int handleGetVideoAcceleration(int argc, char *argv[]) 
     576
     577    ULONG status; 
     578    HKEY hkeyVideo = getVideoKey(false); 
     579 
     580    if (hkeyVideo) 
     581    { 
     582        /* query the actual value */ 
     583        DWORD fAcceleration = 1; 
     584        DWORD len = sizeof(fAcceleration); 
     585        DWORD dwKeyType; 
     586        status = RegQueryValueExA(hkeyVideo, "EnableVideoAccel", NULL, &dwKeyType, (LPBYTE)&fAcceleration, &len); 
     587        if (status != ERROR_SUCCESS) 
     588            RTPrintf("Video acceleration: default\n"); 
     589        else 
     590            RTPrintf("Video acceleration: %s\n", fAcceleration ? "on" : "off"); 
     591        RegCloseKey(hkeyVideo); 
     592    } 
     593    return 0; 
     594
     595 
     596int handleSetVideoAcceleration(int argc, char *argv[]) 
     597
     598    ULONG status; 
     599    HKEY hkeyVideo; 
     600 
     601    /* must have exactly one argument: the new offset */ 
     602    if (   (argc != 1) 
     603        || (   strcmp(argv[0], "on") 
     604            && strcmp(argv[0], "off"))) 
     605    { 
     606        usage(SET_VIDEO_ACCEL); 
     607        return 1; 
     608    } 
     609 
     610    hkeyVideo = getVideoKey(true); 
     611 
     612    if (hkeyVideo) 
     613    { 
     614        int fAccel = 0; 
     615        if (!strcmp(argv[0], "on")) 
     616            fAccel = 1; 
     617        /* set a new value */ 
     618        status = RegSetValueExA(hkeyVideo, "EnableVideoAccel", 0, REG_DWORD, (LPBYTE)&fAccel, sizeof(fAccel)); 
     619        if (status != ERROR_SUCCESS) 
     620        { 
     621            VBoxControlError("Error %d writing video acceleration status!\n", status); 
     622        } 
     623        RegCloseKey(hkeyVideo); 
     624    } 
     625    return 0; 
     626
     627 
     628#define MAX_CUSTOM_MODES 128 
     629 
     630/* the table of custom modes */ 
     631struct 
     632
     633    DWORD xres; 
     634    DWORD yres; 
     635    DWORD bpp; 
     636} customModes[MAX_CUSTOM_MODES] = {0}; 
     637 
     638void getCustomModes(HKEY hkeyVideo) 
     639
     640    ULONG status; 
     641    int curMode = 0; 
     642 
     643    /* null out the table */ 
     644    memset(customModes, 0, sizeof(customModes)); 
     645 
     646    do 
     647    { 
     648        char valueName[20]; 
     649        DWORD xres, yres, bpp = 0; 
     650        DWORD dwType; 
     651        DWORD dwLen = sizeof(DWORD); 
     652 
     653        RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", curMode); 
     654        status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&xres, &dwLen); 
     655        if (status != ERROR_SUCCESS) 
     656            break; 
     657        RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", curMode); 
     658        status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&yres, &dwLen); 
     659        if (status != ERROR_SUCCESS) 
     660            break; 
     661        RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dBPP", curMode); 
     662        status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&bpp, &dwLen); 
     663        if (status != ERROR_SUCCESS) 
     664            break; 
     665 
     666        /* check if the mode is OK */ 
     667        if (   (xres > (1 << 16)) 
     668            && (yres > (1 << 16)) 
     669            && (   (bpp != 16) 
     670                || (bpp != 24) 
     671                || (bpp != 32))) 
     672            break; 
     673 
     674        /* add mode to table */ 
     675        customModes[curMode].xres = xres; 
     676        customModes[curMode].yres = yres; 
     677        customModes[curMode].bpp  = bpp; 
     678 
     679        ++curMode; 
     680 
     681        if (curMode >= MAX_CUSTOM_MODES) 
     682            break; 
     683    } while(1); 
     684
     685 
     686void writeCustomModes(HKEY hkeyVideo) 
     687
     688    ULONG status; 
     689    int tableIndex = 0; 
     690    int modeIndex = 0; 
     691 
     692    /* first remove all values */ 
     693    for (int i = 0; i < MAX_CUSTOM_MODES; i++) 
     694    { 
     695        char valueName[20]; 
     696        RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", i); 
     697        RegDeleteValueA(hkeyVideo, valueName); 
     698        RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", i);