summaryrefslogtreecommitdiff
path: root/src/VBox/Additions/WINNT/VBoxTray
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Additions/WINNT/VBoxTray
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Additions/WINNT/VBoxTray')
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk6
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp6
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.h2
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.cpp2034
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.h50
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.cpp388
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.h5
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.cpp7
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.h4
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxHostVersion.cpp2
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp629
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.h21
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxLA.cpp21
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.cpp96
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.h33
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.cpp2
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.h2
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.cpp145
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.h10
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxSharedFolders.cpp12
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp1143
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxTray.h17
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxTrayMsg.h89
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.cpp24
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.h2
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/resource.h2
-rw-r--r--src/VBox/Additions/WINNT/VBoxTray/testcase/tstSessionHack.cpp2
27 files changed, 3682 insertions, 1072 deletions
diff --git a/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk b/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
index da2b6853..6866ac32 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
+++ b/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
@@ -51,10 +51,16 @@ ifdef VBOX_WITH_SHARED_FOLDERS
VBoxTray_LIBS.win += \
mpr.lib
endif
+ifdef VBOX_WITH_MMR
+ VBoxTray_DEFS += VBOX_WITH_MMR
+ VBoxTray_SOURCES += \
+ VBoxMMR.cpp
+endif
ifdef VBOX_WITH_WDDM
VBoxTray_DEFS += VBOX_WITH_WDDM
# VBoxTray_DEFS += LOG_ENABLED
+ VBoxTray_SOURCES += ../Graphics/Video/disp/wddm/VBoxDispKmt.cpp
endif
# VBoxTray.cpp uses VBOX_SVN_REV.
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
index 971e841c..f73a7e4b 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -609,7 +609,7 @@ static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam,
int VBoxClipboardInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
{
- Log(("VBoxTray: VboxClipboardInit\n"));
+ Log(("VBoxTray: VBoxClipboardInit\n"));
if (gCtx.pEnv)
{
/* Clipboard was already initialized. 2 or more instances are not supported. */
@@ -675,7 +675,7 @@ unsigned __stdcall VBoxClipboardThread(void *pInstance)
break;
}
continue;
- }
+ }
else
{
Log(("VBoxTray: VBoxClipboardThread: VbglR3ClipboardGetHostMsg u32Msg = %ld, u32Formats = %ld\n", u32Msg, u32Formats));
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.h
index 7757d287..10f6e4f9 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.cpp
index 311b4626..422d2193 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.cpp
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -15,7 +15,7 @@
*/
#include "VBoxTray.h"
-
+#define _WIN32_WINNT 0x0601
#include <iprt/log.h>
#include <iprt/err.h>
#include <iprt/assert.h>
@@ -26,6 +26,517 @@
#include <iprt/asm.h>
#endif
+#include "VBoxDisplay.h"
+
+#ifndef NT_SUCCESS
+# define NT_SUCCESS(_Status) ((_Status) >= 0)
+#endif
+
+typedef struct VBOXDISPIF_OP
+{
+ PCVBOXDISPIF pIf;
+ VBOXDISPKMT_ADAPTER Adapter;
+ VBOXDISPKMT_DEVICE Device;
+ VBOXDISPKMT_CONTEXT Context;
+} VBOXDISPIF_OP;
+
+DWORD EnableAndResizeDispDev(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD totalDispNum, UINT Id, DWORD aWidth, DWORD aHeight,
+ DWORD aBitsPerPixel, DWORD aPosX, DWORD aPosY, BOOL fEnabled, BOOL fExtDispSup);
+
+static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes);
+
+static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
+
+static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable);
+
+static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp);
+
+/* APIs specific to win7 and above WDDM architecture. Not available for Vista WDDM.
+ * This is the reason they have not been put in the VBOXDISPIF struct in VBoxDispIf.h
+ */
+typedef struct _VBOXDISPLAYWDDMAPICONTEXT
+{
+ LONG (WINAPI * pfnSetDisplayConfig)(UINT numPathArrayElements,DISPLAYCONFIG_PATH_INFO *pathArray,UINT numModeInfoArrayElements,
+ DISPLAYCONFIG_MODE_INFO *modeInfoArray, UINT Flags);
+ LONG (WINAPI * pfnQueryDisplayConfig)(UINT Flags,UINT *pNumPathArrayElements, DISPLAYCONFIG_PATH_INFO *pPathInfoArray,
+ UINT *pNumModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *pModeInfoArray,
+ DISPLAYCONFIG_TOPOLOGY_ID *pCurrentTopologyId);
+ LONG (WINAPI * pfnGetDisplayConfigBufferSizes)(UINT Flags, UINT *pNumPathArrayElements, UINT *pNumModeInfoArrayElements);
+} _VBOXDISPLAYWDDMAPICONTEXT;
+
+static _VBOXDISPLAYWDDMAPICONTEXT gCtx = {0};
+
+typedef struct VBOXDISPIF_WDDM_DISPCFG
+{
+ UINT32 cPathInfoArray;
+ DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
+ UINT32 cModeInfoArray;
+ DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
+} VBOXDISPIF_WDDM_DISPCFG;
+
+static DWORD vboxDispIfWddmDcCreate(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT32 fFlags)
+{
+ UINT32 cPathInfoArray = 0;
+ UINT32 cModeInfoArray = 0;
+ DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
+ DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
+ DWORD winEr = gCtx.pfnGetDisplayConfigBufferSizes(fFlags, &cPathInfoArray, &cModeInfoArray);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed GetDisplayConfigBufferSizes\n"));
+ return winEr;
+ }
+
+ pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cPathInfoArray * sizeof(DISPLAYCONFIG_PATH_INFO));
+ if (!pPathInfoArray)
+ {
+ WARN(("VBoxTray: (WDDM) malloc failed!\n"));
+ return ERROR_OUTOFMEMORY;
+ }
+ pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
+ if (!pModeInfoArray)
+ {
+ WARN(("VBoxTray: (WDDM) malloc failed!\n"));
+ free(pPathInfoArray);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ winEr = gCtx.pfnQueryDisplayConfig(fFlags, &cPathInfoArray, pPathInfoArray, &cModeInfoArray, pModeInfoArray, NULL);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed QueryDisplayConfig\n"));
+ free(pPathInfoArray);
+ free(pModeInfoArray);
+ return winEr;
+ }
+
+ pCfg->cPathInfoArray = cPathInfoArray;
+ pCfg->pPathInfoArray = pPathInfoArray;
+ pCfg->cModeInfoArray = cModeInfoArray;
+ pCfg->pModeInfoArray = pModeInfoArray;
+ return ERROR_SUCCESS;
+}
+
+static DWORD vboxDispIfWddmDcClone(VBOXDISPIF_WDDM_DISPCFG *pCfg, VBOXDISPIF_WDDM_DISPCFG *pCfgDst)
+{
+ memset(pCfgDst, 0, sizeof (*pCfgDst));
+
+ if (pCfg->cPathInfoArray)
+ {
+ pCfgDst->pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
+ if (!pCfgDst->pPathInfoArray)
+ {
+ WARN(("VBoxTray: (WDDM) malloc failed!\n"));
+ return ERROR_OUTOFMEMORY;
+ }
+
+ memcpy(pCfgDst->pPathInfoArray, pCfg->pPathInfoArray, pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
+
+ pCfgDst->cPathInfoArray = pCfg->cPathInfoArray;
+ }
+
+ if (pCfg->cModeInfoArray)
+ {
+ pCfgDst->pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
+ if (!pCfgDst->pModeInfoArray)
+ {
+ WARN(("VBoxTray: (WDDM) malloc failed!\n"));
+ if (pCfgDst->pPathInfoArray)
+ {
+ free(pCfgDst->pPathInfoArray);
+ pCfgDst->pPathInfoArray = NULL;
+ }
+ return ERROR_OUTOFMEMORY;
+ }
+
+ memcpy(pCfgDst->pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
+
+ pCfgDst->cModeInfoArray = pCfg->cModeInfoArray;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+static VOID vboxDispIfWddmDcTerm(VBOXDISPIF_WDDM_DISPCFG *pCfg)
+{
+ if (pCfg->pPathInfoArray)
+ free(pCfg->pPathInfoArray);
+ if (pCfg->pModeInfoArray)
+ free(pCfg->pModeInfoArray);
+ /* sanity */
+ memset(pCfg, 0, sizeof (*pCfg));
+}
+
+static UINT32 g_cVBoxDispIfWddmDisplays = 0;
+static DWORD vboxDispIfWddmDcQueryNumDisplays(UINT32 *pcDisplays)
+{
+ if (!g_cVBoxDispIfWddmDisplays)
+ {
+ VBOXDISPIF_WDDM_DISPCFG DispCfg;
+ *pcDisplays = 0;
+ DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
+ return winEr;
+ }
+
+ int cDisplays = -1;
+
+ for (UINT iter = 0; iter < DispCfg.cPathInfoArray; ++iter)
+ {
+ if (cDisplays < (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id))
+ cDisplays = (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id);
+ }
+
+ cDisplays++;
+
+ g_cVBoxDispIfWddmDisplays = cDisplays;
+ Assert(g_cVBoxDispIfWddmDisplays);
+
+ vboxDispIfWddmDcTerm(&DispCfg);
+ }
+
+ *pcDisplays = g_cVBoxDispIfWddmDisplays;
+ return ERROR_SUCCESS;
+}
+
+static int vboxDispIfWddmDcSearchPath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
+{
+ for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
+ {
+ if ((srcId == ~0UL || pCfg->pPathInfoArray[iter].sourceInfo.id == srcId)
+ && (trgId == ~0UL || pCfg->pPathInfoArray[iter].targetInfo.id == trgId))
+ {
+ return (int)iter;
+ }
+ }
+ return -1;
+}
+
+static int vboxDispIfWddmDcSearchActivePath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
+{
+ int idx = vboxDispIfWddmDcSearchPath(pCfg, srcId, trgId);
+ if (idx < 0)
+ return idx;
+
+ if (!(pCfg->pPathInfoArray[idx].flags & DISPLAYCONFIG_PATH_ACTIVE))
+ return -1;
+
+ return idx;
+}
+
+static VOID vboxDispIfWddmDcSettingsInvalidateModeIndex(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx)
+{
+ pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+ pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+}
+
+static VOID vboxDispIfWddmDcSettingsInvalidateModeIndeces(VBOXDISPIF_WDDM_DISPCFG *pCfg)
+{
+ for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
+ {
+ vboxDispIfWddmDcSettingsInvalidateModeIndex(pCfg, (int)iter);
+ }
+
+ if (pCfg->pModeInfoArray)
+ {
+ free(pCfg->pModeInfoArray);
+ pCfg->pModeInfoArray = NULL;
+ }
+ pCfg->cModeInfoArray = 0;
+}
+
+static DWORD vboxDispIfWddmDcSettingsModeAdd(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT *pIdx)
+{
+ UINT32 cModeInfoArray = pCfg->cModeInfoArray + 1;
+ DISPLAYCONFIG_MODE_INFO *pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
+ if (!pModeInfoArray)
+ {
+ WARN(("VBoxTray: (WDDM) malloc failed!\n"));
+ return ERROR_OUTOFMEMORY;
+ }
+
+ memcpy (pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
+ memset(&pModeInfoArray[cModeInfoArray-1], 0, sizeof (pModeInfoArray[0]));
+ free(pCfg->pModeInfoArray);
+ *pIdx = cModeInfoArray-1;
+ pCfg->pModeInfoArray = pModeInfoArray;
+ pCfg->cModeInfoArray = cModeInfoArray;
+ return ERROR_SUCCESS;
+}
+
+static DWORD vboxDispIfWddmDcSettingsUpdate(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx, DEVMODE *pDeviceMode, BOOL fInvalidateSrcMode, BOOL fEnable)
+{
+ UINT Id = pCfg->pPathInfoArray[idx].sourceInfo.id;
+
+ if (fInvalidateSrcMode)
+ pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+ else if (pDeviceMode)
+ {
+ UINT iSrcMode = pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx;
+ if (iSrcMode == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)
+ {
+
+ WARN(("VBoxTray: (WDDM) no source mode index specified"));
+ DWORD winEr = vboxDispIfWddmDcSettingsModeAdd(pCfg, &iSrcMode);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcSettingsModeAdd Failed winEr %d\n", winEr));
+ return winEr;
+ }
+ pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = iSrcMode;
+ }
+
+ for (int i = 0; i < (int)pCfg->cPathInfoArray; ++i)
+ {
+ if (i == idx)
+ continue;
+
+ if (pCfg->pPathInfoArray[i].sourceInfo.modeInfoIdx == iSrcMode)
+ {
+ /* this is something we're not expecting/supporting */
+ WARN(("VBoxTray: (WDDM) multiple paths have the same mode index"));
+ return ERROR_NOT_SUPPORTED;
+ }
+ }
+
+ if (pDeviceMode->dmFields & DM_PELSWIDTH)
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.width = pDeviceMode->dmPelsWidth;
+ if (pDeviceMode->dmFields & DM_PELSHEIGHT)
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.height = pDeviceMode->dmPelsHeight;
+ if (pDeviceMode->dmFields & DM_POSITION)
+ {
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x = pDeviceMode->dmPosition.x;
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y = pDeviceMode->dmPosition.y;
+ }
+ if (pDeviceMode->dmFields & DM_BITSPERPEL)
+ {
+ switch (pDeviceMode->dmBitsPerPel)
+ {
+ case 32:
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
+ break;
+ case 24:
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_24BPP;
+ break;
+ case 16:
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_16BPP;
+ break;
+ case 8:
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_8BPP;
+ break;
+ default:
+ LogRel(("VBoxTray: (WDDM) invalid bpp %d, using 32\n", pDeviceMode->dmBitsPerPel));
+ pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
+ break;
+ }
+ }
+ }
+
+ pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+
+ if (fEnable)
+ pCfg->pPathInfoArray[idx].flags |= DISPLAYCONFIG_PATH_ACTIVE;
+ else
+ pCfg->pPathInfoArray[idx].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
+
+ return ERROR_SUCCESS;
+}
+
+static DWORD vboxDispIfWddmDcSet(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT fFlags)
+{
+ DWORD winEr = gCtx.pfnSetDisplayConfig(pCfg->cPathInfoArray, pCfg->pPathInfoArray, pCfg->cModeInfoArray, pCfg->pModeInfoArray, fFlags);
+ if (winEr != ERROR_SUCCESS)
+ Log(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed for Flags 0x%x\n", fFlags));
+ return winEr;
+}
+
+static BOOL vboxDispIfWddmDcSettingsAdjustSupportedPaths(VBOXDISPIF_WDDM_DISPCFG *pCfg)
+{
+ BOOL fAdjusted = FALSE;
+ for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
+ {
+ if (pCfg->pPathInfoArray[iter].sourceInfo.id == pCfg->pPathInfoArray[iter].targetInfo.id)
+ continue;
+
+ if (!(pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
+ continue;
+
+ pCfg->pPathInfoArray[iter].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
+ fAdjusted = TRUE;
+ }
+
+ return fAdjusted;
+}
+
+static void vboxDispIfWddmDcSettingsAttachDisbledToPrimary(VBOXDISPIF_WDDM_DISPCFG *pCfg)
+{
+ for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
+ {
+ if ((pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
+ continue;
+
+ pCfg->pPathInfoArray[iter].sourceInfo.id = 0;
+ pCfg->pPathInfoArray[iter].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+ pCfg->pPathInfoArray[iter].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+ }
+}
+
+static DWORD vboxDispIfWddmDcSettingsIncludeAllTargets(VBOXDISPIF_WDDM_DISPCFG *pCfg)
+{
+ UINT32 cDisplays = 0;
+ VBOXDISPIF_WDDM_DISPCFG AllCfg;
+ BOOL fAllCfgInited = FALSE;
+
+ DWORD winEr = vboxDispIfWddmDcQueryNumDisplays(&cDisplays);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcQueryNumDisplays Failed winEr %d\n", winEr));
+ return winEr;
+ }
+
+ DISPLAYCONFIG_PATH_INFO *pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cDisplays * sizeof(DISPLAYCONFIG_PATH_INFO));
+ if (!pPathInfoArray)
+ {
+ WARN(("malloc failed\n"));
+ return ERROR_OUTOFMEMORY;
+ }
+
+ for (UINT i = 0; i < cDisplays; ++i)
+ {
+ int idx = vboxDispIfWddmDcSearchPath(pCfg, i, i);
+ if (idx < 0)
+ {
+ idx = vboxDispIfWddmDcSearchPath(pCfg, -1, i);
+ if (idx >= 0)
+ {
+ WARN(("VBoxTray:(WDDM) different source and target paare enabled, this is something we would not expect\n"));
+ }
+ }
+
+ if (idx >= 0)
+ pPathInfoArray[i] = pCfg->pPathInfoArray[idx];
+ else
+ {
+ if (!fAllCfgInited)
+ {
+ winEr = vboxDispIfWddmDcCreate(&AllCfg, QDC_ALL_PATHS);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
+ free(pPathInfoArray);
+ return winEr;
+ }
+ fAllCfgInited = TRUE;
+ }
+
+ idx = vboxDispIfWddmDcSearchPath(&AllCfg, i, i);
+ if (idx < 0)
+ {
+ WARN(("VBoxTray:(WDDM) %d %d path not supported\n", i, i));
+ idx = vboxDispIfWddmDcSearchPath(pCfg, -1, i);
+ if (idx < 0)
+ {
+ WARN(("VBoxTray:(WDDM) %d %d path not supported\n", -1, i));
+ }
+ }
+
+ if (idx >= 0)
+ {
+ pPathInfoArray[i] = AllCfg.pPathInfoArray[idx];
+
+ if (pPathInfoArray[i].flags & DISPLAYCONFIG_PATH_ACTIVE)
+ {
+ WARN(("VBoxTray:(WDDM) disabled path %d %d is marked active\n",
+ pPathInfoArray[i].sourceInfo.id, pPathInfoArray[i].targetInfo.id));
+ pPathInfoArray[i].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
+ }
+
+ Assert(pPathInfoArray[i].sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
+ Assert(pPathInfoArray[i].sourceInfo.statusFlags == 0);
+
+ Assert(pPathInfoArray[i].targetInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
+ Assert(pPathInfoArray[i].targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15);
+ Assert(pPathInfoArray[i].targetInfo.rotation == DISPLAYCONFIG_ROTATION_IDENTITY);
+ Assert(pPathInfoArray[i].targetInfo.scaling == DISPLAYCONFIG_SCALING_PREFERRED);
+ Assert(pPathInfoArray[i].targetInfo.refreshRate.Numerator == 0);
+ Assert(pPathInfoArray[i].targetInfo.refreshRate.Denominator == 0);
+ Assert(pPathInfoArray[i].targetInfo.scanLineOrdering == DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED);
+ Assert(pPathInfoArray[i].targetInfo.targetAvailable == TRUE);
+ Assert(pPathInfoArray[i].targetInfo.statusFlags == DISPLAYCONFIG_TARGET_FORCIBLE);
+
+ Assert(pPathInfoArray[i].flags == 0);
+ }
+ else
+ {
+ pPathInfoArray[i].sourceInfo.adapterId = pCfg->pPathInfoArray[0].sourceInfo.adapterId;
+ pPathInfoArray[i].sourceInfo.id = i;
+ pPathInfoArray[i].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+ pPathInfoArray[i].sourceInfo.statusFlags = 0;
+
+ pPathInfoArray[i].targetInfo.adapterId = pPathInfoArray[i].sourceInfo.adapterId;
+ pPathInfoArray[i].targetInfo.id = i;
+ pPathInfoArray[i].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
+ pPathInfoArray[i].targetInfo.outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15;
+ pPathInfoArray[i].targetInfo.rotation = DISPLAYCONFIG_ROTATION_IDENTITY;
+ pPathInfoArray[i].targetInfo.scaling = DISPLAYCONFIG_SCALING_PREFERRED;
+ pPathInfoArray[i].targetInfo.refreshRate.Numerator = 0;
+ pPathInfoArray[i].targetInfo.refreshRate.Denominator = 0;
+ pPathInfoArray[i].targetInfo.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
+ pPathInfoArray[i].targetInfo.targetAvailable = TRUE;
+ pPathInfoArray[i].targetInfo.statusFlags = DISPLAYCONFIG_TARGET_FORCIBLE;
+
+ pPathInfoArray[i].flags = 0;
+ }
+ }
+ }
+
+ free(pCfg->pPathInfoArray);
+ pCfg->pPathInfoArray = pPathInfoArray;
+ pCfg->cPathInfoArray = cDisplays;
+ if (fAllCfgInited)
+ vboxDispIfWddmDcTerm(&AllCfg);
+
+ return ERROR_SUCCESS;
+}
+
+static DWORD vboxDispIfOpBegin(PCVBOXDISPIF pIf, VBOXDISPIF_OP *pOp)
+{
+ pOp->pIf = pIf;
+
+ HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pOp->Adapter);
+ if (SUCCEEDED(hr))
+ {
+ hr = vboxDispKmtCreateDevice(&pOp->Adapter, &pOp->Device);
+ if (SUCCEEDED(hr))
+ {
+ hr = vboxDispKmtCreateContext(&pOp->Device, &pOp->Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE,
+ 0, 0, NULL, 0ULL);
+ if (SUCCEEDED(hr))
+ return ERROR_SUCCESS;
+ else
+ WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
+
+ vboxDispKmtDestroyDevice(&pOp->Device);
+ }
+ else
+ WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
+
+ vboxDispKmtCloseAdapter(&pOp->Adapter);
+ }
+
+ return hr;
+}
+
+static VOID vboxDispIfOpEnd(VBOXDISPIF_OP *pOp)
+{
+ vboxDispKmtDestroyContext(&pOp->Context);
+ vboxDispKmtDestroyDevice(&pOp->Device);
+ vboxDispKmtCloseAdapter(&pOp->Adapter);
+}
+
/* display driver interface abstraction for XPDM & WDDM
* with WDDM we can not use ExtEscape to communicate with our driver
* because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
@@ -44,9 +555,11 @@ static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf);
DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
{
#ifdef VBOX_WITH_WDDM
- if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
+ if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
{
vboxDispIfWddmTerm(pIf);
+
+ vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
}
#endif
@@ -84,7 +597,7 @@ static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
if (OSinfo.dwMajorVersion >= 6)
{
Log((__FUNCTION__": this is vista and up\n"));
- HMODULE hUser = GetModuleHandle("USER32");
+ HMODULE hUser = GetModuleHandle("user32.dll");
if (hUser)
{
*(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
@@ -94,53 +607,39 @@ static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
*(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
Log((__FUNCTION__": VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
-
- /* this is vista and up */
- HMODULE hGdi32 = GetModuleHandle("gdi32");
- if (hGdi32 != NULL)
+ /* for win 7 and above */
+ if (OSinfo.dwMinorVersion >= 1)
{
- pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromHdc");
- Log((__FUNCTION__"pfnD3DKMTOpenAdapterFromHdc = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc));
- bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc);
-
- pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
- Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName));
- bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName);
+ *(uintptr_t *)&gCtx.pfnSetDisplayConfig = (uintptr_t)GetProcAddress(hUser, "SetDisplayConfig");
+ Log((__FUNCTION__": VBoxDisplayInit: pfnSetDisplayConfig = %p\n", gCtx.pfnSetDisplayConfig));
+ bSupported &= !!(gCtx.pfnSetDisplayConfig);
- pIf->modeData.wddm.pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
- Log((__FUNCTION__": pfnD3DKMTCloseAdapter = %p\n", pIf->modeData.wddm.pfnD3DKMTCloseAdapter));
- bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
+ *(uintptr_t *)&gCtx.pfnQueryDisplayConfig = (uintptr_t)GetProcAddress(hUser, "QueryDisplayConfig");
+ Log((__FUNCTION__": VBoxDisplayInit: pfnQueryDisplayConfig = %p\n", gCtx.pfnQueryDisplayConfig));
+ bSupported &= !!(gCtx.pfnQueryDisplayConfig);
- pIf->modeData.wddm.pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(hGdi32, "D3DKMTEscape");
- Log((__FUNCTION__": pfnD3DKMTEscape = %p\n", pIf->modeData.wddm.pfnD3DKMTEscape));
- bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
-
- pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn = (PFND3DKMT_INVALIDATEACTIVEVIDPN)GetProcAddress(hGdi32, "D3DKMTInvalidateActiveVidPn");
- Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn = %p\n", pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn));
- bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn);
-
- if (!bSupported)
- {
- Log((__FUNCTION__": one of pfnD3DKMT function pointers failed to initialize\n"));
- err = ERROR_NOT_SUPPORTED;
- }
+ *(uintptr_t *)&gCtx.pfnGetDisplayConfigBufferSizes = (uintptr_t)GetProcAddress(hUser, "GetDisplayConfigBufferSizes");
+ Log((__FUNCTION__": VBoxDisplayInit: pfnGetDisplayConfigBufferSizes = %p\n", gCtx.pfnGetDisplayConfigBufferSizes));
+ bSupported &= !!(gCtx.pfnGetDisplayConfigBufferSizes);
}
- else
+
+ /* this is vista and up */
+ HRESULT hr = vboxDispKmtCallbacksInit(&pIf->modeData.wddm.KmtCallbacks);
+ if (FAILED(hr))
{
- Log((__FUNCTION__": GetModuleHandle(gdi32) failed, err(%d)\n", GetLastError()));
- err = ERROR_NOT_SUPPORTED;
+ WARN(("VBoxTray: vboxDispKmtCallbacksInit failed hr 0x%x\n", hr));
+ err = hr;
}
-
}
else
{
- Log((__FUNCTION__": GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
+ WARN((__FUNCTION__": GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
err = ERROR_NOT_SUPPORTED;
}
}
else
{
- Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
+ WARN((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
err = ERROR_NOT_SUPPORTED;
}
@@ -152,6 +651,11 @@ static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
return err;
}
+static DWORD vboxDispIfSwitchToWDDM_W7(PVBOXDISPIF pIf)
+{
+ return vboxDispIfSwitchToWDDM(pIf);
+}
+
static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
{
DWORD winEr = ERROR_INVALID_STATE;
@@ -174,179 +678,57 @@ static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE
else
{
winEr = GetLastError();
- Assert(0);
+ WARN(("CreateDC failed %d", winEr));
break;
}
}
+ Log(("display data no match display(%d): i(%d), flags(%d)", iDisplay, i, pDev->StateFlags));
}
else
{
winEr = GetLastError();
- Assert(0);
+ WARN(("EnumDisplayDevices failed %d", winEr));
break;
}
}
+ WARN(("vboxDispIfWDDMAdpHdcCreate failure branch %d", winEr));
return winEr;
}
-
-typedef DECLCALLBACK(BOOLEAN) FNVBOXDISPIFWDDM_ADAPTEROP(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext);
-typedef FNVBOXDISPIFWDDM_ADAPTEROP *PFNVBOXDISPIFWDDM_ADAPTEROP;
-static DWORD vboxDispIfWDDMAdapterOp(PCVBOXDISPIF pIf, int iDisplay, PFNVBOXDISPIFWDDM_ADAPTEROP pfnOp, PVOID pContext)
+static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
{
- D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
- DISPLAY_DEVICE DDev;
- DWORD err = vboxDispIfWDDMAdpHdcCreate(iDisplay, &OpenAdapterData.hDc, &DDev);
- Assert(err == NO_ERROR);
- if (err == NO_ERROR)
+ DWORD winEr = ERROR_SUCCESS;
+ VBOXDISPKMT_ADAPTER Adapter;
+ HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &Adapter);
+ if (!SUCCEEDED(hr))
{
- NTSTATUS Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
- Assert(!Status);
- if (!Status)
- {
- BOOLEAN bCloseAdapter = pfnOp(pIf, OpenAdapterData.hAdapter, &DDev, pContext);
-
- if (bCloseAdapter)
- {
- D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
- ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
- Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
- if (Status)
- {
- Log((__FUNCTION__": pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
- }
- }
- }
- else
- {
- Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
- err = ERROR_GEN_FAILURE;
- }
-
- DeleteDC(OpenAdapterData.hDc);
+ WARN(("VBoxTray: vboxDispKmtOpenAdapter failed hr 0x%x\n", hr));
+ return hr;
}
- return err;
-}
-
-typedef struct
-{
- NTSTATUS Status;
- PVBOXDISPIFESCAPE pEscape;
- int cbData;
- D3DDDI_ESCAPEFLAGS EscapeFlags;
-} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
-
-DECLCALLBACK(BOOLEAN) vboxDispIfEscapeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
-{
- PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
-
D3DKMT_ESCAPE EscapeData = {0};
- EscapeData.hAdapter = hAdapter;
+ EscapeData.hAdapter = Adapter.hAdapter;
//EscapeData.hDevice = NULL;
EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
- EscapeData.Flags = pCtx->EscapeFlags;
- EscapeData.pPrivateDriverData = pCtx->pEscape;
- EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
- //EscapeData.hContext = NULL;
-
- pCtx->Status = pIf->modeData.wddm.pfnD3DKMTEscape(&EscapeData);
-
- return TRUE;
-}
-
-static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
-{
- VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
- Ctx.pEscape = pEscape;
- Ctx.cbData = cbData;
if (fHwAccess)
- Ctx.EscapeFlags.HardwareAccess = 1;
- DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
- if (err == NO_ERROR)
- {
- if (!Ctx.Status)
- err = NO_ERROR;
- else
- {
- if (Ctx.Status == 0xC00000BBL) /* not supported */
- err = ERROR_NOT_SUPPORTED;
- else
- err = ERROR_GEN_FAILURE;
- Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
- }
- }
- else
- Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
-
- return err;
-}
-
-typedef struct
-{
- NTSTATUS Status;
- VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO Info;
-} VBOXDISPIFWDDM_RESIZEOP_CONTEXT, *PVBOXDISPIFWDDM_RESIZEOP_CONTEXT;
-
-DECLCALLBACK(BOOLEAN) vboxDispIfResizeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
-{
- PVBOXDISPIFWDDM_RESIZEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_RESIZEOP_CONTEXT)pContext;
- D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
- uint32_t cbData = VBOXWDDM_RECOMMENDVIDPN_SIZE(1);
- PVBOXWDDM_RECOMMENDVIDPN pData = (PVBOXWDDM_RECOMMENDVIDPN)malloc(cbData);
- if (pData)
- {
- memset(pData, 0, cbData);
- pData->cScreenInfos = 1;
- memcpy(&pData->aScreenInfos[0], &pCtx->Info, sizeof (VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO));
-
- IAVidPnData.hAdapter = hAdapter;
- IAVidPnData.pPrivateDriverData = pData;
- IAVidPnData.PrivateDriverDataSize = cbData;
-
- pCtx->Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
- Assert(!pCtx->Status);
- if (pCtx->Status)
- Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", pCtx->Status));
+ EscapeData.Flags.HardwareAccess = 1;
+ EscapeData.pPrivateDriverData = pEscape;
+ EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
+ //EscapeData.hContext = NULL;
- free(pData);
- }
+ NTSTATUS Status = pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
+ if (NT_SUCCESS(Status))
+ winEr = ERROR_SUCCESS;
else
{
- Log((__FUNCTION__": malloc failed\n"));
- pCtx->Status = -1;
+ WARN(("VBoxTray: pfnD3DKMTEscape failed Status 0x%x\n", Status));
+ winEr = ERROR_GEN_FAILURE;
}
- return TRUE;
-}
+ vboxDispKmtCloseAdapter(&Adapter);
-static DWORD vboxDispIfResizeWDDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
-{
- VBOXDISPIFWDDM_RESIZEOP_CONTEXT Ctx = {0};
- Ctx.Info.Id = Id;
- Ctx.Info.Width = Width;
- Ctx.Info.Height = Height;
- Ctx.Info.BitsPerPixel = BitsPerPixel;
- DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1, /* (int)Id - always say -1 to use primary display since the display does not really matter here */
- vboxDispIfResizeWDDMOp, &Ctx);
- if (err == NO_ERROR)
- {
- if (!Ctx.Status)
- err = NO_ERROR;
- else
- {
- if (Ctx.Status == 0xC00000BBL) /* not supported */
- err = ERROR_NOT_SUPPORTED;
- else
- err = ERROR_GEN_FAILURE;
- Log((__FUNCTION__": vboxDispIfResizeWDDMOp failed, Status (0x%x)\n", Ctx.Status));
- }
- }
- else
- Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
-
- return err;
+ return winEr;
}
#endif
@@ -359,6 +741,7 @@ DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 1);
#ifdef VBOX_WITH_WDDM
case VBOXDISPIF_MODE_WDDM:
+ case VBOXDISPIF_MODE_WDDM_W7:
return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
#endif
default:
@@ -376,6 +759,7 @@ DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, i
return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 0);
#ifdef VBOX_WITH_WDDM
case VBOXDISPIF_MODE_WDDM:
+ case VBOXDISPIF_MODE_WDDM_W7:
return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
#endif
default:
@@ -384,60 +768,138 @@ DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, i
}
}
-static DWORD vboxDispIfResizeXPDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
+#ifdef VBOX_WITH_WDDM
+
+#define VBOXRR_TIMER_ID 1234
+
+typedef struct VBOXRR
{
- return ERROR_NOT_SUPPORTED;
-}
+ HANDLE hThread;
+ DWORD idThread;
+ HANDLE hEvent;
+ HWND hWnd;
+ CRITICAL_SECTION CritSect;
+ UINT_PTR idTimer;
+ PCVBOXDISPIF pIf;
+ UINT iChangedMode;
+ BOOL fEnable;
+ BOOL fExtDispSup;
+ DISPLAY_DEVICE *paDisplayDevices;
+ DEVMODE *paDeviceModes;
+ UINT cDevModes;
+} VBOXRR, *PVBOXRR;
+
+static VBOXRR g_VBoxRr = {0};
+
+#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
+#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
-DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
+static void vboxRrRetryStopLocked()
{
- switch (pIf->enmMode)
+ PVBOXRR pMon = &g_VBoxRr;
+ if (pMon->pIf)
{
- case VBOXDISPIF_MODE_XPDM_NT4:
- return ERROR_NOT_SUPPORTED;
- case VBOXDISPIF_MODE_XPDM:
- return vboxDispIfResizeXPDM(pIf, Id, Width, Height, BitsPerPixel);
-#ifdef VBOX_WITH_WDDM
- case VBOXDISPIF_MODE_WDDM:
- return vboxDispIfResizeWDDM(pIf, Id, Width, Height, BitsPerPixel);
-#endif
- default:
- Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
- return ERROR_INVALID_PARAMETER;
+ if (pMon->paDisplayDevices)
+ {
+ free(pMon->paDisplayDevices);
+ pMon->paDisplayDevices = NULL;
+ }
+
+ if (pMon->paDeviceModes)
+ {
+ free(pMon->paDeviceModes);
+ pMon->paDeviceModes = NULL;
+ }
+
+ if (pMon->idTimer)
+ {
+ KillTimer(pMon->hWnd, pMon->idTimer);
+ pMon->idTimer = 0;
+ }
+
+ pMon->cDevModes = 0;
+ pMon->pIf = NULL;
}
}
+static void VBoxRrRetryStop()
+{
+ PVBOXRR pMon = &g_VBoxRr;
+ EnterCriticalSection(&pMon->CritSect);
+ vboxRrRetryStopLocked();
+ LeaveCriticalSection(&pMon->CritSect);
+}
-#ifdef VBOX_WITH_WDDM
-/**/
-typedef DECLCALLBACK(VOID) FNVBOXSCREENMONRUNNER_CB(void *pvCb);
-typedef FNVBOXSCREENMONRUNNER_CB *PFNVBOXSCREENMONRUNNER_CB;
+//static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
-typedef struct VBOXSCREENMON
+static void vboxRrRetryReschedule()
{
- HANDLE hThread;
- DWORD idThread;
- HANDLE hEvent;
- HWND hWnd;
- PFNVBOXSCREENMONRUNNER_CB pfnCb;
- void *pvCb;
-} VBOXSCREENMON, *PVBOXSCREENMON;
+}
+static void VBoxRrRetrySchedule(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
+{
+ PVBOXRR pMon = &g_VBoxRr;
+ EnterCriticalSection(&pMon->CritSect);
+ vboxRrRetryStopLocked();
-static VBOXSCREENMON g_VBoxScreenMon;
+ pMon->pIf = pIf;
+ pMon->iChangedMode = iChangedMode;
+ pMon->fEnable = fEnable;
+ pMon->fExtDispSup = fExtDispSup;
+ if (cDevModes)
+ {
+ pMon->paDisplayDevices = (DISPLAY_DEVICE*)malloc(sizeof (*paDisplayDevices) * cDevModes);
+ Assert(pMon->paDisplayDevices);
+ if (!pMon->paDisplayDevices)
+ {
+ Log(("malloc failed!"));
+ vboxRrRetryStopLocked();
+ LeaveCriticalSection(&pMon->CritSect);
+ return;
+ }
+ memcpy(pMon->paDisplayDevices, paDisplayDevices, sizeof (*paDisplayDevices) * cDevModes);
-#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
-#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
+ pMon->paDeviceModes = (DEVMODE*)malloc(sizeof (*paDeviceModes) * cDevModes);
+ Assert(pMon->paDeviceModes);
+ if (!pMon->paDeviceModes)
+ {
+ Log(("malloc failed!"));
+ vboxRrRetryStopLocked();
+ LeaveCriticalSection(&pMon->CritSect);
+ return;
+ }
+ memcpy(pMon->paDeviceModes, paDeviceModes, sizeof (*paDeviceModes) * cDevModes);
+ }
+ pMon->cDevModes = cDevModes;
+ pMon->idTimer = SetTimer(pMon->hWnd, VBOXRR_TIMER_ID, 1000, (TIMERPROC)NULL);
+ Assert(pMon->idTimer);
+ if (!pMon->idTimer)
+ {
+ WARN(("VBoxTray: SetTimer failed!, err %d\n", GetLastError()));
+ vboxRrRetryStopLocked();
+ }
-static void vboxScreenMonOnChange()
+ LeaveCriticalSection(&pMon->CritSect);
+}
+
+static void vboxRrRetryPerform()
{
- PVBOXSCREENMON pMon = &g_VBoxScreenMon;
- pMon->pfnCb(pMon->pvCb);
+ PVBOXRR pMon = &g_VBoxRr;
+ EnterCriticalSection(&pMon->CritSect);
+ if (pMon->pIf)
+ {
+ DWORD dwErr = vboxDispIfResizePerform(pMon->pIf, pMon->iChangedMode, pMon->fEnable, pMon->fExtDispSup, pMon->paDisplayDevices, pMon->paDeviceModes, pMon->cDevModes);
+ if (ERROR_RETRY != dwErr)
+ VBoxRrRetryStop();
+ else
+ vboxRrRetryReschedule();
+ }
+ LeaveCriticalSection(&pMon->CritSect);
}
-static LRESULT CALLBACK vboxScreenMonWndProc(HWND hwnd,
+static LRESULT CALLBACK vboxRrWndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
@@ -447,7 +909,19 @@ static LRESULT CALLBACK vboxScreenMonWndProc(HWND hwnd,
{
case WM_DISPLAYCHANGE:
{
- vboxScreenMonOnChange();
+ Log(("VBoxTray: WM_DISPLAYCHANGE\n"));
+ VBoxRrRetryStop();
+ return 0;
+ }
+ case WM_TIMER:
+ {
+ if (wParam == VBOXRR_TIMER_ID)
+ {
+ Log(("VBoxTray: VBOXRR_TIMER_ID\n"));
+ vboxRrRetryPerform();
+ return 0;
+ }
+ break;
}
case WM_CLOSE:
Log((__FUNCTION__": got WM_CLOSE for hwnd(0x%x)", hwnd));
@@ -458,23 +932,25 @@ static LRESULT CALLBACK vboxScreenMonWndProc(HWND hwnd,
case WM_NCHITTEST:
Log((__FUNCTION__": got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
return HTNOWHERE;
+ default:
+ break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
-#define VBOXSCREENMONWND_NAME "VboxScreenMonWnd"
+#define VBOXRRWND_NAME "VBoxRrWnd"
-static HRESULT vboxScreenMonWndCreate(HWND *phWnd)
+static HRESULT vboxRrWndCreate(HWND *phWnd)
{
HRESULT hr = S_OK;
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
/* Register the Window Class. */
WNDCLASS wc;
- if (!GetClassInfo(hInstance, VBOXSCREENMONWND_NAME, &wc))
+ if (!GetClassInfo(hInstance, VBOXRRWND_NAME, &wc))
{
wc.style = 0;//CS_OWNDC;
- wc.lpfnWndProc = vboxScreenMonWndProc;
+ wc.lpfnWndProc = vboxRrWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
@@ -482,11 +958,11 @@ static HRESULT vboxScreenMonWndCreate(HWND *phWnd)
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
- wc.lpszClassName = VBOXSCREENMONWND_NAME;
+ wc.lpszClassName = VBOXRRWND_NAME;
if (!RegisterClass(&wc))
{
DWORD winErr = GetLastError();
- Log((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
+ WARN((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
hr = E_FAIL;
}
}
@@ -494,7 +970,7 @@ static HRESULT vboxScreenMonWndCreate(HWND *phWnd)
if (hr == S_OK)
{
HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
- VBOXSCREENMONWND_NAME, VBOXSCREENMONWND_NAME,
+ VBOXRRWND_NAME, VBOXRRWND_NAME,
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
-100, -100,
10, 10,
@@ -510,7 +986,7 @@ static HRESULT vboxScreenMonWndCreate(HWND *phWnd)
else
{
DWORD winErr = GetLastError();
- Log((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
+ WARN((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
hr = E_FAIL;
}
}
@@ -518,42 +994,41 @@ static HRESULT vboxScreenMonWndCreate(HWND *phWnd)
return hr;
}
-static HRESULT vboxScreenMonWndDestroy(HWND hWnd)
+static HRESULT vboxRrWndDestroy(HWND hWnd)
{
BOOL bResult = DestroyWindow(hWnd);
if (bResult)
return S_OK;
DWORD winErr = GetLastError();
- Log((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
- Assert(0);
+ WARN((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
return HRESULT_FROM_WIN32(winErr);
}
-static HRESULT vboxScreenMonWndInit()
+static HRESULT vboxRrWndInit()
{
- PVBOXSCREENMON pMon = &g_VBoxScreenMon;
- return vboxScreenMonWndCreate(&pMon->hWnd);
+ PVBOXRR pMon = &g_VBoxRr;
+ return vboxRrWndCreate(&pMon->hWnd);
}
-HRESULT vboxScreenMonWndTerm()
+HRESULT vboxRrWndTerm()
{
- PVBOXSCREENMON pMon = &g_VBoxScreenMon;
- HRESULT tmpHr = vboxScreenMonWndDestroy(pMon->hWnd);
+ PVBOXRR pMon = &g_VBoxRr;
+ HRESULT tmpHr = vboxRrWndDestroy(pMon->hWnd);
Assert(tmpHr == S_OK);
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
- UnregisterClass(VBOXSCREENMONWND_NAME, hInstance);
+ UnregisterClass(VBOXRRWND_NAME, hInstance);
return S_OK;
}
-#define WM_VBOXSCREENMON_INIT_QUIT (WM_APP+2)
+#define WM_VBOXRR_INIT_QUIT (WM_APP+2)
-HRESULT vboxScreenMonRun()
+HRESULT vboxRrRun()
{
- PVBOXSCREENMON pMon = &g_VBoxScreenMon;
+ PVBOXRR pMon = &g_VBoxRr;
MSG Msg;
HRESULT hr = S_FALSE;
@@ -564,17 +1039,8 @@ HRESULT vboxScreenMonRun()
WM_USER /* UINT wMsgFilterMax */,
PM_NOREMOVE);
- BOOL bCheck = TRUE;
-
do
{
- if (bCheck)
- {
- vboxScreenMonOnChange();
-
- bCheck = FALSE;
- }
-
BOOL bResult = GetMessage(&Msg,
0 /*HWND hWnd*/,
0 /*UINT wMsgFilterMin*/,
@@ -584,6 +1050,8 @@ HRESULT vboxScreenMonRun()
if(!bResult) /* WM_QUIT was posted */
{
hr = S_FALSE;
+ Log(("VBoxTray: GetMessage returned FALSE\n"));
+ VBoxRrRetryStop();
break;
}
@@ -591,25 +1059,26 @@ HRESULT vboxScreenMonRun()
{
DWORD winEr = GetLastError();
hr = HRESULT_FROM_WIN32(winEr);
- Assert(0);
/* just ensure we never return success in this case */
Assert(hr != S_OK);
Assert(hr != S_FALSE);
if (hr == S_OK || hr == S_FALSE)
hr = E_FAIL;
+ WARN(("VBoxTray: GetMessage returned -1, err %d\n", winEr));
+ VBoxRrRetryStop();
break;
}
switch (Msg.message)
{
- case WM_VBOXSCREENMON_INIT_QUIT:
+ case WM_VBOXRR_INIT_QUIT:
case WM_CLOSE:
{
+ Log(("VBoxTray: closing Rr %d\n", Msg.message));
+ VBoxRrRetryStop();
PostQuitMessage(0);
break;
}
- case WM_DISPLAYCHANGE:
- bCheck = TRUE;
default:
TranslateMessage(&Msg);
DispatchMessage(&Msg);
@@ -619,41 +1088,39 @@ HRESULT vboxScreenMonRun()
return 0;
}
-static DWORD WINAPI vboxScreenMonRunnerThread(void *pvUser)
+static DWORD WINAPI vboxRrRunnerThread(void *pvUser)
{
- PVBOXSCREENMON pMon = &g_VBoxScreenMon;
+ PVBOXRR pMon = &g_VBoxRr;
BOOL bRc = SetEvent(pMon->hEvent);
if (!bRc)
{
DWORD winErr = GetLastError();
- Log((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
+ WARN((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
- Assert(0);
Assert(tmpHr != S_OK);
}
- HRESULT hr = vboxScreenMonWndInit();
+ HRESULT hr = vboxRrWndInit();
Assert(hr == S_OK);
if (hr == S_OK)
{
- hr = vboxScreenMonRun();
+ hr = vboxRrRun();
Assert(hr == S_OK);
- vboxScreenMonWndTerm();
+ vboxRrWndTerm();
}
return 0;
}
-HRESULT VBoxScreenMonInit(PFNVBOXSCREENMONRUNNER_CB pfnCb, void *pvCb)
+HRESULT VBoxRrInit()
{
HRESULT hr = E_FAIL;
- PVBOXSCREENMON pMon = &g_VBoxScreenMon;
+ PVBOXRR pMon = &g_VBoxRr;
memset(pMon, 0, sizeof (*pMon));
- pMon->pfnCb = pfnCb;
- pMon->pvCb = pvCb;
+ InitializeCriticalSection(&pMon->CritSect);
pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
TRUE, /* BOOL bManualReset*/
@@ -664,7 +1131,7 @@ HRESULT VBoxScreenMonInit(PFNVBOXSCREENMONRUNNER_CB pfnCb, void *pvCb)
{
pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
0 /* SIZE_T dwStackSize */,
- vboxScreenMonRunnerThread,
+ vboxRrRunnerThread,
pMon,
0 /* DWORD dwCreationFlags */,
&pMon->idThread);
@@ -682,9 +1149,8 @@ HRESULT VBoxScreenMonInit(PFNVBOXSCREENMONRUNNER_CB pfnCb, void *pvCb)
else
{
DWORD winErr = GetLastError();
- Log((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
+ WARN((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
hr = HRESULT_FROM_WIN32(winErr);
- Assert(0);
Assert(hr != S_OK);
}
CloseHandle(pMon->hEvent);
@@ -692,23 +1158,24 @@ HRESULT VBoxScreenMonInit(PFNVBOXSCREENMONRUNNER_CB pfnCb, void *pvCb)
else
{
DWORD winErr = GetLastError();
- Log((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
+ WARN((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
hr = HRESULT_FROM_WIN32(winErr);
- Assert(0);
Assert(hr != S_OK);
}
+ DeleteCriticalSection(&pMon->CritSect);
+
return hr;
}
-VOID VBoxScreenMonTerm()
+VOID VBoxRrTerm()
{
HRESULT hr;
- PVBOXSCREENMON pMon = &g_VBoxScreenMon;
+ PVBOXRR pMon = &g_VBoxRr;
if (!pMon->hThread)
return;
- BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXSCREENMON_INIT_QUIT, 0, 0);
+ BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXRR_INIT_QUIT, 0, 0);
DWORD winErr;
if (bResult
|| (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
@@ -722,432 +1189,487 @@ VOID VBoxScreenMonTerm()
{
winErr = GetLastError();
hr = HRESULT_FROM_WIN32(winErr);
- Assert(0);
}
}
else
{
hr = HRESULT_FROM_WIN32(winErr);
- Assert(0);
}
+ DeleteCriticalSection(&pMon->CritSect);
+
CloseHandle(pMon->hThread);
pMon->hThread = 0;
CloseHandle(pMon->hEvent);
pMon->hThread = 0;
}
-/**/
-typedef struct VBOXDISPIF_WDDM_INTERNAL
+static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
{
- PCVBOXDISPIF pIf;
-
- HANDLE hResizeEvent;
-} VBOXDISPIF_WDDM_INTERNAL, *PVBOXDISPIF_WDDM_INTERNAL;
+ HRESULT hr = VBoxRrInit();
+ if (SUCCEEDED(hr))
+ {
+ return ERROR_SUCCESS;
+ }
+ WARN(("VBoxTray: VBoxRrInit failed hr 0x%x\n", hr));
+ return hr;
+}
-static VBOXDISPIF_WDDM_INTERNAL g_VBoxDispIfWddm;
+static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
+{
+ VBoxRrTerm();
+}
-static BOOL vboxDispIfWddmValidateResize(DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
+static DWORD vboxDispIfQueryDisplayConnection(VBOXDISPIF_OP *pOp, UINT32 iDisplay, BOOL *pfConnected)
{
- DISPLAY_DEVICE DisplayDevice;
- int i = 0;
- UINT cMatched = 0;
- DEVMODE DeviceMode;
- for (int i = 0; ; ++i)
+ if (pOp->pIf->enmMode == VBOXDISPIF_MODE_WDDM)
{
- ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
- DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
+ /* @todo: do we need ti impl it? */
+ *pfConnected = TRUE;
+ return ERROR_SUCCESS;
+ }
- if (!EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
- break;
+ *pfConnected = FALSE;
- Log(("VBoxTray: vboxDispIfValidateResize: [%d(%d)] %s\n", i, cMatched, DisplayDevice.DeviceName));
+ VBOXDISPIF_WDDM_DISPCFG DispCfg;
+ DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
+ return winEr;
+ }
- BOOL bFetchDevice = FALSE;
+ int idx = vboxDispIfWddmDcSearchPath(&DispCfg, iDisplay, iDisplay);
+ *pfConnected = (idx >= 0);
- if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
- {
- Log(("VBoxTray: vboxDispIfValidateResize: Found primary device. err %d\n", GetLastError ()));
- bFetchDevice = TRUE;
- }
- else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
- {
+ vboxDispIfWddmDcTerm(&DispCfg);
- Log(("VBoxTray: vboxDispIfValidateResize: Found secondary device. err %d\n", GetLastError ()));
- bFetchDevice = TRUE;
- }
+ return ERROR_SUCCESS;
+}
- if (bFetchDevice)
+static DWORD vboxDispIfWaitDisplayDataInited(VBOXDISPIF_OP *pOp, const uint8_t *pu8DisplayMask)
+{
+ DWORD winEr = ERROR_SUCCESS;
+ do
+ {
+ Sleep(100);
+
+ D3DKMT_POLLDISPLAYCHILDREN PollData = {0};
+ PollData.hAdapter = pOp->Adapter.hAdapter;
+ PollData.NonDestructiveOnly = 1;
+ NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTPollDisplayChildren(&PollData);
+ if (Status != 0)
{
- if (cMatched >= cDevModes)
- {
- Log(("VBoxTray: vboxDispIfValidateResize: %d >= %d\n", cDevModes, cMatched));
- return FALSE;
- }
+ Log(("VBoxTray: (WDDM) pfnD3DKMTPollDisplayChildren failed, Status (0x%x)\n", Status));
+ continue;
+ }
- /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
- * A secondary display could be not active at the moment and would not have
- * a current video mode (ENUM_CURRENT_SETTINGS).
- */
- ZeroMemory(&DeviceMode, sizeof(DeviceMode));
- DeviceMode.dmSize = sizeof(DEVMODE);
- if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
- ENUM_REGISTRY_SETTINGS, &DeviceMode))
- {
- Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings error %d\n", GetLastError ()));
- return FALSE;
- }
+ BOOL fFound = FALSE;
+#if 0
+ for (UINT i = 0; i < VBOXWDDM_SCREENMASK_SIZE; ++i)
+ {
+ if (pu8DisplayMask && !ASMBitTest(pu8DisplayMask, i))
+ continue;
- if ( DeviceMode.dmPelsWidth == 0
- || DeviceMode.dmPelsHeight == 0)
+ BOOL fConnected = FALSE;
+ winEr = vboxDispIfQueryDisplayConnection(pOp, i, &fConnected);
+ if (winEr != ERROR_SUCCESS)
{
- /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
- * Get the current video mode then.
- */
- ZeroMemory(&DeviceMode, sizeof(DeviceMode));
- DeviceMode.dmSize = sizeof(DeviceMode);
- if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
- ENUM_CURRENT_SETTINGS, &DeviceMode))
- {
- /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
- * for example a disabled secondary display */
- Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
- return FALSE;
- }
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfQueryDisplayConnection winEr %d\n", winEr));
+ return winEr;
}
- UINT j = 0;
- for (; j < cDevModes; ++j)
+ if (!fConnected)
{
- if (!strncmp(DisplayDevice.DeviceName, paDisplayDevices[j].DeviceName, RT_ELEMENTS(DeviceMode.dmDeviceName)))
- {
- if (paDeviceModes[j].dmBitsPerPel != DeviceMode.dmBitsPerPel
- || (paDeviceModes[j].dmPelsWidth & 0xfff8) != (DeviceMode.dmPelsWidth & 0xfff8)
- || (paDeviceModes[j].dmPelsHeight & 0xfff8) != (DeviceMode.dmPelsHeight & 0xfff8)
- || (paDeviceModes[j].dmPosition.x & 0xfff8) != (DeviceMode.dmPosition.x & 0xfff8)
- || (paDeviceModes[j].dmPosition.y & 0xfff8) != (DeviceMode.dmPosition.y & 0xfff8)
- || (paDisplayDevices[j].StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
- {
- return FALSE;
- }
- break;
- }
+ WARN(("VBoxTray: (WDDM) Display %d not connected, not expected\n", i));
+ fFound = TRUE;
+ break;
}
-
- if (j == cDevModes)
- return FALSE;
-
- ++cMatched;
}
- }
+#endif
+ if (!fFound)
+ break;
+ } while (1);
- return cMatched == cDevModes;
+ return winEr;
}
-static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
+static DWORD vboxDispIfReninitModesWDDM(VBOXDISPIF_OP *pOp, const uint8_t *pScreenIdMask)
{
- if (vboxDispIfWddmValidateResize(paDisplayDevices, paDeviceModes, cDevModes))
- return NO_ERROR;
+ DWORD winEr = ERROR_SUCCESS;
+ VBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK EscData = {0};
+ EscData.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
+ memcpy(EscData.ScreenMask, pScreenIdMask, sizeof (EscData.ScreenMask));
- DWORD winEr;
- LONG status = DISP_CHANGE_SUCCESSFUL;
-
- /* now try to resize in a "regular" way */
- /* Assign the new rectangles to displays. */
- for (UINT i = 0; i < cDevModes; i++)
- {
- /* On Vista one must specify DM_BITSPERPEL.
- * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
- */
- paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
-
- Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
- pIf->modeData.wddm.pfnChangeDisplaySettingsEx,
- paDeviceModes[i].dmPelsWidth,
- paDeviceModes[i].dmPelsHeight,
- paDeviceModes[i].dmBitsPerPel,
- paDeviceModes[i].dmPosition.x,
- paDeviceModes[i].dmPosition.y));
-
- /* the miniport might have been adjusted the display mode stuff,
- * adjust the paDeviceModes[i] by picking the closest available one */
-// DEVMODE AdjustedMode = paDeviceModes[i];
-// vboxDispIfAdjustMode(&paDisplayDevices[i], &AdjustedMode);
-
- LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
- &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
- Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", tmpStatus, GetLastError ()));
-
- if (tmpStatus != DISP_CHANGE_SUCCESSFUL)
- {
- status = tmpStatus;
- }
- }
+ D3DKMT_ESCAPE EscapeData = {0};
+ EscapeData.hAdapter = pOp->Adapter.hAdapter;
+#ifdef VBOX_DISPIF_WITH_OPCONTEXT
+ /* win8.1 does not allow context-based escapes for display-only mode */
+ EscapeData.hDevice = pOp->Device.hDevice;
+ EscapeData.hContext = pOp->Context.hContext;
+#endif
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ EscapeData.Flags.HardwareAccess = 1;
+ EscapeData.pPrivateDriverData = &EscData;
+ EscapeData.PrivateDriverDataSize = sizeof (EscData);
- /* A second call to ChangeDisplaySettings updates the monitor. */
- LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
- Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
- if (tmpStatus == DISP_CHANGE_SUCCESSFUL)
+ NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
+ if (NT_SUCCESS(Status))
+ winEr = ERROR_SUCCESS;
+ else
{
- if (status == DISP_CHANGE_SUCCESSFUL)
- {
- return NO_ERROR;
- }
- tmpStatus = status;
+ WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_REINITVIDEOMODESBYMASK failed Status 0x%x\n", Status));
+ winEr = ERROR_GEN_FAILURE;
}
- winEr = ERROR_GEN_FAILURE;
+ winEr = vboxDispIfWaitDisplayDataInited(pOp, pScreenIdMask);
+ if (winEr != NO_ERROR)
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWaitDisplayDataInited winEr %d\n", winEr));
+
return winEr;
}
-static DECLCALLBACK(VOID) vboxDispIfWddmScreenMonCb(void *pvCb)
+DWORD vboxDispIfCancelPendingResizeWDDM(PCVBOXDISPIF const pIf)
{
- PVBOXDISPIF_WDDM_INTERNAL pData = (PVBOXDISPIF_WDDM_INTERNAL)pvCb;
-
- SetEvent(pData->hResizeEvent);
+ Log(("VBoxTray: cancelling pending resize\n"));
+ VBoxRrRetryStop();
+ return NO_ERROR;
}
-static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
+static DWORD vboxDispIfWddmResizeDisplayVista(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD cDevModes, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup)
{
- memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
- g_VBoxDispIfWddm.pIf = pIf;
- g_VBoxDispIfWddm.hResizeEvent = CreateEvent(NULL,
- FALSE, /* BOOL bManualReset */
- FALSE, /* BOOL bInitialState */
- NULL /* LPCTSTR lpName */
- );
- if (g_VBoxDispIfWddm.hResizeEvent)
+ /* Without this, Windows will not ask the miniport for its
+ * mode table but uses an internal cache instead.
+ */
+ for (DWORD i = 0; i < cDevModes; i++)
{
- HRESULT hr = VBoxScreenMonInit(vboxDispIfWddmScreenMonCb, &g_VBoxDispIfWddm);
- if (SUCCEEDED(hr))
- {
- /* ensure event is reset */
- WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 0);
- return ERROR_SUCCESS;
- }
- CloseHandle(g_VBoxDispIfWddm.hResizeEvent);
+ DEVMODE tempDevMode;
+ ZeroMemory (&tempDevMode, sizeof (tempDevMode));
+ tempDevMode.dmSize = sizeof(DEVMODE);
+ EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
+ Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
}
- return ERROR_GEN_FAILURE;
+
+ DWORD winEr = EnableAndResizeDispDev(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, paDeviceModes[iChangedMode].dmPelsWidth, paDeviceModes[iChangedMode].dmPelsHeight,
+ paDeviceModes[iChangedMode].dmBitsPerPel, paDeviceModes[iChangedMode].dmPosition.x, paDeviceModes[iChangedMode].dmPosition.y, fEnable, fExtDispSup);
+ if (winEr != NO_ERROR)
+ WARN(("VBoxTray: (WDDM) Failed EnableAndResizeDispDev winEr %d\n", winEr));
+
+ return winEr;
}
-static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
+static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
{
- VBoxScreenMonTerm();
- CloseHandle(g_VBoxDispIfWddm.hResizeEvent);
- memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
+ DWORD winEr;
+ if (pIf->enmMode > VBOXDISPIF_MODE_WDDM)
+ {
+ winEr = vboxDispIfWddmResizeDisplay(pIf, iChangedMode, fEnable, paDisplayDevices, paDeviceModes, cDevModes);
+ if (winEr != NO_ERROR)
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplay winEr %d\n", winEr));
+ }
+ else
+ {
+ winEr = vboxDispIfWddmResizeDisplayVista(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, fEnable, fExtDispSup);
+ if (winEr != NO_ERROR)
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplayVista winEr %d\n", winEr));
+ }
+ return winEr;
}
-static DWORD vboxDispIfReninitModesWDDM(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
+DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
{
- VBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK Data = {0};
- Data.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
- if (fReconnectDisplaysOnChange)
- Data.EscapeHdr.u32CmdSpecific = VBOXWDDM_REINITVIDEOMODESBYMASK_F_RECONNECT_DISPLAYS_ON_CHANGE;
+ UINT cbVidPnInfo = VBOXWDDM_RECOMMENDVIDPN_SIZE(cDevModes);
+ PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = (PVBOXWDDM_RECOMMENDVIDPN)alloca(cbVidPnInfo);
+ pVidPnInfo->cScreenInfos = cDevModes;
+ D3DKMT_HANDLE hAdapter = NULL;
+ DWORD winEr = NO_ERROR;
+ UINT i = 0;
- memcpy(Data.ScreenMask, pScreenIdMask, sizeof (Data.ScreenMask));
+ Log(("VBoxTray: vboxDispIfResizeModesWDDM\n"));
+ VBoxRrRetryStop();
- DWORD err = vboxDispIfEscapeWDDM(pIf, &Data.EscapeHdr, sizeof (Data) - sizeof (Data.EscapeHdr), fReconnectDisplaysOnChange ? FALSE /* hw access must be false here,
- * otherwise the miniport driver would fail
- * request to prevent a deadlock */
- : TRUE);
- if (err != NO_ERROR)
+ VBOXDISPIF_OP Op;
+
+ winEr = vboxDispIfOpBegin(pIf, &Op);
+ if (winEr != NO_ERROR)
{
- Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
+ WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x", winEr));
+ return winEr;
}
- return err;
+
+
+// if (fEnable)
+ {
+
+ uint8_t ScreenMask[VBOXWDDM_SCREENMASK_SIZE] = {0};
+ ASMBitSet(ScreenMask, iChangedMode);
+ vboxDispIfReninitModesWDDM(&Op, ScreenMask);
+ }
+
+ winEr = vboxDispIfResizePerform(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
+
+ if (winEr == ERROR_RETRY)
+ {
+ VBoxRrRetrySchedule(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
+ /* just pretend everything is fine so far */
+ winEr = NO_ERROR;
+ }
+
+ vboxDispIfOpEnd(&Op);
+
+ return winEr;
}
-static DWORD vboxDispIfAdjustMode(DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
+static DWORD vboxDispIfWddmEnableDisplays(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnabled, BOOL fSetTopology, DEVMODE *pDeviceMode)
{
- DEVMODE CurMode;
- DEVMODE BestMatchMode;
- DWORD i = 0;
- int64_t diffWH = INT64_MAX;
- int diffBpp = INT32_MAX;
- for (; ; ++i)
+ VBOXDISPIF_WDDM_DISPCFG DispCfg;
+
+ DWORD winEr;
+ int iPath;
+
+ winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
+ if (winEr != ERROR_SUCCESS)
{
- CurMode.dmSize = sizeof (CurMode);
- CurMode.dmDriverExtra = 0;
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
+ return winEr;
+ }
- if (!EnumDisplaySettings(pDisplayDevice->DeviceName, i, &CurMode))
- break;
+ UINT cChangeIds = 0;
+ UINT *pChangeIds = (UINT*)alloca(cIds * sizeof (*pChangeIds));
+ if (!pChangeIds)
+ {
+ WARN(("VBoxTray: (WDDM) Failed to alloc change ids\n"));
+ winEr = ERROR_OUTOFMEMORY;
+ goto done;
+ }
- if (CurMode.dmPelsWidth == pDeviceMode->dmPelsWidth
- && CurMode.dmPelsHeight == pDeviceMode->dmPelsHeight
- && CurMode.dmBitsPerPel == pDeviceMode->dmBitsPerPel)
+ for (UINT i = 0; i < cIds; ++i)
+ {
+ UINT Id = pIds[i];
+ bool fIsDup = false;
+ for (UINT j = 0; j < cChangeIds; ++j)
{
- Log(("Exact match found"));
- *pDeviceMode = CurMode;
- return NO_ERROR;
+ if (pChangeIds[j] == Id)
+ {
+ fIsDup = true;
+ break;
+ }
}
- int diffCurrW = RT_ABS((int)(CurMode.dmPelsWidth - pDeviceMode->dmPelsWidth));
- int diffCurrH = RT_ABS((int)(CurMode.dmPelsHeight - pDeviceMode->dmPelsHeight));
- int diffCurrBpp = RT_ABS((int)(CurMode.dmBitsPerPel - pDeviceMode->dmBitsPerPel)
- - 1 /* <- to make higher bpp take precedence over lower ones */
- );
+ if (fIsDup)
+ continue;
- int64_t diffCurrHW = (int64_t)diffCurrW*diffCurrW + (int64_t)diffCurrH*diffCurrH;
+ iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
- if (i == 0
- || diffCurrHW < diffWH
- || (diffCurrHW == diffWH && diffCurrBpp < diffBpp))
+ if (!((iPath >= 0) && (DispCfg.pPathInfoArray[iPath].flags & DISPLAYCONFIG_PATH_ACTIVE)) != !fEnabled)
{
- /* first run */
- BestMatchMode = CurMode;
- diffWH = diffCurrHW;
- diffBpp = diffCurrBpp;
- continue;
+ pChangeIds[cChangeIds] = Id;
+ ++cChangeIds;
}
}
- if (i == 0)
+ if (cChangeIds == 0)
{
- Log(("No modes found!"));
- return NO_ERROR;
+ Log(("VBoxTray: (WDDM) vboxDispIfWddmEnableDisplay: settings are up to date\n"));
+ winEr = ERROR_SUCCESS;
+ goto done;
}
- *pDeviceMode = BestMatchMode;
- return NO_ERROR;
-}
-
-static DWORD vboxDispIfAdjustModeValues(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
-{
- VBOXDISPIFESCAPE_ADJUSTVIDEOMODES Data = {0};
- Data.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
- Data.EscapeHdr.u32CmdSpecific = 1;
- Data.aScreenInfos[0].Mode.Id =
- Data.aScreenInfos[0].Mode.Width = pDeviceMode->dmPelsWidth;
- Data.aScreenInfos[0].Mode.Height = pDeviceMode->dmPelsHeight;
- Data.aScreenInfos[0].Mode.BitsPerPixel = pDeviceMode->dmBitsPerPel;
- DWORD err = vboxDispIfEscapeWDDM(pIf, &Data.EscapeHdr, sizeof (Data) - sizeof (Data.EscapeHdr), TRUE);
- if (err != NO_ERROR)
+ /* we want to set primary for every disabled for non-topoly mode only */
+ winEr = vboxDispIfWddmDcSettingsIncludeAllTargets(&DispCfg);
+ if (winEr != ERROR_SUCCESS)
{
- Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsIncludeAllTargets winEr %d\n", winEr));
+ return winEr;
}
- return err;
-}
-DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
-{
- UINT cbVidPnInfo = VBOXWDDM_RECOMMENDVIDPN_SIZE(cDevModes);
- PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = (PVBOXWDDM_RECOMMENDVIDPN)alloca(cbVidPnInfo);
- pVidPnInfo->cScreenInfos = cDevModes;
- D3DKMT_HANDLE hAdapter = NULL;
- NTSTATUS Status;
- DWORD winEr = NO_ERROR;
- UINT i = 0;
+ if (fSetTopology)
+ vboxDispIfWddmDcSettingsInvalidateModeIndeces(&DispCfg);
- for (; i < cDevModes; i++)
+ for (UINT i = 0; i < cChangeIds; ++i)
{
- PVBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO pInfo = &pVidPnInfo->aScreenInfos[i];
- D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
- OpenAdapterData.hDc = CreateDC(NULL, paDisplayDevices[i].DeviceName, NULL, NULL);
- if (!OpenAdapterData.hDc)
+ UINT Id = pChangeIds[i];
+ /* re-query paths */
+ iPath = vboxDispIfWddmDcSearchPath(&DispCfg, -1, Id);
+ if (iPath < 0)
{
- winEr = GetLastError();
- Assert(0);
- break;
+ WARN(("VBoxTray: (WDDM) path index not found while it should"));
+ winEr = ERROR_GEN_FAILURE;
+ goto done;
}
- Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
- Assert(!Status);
- if (Status)
+ winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, pDeviceMode, !fEnabled || fSetTopology, fEnabled);
+ if (winEr != ERROR_SUCCESS)
{
- winEr = ERROR_GEN_FAILURE;
- Assert(0);
- break;
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
+ goto done;
}
+ }
+
+ if (!fSetTopology)
+ vboxDispIfWddmDcSettingsAttachDisbledToPrimary(&DispCfg);
- pInfo->Id = OpenAdapterData.VidPnSourceId;
- pInfo->Width = paDeviceModes[i].dmPelsWidth;
- pInfo->Height = paDeviceModes[i].dmPelsHeight;
- pInfo->BitsPerPixel = paDeviceModes[i].dmBitsPerPel;
+#if 0
+ /* ensure the zero-index (primary) screen is enabled */
+ iPath = vboxDispIfWddmDcSearchPath(&DispCfg, 0, 0);
+ if (iPath < 0)
+ {
+ WARN(("VBoxTray: (WDDM) path index not found while it should"));
+ winEr = ERROR_GEN_FAILURE;
+ goto done;
+ }
- if (!hAdapter)
+ winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, /* just re-use device node here*/ pDeviceMode, fSetTopology, TRUE);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
+ goto done;
+ }
+#endif
+
+ UINT fSetFlags = !fSetTopology ? (SDC_USE_SUPPLIED_DISPLAY_CONFIG) : (SDC_ALLOW_PATH_ORDER_CHANGES | SDC_TOPOLOGY_SUPPLIED);
+ winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
+ if (winEr != ERROR_SUCCESS)
+ {
+ if (!fSetTopology)
{
- hAdapter = OpenAdapterData.hAdapter;
+ WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet validation failed winEr, trying with changes %d\n", winEr));
+ fSetFlags |= SDC_ALLOW_CHANGES;
}
else
{
- D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
- ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
- Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
- Assert(!Status);
+ Log(("VBoxTray: (WDDM) vboxDispIfWddmDcSet topology validation failed winEr %d\n", winEr));
+ goto done;
}
}
- BOOL fAbleToInvalidateVidPn = FALSE;
+ if (!fSetTopology)
+ fSetFlags |= SDC_SAVE_TO_DATABASE;
- if (winEr == NO_ERROR)
+ winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_APPLY);
+ if (winEr != ERROR_SUCCESS)
+ WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet apply failed winEr %d\n", winEr));
+
+done:
+ vboxDispIfWddmDcTerm(&DispCfg);
+
+ return winEr;
+}
+
+static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable)
+{
+ DWORD winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, FALSE, NULL);
+ if (winEr != ERROR_SUCCESS)
{
- Assert(hAdapter);
+ if (fEnable)
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
+ else
+ Log(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
+ winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, TRUE, NULL);
+ if (winEr != ERROR_SUCCESS)
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
+ }
+
+ return winEr;
+}
- D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
- IAVidPnData.hAdapter = hAdapter;
- IAVidPnData.pPrivateDriverData = pVidPnInfo;
- IAVidPnData.PrivateDriverDataSize = cbVidPnInfo;
+static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes)
+{
+ VBOXDISPIF_WDDM_DISPCFG DispCfg;
+ DWORD winEr;
+ int iPath;
- DWORD winEr = NO_ERROR;
- Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
- Assert(!Status);
- if (Status)
+ winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate\n"));
+ return winEr;
+ }
+
+ iPath = vboxDispIfWddmDcSearchActivePath(&DispCfg, Id, Id);
+
+ if (iPath < 0)
+ {
+ vboxDispIfWddmDcTerm(&DispCfg);
+
+ if (!fEnable)
{
- Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", Status));
- winEr = ERROR_GEN_FAILURE;
+ /* nothing to be done here, just leave */
+ return ERROR_SUCCESS;
}
- else
+
+ winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
+ return winEr;
+ }
+
+ winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
+ return winEr;
+ }
+
+ iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
+ if (iPath < 0)
{
- fAbleToInvalidateVidPn = TRUE;
+ WARN(("VBoxTray: (WDDM) path (%d) is still disabled, going to retry winEr %d\n", winEr));
+ vboxDispIfWddmDcTerm(&DispCfg);
+ return ERROR_RETRY;
}
}
- if (hAdapter)
+ Assert(iPath >= 0);
+
+ if (!fEnable)
{
- D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
- ClosaAdapterData.hAdapter = hAdapter;
- Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
- Assert(!Status);
+ /* need to disable it, and we are done */
+ vboxDispIfWddmDcTerm(&DispCfg);
+
+ winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
+ return winEr;
+ }
+
+ return winEr;
}
-// for (i = 0; i < cDevModes; i++)
-// {
-// vboxDispIfAdjustMode(&paDisplayDevices[i], &paDeviceModes[i]);
-// }
+ Assert(fEnable);
- if (fAbleToInvalidateVidPn)
+ winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, &paDeviceMode[Id], FALSE, fEnable);
+ if (winEr != ERROR_SUCCESS)
{
- winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
+ WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate\n"));
+ vboxDispIfWddmDcTerm(&DispCfg);
+ return winEr;
}
- else
- {
- /* fallback impl needed for display-only driver
- * since D3DKMTInvalidateActiveVidPn is not available for WDDM > 1.0:
- * make the driver invalidate VidPn,
- * which is done by emulating a monitor re-plug currently */
- /* ensure event is reset */
- WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 0);
- uint8_t ScreenMask[VBOXWDDM_SCREENMASK_SIZE] = {0};
- ASMBitSet(ScreenMask, iChangedMode);
- vboxDispIfReninitModesWDDM(pIf, ScreenMask, TRUE);
-
- for (UINT i = 0; i < 4; ++i)
- {
- WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 500);
- winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
- if (winEr == NO_ERROR)
- break;
- }
+ UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
+ winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
+ fSetFlags |= SDC_ALLOW_CHANGES;
+ }
- Assert(winEr == NO_ERROR);
+ winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
+ if (winEr != ERROR_SUCCESS)
+ {
+ WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
}
+ vboxDispIfWddmDcTerm(&DispCfg);
+
return winEr;
}
+
#endif /* VBOX_WITH_WDDM */
-DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
+DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
{
switch (pIf->enmMode)
{
@@ -1157,28 +1679,208 @@ DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_D
return ERROR_NOT_SUPPORTED;
#ifdef VBOX_WITH_WDDM
case VBOXDISPIF_MODE_WDDM:
- return vboxDispIfResizeModesWDDM(pIf, iChangedMode, paDisplayDevices, paDeviceModes, cDevModes);
+ case VBOXDISPIF_MODE_WDDM_W7:
+ return vboxDispIfResizeModesWDDM(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
#endif
default:
- Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
+ WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
return ERROR_INVALID_PARAMETER;
}
}
-DWORD VBoxDispIfReninitModes(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
+DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf)
{
switch (pIf->enmMode)
{
case VBOXDISPIF_MODE_XPDM_NT4:
- return ERROR_NOT_SUPPORTED;
+ return NO_ERROR;
case VBOXDISPIF_MODE_XPDM:
- return ERROR_NOT_SUPPORTED;
+ return NO_ERROR;
#ifdef VBOX_WITH_WDDM
case VBOXDISPIF_MODE_WDDM:
- return vboxDispIfReninitModesWDDM(pIf, pScreenIdMask, fReconnectDisplaysOnChange);
+ case VBOXDISPIF_MODE_WDDM_W7:
+ return vboxDispIfCancelPendingResizeWDDM(pIf);
#endif
default:
- Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
+ WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
+ return ERROR_INVALID_PARAMETER;
+ }
+}
+
+static DWORD vboxDispIfConfigureTargetsWDDM(VBOXDISPIF_OP *pOp, uint32_t *pcConnected)
+{
+ VBOXDISPIFESCAPE EscapeHdr = {0};
+ EscapeHdr.escapeCode = VBOXESC_CONFIGURETARGETS;
+ EscapeHdr.u32CmdSpecific = 0;
+
+ D3DKMT_ESCAPE EscapeData = {0};
+ EscapeData.hAdapter = pOp->Adapter.hAdapter;
+#ifdef VBOX_DISPIF_WITH_OPCONTEXT
+ /* win8.1 does not allow context-based escapes for display-only mode */
+ EscapeData.hDevice = pOp->Device.hDevice;
+ EscapeData.hContext = pOp->Context.hContext;
+#endif
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ EscapeData.Flags.HardwareAccess = 1;
+ EscapeData.pPrivateDriverData = &EscapeHdr;
+ EscapeData.PrivateDriverDataSize = sizeof (EscapeHdr);
+
+ NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
+ if (NT_SUCCESS(Status))
+ {
+ if (pcConnected)
+ *pcConnected = EscapeHdr.u32CmdSpecific;
+ return NO_ERROR;
+ }
+ WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_CONFIGURETARGETS failed Status 0x%x\n", Status));
+ return Status;
+}
+
+static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp)
+{
+ DWORD NumDevices = VBoxGetDisplayConfigCount();
+ if (NumDevices == 0)
+ {
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
+ return ERROR_GEN_FAILURE;
+ }
+
+ DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
+ DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
+ DWORD DevNum = 0;
+ DWORD DevPrimaryNum = 0;
+
+ DWORD winEr = VBoxGetDisplayConfig(NumDevices, &DevPrimaryNum, &DevNum, paDisplayDevices, paDeviceModes);
+ if (winEr != NO_ERROR)
+ {
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed, %d\n", winEr));
+ return winEr;
+ }
+
+ if (NumDevices != DevNum)
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != DevNum(%d)\n", NumDevices, DevNum));
+
+
+ uint32_t cConnected = 0;
+ winEr = vboxDispIfConfigureTargetsWDDM(pOp, &cConnected);
+ if (winEr != NO_ERROR)
+ {
+ WARN(("VBoxTray: vboxDispIfConfigureTargetsWDDM failed winEr 0x%x\n", winEr));
+ return winEr;
+ }
+
+ if (!cConnected)
+ {
+ Log(("VBoxTray: all targets already connected, nothing to do\n"));
+ return NO_ERROR;
+ }
+
+ winEr = vboxDispIfWaitDisplayDataInited(pOp, NULL);
+ if (winEr != NO_ERROR)
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWaitDisplayDataInited failed winEr 0x%x\n", winEr));
+
+ DWORD NewNumDevices = VBoxGetDisplayConfigCount();
+ if (NewNumDevices == 0)
+ {
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
+ return ERROR_GEN_FAILURE;
+ }
+
+ if (NewNumDevices != NumDevices)
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != NewNumDevices(%d)\n", NumDevices, NewNumDevices));
+
+ DISPLAY_DEVICE *paNewDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NewNumDevices);
+ DEVMODE *paNewDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NewNumDevices);
+ DWORD NewDevNum = 0;
+ DWORD NewDevPrimaryNum = 0;
+
+ winEr = VBoxGetDisplayConfig(NewNumDevices, &NewDevPrimaryNum, &NewDevNum, paNewDisplayDevices, paNewDeviceModes);
+ if (winEr != NO_ERROR)
+ {
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed for new devices, %d\n", winEr));
+ return winEr;
+ }
+
+ if (NewNumDevices != NewDevNum)
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NewNumDevices(%d) != NewDevNum(%d)\n", NewNumDevices, NewDevNum));
+
+ DWORD minDevNum = RT_MIN(DevNum, NewDevNum);
+ UINT *pIds = (UINT*)alloca (sizeof (UINT) * minDevNum);
+ UINT cIds = 0;
+ for (DWORD i = 0; i < minDevNum; ++i)
+ {
+ if ((paNewDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE)
+ && !(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
+ {
+ pIds[cIds] = i;
+ ++cIds;
+ }
+ }
+
+ if (!cIds)
+ {
+ /* this is something we would not regularly expect */
+ WARN(("VBoxTray: all targets already have proper config, nothing to do\n"));
+ return NO_ERROR;
+ }
+
+ if (pOp->pIf->enmMode > VBOXDISPIF_MODE_WDDM)
+ {
+ winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pOp->pIf, cIds, pIds, FALSE);
+ if (winEr != NO_ERROR)
+ WARN(("VBoxTray: vboxDispIfWddmEnableDisplaysTryingTopology failed to record current settings, %d, ignoring\n", winEr));
+ }
+ else
+ {
+ for (DWORD i = 0; i < cIds; ++i)
+ {
+ winEr = vboxDispIfWddmResizeDisplayVista(paNewDeviceModes, paNewDisplayDevices, NewDevNum, i, FALSE, TRUE);
+ if (winEr != NO_ERROR)
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWddmResizeDisplayVista failed winEr 0x%x\n", winEr));
+ }
+ }
+
+ return winEr;
+}
+
+
+static DWORD vboxDispIfResizeStartedWDDM(PCVBOXDISPIF const pIf)
+{
+ VBOXDISPIF_OP Op;
+
+ DWORD winEr = vboxDispIfOpBegin(pIf, &Op);
+ if (winEr != NO_ERROR)
+ {
+ WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x\n", winEr));
+ return winEr;
+ }
+
+ winEr = vboxDispIfResizeStartedWDDMOp(&Op);
+ if (winEr != NO_ERROR)
+ {
+ WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp failed winEr 0x%x\n", winEr));
+ }
+
+ vboxDispIfOpEnd(&Op);
+
+ return winEr;
+}
+
+DWORD VBoxDispIfResizeStarted(PCVBOXDISPIF const pIf)
+{
+ switch (pIf->enmMode)
+ {
+ case VBOXDISPIF_MODE_XPDM_NT4:
+ return NO_ERROR;
+ case VBOXDISPIF_MODE_XPDM:
+ return NO_ERROR;
+#ifdef VBOX_WITH_WDDM
+ case VBOXDISPIF_MODE_WDDM:
+ case VBOXDISPIF_MODE_WDDM_W7:
+ return vboxDispIfResizeStartedWDDM(pIf);
+#endif
+ default:
+ WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
return ERROR_INVALID_PARAMETER;
}
}
@@ -1197,7 +1899,7 @@ static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
GetVersionEx (&OSinfo);
if (OSinfo.dwMajorVersion >= 5)
{
- HMODULE hUser = GetModuleHandle("USER32");
+ HMODULE hUser = GetModuleHandle("user32.dll");
if (NULL != hUser)
{
bool bSupported = true;
@@ -1207,19 +1909,19 @@ static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
if (!bSupported)
{
- Log((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
+ WARN((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
err = ERROR_NOT_SUPPORTED;
}
}
else
{
- Log((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
+ WARN((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
err = ERROR_NOT_SUPPORTED;
}
}
else
{
- Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
+ WARN((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
err = ERROR_NOT_SUPPORTED;
}
@@ -1237,9 +1939,11 @@ DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_
return NO_ERROR;
#ifdef VBOX_WITH_WDDM
- if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
+ if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
{
vboxDispIfWddmTerm(pIf);
+
+ vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
}
#endif
@@ -1255,7 +1959,7 @@ DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_
pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
}
else
- Log((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
+ WARN((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
break;
case VBOXDISPIF_MODE_XPDM:
Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
@@ -1266,7 +1970,7 @@ DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_
pIf->enmMode = VBOXDISPIF_MODE_XPDM;
}
else
- Log((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
+ WARN((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
break;
#ifdef VBOX_WITH_WDDM
case VBOXDISPIF_MODE_WDDM:
@@ -1279,7 +1983,20 @@ DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_
pIf->enmMode = VBOXDISPIF_MODE_WDDM;
}
else
- Log((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
+ WARN((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
+ break;
+ }
+ case VBOXDISPIF_MODE_WDDM_W7:
+ {
+ Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM_W7\n"));
+ err = vboxDispIfSwitchToWDDM_W7(pIf);
+ if (err == NO_ERROR)
+ {
+ Log((__FUNCTION__": successfully switched to WDDM mode\n"));
+ pIf->enmMode = VBOXDISPIF_MODE_WDDM_W7;
+ }
+ else
+ WARN((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
break;
}
#endif
@@ -1289,3 +2006,140 @@ DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_
}
return err;
}
+
+static DWORD vboxDispIfSeamlesCreateWDDM(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
+{
+ HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pSeamless->modeData.wddm.Adapter);
+ if (SUCCEEDED(hr))
+ {
+#ifdef VBOX_DISPIF_WITH_OPCONTEXT
+ hr = vboxDispKmtCreateDevice(&pSeamless->modeData.wddm.Adapter, &pSeamless->modeData.wddm.Device);
+ if (SUCCEEDED(hr))
+ {
+ hr = vboxDispKmtCreateContext(&pSeamless->modeData.wddm.Device, &pSeamless->modeData.wddm.Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS,
+ 0, 0, hEvent, 0ULL);
+ if (SUCCEEDED(hr))
+#endif
+ return ERROR_SUCCESS;
+#ifdef VBOX_DISPIF_WITH_OPCONTEXT
+ else
+ WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
+
+ vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
+ }
+ else
+ WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
+
+ vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
+#endif
+ }
+
+ return hr;
+}
+
+static DWORD vboxDispIfSeamlesTermWDDM(VBOXDISPIF_SEAMLESS *pSeamless)
+{
+#ifdef VBOX_DISPIF_WITH_OPCONTEXT
+ vboxDispKmtDestroyContext(&pSeamless->modeData.wddm.Context);
+ vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
+#endif
+ vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
+
+ return NO_ERROR;
+}
+
+static DWORD vboxDispIfSeamlesSubmitWDDM(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
+{
+ D3DKMT_ESCAPE EscapeData = {0};
+ EscapeData.hAdapter = pSeamless->modeData.wddm.Adapter.hAdapter;
+#ifdef VBOX_DISPIF_WITH_OPCONTEXT
+ EscapeData.hDevice = pSeamless->modeData.wddm.Device.hDevice;
+ EscapeData.hContext = pSeamless->modeData.wddm.Context.hContext;
+#endif
+ EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
+ /*EscapeData.Flags.HardwareAccess = 1;*/
+ EscapeData.pPrivateDriverData = pData;
+ EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
+
+ NTSTATUS Status = pSeamless->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
+ if (NT_SUCCESS(Status))
+ return ERROR_SUCCESS;
+
+ WARN(("VBoxTray: pfnD3DKMTEscape Seamless failed Status 0x%x\n", Status));
+ return Status;
+}
+
+DWORD VBoxDispIfSeamlesCreate(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
+{
+ memset(pSeamless, 0, sizeof (*pSeamless));
+ pSeamless->pIf = pIf;
+
+ switch (pIf->enmMode)
+ {
+ case VBOXDISPIF_MODE_XPDM_NT4:
+ case VBOXDISPIF_MODE_XPDM:
+ return NO_ERROR;
+#ifdef VBOX_WITH_WDDM
+ case VBOXDISPIF_MODE_WDDM:
+ case VBOXDISPIF_MODE_WDDM_W7:
+ return vboxDispIfSeamlesCreateWDDM(pIf, pSeamless, hEvent);
+#endif
+ default:
+ WARN(("VBoxTray: VBoxDispIfSeamlesCreate: invalid mode %d\n", pIf->enmMode));
+ return ERROR_INVALID_PARAMETER;
+ }
+}
+
+DWORD VBoxDispIfSeamlesTerm(VBOXDISPIF_SEAMLESS *pSeamless)
+{
+ PCVBOXDISPIF const pIf = pSeamless->pIf;
+ DWORD winEr;
+ switch (pIf->enmMode)
+ {
+ case VBOXDISPIF_MODE_XPDM_NT4:
+ case VBOXDISPIF_MODE_XPDM:
+ winEr = NO_ERROR;
+ break;
+#ifdef VBOX_WITH_WDDM
+ case VBOXDISPIF_MODE_WDDM:
+ case VBOXDISPIF_MODE_WDDM_W7:
+ winEr = vboxDispIfSeamlesTermWDDM(pSeamless);
+ break;
+#endif
+ default:
+ WARN(("VBoxTray: VBoxDispIfSeamlesTerm: invalid mode %d\n", pIf->enmMode));
+ winEr = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (winEr == NO_ERROR)
+ memset(pSeamless, 0, sizeof (*pSeamless));
+
+ return winEr;
+}
+
+DWORD VBoxDispIfSeamlesSubmit(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
+{
+ PCVBOXDISPIF const pIf = pSeamless->pIf;
+
+ if (pData->escapeCode != VBOXESC_SETVISIBLEREGION)
+ {
+ WARN(("VBoxTray: invalid escape code for Seamless submit %d\n", pData->escapeCode));
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ switch (pIf->enmMode)
+ {
+ case VBOXDISPIF_MODE_XPDM_NT4:
+ case VBOXDISPIF_MODE_XPDM:
+ return VBoxDispIfEscape(pIf, pData, cbData);
+#ifdef VBOX_WITH_WDDM
+ case VBOXDISPIF_MODE_WDDM:
+ case VBOXDISPIF_MODE_WDDM_W7:
+ return vboxDispIfSeamlesSubmitWDDM(pSeamless, pData, cbData);
+#endif
+ default:
+ WARN(("VBoxTray: VBoxDispIfSeamlesSubmit: invalid mode %d\n", pIf->enmMode));
+ return ERROR_INVALID_PARAMETER;
+ }
+}
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.h
index e98edaf3..75647346 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -18,6 +18,7 @@
#ifdef VBOX_WITH_WDDM
# define D3DKMDT_SPECIAL_MULTIPLATFORM_TOOL
# include <d3dkmthk.h>
+# include "../Graphics/Video/disp/wddm/VBoxDispKmt.h"
#endif
#include <VBoxDisplay.h>
@@ -29,6 +30,7 @@ typedef enum
VBOXDISPIF_MODE_XPDM
#ifdef VBOX_WITH_WDDM
, VBOXDISPIF_MODE_WDDM
+ , VBOXDISPIF_MODE_WDDM_W7
#endif
} VBOXDISPIF_MODE;
/* display driver interface abstraction for XPDM & WDDM
@@ -58,15 +60,7 @@ typedef struct VBOXDISPIF
/* EnumDisplayDevices does not exist in NT. isVBoxDisplayDriverActive et al. are using these functions. */
BOOL (WINAPI * pfnEnumDisplayDevices)(IN LPCSTR lpDevice, IN DWORD iDevNum, OUT PDISPLAY_DEVICEA lpDisplayDevice, IN DWORD dwFlags);
- /* open adapter */
- PFND3DKMT_OPENADAPTERFROMHDC pfnD3DKMTOpenAdapterFromHdc;
- PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME pfnD3DKMTOpenAdapterFromGdiDisplayName;
- /* close adapter */
- PFND3DKMT_CLOSEADAPTER pfnD3DKMTCloseAdapter;
- /* escape */
- PFND3DKMT_ESCAPE pfnD3DKMTEscape;
- /* auto resize support */
- PFND3DKMT_INVALIDATEACTIVEVIDPN pfnD3DKMTInvalidateActiveVidPn;
+ VBOXDISPKMT_CALLBACKS KmtCallbacks;
} wddm;
#endif
} modeData;
@@ -82,6 +76,36 @@ DECLINLINE(VBOXDISPIF_MODE) VBoxDispGetMode(PVBOXDISPIF pIf) { return pIf->enmMo
DWORD VBoxDispIfTerm(PVBOXDISPIF pIf);
DWORD VBoxDispIfEscape(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, int cbData);
DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, int cbData);
-DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel);
-DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
-//DWORD VBoxDispIfReninitModes(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange);
+DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
+DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf);
+
+DWORD VBoxDispIfResizeStarted(PCVBOXDISPIF const pIf);
+
+
+typedef struct VBOXDISPIF_SEAMLESS
+{
+ PCVBOXDISPIF pIf;
+
+ union
+ {
+#ifdef VBOX_WITH_WDDM
+ struct
+ {
+ VBOXDISPKMT_ADAPTER Adapter;
+# ifdef VBOX_DISPIF_WITH_OPCONTEXT
+ VBOXDISPKMT_DEVICE Device;
+ VBOXDISPKMT_CONTEXT Context;
+# endif
+ } wddm;
+#endif
+ } modeData;
+} VBOXDISPIF_SEAMLESS;
+
+DECLINLINE(bool) VBoxDispIfSeamlesIsValid(VBOXDISPIF_SEAMLESS *pSeamless)
+{
+ return !!pSeamless->pIf;
+}
+
+DWORD VBoxDispIfSeamlesCreate(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent);
+DWORD VBoxDispIfSeamlesTerm(VBOXDISPIF_SEAMLESS *pSeamless);
+DWORD VBoxDispIfSeamlesSubmit(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData);
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.cpp
index b0c19261..a3473600 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -62,7 +62,7 @@ int VBoxDisplayInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStart
OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
GetVersionEx (&OSinfo);
- HMODULE hUser = GetModuleHandle("USER32");
+ HMODULE hUser = GetModuleHandle("user32.dll");
gCtx.pEnv = pEnv;
@@ -89,7 +89,8 @@ int VBoxDisplayInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStart
{
Log(("VBoxTray: VBoxDisplayInit: WDDM driver is installed, switching display driver if to WDDM mode\n"));
/* this is hacky, but the most easiest way */
- DWORD err = VBoxDispIfSwitchMode(const_cast<PVBOXDISPIF>(&pEnv->dispIf), VBOXDISPIF_MODE_WDDM, NULL /* old mode, we don't care about it */);
+ VBOXDISPIF_MODE enmMode = (OSinfo.dwMajorVersion > 6 || OSinfo.dwMinorVersion > 0) ? VBOXDISPIF_MODE_WDDM_W7 : VBOXDISPIF_MODE_WDDM;
+ DWORD err = VBoxDispIfSwitchMode(const_cast<PVBOXDISPIF>(&pEnv->dispIf), enmMode, NULL /* old mode, we don't care about it */);
if (err == NO_ERROR)
Log(("VBoxTray: VBoxDisplayInit: DispIf switched to WDDM mode successfully\n"));
else
@@ -212,19 +213,108 @@ static bool isVBoxDisplayDriverActive(VBOXDISPLAYCONTEXT *pCtx)
#endif
}
-/* Returns TRUE to try again. */
-static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel,
- VBOXDISPLAYCONTEXT *pCtx)
+DWORD EnableAndResizeDispDev(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD totalDispNum, UINT Id, DWORD aWidth, DWORD aHeight,
+ DWORD aBitsPerPixel, DWORD aPosX, DWORD aPosY, BOOL fEnabled, BOOL fExtDispSup)
{
- BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
+ DISPLAY_DEVICE displayDeviceTmp;
+ DISPLAY_DEVICE displayDevice;
+ DEVMODE deviceMode;
+ DWORD dwStatus = DISP_CHANGE_SUCCESSFUL;
+ DWORD iter ;
- if (!gCtx.fAnyX)
- Width &= 0xFFF8;
+ deviceMode = paDeviceModes[Id];
+ displayDevice = paDisplayDevices[Id];
+
+ for (iter = 0; iter < totalDispNum; iter++)
+ {
+ if (iter != 0 && iter != Id && !(paDisplayDevices[iter].StateFlags & DISPLAY_DEVICE_ACTIVE))
+ {
+ LogRel(("VBoxTray:Initially disabling the monitor with id = %d . Total Monitor=%d\n", iter, totalDispNum));
+ DEVMODE deviceModeTmp;
+ ZeroMemory(&deviceModeTmp, sizeof(DEVMODE));
+ deviceModeTmp.dmSize = sizeof(DEVMODE);
+ deviceModeTmp.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_POSITION
+ | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS ;
+ displayDeviceTmp = paDisplayDevices[iter];
+ gCtx.pfnChangeDisplaySettingsEx(displayDeviceTmp.DeviceName, &deviceModeTmp, NULL,
+ (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
+ }
+ }
+
+ if (fExtDispSup) /* Extended Display Support possible*/
+ {
+ if (fEnabled)
+ {
+ /* Special case for enabling the secondary monitor. */
+ if(!(displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE))
+ {
+ LogRel(("VBoxTray: Secondary Monitor with ID=%d and name=%s Not Enabled. Enabling it.\n", Id, displayDevice.DeviceName));
+ deviceMode.dmPosition.x = paDeviceModes[0].dmPelsWidth;
+ deviceMode.dmPosition.y = 0;
+ deviceMode.dmBitsPerPel = 32;
+ OSVERSIONINFO OSinfo;
+ OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
+ GetVersionEx (&OSinfo);
+
+ if (OSinfo.dwMajorVersion < 6)
+ /* dont any more flags here as, only DM_POISITON is used to enable the secondary display */
+ deviceMode.dmFields = DM_POSITION;
+ else /* for win 7 and above */
+ /* for vista and above DM_BITSPERPEL is necessary */
+ deviceMode.dmFields = DM_BITSPERPEL | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
+
+ dwStatus = gCtx.pfnChangeDisplaySettingsEx((LPSTR)displayDevice.DeviceName,&deviceMode, NULL, (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
+ /* A second call to ChangeDisplaySettings updates the monitor.*/
+ gCtx.pfnChangeDisplaySettingsEx(NULL, NULL, NULL,0, NULL);
+ }
+ else /* secondary monitor already enabled. Request to change the resolution or position. */
+ {
+ if (aWidth !=0 && aHeight != 0)
+ {
+ LogRel(("VBoxTray: Display : %s , Change Height: %d & Width: %d\n", displayDevice.DeviceName, aWidth, aHeight));
+ deviceMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL
+ | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS;
+ deviceMode.dmPelsWidth = aWidth;
+ deviceMode.dmPelsHeight = aHeight;
+ deviceMode.dmBitsPerPel = aBitsPerPixel;
+ }
+ if (aPosX != 0 || aPosY != 0)
+ {
+ LogRel(("VBoxTray: Display: %s PosX: %d, PosY: %d\n", displayDevice.DeviceName, aPosX, aPosY));
+ deviceMode.dmFields |= DM_POSITION;
+ deviceMode.dmPosition.x = aPosX;
+ deviceMode.dmPosition.y = aPosY;
+ }
+ dwStatus = gCtx.pfnChangeDisplaySettingsEx((LPSTR)displayDevice.DeviceName,
+ &deviceMode, NULL, CDS_NORESET|CDS_UPDATEREGISTRY, NULL);
+ /* A second call to ChangeDisplaySettings updates the monitor. */
+ gCtx.pfnChangeDisplaySettingsEx(NULL, NULL, NULL,0, NULL);
+ }
+ }
+ else /* Request is there to disable the monitor with ID = Id*/
+ {
+ LogRel(("VBoxTray: Disable the Display: %d\n", displayDevice.DeviceName));
+
+ DEVMODE deviceModeTmp;
+ ZeroMemory(&deviceModeTmp, sizeof(DEVMODE));
+ deviceModeTmp.dmSize = sizeof(DEVMODE);
+ deviceModeTmp.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_POSITION
+ | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS ;
+ displayDeviceTmp = paDisplayDevices[Id];
+ dwStatus = gCtx.pfnChangeDisplaySettingsEx(displayDeviceTmp.DeviceName, &deviceModeTmp, NULL,
+ (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
+ gCtx.pfnChangeDisplaySettingsEx(NULL, NULL, NULL,0, NULL);
+ }
+ }
+ return dwStatus;
+}
+DWORD VBoxGetDisplayConfigCount()
+{
DISPLAY_DEVICE DisplayDevice;
- ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
- DisplayDevice.cb = sizeof(DisplayDevice);
+ ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
+ DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
/* Find out how many display devices the system has */
DWORD NumDevices = 0;
@@ -250,26 +340,21 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
i++;
}
- Log(("VBoxTray: ResizeDisplayDevice: Found total %d devices. err %d\n", NumDevices, GetLastError ()));
-
- if (NumDevices == 0 || Id >= NumDevices)
- {
- Log(("VBoxTray: ResizeDisplayDevice: Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
- return FALSE;
- }
-
- DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
- DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
- RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
+ return NumDevices;
+}
+DWORD VBoxGetDisplayConfig(const DWORD NumDevices, DWORD *pDevPrimaryNum, DWORD *pNumDevices, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes)
+{
/* Fetch information about current devices and modes. */
DWORD DevNum = 0;
DWORD DevPrimaryNum = 0;
+ DISPLAY_DEVICE DisplayDevice;
+
ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
- i = 0;
+ DWORD i = 0;
while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
{
Log(("VBoxTray: ResizeDisplayDevice: [%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
@@ -293,8 +378,8 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
{
if (DevNum >= NumDevices)
{
- Log(("VBoxTray: ResizeDisplayDevice: %d >= %d\n", NumDevices, DevNum));
- return FALSE;
+ WARN(("VBoxTray: ResizeDisplayDevice: %d >= %d\n", NumDevices, DevNum));
+ return ERROR_BUFFER_OVERFLOW;
}
paDisplayDevices[DevNum] = DisplayDevice;
@@ -309,7 +394,6 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
{
Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings error %d\n", GetLastError ()));
- return FALSE;
}
if ( paDeviceModes[DevNum].dmPelsWidth == 0
@@ -328,21 +412,10 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
* Do not return here, ignore the error and set the display info to 0x0x0.
*/
Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
- ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
}
}
- Log(("VBoxTray: ResizeDisplayDevice: %dx%dx%d at %d,%d\n",
- paDeviceModes[DevNum].dmPelsWidth,
- paDeviceModes[DevNum].dmPelsHeight,
- paDeviceModes[DevNum].dmBitsPerPel,
- paDeviceModes[DevNum].dmPosition.x,
- paDeviceModes[DevNum].dmPosition.y));
-
- paRects[DevNum].left = paDeviceModes[DevNum].dmPosition.x;
- paRects[DevNum].top = paDeviceModes[DevNum].dmPosition.y;
- paRects[DevNum].right = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
- paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
+
DevNum++;
}
@@ -351,32 +424,146 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
i++;
}
+ *pNumDevices = DevNum;
+
+ return NO_ERROR;
+}
+
+/* Returns TRUE to try again. */
+static BOOL ResizeDisplayDevice(UINT Id, DWORD Width, DWORD Height, DWORD BitsPerPixel,
+ BOOL fEnabled, DWORD dwNewPosX, DWORD dwNewPosY,
+ VBOXDISPLAYCONTEXT *pCtx, BOOL fExtDispSup)
+{
+ BOOL fDispAlreadyEnabled = false; /* check whether the monitor with ID is already enabled. */
+ BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0 &&
+ dwNewPosX == 0 && dwNewPosY == 0);
+ DWORD dmFields = 0;
+
+ Log(("VBoxTray: ResizeDisplayDevice Width= %d, Height=%d , PosX=%d and PosY=%d \
+ fEnabled = %d, fExtDisSup = %d\n",
+ Width, Height, dwNewPosX, dwNewPosY, fEnabled, fExtDispSup));
+
+ if (!gCtx.fAnyX)
+ Width &= 0xFFF8;
+
+ VBoxDispIfCancelPendingResize(&pCtx->pEnv->dispIf);
+
+ DWORD NumDevices = VBoxGetDisplayConfigCount();
+
+ if (NumDevices == 0 || Id >= NumDevices)
+ {
+ WARN(("VBoxTray: ResizeDisplayDevice: Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
+ return FALSE;
+ }
+
+ Log(("VBoxTray: ResizeDisplayDevice: Found total %d devices. err %d\n", NumDevices, GetLastError ()));
+
+ DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
+ DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
+ RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
+ DWORD DevNum = 0;
+ DWORD DevPrimaryNum = 0;
+ DWORD dwStatus = VBoxGetDisplayConfig(NumDevices, &DevPrimaryNum, &DevNum, paDisplayDevices, paDeviceModes);
+ if (dwStatus != NO_ERROR)
+ {
+ WARN(("VBoxTray: ResizeDisplayDevice: VBoxGetDisplayConfig failed, %d\n", dwStatus));
+ return dwStatus;
+ }
+
+ if (NumDevices != DevNum)
+ WARN(("VBoxTray: ResizeDisplayDevice: NumDevices(%d) != DevNum(%d)\n", NumDevices, DevNum));
+
+ DWORD i = 0;
+
+ for (i = 0; i < DevNum; ++i)
+ {
+ if (fExtDispSup)
+ {
+ LogRel(("VBoxTray: Extended Display Support.\n"));
+ Log(("VBoxTray: ResizeDisplayDevice1: %dx%dx%d at %d,%d . Id = %d and DevNum=%d, fEnabled=%d\n",
+ paDeviceModes[Id].dmPelsWidth,
+ paDeviceModes[Id].dmPelsHeight,
+ paDeviceModes[Id].dmBitsPerPel,
+ paDeviceModes[Id].dmPosition.x,
+ paDeviceModes[Id].dmPosition.y,
+ Id, DevNum, fEnabled));
+ }
+ else
+ {
+ LogRel(("VBoxTray: NO Ext Display Support \n"));
+ }
+
+ paRects[i].left = paDeviceModes[i].dmPosition.x;
+ paRects[i].top = paDeviceModes[i].dmPosition.y;
+ paRects[i].right = paDeviceModes[i].dmPosition.x + paDeviceModes[i].dmPelsWidth;
+ paRects[i].bottom = paDeviceModes[i].dmPosition.y + paDeviceModes[i].dmPelsHeight;
+ }
+
+ /* Keep a record if the display with ID is already active or not. */
+ if (paDisplayDevices[Id].StateFlags & DISPLAY_DEVICE_ACTIVE)
+ {
+ LogRel(("VBoxTray: Display with ID=%d already enabled\n", Id));
+ fDispAlreadyEnabled = TRUE;
+ }
+
/* Width, height equal to 0 means that this value must be not changed.
* Update input parameters if necessary.
* Note: BitsPerPixel is taken into account later, when new rectangles
* are assigned to displays.
*/
if (Width == 0)
- {
Width = paRects[Id].right - paRects[Id].left;
- }
+ else
+ dmFields |= DM_PELSWIDTH;
if (Height == 0)
- {
Height = paRects[Id].bottom - paRects[Id].top;
+ else
+ dmFields |= DM_PELSHEIGHT;
+
+ if (BitsPerPixel == 0)
+ BitsPerPixel = paDeviceModes[Id].dmBitsPerPel;
+ else
+ dmFields |= DM_BITSPERPEL;
+
+ if (!dwNewPosX && !dwNewPosY)
+ {
+ /* @fixme: zero position is a valid state, so another values should be used as a special case !!! */
+ dwNewPosX = paRects[Id].left;
+ dwNewPosY = paRects[Id].top;
}
+ else
+ dmFields |= DM_POSITION;
- /* Check whether a mode reset or a change is requested. */
- if ( !fModeReset
+ /* Check whether a mode reset or a change is requested.
+ * Rectangle position is recalculated only if fEnabled is 1.
+ * For non extended supported modes (old Host VMs), fEnabled
+ * is always 1.
+ */
+ /* Handled the case where previouseresolution of secondary monitor
+ * was for eg. 1024*768*32 and monitor was in disabled state.
+ * User gives the command
+ * setvideomode 1024 768 32 1 yes.
+ * Now in this case the resolution request is same as previous one but
+ * monitor is going from disabled to enabled state so the below condition
+ * shour return false
+ * The below condition will only return true , if no mode reset has
+ * been requested AND fEnabled is 1 and fDispAlreadyEnabled is also 1 AND
+ * all rect conditions are true. Thus in this case nothing has to be done.
+ */
+ if ( !fModeReset && (!fEnabled == !fDispAlreadyEnabled)
+ && paRects[Id].left == dwNewPosX
+ && paRects[Id].top == dwNewPosY
&& paRects[Id].right - paRects[Id].left == Width
&& paRects[Id].bottom - paRects[Id].top == Height
&& paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
{
- Log(("VBoxTray: ResizeDisplayDevice: Already at desired resolution\n"));
+ LogRel(("VBoxTray: Already at desired resolution. No Change.\n"));
return FALSE;
}
- hlpResizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
+ hlpResizeRect(paRects, NumDevices, DevPrimaryNum, Id,
+ fEnabled ? Width : 0, fEnabled ? Height : 0, dwNewPosX, dwNewPosY);
#ifdef Log
for (i = 0; i < NumDevices; i++)
{
@@ -399,35 +586,38 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
+ if (i == Id)
+ paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
+
+ paDeviceModes[i].dmFields |= dmFields;
+
/* On Vista one must specify DM_BITSPERPEL.
* Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
*/
- paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
-
- if ( i == Id
- && BitsPerPixel != 0)
+ if (!(paDeviceModes[i].dmFields & DM_BITSPERPEL))
{
- /* Change dmBitsPerPel if requested. */
- paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
+ WARN(("VBoxTray: (WDDM) no DM_BITSPERPEL\n"));
+ paDeviceModes[i].dmFields |= DM_BITSPERPEL;
+ paDeviceModes[i].dmBitsPerPel = 32;
}
- Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
+ Log(("VBoxTray: (WDDM) ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
gCtx.pfnChangeDisplaySettingsEx,
paDeviceModes[i].dmPelsWidth,
paDeviceModes[i].dmPelsHeight,
paDeviceModes[i].dmBitsPerPel,
paDeviceModes[i].dmPosition.x,
paDeviceModes[i].dmPosition.y));
-
}
- DWORD err = VBoxDispIfResizeModes(&pCtx->pEnv->dispIf, Id, paDisplayDevices, paDeviceModes, NumDevices);
+ Log(("VBoxTray: (WDDM) Request to resize the displa\n"));
+ DWORD err = VBoxDispIfResizeModes(&pCtx->pEnv->dispIf, Id, fEnabled, fExtDispSup, paDisplayDevices, paDeviceModes, DevNum);
if (err == NO_ERROR || err != ERROR_RETRY)
{
if (err == NO_ERROR)
Log(("VBoxTray: VBoxDisplayThread: (WDDM) VBoxDispIfResizeModes succeeded\n"));
else
- Log(("VBoxTray: VBoxDisplayThread: (WDDM) Failure VBoxDispIfResizeModes (%d)\n", err));
+ WARN(("VBoxTray: VBoxDisplayThread: (WDDM) Failure VBoxDispIfResizeModes (%d)\n", err));
return FALSE;
}
@@ -467,8 +657,8 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
}
- Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
- gCtx.pfnChangeDisplaySettingsEx,
+ Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx Current MonitorId=%d: %dx%dx%d at %d,%d\n",
+ i,
paDeviceModes[i].dmPelsWidth,
paDeviceModes[i].dmPelsHeight,
paDeviceModes[i].dmBitsPerPel,
@@ -480,15 +670,18 @@ static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsP
Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", status, GetLastError ()));
}
- /* A second call to ChangeDisplaySettings updates the monitor. */
- LONG status = gCtx.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
- Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
- if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
+ Log(("VBoxTray: Enable And Resize Device. Id = %d, Width=%d Height=%d, \
+ dwNewPosX = %d, dwNewPosY = %d fEnabled=%d & fExtDispSupport = %d \n",
+ Id, Width, Height, dwNewPosX, dwNewPosY, fEnabled, fExtDispSup));
+ dwStatus = EnableAndResizeDispDev(paDeviceModes, paDisplayDevices, DevNum, Id, Width, Height, BitsPerPixel,
+ dwNewPosX, dwNewPosY, fEnabled, fExtDispSup);
+ if (dwStatus == DISP_CHANGE_SUCCESSFUL || dwStatus == DISP_CHANGE_BADMODE)
{
- /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
+ /* Successfully set new video mode or our driver can not set
+ * the requested mode. Stop trying.
+ */
return FALSE;
}
-
/* Retry the request. */
return TRUE;
}
@@ -515,15 +708,13 @@ unsigned __stdcall VBoxDisplayThread(void *pInstance)
return 0;
}
- int rc = VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0);
- if (RT_FAILURE(rc))
- {
- LogRel(("VBoxTray: VBoxDisplayThread: Failed to set the graphics capability with rc=%Rrc, thread exiting\n", rc));
- return 0;
- }
+ PostMessage(ghwndToolWindow, WM_VBOX_GRAPHICS_SUPPORTED, 0, 0);
+
+ VBoxDispIfResizeStarted(&pCtx->pEnv->dispIf);
do
{
+ BOOL fExtDispSup = TRUE;
/* Wait for a display change event. */
VBoxGuestWaitEventInfo waitEvent;
waitEvent.u32TimeoutIn = 1000;
@@ -552,20 +743,44 @@ unsigned __stdcall VBoxDisplayThread(void *pInstance)
if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
{
Log(("VBoxTray: VBoxDisplayThread: going to get display change information\n"));
+ BOOL fDisplayChangeQueried;
+
/* We got at least one event. Read the requested resolution
* and try to set it until success. New events will not be seen
* but a new resolution will be read in this poll loop.
*/
- VMMDevDisplayChangeRequest2 displayChangeRequest = {0};
- displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest2);
+ /* Try if extended mode display information is available from the host. */
+ VMMDevDisplayChangeRequestEx displayChangeRequest = {0};
+ fExtDispSup = TRUE;
+ displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequestEx);
displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
- displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest2;
+ displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequestEx;
displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
- BOOL fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequest2)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2),
+ fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequestEx)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequestEx),
+ &displayChangeRequest, sizeof(VMMDevDisplayChangeRequestEx), &cbReturned, NULL);
+
+ if (!fDisplayChangeQueried)
+ {
+ Log(("VBoxTray: Extended Display Not Supported. Trying VMMDevDisplayChangeRequest2\n"));
+ fExtDispSup = FALSE; /* Extended display Change request is not supported */
+
+ displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest2);
+ displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest2;
+ displayChangeRequest.eventAck = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
+ fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequest2)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2),
&displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2), &cbReturned, NULL);
+ displayChangeRequest.cxOrigin = 0;
+ displayChangeRequest.cyOrigin = 0;
+ displayChangeRequest.fChangeOrigin = 0;
+ displayChangeRequest.fEnabled = 1; /* Always Enabled for old VMs on Host.*/
+ }
+
if (!fDisplayChangeQueried)
{
+ Log(("VBoxTray: Extended Display Not Supported. Trying VMMDevDisplayChangeRequest\n"));
+ fExtDispSup = FALSE; /*Extended display Change request is not supported */
/* Try the old version of the request for old VBox hosts. */
displayChangeRequest.header.size = sizeof(VMMDevDisplayChangeRequest);
displayChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION;
@@ -574,6 +789,10 @@ unsigned __stdcall VBoxDisplayThread(void *pInstance)
fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevDisplayChangeRequest)), &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest),
&displayChangeRequest, sizeof(VMMDevDisplayChangeRequest), &cbReturned, NULL);
displayChangeRequest.display = 0;
+ displayChangeRequest.cxOrigin = 0;
+ displayChangeRequest.cyOrigin = 0;
+ displayChangeRequest.fChangeOrigin = 0;
+ displayChangeRequest.fEnabled = 1; /* Always Enabled for old VMs on Host.*/
}
if (fDisplayChangeQueried)
@@ -602,17 +821,31 @@ unsigned __stdcall VBoxDisplayThread(void *pInstance)
if (pCtx->pfnChangeDisplaySettingsEx != 0)
{
Log(("VBoxTray: VBoxDisplayThread: Detected W2K or later\n"));
-
/* W2K or later. */
+ Log(("DisplayChangeReqEx parameters aDisplay=%d x xRes=%d x yRes=%d x bpp=%d x SecondayMonEnb=%d x NewOriginX=%d x NewOriginY=%d x ChangeOrigin=%d\n",
+ displayChangeRequest.display,
+ displayChangeRequest.xres,
+ displayChangeRequest.yres,
+ displayChangeRequest.bpp,
+ displayChangeRequest.fEnabled,
+ displayChangeRequest.cxOrigin,
+ displayChangeRequest.cyOrigin,
+ displayChangeRequest.fChangeOrigin));
if (!ResizeDisplayDevice(displayChangeRequest.display,
displayChangeRequest.xres,
displayChangeRequest.yres,
displayChangeRequest.bpp,
- pCtx
+ displayChangeRequest.fEnabled,
+ displayChangeRequest.cxOrigin,
+ displayChangeRequest.cyOrigin,
+ pCtx,
+ fExtDispSup
))
{
+ Log(("ResizeDipspalyDevice return 0\n"));
break;
}
+
}
else
{
@@ -727,7 +960,8 @@ unsigned __stdcall VBoxDisplayThread(void *pInstance)
}
if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED)
hlpReloadCursor();
- } else
+ }
+ else
{
Log(("VBoxTray: VBoxDisplayThread: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
/* sleep a bit to not eat too much CPU in case the above call always fails */
@@ -746,7 +980,7 @@ unsigned __stdcall VBoxDisplayThread(void *pInstance)
maskInfo.u32NotMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED;
if (!DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
Log(("VBoxTray: VBoxDisplayThread: DeviceIOControl(CtlMask - not) failed\n"));
- VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS);
+ PostMessage(ghwndToolWindow, WM_VBOX_GRAPHICS_UNSUPPORTED, 0, 0);
Log(("VBoxTray: VBoxDisplayThread: finished display change request thread\n"));
return 0;
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.h
index b2eaa421..81c90e93 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxDisplay.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -22,6 +22,9 @@ int VBoxDisplayInit (const VBOXSERVICEENV *pEnv, void **ppInst
unsigned __stdcall VBoxDisplayThread (void *pInstance);
void VBoxDisplayDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
+DWORD VBoxGetDisplayConfigCount();
+DWORD VBoxGetDisplayConfig(const DWORD NumDevices, DWORD *pDevPrimaryNum, DWORD *pNumDevices, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes);
+
#ifndef VBOX_WITH_WDDM
static bool isVBoxDisplayDriverActive (void);
#else
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.cpp
index f038f51c..bb9984cb 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.cpp
@@ -111,7 +111,8 @@ static unsigned hlpNextAdjacentRectYN(RECTL *paRects, unsigned nRects, unsigned
}
void hlpResizeRect(RECTL *paRects, unsigned nRects, unsigned uPrimary,
- unsigned uResized, int iNewWidth, int iNewHeight)
+ unsigned uResized, int iNewWidth, int iNewHeight,
+ int iNewPosX, int iNewPosY)
{
DDCLOG(("nRects %d, iPrimary %d, iResized %d, NewWidth %d, NewHeight %d\n", nRects, uPrimary, uResized, iNewWidth, iNewHeight));
@@ -119,6 +120,10 @@ void hlpResizeRect(RECTL *paRects, unsigned nRects, unsigned uPrimary,
memcpy (paNewRects, paRects, sizeof (RECTL) * nRects);
paNewRects[uResized].right += iNewWidth - (paNewRects[uResized].right - paNewRects[uResized].left);
paNewRects[uResized].bottom += iNewHeight - (paNewRects[uResized].bottom - paNewRects[uResized].top);
+ paNewRects[uResized].right += iNewPosX - paNewRects[uResized].left;
+ paNewRects[uResized].bottom += iNewPosY - paNewRects[uResized].top;
+ paNewRects[uResized].left = iNewPosX;
+ paNewRects[uResized].top = iNewPosY;
/* Verify all pairs of originally adjacent rectangles for all 4 directions.
* If the pair has a "good" delta (that is the first rectangle intersects the second)
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.h
index 4924ac6d..176f8867 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -28,7 +28,7 @@
extern int hlpReportStatus(VBoxGuestFacilityStatus statusCurrent);
extern void hlpReloadCursor(void);
-extern void hlpResizeRect(RECTL *paRects, unsigned nRects, unsigned uPrimary, unsigned uResized, int iNewWidth, int iNewHeight);
+extern void hlpResizeRect(RECTL *paRects, unsigned nRects, unsigned uPrimary, unsigned uResized, int iNewWidth, int iNewHeight, int iNewPosX, int iNewPosY);
extern int hlpShowBalloonTip(HINSTANCE hInst, HWND hWnd, UINT uID, const char *pszMsg, const char *pszTitle, UINT uTimeout, DWORD dwInfoFlags);
#endif /* !___VBOXTRAY_HELPERS_H */
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxHostVersion.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxHostVersion.cpp
index dc429e50..792477eb 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxHostVersion.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxHostVersion.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp
index 3245383e..e8b8cfc1 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp
@@ -1,10 +1,12 @@
/* $Id: VBoxIPC.cpp $ */
/** @file
- * VboxIPC - IPC thread.
+ * VBoxIPC - IPC thread, acts as a (purely) local IPC server.
+ * Multiple sessions are supported, whereas every session
+ * has its own thread for processing requests.
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -20,133 +22,132 @@
#include "VBoxHelpers.h"
#include "VBoxIPC.h"
+#include <iprt/asm.h>
#include <iprt/assert.h>
+#include <iprt/critsect.h>
#include <iprt/err.h>
+#include <iprt/ldr.h>
+#include <iprt/list.h>
+#include <iprt/localipc.h>
#include <iprt/mem.h>
#include <VBoxGuestInternal.h>
-typedef struct _VBOXIPCCONTEXT
+
+/**
+ * IPC context data.
+ */
+typedef struct VBOXIPCCONTEXT
{
- const VBOXSERVICEENV *pEnv;
- HANDLE hPipe;
+ /** Pointer to the service environment. */
+ const VBOXSERVICEENV *pEnv;
+ /** Handle for the local IPC server. */
+ RTLOCALIPCSERVER hServer;
+ /** Critical section serializing access to the session list, the state,
+ * the response event, the session event, and the thread event. */
+ RTCRITSECT CritSect;
+ /** List of all active IPC sessions. */
+ RTLISTANCHOR SessionList;
} VBOXIPCCONTEXT, *PVBOXIPCCONTEXT;
-
static VBOXIPCCONTEXT gCtx = {0};
+/** Function pointer for GetLastInputInfo(). */
+typedef BOOL (WINAPI *PFNGETLASTINPUTINFO)(PLASTINPUTINFO);
/**
- * Reads an IPC message from a connected client, represented by the IPC
- * context.
- *
- * @return IPRT status code.
- * @param pCtx The IPC context.
- * @param pMessage Buffer for receiving the message to be read.
- * @param cbMessage Size (in bytes) of buffer for received message.
+ * IPC per-session thread data.
*/
-int VBoxIPCReadMessage(PVBOXIPCCONTEXT pCtx, BYTE *pMessage, DWORD cbMessage)
+typedef struct VBOXIPCSESSION
{
- int rc = VINF_SUCCESS;
- do
- {
- DWORD dwRead;
- if (!ReadFile(pCtx->hPipe, pMessage, cbMessage, &dwRead, 0))
- {
- rc = RTErrConvertFromWin32(GetLastError());
- }
- else
- {
- if (rc == VERR_MORE_DATA)
- rc = VINF_SUCCESS;
- pMessage += dwRead;
- cbMessage -= dwRead;
- }
- }
- while (cbMessage && RT_SUCCESS(rc));
- return rc;
+ /** The list node required to be part of the
+ * IPC session list. */
+ RTLISTNODE Node;
+ /** Pointer to the IPC context data. */
+ PVBOXIPCCONTEXT volatile pCtx;
+ /** The local ipc client handle. */
+ RTLOCALIPCSESSION volatile hSession;
+ /** Indicate that the thread should terminate ASAP. */
+ bool volatile fTerminate;
+ /** The thread handle. */
+ RTTHREAD hThread;
+
+} VBOXIPCSESSION, *PVBOXIPCSESSION;
+
+/** Static pointer to GetLastInputInfo() function. */
+static PFNGETLASTINPUTINFO s_pfnGetLastInputInfo = NULL;
+
+int vboxIPCSessionStop(PVBOXIPCSESSION pSession);
+
+static int vboxIPCHandleVBoxTrayRestart(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
+
+ /** @todo Not implemented yet; don't return an error here. */
+ return VINF_SUCCESS;
}
-/**
- * Skips an IPC message by reading out the outstanding message
- * body to discard it.
- *
- * @return IPRT status code.
- * @param pCtx The IPC context.
- * @param pHdr The header of message to skip.
- */
-int VBoxIPCSkipMessage(PVBOXIPCCONTEXT pCtx, PVBOXTRAYIPCHEADER pHdr)
+static int vboxIPCHandleShowBalloonMsg(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
{
- Assert(pHdr->cbBody);
- BYTE *pbBuf = (BYTE*)RTMemAlloc(pHdr->cbBody);
- if (!pbBuf)
- return VERR_NO_MEMORY;
- int rc = VBoxIPCReadMessage(pCtx, pbBuf, pHdr->cbBody);
- RTMemFree(pbBuf);
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
+ AssertReturn(pHdr->uMsgLen > 0, VERR_INVALID_PARAMETER);
+
+ VBOXTRAYIPCMSG_SHOWBALLOONMSG ipcMsg;
+ int rc = RTLocalIpcSessionRead(pSession->hSession, &ipcMsg, pHdr->uMsgLen,
+ NULL /* Exact read, blocking */);
+ if (RT_SUCCESS(rc))
+ {
+ /* Showing the balloon tooltip is not critical. */
+ int rc2 = hlpShowBalloonTip(ghInstance, ghwndToolWindow, ID_TRAYICON,
+ ipcMsg.szMsgContent, ipcMsg.szMsgTitle,
+ ipcMsg.uShowMS, ipcMsg.uType);
+ LogFlowFunc(("Showing \"%s\" - \"%s\" (type %RU32, %RU32ms), rc=%Rrc\n",
+ ipcMsg.szMsgTitle, ipcMsg.szMsgContent,
+ ipcMsg.uType, ipcMsg.uShowMS, rc2));
+ }
+
return rc;
}
-/**
- * Writes an IPC message to the IPC context's client.
- *
- * @return IPRT status code.
- * @param pCtx The IPC context.
- * @param pMessage Pointer to message to send.
- * @param cbMessage Size (in bytes) of message to send.
- */
-int VBoxIPCWriteMessage(PVBOXIPCCONTEXT pCtx, BYTE *pMessage, DWORD cbMessage)
+static int vboxIPCHandleUserLastInput(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHdr, VERR_INVALID_POINTER);
+ /* No actual message from client. */
+
int rc = VINF_SUCCESS;
- while (RT_SUCCESS(rc))
+
+ bool fLastInputAvailable = false;
+ VBOXTRAYIPCRES_USERLASTINPUT ipcRes;
+ if (s_pfnGetLastInputInfo)
{
- DWORD cbWritten;
- if (!WriteFile(pCtx->hPipe, pMessage, cbMessage, &cbWritten, 0))
+ /* Note: This only works up to 49.7 days (= 2^32, 32-bit counter)
+ since Windows was started. */
+ LASTINPUTINFO lastInput;
+ lastInput.cbSize = sizeof(LASTINPUTINFO);
+ BOOL fRc = s_pfnGetLastInputInfo(&lastInput);
+ if (fRc)
+ {
+ ipcRes.uLastInput = (GetTickCount() - lastInput.dwTime) / 1000;
+ fLastInputAvailable = true;
+ }
+ else
rc = RTErrConvertFromWin32(GetLastError());
- pMessage += cbWritten;
}
- return rc;
-}
-
-int VBoxIPCPostQuitMessage(PVBOXIPCCONTEXT pCtx)
-{
- VBOXTRAYIPCHEADER hdr;
- hdr.ulMsg = VBOXTRAYIPCMSGTYPE_IPC_QUIT;
- return VBoxIPCWriteMessage(pCtx, (BYTE*)&hdr, sizeof(hdr));
-}
-/**
- * Shows a balloon tooltip message in VBoxTray's
- * message area in the Windows main taskbar.
- *
- * @return IPRT status code.
- * @param pCtx IPC context of the caller.
- * @param wParam wParam of received IPC message.
- * @param lParam lParam of received IPC message.
- */
-int VBoxIPCMsgShowBalloonMsg(PVBOXIPCCONTEXT pCtx, UINT wParam, UINT lParam)
-{
- VBOXTRAYIPCMSG_SHOWBALLOONMSG msg;
- int rc = VBoxIPCReadMessage(pCtx,(BYTE*)&msg, sizeof(msg));
- if (RT_SUCCESS(rc))
+ if (!fLastInputAvailable)
{
- hlpShowBalloonTip(ghInstance, ghwndToolWindow, ID_TRAYICON,
- msg.szContent, msg.szTitle,
- msg.ulShowMS, msg.ulType);
+ /* No last input available. */
+ ipcRes.uLastInput = UINT32_MAX;
}
- return rc;
-}
-/**
- * Takes action to restart VBoxTray (this application).
- *
- * @return IPRT status code.
- * @param pCtx IPC context of the caller.
- * @param wParam wParam of received IPC message.
- * @param lParam lParam of received IPC message.
- */
-int VBoxIPCMsgRestart(PVBOXIPCCONTEXT pCtx, UINT wParam, UINT lParam)
-{
- return 0;
+ int rc2 = RTLocalIpcSessionWrite(pSession->hSession, &ipcRes, sizeof(ipcRes));
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+
+ return rc;
}
/**
@@ -159,149 +160,405 @@ int VBoxIPCMsgRestart(PVBOXIPCCONTEXT pCtx, UINT wParam, UINT lParam)
*/
int VBoxIPCInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
{
- Log(("VBoxTray: VBoxIPCInit\n"));
+ AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
+ /** ppInstance not used here. */
+ AssertPtrReturn(pfStartThread, VERR_INVALID_POINTER);
+
+ LogFlowFuncEnter();
*pfStartThread = false;
- gCtx.pEnv = pEnv;
- int rc = VINF_SUCCESS;
- SECURITY_ATTRIBUTES sa;
- sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)RTMemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
- if (!sa.lpSecurityDescriptor)
- rc = VERR_NO_MEMORY;
- else
+ int rc = RTCritSectInit(&gCtx.CritSect);
+ if (RT_SUCCESS(rc))
{
- if (!InitializeSecurityDescriptor(sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
+ RTUTF16 wszUserName[255];
+ DWORD cchUserName = sizeof(wszUserName) / sizeof(RTUTF16);
+ BOOL fRc = GetUserNameW(wszUserName, &cchUserName);
+ if (!fRc)
rc = RTErrConvertFromWin32(GetLastError());
- else
- {
- if (!SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, (PACL)0, FALSE))
- rc = RTErrConvertFromWin32(GetLastError());
- else
- {
- sa.nLength = sizeof(sa);
- sa.bInheritHandle = TRUE;
- }
- }
if (RT_SUCCESS(rc))
{
- gCtx.hPipe = CreateNamedPipe((LPSTR)VBOXTRAY_PIPE_IPC,
- PIPE_ACCESS_DUPLEX,
- PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- VBOXTRAY_PIPE_IPC_BUFSIZE, /* Output buffer size. */
- VBOXTRAY_PIPE_IPC_BUFSIZE, /* Input buffer size. */
- NMPWAIT_USE_DEFAULT_WAIT,
- &sa);
- if (gCtx.hPipe == INVALID_HANDLE_VALUE)
- rc = RTErrConvertFromWin32(GetLastError());
- else
+ char *pszUserName;
+ rc = RTUtf16ToUtf8(wszUserName, &pszUserName);
+ if (RT_SUCCESS(rc))
{
- *pfStartThread = true;
- *ppInstance = &gCtx;
+ char szPipeName[255];
+ if (RTStrPrintf(szPipeName, sizeof(szPipeName), "%s%s",
+ VBOXTRAY_IPC_PIPE_PREFIX, pszUserName))
+ {
+ rc = RTLocalIpcServerCreate(&gCtx.hServer, szPipeName,
+ RTLOCALIPC_FLAGS_MULTI_SESSION);
+ if (RT_SUCCESS(rc))
+ {
+ RTStrFree(pszUserName);
+
+ gCtx.pEnv = pEnv;
+ RTListInit(&gCtx.SessionList);
+
+ *ppInstance = &gCtx;
+ *pfStartThread = true;
+
+ /* GetLastInputInfo only is available starting at Windows 2000. */
+ s_pfnGetLastInputInfo = (PFNGETLASTINPUTINFO)
+ RTLdrGetSystemSymbol("User32.dll", "GetLastInputInfo");
+
+ LogRelFunc(("Local IPC server now running at \"%s\"\n",
+ szPipeName));
+ return VINF_SUCCESS;
+ }
+
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ RTStrFree(pszUserName);
}
}
- RTMemFree(sa.lpSecurityDescriptor);
+
+ RTCritSectDelete(&gCtx.CritSect);
}
+
+ LogRelFunc(("Creating local IPC server failed with rc=%Rrc\n", rc));
return rc;
}
-
-void VBoxIPCDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
+void VBoxIPCStop(const VBOXSERVICEENV *pEnv, void *pInstance)
{
- Log(("VBoxTray: VBoxIPCDestroy\n"));
+ AssertPtrReturnVoid(pEnv);
+ AssertPtrReturnVoid(pInstance);
+
+ LogFunc(("Stopping pInstance=%p\n", pInstance));
+ /* Shut down local IPC server. */
PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
AssertPtr(pCtx);
- if (pCtx->hPipe)
+ if (pCtx->hServer != NIL_RTLOCALIPCSERVER)
+ {
+ int rc2 = RTLocalIpcServerCancel(pCtx->hServer);
+ if (RT_FAILURE(rc2))
+ LogFunc(("Cancelling current listening call failed with rc=%Rrc\n", rc2));
+ }
+
+ /* Stop all remaining session threads. */
+ int rc = RTCritSectEnter(&pCtx->CritSect);
+ if (RT_SUCCESS(rc))
{
- VBoxIPCPostQuitMessage(pCtx);
- CloseHandle(pCtx->hPipe);
+ PVBOXIPCSESSION pSession;
+ RTListForEach(&pCtx->SessionList, pSession, VBOXIPCSESSION, Node)
+ {
+ int rc2 = vboxIPCSessionStop(pSession);
+ if (RT_FAILURE(rc2))
+ {
+ LogFunc(("Stopping IPC session %p failed with rc=%Rrc\n",
+ pSession, rc2));
+ /* Keep going. */
+ }
+ }
}
- return;
}
-/**
- * Thread function to wait for and process seamless mode change
- * requests
- */
-unsigned __stdcall VBoxIPCThread(void *pInstance)
+void VBoxIPCDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
{
- Log(("VBoxTray: VBoxIPCThread\n"));
+ AssertPtrReturnVoid(pEnv);
+ AssertPtrReturnVoid(pInstance);
+
+ LogFunc(("Destroying pInstance=%p\n", pInstance));
PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
AssertPtr(pCtx);
- bool fTerminate = false;
- int rc = VINF_SUCCESS;
+ /* Shut down local IPC server. */
+ int rc = RTCritSectEnter(&pCtx->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLocalIpcServerDestroy(pCtx->hServer);
+ if (RT_FAILURE(rc))
+ LogFunc(("Unable to destroy IPC server, rc=%Rrc\n", rc));
+
+ int rc2 = RTCritSectLeave(&pCtx->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ LogFunc(("Waiting for remaining IPC sessions to shut down ...\n"));
+ /* Wait for all IPC session threads to shut down. */
+ bool fListIsEmpty = true;
do
{
- DWORD dwErr = ERROR_SUCCESS;
- BOOL fConnected = ConnectNamedPipe(pCtx->hPipe, NULL)
- ? TRUE
- : (GetLastError() == ERROR_PIPE_CONNECTED);
+ int rc2 = RTCritSectEnter(&pCtx->CritSect);
+ if (RT_SUCCESS(rc2))
+ {
+ fListIsEmpty = RTListIsEmpty(&pCtx->SessionList);
+ rc2 = RTCritSectLeave(&pCtx->CritSect);
+
+ if (!fListIsEmpty) /* Don't hog CPU while waiting. */
+ RTThreadSleep(100);
+ }
- /* Are we supposed to stop? */
- if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
+ if (RT_FAILURE(rc2))
break;
- if (fConnected)
- {
- VBOXTRAYIPCHEADER hdr;
- DWORD read = 0;
+ } while (!fListIsEmpty);
+
+ AssertMsg(fListIsEmpty,
+ ("Session thread list is not empty when it should\n"));
- if (!ReadFile(pCtx->hPipe, &hdr, sizeof(hdr), &read, 0))
- dwErr = GetLastError();
+ LogFunc(("All remaining IPC sessions shut down\n"));
- /** @todo We might want to spawn a thread per connected client
- * in order to perform longer tasks. */
+ int rc2 = RTCritSectDelete(&pCtx->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
- if (SUCCEEDED(dwErr))
+ LogFunc(("Destroyed pInstance=%p, rc=%Rrc\n",
+ pInstance, rc));
+}
+
+/**
+ * Services a client session.
+ *
+ * @returns VINF_SUCCESS.
+ * @param hThread The thread handle.
+ * @param pvSession Pointer to the session instance data.
+ */
+static DECLCALLBACK(int) vboxIPCSessionThread(RTTHREAD hThread, void *pvSession)
+{
+ PVBOXIPCSESSION pThis = (PVBOXIPCSESSION)pvSession;
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ RTLOCALIPCSESSION hSession = pThis->hSession;
+ AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
+
+ LogFunc(("pThis=%p\n", pThis));
+
+ int rc = VINF_SUCCESS;
+
+ /*
+ * Process client requests until it quits or we're cancelled on termination.
+ */
+ while ( !ASMAtomicUoReadBool(&pThis->fTerminate)
+ && RT_SUCCESS(rc))
+ {
+ /* The next call will be cancelled via VBoxIPCStop if needed. */
+ rc = RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_CANCELLED)
{
- Log(("VBoxTray: VBoxIPCThread: Received message %ld ...\n", hdr.ulMsg));
- switch (hdr.ulMsg)
+ LogFunc(("Session %p: Waiting for data cancelled\n", pThis));
+ rc = VINF_SUCCESS;
+ break;
+ }
+ else
+ LogFunc(("Session %p: Waiting for session data failed with rc=%Rrc\n",
+ pThis, rc));
+ }
+ else
+ {
+ VBOXTRAYIPCHEADER ipcHdr;
+ rc = RTLocalIpcSessionRead(hSession, &ipcHdr, sizeof(ipcHdr),
+ NULL /* Exact read, blocking */);
+ bool fRejected = false; /* Reject current command? */
+ if (RT_SUCCESS(rc))
+ fRejected = ipcHdr.uMagic != VBOXTRAY_IPC_HDR_MAGIC
+ || ipcHdr.uHdrVersion != 0; /* We only know version 0 commands for now. */
+
+ if ( !fRejected
+ && RT_SUCCESS(rc))
+ {
+ switch (ipcHdr.uMsgType)
{
case VBOXTRAYIPCMSGTYPE_RESTART:
- rc = VBoxIPCMsgRestart(pCtx, hdr.wParam, hdr.lParam);
- if (RT_SUCCESS(rc))
- fTerminate = true;
+ rc = vboxIPCHandleVBoxTrayRestart(pThis, &ipcHdr);
break;
- case VBOXTRAYIPCMSGTYPE_IPC_QUIT:
- fTerminate = true;
+ case VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG:
+ rc = vboxIPCHandleShowBalloonMsg(pThis, &ipcHdr);
break;
- case VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG:
- rc = VBoxIPCMsgShowBalloonMsg(pCtx, hdr.wParam, hdr.lParam);
+ case VBOXTRAYIPCMSGTYPE_USERLASTINPUT:
+ rc = vboxIPCHandleUserLastInput(pThis, &ipcHdr);
break;
default:
- /* Unknown message received, try to receive the body and
- * just skip it. */
- Log(("VBoxTray: VBoxIPCThread: Unknown message %ld, skipping ...\n", hdr.ulMsg));
- if (hdr.cbBody)
- rc = VBoxIPCSkipMessage(pCtx, &hdr);
+ {
+ /* Unknown command, reject. */
+ fRejected = true;
break;
+ }
}
+
+ if (RT_FAILURE(rc))
+ LogFunc(("Session %p: Handling command %RU32 failed with rc=%Rrc\n",
+ pThis, ipcHdr.uMsgType, rc));
}
- /* Disconnect the client from the pipe. */
- DisconnectNamedPipe(pCtx->hPipe);
+ if (fRejected)
+ {
+ static int s_cRejectedCmds = 0;
+ if (++s_cRejectedCmds <= 3)
+ {
+ LogRelFunc(("Session %p: Received invalid/unknown command %RU32 (%RU32 bytes), rejecting (%RU32/3)\n",
+ pThis, ipcHdr.uMsgType, ipcHdr.uMsgLen, s_cRejectedCmds + 1));
+ if (ipcHdr.uMsgLen)
+ {
+ /* Get and discard payload data. */
+ size_t cbRead;
+ uint8_t devNull[_1K];
+ while (ipcHdr.uMsgLen)
+ {
+ rc = RTLocalIpcSessionRead(hSession, &devNull, sizeof(devNull), &cbRead);
+ if (RT_FAILURE(rc))
+ break;
+ AssertRelease(cbRead <= ipcHdr.uMsgLen);
+ ipcHdr.uMsgLen -= (uint32_t)cbRead;
+ }
+ }
+ }
+ else
+ rc = VERR_INVALID_PARAMETER; /* Enough fun, bail out. */
+ }
+ }
+ }
+
+ LogFunc(("Session %p: Handler ended with rc=%Rrc\n",
+ pThis, rc));
+
+ /*
+ * Close the session.
+ */
+ int rc2 = RTLocalIpcSessionClose(hSession);
+ if (RT_FAILURE(rc2))
+ LogFunc(("Session %p: Failed closing session %p, rc=%Rrc\n", pThis, rc2));
+
+ /*
+ * Clean up the session.
+ */
+ PVBOXIPCCONTEXT pCtx = ASMAtomicReadPtrT(&pThis->pCtx, PVBOXIPCCONTEXT);
+ AssertMsg(pCtx, ("Session %p: No context found\n", pThis));
+ rc2 = RTCritSectEnter(&pCtx->CritSect);
+ if (RT_SUCCESS(rc2))
+ {
+ /* Remove this session from the session list. */
+ RTListNodeRemove(&pThis->Node);
+
+ rc2 = RTCritSectLeave(&pCtx->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ LogFunc(("Session %p: Terminated with rc=%Rrc, freeing ...\n",
+ pThis, rc));
+
+ RTMemFree(pThis);
+ pThis = NULL;
+
+ return rc;
+}
+
+static int vboxIPCSessionCreate(PVBOXIPCCONTEXT pCtx, RTLOCALIPCSESSION hSession)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
+
+ int rc = RTCritSectEnter(&pCtx->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXIPCSESSION pSession = (PVBOXIPCSESSION)RTMemAllocZ(sizeof(VBOXIPCSESSION));
+ if (pSession)
+ {
+ pSession->pCtx = pCtx;
+ pSession->hSession = hSession;
+ pSession->fTerminate = false;
+ pSession->hThread = NIL_RTTHREAD;
+
+ /* Start IPC session thread. */
+ LogFlowFunc(("Creating thread for session %p ...\n", pSession));
+ rc = RTThreadCreate(&pSession->hThread, vboxIPCSessionThread,
+ pSession /* pvUser */, 0 /* Default stack size */,
+ RTTHREADTYPE_DEFAULT, 0 /* Flags */, "VBXTRYIPCSESS");
+ if (RT_SUCCESS(rc))
+ {
+ /* Add session thread to session IPC list. */
+ RTListAppend(&pCtx->SessionList, &pSession->Node);
+ }
+ else
+ {
+ int rc2 = RTLocalIpcSessionClose(hSession);
+ if (RT_FAILURE(rc2))
+ LogFunc(("Failed closing session %p, rc=%Rrc\n", pSession, rc2));
+
+ LogFunc(("Failed to create thread for session %p, rc=%Rrc\n", pSession, rc));
+ RTMemFree(pSession);
+ }
}
else
- CloseHandle(pCtx->hPipe);
+ rc = VERR_NO_MEMORY;
+
+ int rc2 = RTCritSectLeave(&pCtx->CritSect);
+ AssertRC(rc2);
+ }
+
+ return rc;
+}
+
+static int vboxIPCSessionStop(PVBOXIPCSESSION pSession)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+
+ ASMAtomicWriteBool(&pSession->fTerminate, true);
+
+ RTLOCALIPCSESSION hSession;
+ ASMAtomicXchgHandle(&pSession->hSession, NIL_RTLOCALIPCSESSION, &hSession);
+ if (hSession)
+ return RTLocalIpcSessionClose(hSession);
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Thread function to wait for and process seamless mode change
+ * requests
+ */
+unsigned __stdcall VBoxIPCThread(void *pInstance)
+{
+ LogFlowFuncEnter();
+
+ PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
+ AssertPtr(pCtx);
+
+ bool fShutdown = false;
+ for (;;)
+ {
+ RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
+ int rc = RTLocalIpcServerListen(pCtx->hServer, &hClientSession);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_CANCELLED)
+ {
+ LogFlow(("Cancelled\n"));
+ fShutdown = true;
+ }
+ else
+ LogRelFunc(("Listening failed with rc=%Rrc\n", rc));
+ }
- /* Sleep a bit to not eat too much CPU in case the above call always fails. */
- if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
- fTerminate = true;
- if (fTerminate)
- Log(("VBoxTray: VBoxIPCThread: Terminating ...\n"));
- } while (!fTerminate);
+ if (fShutdown)
+ break;
+ rc = vboxIPCSessionCreate(pCtx, hClientSession);
+ if (RT_FAILURE(rc))
+ {
+ LogRelFunc(("Creating new IPC server session failed with rc=%Rrc\n", rc));
+ /* Keep going. */
+ }
+
+ AssertPtr(pCtx->pEnv);
+ if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0 /* No waiting */) == WAIT_OBJECT_0)
+ break;
+ }
- Log(("VBoxTray: VBoxIPCThread exited\n"));
+ LogFlowFuncLeave();
return 0;
}
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.h
index 5f3a531a..70ae2d0d 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.h
@@ -1,9 +1,12 @@
+/* $Id: VBoxIPC.h $ */
/** @file
- * VBoxSeamless - Seamless windows
+ * VBoxIPC - IPC thread, acts as a (purely) local IPC server.
+ * Multiple sessions are supported, whereas every session
+ * has its own thread for processing requests.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -14,12 +17,12 @@
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
-#ifndef __VBOXSERVICEIPC__H
-#define __VBOXSERVICEIPC__H
+#ifndef __VBOXTRAYIPCSERVER__H
+#define __VBOXTRAYIPCSERVER__H
-/* The seamless windows service prototypes */
-int VBoxIPCInit (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
-unsigned __stdcall VBoxIPCThread (void *pInstance);
-void VBoxIPCDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
+int VBoxIPCInit (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
+unsigned __stdcall VBoxIPCThread (void *pInstance);
+void VBoxIPCStop (const VBOXSERVICEENV *pEnv, void *pInstance);
+void VBoxIPCDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
-#endif /* __VBOXSERVICEIPC__H */
+#endif /* __VBOXTRAYIPCSERVER__H */
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxLA.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxLA.cpp
index 5856c728..a23219b7 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxLA.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxLA.cpp
@@ -26,6 +26,7 @@
#include <iprt/assert.h>
#include <iprt/alloc.h>
#include <iprt/list.h>
+#include <iprt/ldr.h>
#define LALOG(a) do { if (gCtx.fLogEnabled) LogRel(a); } while(0)
#define LALOGFORCE(a) do { LogRel(a); } while(0)
@@ -87,8 +88,6 @@ struct VBOXLACONTEXT
char *pszPropWaitPattern; /* Which properties are monitored. */
} activeClient;
- HMODULE hModuleKernel32;
-
BOOL (WINAPI * pfnProcessIdToSessionId)(DWORD dwProcessId, DWORD *pSessionId);
};
@@ -1249,16 +1248,7 @@ int VBoxLAInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThrea
RT_ZERO(gCtx.activeClient);
- gCtx.hModuleKernel32 = LoadLibrary("KERNEL32");
-
- if (gCtx.hModuleKernel32)
- {
- *(uintptr_t *)&gCtx.pfnProcessIdToSessionId = (uintptr_t)GetProcAddress(gCtx.hModuleKernel32, "ProcessIdToSessionId");
- }
- else
- {
- gCtx.pfnProcessIdToSessionId = NULL;
- }
+ *(void **)&gCtx.pfnProcessIdToSessionId = RTLdrGetSystemSymbol("kernel32.dll", "ProcessIdToSessionId");
*pfStartThread = true;
*ppInstance = &gCtx;
return VINF_SUCCESS;
@@ -1279,12 +1269,7 @@ void VBoxLADestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
ActionExecutorDeleteActions(&pCtx->listAttachActions);
ActionExecutorDeleteActions(&pCtx->listDetachActions);
- if (pCtx->hModuleKernel32)
- {
- FreeLibrary(pCtx->hModuleKernel32);
- pCtx->pfnProcessIdToSessionId = NULL;
- }
- pCtx->hModuleKernel32 = NULL;
+ pCtx->pfnProcessIdToSessionId = NULL;
}
/*
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.cpp
new file mode 100644
index 00000000..4708c0bc
--- /dev/null
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.cpp
@@ -0,0 +1,96 @@
+/* $Id: VBoxMMR.cpp $ */
+/** @file
+ * VBoxMMR - Multimedia Redirection
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "VBoxTray.h"
+#include "VBoxMMR.h"
+#include <iprt/ldr.h>
+
+struct VBOXMMRCONTEXT
+{
+ RTLDRMOD hModHook;
+ HHOOK hHook;
+};
+
+static VBOXMMRCONTEXT gCtx = {0};
+
+static const char *g_pszMMRDLL = "VBoxMMRHook";
+static const char *g_pszMMRPROC = "CBTProc";
+
+void VBoxMMRCleanup(VBOXMMRCONTEXT *pCtx)
+{
+ if (pCtx->hHook)
+ {
+ UnhookWindowsHookEx(pCtx->hHook);
+ pCtx->hHook = NULL;
+ }
+
+ if (pCtx->hModHook != NIL_RTLDRMOD)
+ {
+ RTLdrClose(pCtx->hModHook);
+ pCtx->hModHook = NIL_RTLDRMOD;
+ }
+}
+
+int VBoxMMRInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
+{
+ LogRel2(("VBoxMMR: Initializing\n"));
+
+ int rc = RTLdrLoadAppPriv(g_pszMMRDLL, &gCtx.hModHook);
+ if (RT_SUCCESS(rc))
+ {
+ HOOKPROC pHook = (HOOKPROC)RTLdrGetFunction(gCtx.hModHook, g_pszMMRPROC);
+ if (pHook)
+ {
+ HMODULE hMod = (HMODULE)RTLdrGetNativeHandle(gCtx.hModHook);
+ Assert(hMod != (HMODULE)~(uintptr_t)0);
+ gCtx.hHook = SetWindowsHookEx(WH_CBT, pHook, hMod, 0);
+ if (gCtx.hHook)
+ {
+ *ppInstance = &gCtx;
+ return VINF_SUCCESS;
+ }
+
+ rc = RTErrConvertFromWin32(GetLastError());
+ LogRel2(("VBoxMMR: Error installing hooking proc: %Rrc\n", rc));
+ }
+ else
+ {
+ LogRel2(("VBoxMMR: Hooking proc not found\n"));
+ rc = VERR_NOT_FOUND;
+ }
+
+ RTLdrClose(gCtx.hModHook);
+ gCtx.hModHook = NIL_RTLDRMOD;
+ }
+ else
+ LogRel2(("VBoxMMR: Hooking library not found (%Rrc)\n", rc));
+
+ return rc;
+}
+
+void VBoxMMRDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
+{
+ VBOXMMRCONTEXT *pCtx = (VBOXMMRCONTEXT *) pInstance;
+
+ VBoxMMRCleanup(pCtx);
+}
+
+unsigned __stdcall VBoxMMRThread(void *pInstance)
+{
+ return 0;
+}
+
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.h
new file mode 100644
index 00000000..40c80490
--- /dev/null
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxMMR.h
@@ -0,0 +1,33 @@
+/* $Id: VBoxMMR.h $ */
+/** @file
+ * VBoxMMR - Multimedia Redirection
+ */
+
+/*
+ * Copyright (C) 2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __VBOXSERVICEMMR__H
+#define __VBOXSERVICEMMR__H
+
+int VBoxMMRInit(
+ const VBOXSERVICEENV *pEnv,
+ void **ppInstance,
+ bool *pfStartThread);
+
+unsigned __stdcall VBoxMMRThread(
+ void *pInstance);
+
+void VBoxMMRDestroy(
+ const VBOXSERVICEENV *pEnv,
+ void *pInstance);
+
+#endif /* __VBOXSERVICEMMR__H */
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.cpp
index d66c5c9d..d95ba82d 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.h
index 1cab5da9..7a04d0c9 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxRestore.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.cpp
index 9c1fbecc..1b81c26d 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -24,16 +24,17 @@
#include <VBoxDisplay.h>
#include <VBox/VMMDev.h>
#include <iprt/assert.h>
+#include <iprt/ldr.h>
#include <VBoxGuestInternal.h>
typedef struct _VBOXSEAMLESSCONTEXT
{
const VBOXSERVICEENV *pEnv;
- HMODULE hModule;
+ RTLDRMOD hModHook;
- BOOL (* pfnVBoxInstallHook)(HMODULE hDll);
- BOOL (* pfnVBoxRemoveHook)();
+ BOOL (* pfnVBoxHookInstallWindowTracker)(HMODULE hDll);
+ BOOL (* pfnVBoxHookRemoveWindowTracker)();
PVBOXDISPIFESCAPE lpEscapeData;
} VBOXSEAMLESSCONTEXT;
@@ -54,6 +55,7 @@ int VBoxSeamlessInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStar
*pfStartThread = false;
gCtx.pEnv = pEnv;
+ gCtx.hModHook = NIL_RTLDRMOD;
OSVERSIONINFO OSinfo;
OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
@@ -71,27 +73,25 @@ int VBoxSeamlessInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStar
else
{
/* Will fail if SetWinEventHook is not present (version < NT4 SP6 apparently) */
- gCtx.hModule = LoadLibrary(VBOXHOOK_DLL_NAME);
- if (gCtx.hModule)
+ rc = RTLdrLoadAppPriv(VBOXHOOK_DLL_NAME, &gCtx.hModHook);
+ if (RT_SUCCESS(rc))
{
- *(uintptr_t *)&gCtx.pfnVBoxInstallHook = (uintptr_t)GetProcAddress(gCtx.hModule, "VBoxInstallHook");
- *(uintptr_t *)&gCtx.pfnVBoxRemoveHook = (uintptr_t)GetProcAddress(gCtx.hModule, "VBoxRemoveHook");
+ *(PFNRT *)&gCtx.pfnVBoxHookInstallWindowTracker = RTLdrGetFunction(gCtx.hModHook, "VBoxHookInstallWindowTracker");
+ *(PFNRT *)&gCtx.pfnVBoxHookRemoveWindowTracker = RTLdrGetFunction(gCtx.hModHook, "VBoxHookRemoveWindowTracker");
- /* Inform the host that we support the seamless window mode. */
- rc = VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_SEAMLESS, 0);
- if (RT_SUCCESS(rc))
+ /* rc should contain success status */
+ AssertRC(rc);
+
+ VBoxSeamlessSetSupported(TRUE);
+
+// if (RT_SUCCESS(rc))
{
*pfStartThread = true;
*ppInstance = &gCtx;
}
- else
- Log(("VBoxTray: VBoxSeamlessInit: Failed to set seamless capability\n"));
}
else
- {
- rc = RTErrConvertFromWin32(GetLastError());
Log(("VBoxTray: VBoxSeamlessInit: LoadLibrary of \"%s\" failed with rc=%Rrc\n", VBOXHOOK_DLL_NAME, rc));
- }
}
return rc;
@@ -102,34 +102,36 @@ void VBoxSeamlessDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
{
Log(("VBoxTray: VBoxSeamlessDestroy\n"));
+ VBoxSeamlessSetSupported(FALSE);
+
/* Inform the host that we no longer support the seamless window mode. */
- int rc = VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_SEAMLESS);
- if (RT_FAILURE(rc))
- Log(("VBoxTray: VBoxSeamlessDestroy: Failed to unset seamless capability, rc=%Rrc\n", rc));
-
- if (gCtx.pfnVBoxRemoveHook)
- gCtx.pfnVBoxRemoveHook();
- if (gCtx.hModule)
- FreeLibrary(gCtx.hModule);
- gCtx.hModule = 0;
+ if (gCtx.pfnVBoxHookRemoveWindowTracker)
+ gCtx.pfnVBoxHookRemoveWindowTracker();
+ if (gCtx.hModHook != NIL_RTLDRMOD)
+ {
+ RTLdrClose(gCtx.hModHook);
+ gCtx.hModHook = NIL_RTLDRMOD;
+ }
return;
}
-void VBoxSeamlessInstallHook()
+static void VBoxSeamlessInstallHook()
{
- if (gCtx.pfnVBoxInstallHook)
+ if (gCtx.pfnVBoxHookInstallWindowTracker)
{
/* Check current visible region state */
- VBoxSeamlessCheckWindows();
+ VBoxSeamlessCheckWindows(true);
- gCtx.pfnVBoxInstallHook(gCtx.hModule);
+ HMODULE hMod = (HMODULE)RTLdrGetNativeHandle(gCtx.hModHook);
+ Assert(hMod != (HMODULE)~(uintptr_t)0);
+ gCtx.pfnVBoxHookInstallWindowTracker(hMod);
}
}
-void VBoxSeamlessRemoveHook()
+static void VBoxSeamlessRemoveHook()
{
- if (gCtx.pfnVBoxRemoveHook)
- gCtx.pfnVBoxRemoveHook();
+ if (gCtx.pfnVBoxHookRemoveWindowTracker)
+ gCtx.pfnVBoxHookRemoveWindowTracker();
if (gCtx.lpEscapeData)
{
@@ -138,6 +140,27 @@ void VBoxSeamlessRemoveHook()
}
}
+extern HANDLE ghSeamlessKmNotifyEvent;
+
+static VBOXDISPIF_SEAMLESS gVBoxDispIfSeamless;
+
+
+void VBoxSeamlessEnable()
+{
+ Assert(ghSeamlessKmNotifyEvent);
+
+ VBoxDispIfSeamlesCreate(&gCtx.pEnv->dispIf, &gVBoxDispIfSeamless, ghSeamlessKmNotifyEvent);
+
+ VBoxSeamlessInstallHook();
+}
+
+void VBoxSeamlessDisable()
+{
+ VBoxSeamlessRemoveHook();
+
+ VBoxDispIfSeamlesTerm(&gVBoxDispIfSeamless);
+}
+
BOOL CALLBACK VBoxEnumFunc(HWND hwnd, LPARAM lParam)
{
PVBOX_ENUM_PARAM lpParam = (PVBOX_ENUM_PARAM)lParam;
@@ -154,27 +177,60 @@ BOOL CALLBACK VBoxEnumFunc(HWND hwnd, LPARAM lParam)
/* Only visible windows that are present on the desktop are interesting here */
if (GetWindowRect(hwnd, &rectWindow))
{
- rectVisible = rectWindow;
-
char szWindowText[256];
szWindowText[0] = 0;
+ OSVERSIONINFO OSinfo;
+ HWND hStart = NULL;
GetWindowText(hwnd, szWindowText, sizeof(szWindowText));
+ OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
+ GetVersionEx (&OSinfo);
+ if (OSinfo.dwMajorVersion >= 6)
+ {
+ hStart = ::FindWindowEx(GetDesktopWindow(), NULL, "Button", "Start");
+ if ( hwnd == hStart && szWindowText != NULL
+ && !(strcmp(szWindowText, "Start"))
+ )
+ {
+ /* for vista and above. To solve the issue of small bar above
+ * the Start button when mouse is hovered over the start button in seamless mode.
+ * Difference of 7 is observed in Win 7 platform between the dimensionsof rectangle with Start title and its shadow.
+ */
+ rectWindow.top += 7;
+ rectWindow.bottom -=7;
+ }
+ }
+ rectVisible = rectWindow;
+
+#ifdef LOG_ENABLED
+ DWORD pid = 0;
+ DWORD tid = GetWindowThreadProcessId(hwnd, &pid);
+#endif
/* Filter out Windows XP shadow windows */
/** @todo still shows inside the guest */
if ( szWindowText[0] == 0
- && dwStyle == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS)
- && dwExStyle == (WS_EX_LAYERED|WS_EX_TOOLWINDOW|WS_EX_TRANSPARENT|WS_EX_TOPMOST))
+ && (
+ (dwStyle == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS)
+ && dwExStyle == (WS_EX_LAYERED|WS_EX_TOOLWINDOW|WS_EX_TRANSPARENT|WS_EX_TOPMOST))
+ || (dwStyle == (WS_POPUP|WS_VISIBLE|WS_DISABLED|WS_CLIPSIBLINGS|WS_CLIPCHILDREN)
+ && dwExStyle == (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE))
+ || (dwStyle == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN)
+ && dwExStyle == (WS_EX_TOOLWINDOW))
+ ))
{
Log(("VBoxTray: Filter out shadow window style=%x exstyle=%x\n", dwStyle, dwExStyle));
+ Log(("VBoxTray: Enum hwnd=%x rect (%d,%d) (%d,%d) (filtered)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
+ Log(("VBoxTray: title=%s style=%x exStyle=%x\n", szWindowText, dwStyle, dwExStyle));
+ Log(("VBoxTray: pid=%d tid=%d\n", pid, tid));
return TRUE;
}
/** @todo will this suffice? The Program Manager window covers the whole screen */
if (strcmp(szWindowText, "Program Manager"))
{
- Log(("VBoxTray: Enum hwnd=%x rect (%d,%d) (%d,%d)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
+ Log(("VBoxTray: Enum hwnd=%x rect (%d,%d) (%d,%d) (applying)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
Log(("VBoxTray: title=%s style=%x exStyle=%x\n", szWindowText, dwStyle, dwExStyle));
+ Log(("VBoxTray: pid=%d tid=%d\n", pid, tid));
HRGN hrgn = CreateRectRgn(0,0,0,0);
@@ -203,13 +259,17 @@ BOOL CALLBACK VBoxEnumFunc(HWND hwnd, LPARAM lParam)
{
Log(("VBoxTray: Enum hwnd=%x rect (%d,%d) (%d,%d) (ignored)\n", hwnd, rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom));
Log(("VBoxTray: title=%s style=%x\n", szWindowText, dwStyle));
+ Log(("VBoxTray: pid=%d tid=%d\n", pid, tid));
}
}
return TRUE; /* continue enumeration */
}
-void VBoxSeamlessCheckWindows()
+void VBoxSeamlessCheckWindows(bool fForce)
{
+ if (!VBoxDispIfSeamlesIsValid(&gVBoxDispIfSeamless))
+ return;
+
VBOX_ENUM_PARAM param;
param.hdc = GetDC(HWND_DESKTOP);
@@ -243,12 +303,13 @@ void VBoxSeamlessCheckWindows()
}
#endif
LPRGNDATA lpCtxRgnData = VBOXDISPIFESCAPE_DATA(gCtx.lpEscapeData, RGNDATA);
- if ( !gCtx.lpEscapeData
+ if (fForce
+ || !gCtx.lpEscapeData
|| (lpCtxRgnData->rdh.dwSize + lpCtxRgnData->rdh.nRgnSize != cbSize)
|| memcmp(lpCtxRgnData, lpRgnData, cbSize))
{
/* send to display driver */
- VBoxDispIfEscape(&gCtx.pEnv->dispIf, lpEscapeData, cbSize);
+ VBoxDispIfSeamlesSubmit(&gVBoxDispIfSeamless, lpEscapeData, cbSize);
if (gCtx.lpEscapeData)
free(gCtx.lpEscapeData);
@@ -341,7 +402,7 @@ unsigned __stdcall VBoxSeamlessThread(void *pInstance)
if (!ret)
Log(("VBoxTray: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
}
- PostMessage(ghwndToolWindow, WM_VBOX_REMOVE_SEAMLESS_HOOK, 0, 0);
+ PostMessage(ghwndToolWindow, WM_VBOX_SEAMLESS_DISABLE, 0, 0);
break;
case VMMDev_Seamless_Visible_Region:
@@ -355,7 +416,7 @@ unsigned __stdcall VBoxSeamlessThread(void *pInstance)
ret = SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
if (!ret)
Log(("VBoxTray: SystemParametersInfo SPI_SETSCREENSAVEACTIVE failed with %d\n", GetLastError()));
- PostMessage(ghwndToolWindow, WM_VBOX_INSTALL_SEAMLESS_HOOK, 0, 0);
+ PostMessage(ghwndToolWindow, WM_VBOX_SEAMLESS_ENABLE, 0, 0);
break;
case VMMDev_Seamless_Host_Window:
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.h
index bf4bfb87..e093d042 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxSeamless.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -23,8 +23,10 @@ unsigned __stdcall VBoxSeamlessThread (void *pInstance);
void VBoxSeamlessDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
-void VBoxSeamlessInstallHook();
-void VBoxSeamlessRemoveHook();
-void VBoxSeamlessCheckWindows();
+void VBoxSeamlessEnable();
+void VBoxSeamlessDisable();
+void VBoxSeamlessCheckWindows(bool fForce);
+
+void VBoxSeamlessSetSupported(BOOL fSupported);
#endif /* __VBOXSERVICESEAMLESS__H */
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxSharedFolders.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxSharedFolders.cpp
index 2ac9d078..400562e3 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxSharedFolders.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxSharedFolders.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -26,9 +26,7 @@ int VBoxSharedFoldersAutoMount(void)
{
uint32_t u32ClientId;
int rc = VbglR3SharedFolderConnect(&u32ClientId);
- if (RT_FAILURE(rc))
- Log(("VBoxTray: Failed to connect to the shared folder service, error %Rrc\n", rc));
- else
+ if (RT_SUCCESS(rc))
{
uint32_t cMappings;
VBGLR3SHAREDFOLDERMAPPING *paMappings;
@@ -127,6 +125,12 @@ int VBoxSharedFoldersAutoMount(void)
Log(("VBoxTray: Error while getting the shared folder mappings, rc = %Rrc\n", rc));
VbglR3SharedFolderDisconnect(u32ClientId);
}
+ else
+ {
+ Log(("VBoxTray: Failed to connect to the shared folder service, error %Rrc\n", rc));
+ /* return success, otherwise VBoxTray will not start! */
+ rc = VINF_SUCCESS;
+ }
return rc;
}
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
index 7bcf3cdc..e9862389 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,6 +31,7 @@
#include "VBoxSharedFolders.h"
#include "VBoxIPC.h"
#include "VBoxLA.h"
+#include "VBoxMMR.h"
#include <VBoxHook.h>
#include "resource.h"
#include <malloc.h>
@@ -39,7 +40,71 @@
#include <sddl.h>
#include <iprt/buildconfig.h>
+#include <iprt/ldr.h>
+/* Default desktop state tracking */
+#include <Wtsapi32.h>
+
+/*
+ * St (session [state] tracking) functionality API
+ *
+ * !!!NOTE: this API is NOT thread-safe!!!
+ * it is supposed to be called & used from within the window message handler thread
+ * of the window passed to vboxStInit */
+static int vboxStInit(HWND hWnd);
+static void vboxStTerm(void);
+/* @returns true on "IsActiveConsole" state change */
+static BOOL vboxStHandleEvent(WPARAM EventID, LPARAM SessionID);
+static BOOL vboxStIsActiveConsole();
+static BOOL vboxStCheckTimer(WPARAM wEvent);
+
+/*
+ * Dt (desktop [state] tracking) functionality API
+ *
+ * !!!NOTE: this API is NOT thread-safe!!!
+ * */
+static int vboxDtInit();
+static void vboxDtTerm();
+/* @returns true on "IsInputDesktop" state change */
+static BOOL vboxDtHandleEvent();
+/* @returns true iff the application (VBoxTray) desktop is input */
+static BOOL vboxDtIsInputDesktop();
+static HANDLE vboxDtGetNotifyEvent();
+static BOOL vboxDtCheckTimer(WPARAM wParam);
+
+/* caps API */
+#define VBOXCAPS_ENTRY_IDX_SEAMLESS 0
+#define VBOXCAPS_ENTRY_IDX_GRAPHICS 1
+#define VBOXCAPS_ENTRY_IDX_COUNT 2
+
+typedef enum VBOXCAPS_ENTRY_FUNCSTATE
+{
+ /* the cap is unsupported */
+ VBOXCAPS_ENTRY_FUNCSTATE_UNSUPPORTED = 0,
+ /* the cap is supported */
+ VBOXCAPS_ENTRY_FUNCSTATE_SUPPORTED,
+ /* the cap functionality is started, it can be disabled however if its AcState is not ACQUIRED */
+ VBOXCAPS_ENTRY_FUNCSTATE_STARTED,
+} VBOXCAPS_ENTRY_FUNCSTATE;
+
+
+static void VBoxCapsEntryFuncStateSet(uint32_t iCup, VBOXCAPS_ENTRY_FUNCSTATE enmFuncState);
+static int VBoxCapsInit();
+static int VBoxCapsReleaseAll();
+static void VBoxCapsTerm();
+static BOOL VBoxCapsEntryIsAcquired(uint32_t iCap);
+static BOOL VBoxCapsEntryIsEnabled(uint32_t iCap);
+static BOOL VBoxCapsCheckTimer(WPARAM wParam);
+static int VBoxCapsEntryRelease(uint32_t iCap);
+static int VBoxCapsEntryAcquire(uint32_t iCap);
+static int VBoxCapsAcquireAllSupported();
+
+/* console-related caps API */
+static BOOL VBoxConsoleIsAllowed();
+static void VBoxConsoleEnable(BOOL fEnable);
+static void VBoxConsoleCapSetSupported(uint32_t iCap, BOOL fSupported);
+
+static void VBoxGrapicsSetSupported(BOOL fSupported);
/*******************************************************************************
* Internal Functions *
@@ -51,13 +116,15 @@ static LRESULT CALLBACK vboxToolWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
static int vboxTrayGlMsgTaskbarCreated(WPARAM lParam, LPARAM wParam);
/*static int vboxTrayGlMsgShowBalloonMsg(WPARAM lParam, LPARAM wParam);*/
+static int VBoxAcquireGuestCaps(uint32_t fOr, uint32_t fNot, bool fCfg);
/*******************************************************************************
* Global Variables *
*******************************************************************************/
HANDLE ghVBoxDriver;
HANDLE ghStopSem;
-HANDLE ghSeamlessNotifyEvent = 0;
+HANDLE ghSeamlessWtNotifyEvent = 0;
+HANDLE ghSeamlessKmNotifyEvent = 0;
SERVICE_STATUS gVBoxServiceStatus;
SERVICE_STATUS_HANDLE gVBoxServiceStatusHandle;
HINSTANCE ghInstance;
@@ -73,18 +140,21 @@ static VBOXSERVICEINFO vboxServiceTable[] =
"Display",
VBoxDisplayInit,
VBoxDisplayThread,
+ NULL /* pfnStop */,
VBoxDisplayDestroy
},
{
"Shared Clipboard",
VBoxClipboardInit,
VBoxClipboardThread,
+ NULL /* pfnStop */,
VBoxClipboardDestroy
},
{
"Seamless Windows",
VBoxSeamlessInit,
VBoxSeamlessThread,
+ NULL /* pfnStop */,
VBoxSeamlessDestroy
},
#ifdef VBOX_WITH_VRDP_SESSION_HANDLING
@@ -92,6 +162,7 @@ static VBOXSERVICEINFO vboxServiceTable[] =
"Restore",
VBoxRestoreInit,
VBoxRestoreThread,
+ NULL /* pfnStop */,
VBoxRestoreDestroy
},
#endif
@@ -99,20 +170,32 @@ static VBOXSERVICEINFO vboxServiceTable[] =
"VRDP",
VBoxVRDPInit,
VBoxVRDPThread,
+ NULL /* pfnStop */,
VBoxVRDPDestroy
},
{
"IPC",
VBoxIPCInit,
VBoxIPCThread,
+ VBoxIPCStop,
VBoxIPCDestroy
},
{
"Location Awareness",
VBoxLAInit,
VBoxLAThread,
+ NULL /* pfnStop */,
VBoxLADestroy
},
+#ifdef VBOX_WITH_MMR
+ {
+ "Multimedia Redirection",
+ VBoxMMRInit,
+ VBoxMMRThread,
+ NULL /* pfnStop */,
+ VBoxMMRDestroy
+ },
+#endif
{
NULL
}
@@ -203,9 +286,14 @@ static void vboxTrayRemoveTrayIcon()
static int vboxTrayStartServices(VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
{
+ AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
+ AssertPtrReturn(pTable, VERR_INVALID_POINTER);
+
Log(("VBoxTray: Starting services ...\n"));
- pEnv->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ /** @todo Use IPRT events here. */
+ pEnv->hStopEvent = CreateEvent(NULL, TRUE /* bManualReset */,
+ FALSE /* bInitialState */, NULL);
if (!pEnv->hStopEvent)
{
@@ -213,7 +301,8 @@ static int vboxTrayStartServices(VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
return VERR_NOT_SUPPORTED;
}
- while (pTable->pszName)
+ while ( pTable
+ && pTable->pszName)
{
Log(("VBoxTray: Starting %s ...\n", pTable->pszName));
@@ -226,24 +315,26 @@ static int vboxTrayStartServices(VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
pTable->fStarted = false;
if (pTable->pfnInit)
- rc = pTable->pfnInit (pEnv, &pTable->pInstance, &fStartThread);
+ rc = pTable->pfnInit(pEnv, &pTable->pInstance, &fStartThread);
if (RT_FAILURE(rc))
{
- Log(("VBoxTray: Failed to initialize rc = %Rrc\n", rc));
+ LogRel(("VBoxTray: Failed to initialize service \"%s\", rc=%Rrc\n",
+ pTable->pszName, rc));
}
else
{
- if (pTable->pfnThread && fStartThread)
+ if ( pTable->pfnThread
+ && fStartThread)
{
unsigned threadid;
+ /** @todo Use RTThread* here. */
pTable->hThread = (HANDLE)_beginthreadex(NULL, /* security */
0, /* stacksize */
pTable->pfnThread,
pTable->pInstance,
0, /* initflag */
&threadid);
-
if (pTable->hThread == (HANDLE)(0))
rc = VERR_NOT_SUPPORTED;
}
@@ -273,26 +364,42 @@ static void vboxTrayStopServices(VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
/* Signal to all threads. */
SetEvent(pEnv->hStopEvent);
- while (pTable->pszName)
+ VBOXSERVICEINFO *pCurTable = pTable;
+ while ( pCurTable
+ && pCurTable->pszName)
{
- if (pTable->fStarted)
+ if (pCurTable->pfnStop)
+ pCurTable->pfnStop(pEnv, pCurTable->pInstance);
+
+ /* Advance to next table element. */
+ pCurTable++;
+ }
+
+ pCurTable = pTable; /* Reset to first element. */
+ while ( pCurTable
+ && pCurTable->pszName)
+ {
+ if (pCurTable->fStarted)
{
- if (pTable->pfnThread)
+ if (pCurTable->pfnThread)
{
/* There is a thread, wait for termination. */
- WaitForSingleObject(pTable->hThread, INFINITE);
+ /** @todo Use RTThread* here. */
+ /** @todo Don't wait forever here. Use a sensible default. */
+ WaitForSingleObject(pCurTable->hThread, INFINITE);
- CloseHandle(pTable->hThread);
- pTable->hThread = 0;
+ /** @todo Dito. */
+ CloseHandle(pCurTable->hThread);
+ pCurTable->hThread = NULL;
}
- if (pTable->pfnDestroy)
- pTable->pfnDestroy (pEnv, pTable->pInstance);
- pTable->fStarted = false;
+ if (pCurTable->pfnDestroy)
+ pCurTable->pfnDestroy(pEnv, pCurTable->pInstance);
+ pCurTable->fStarted = false;
}
/* Advance to next table element. */
- pTable++;
+ pCurTable++;
}
CloseHandle(pEnv->hStopEvent);
@@ -464,48 +571,38 @@ static int vboxTraySetupSeamless(void)
if (gMajorVersion >= 6)
{
BOOL (WINAPI * pfnConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR StringSecurityDescriptor, DWORD StringSDRevision, PSECURITY_DESCRIPTOR *SecurityDescriptor, PULONG SecurityDescriptorSize);
-
- HMODULE hModule = LoadLibrary("ADVAPI32.DLL");
- if (!hModule)
- {
- dwErr = GetLastError();
- Log(("VBoxTray: Loading module ADVAPI32.DLL failed with last error = %08X\n", dwErr));
- }
- else
+ *(void **)&pfnConvertStringSecurityDescriptorToSecurityDescriptorA =
+ RTLdrGetSystemSymbol("advapi32.dll", "ConvertStringSecurityDescriptorToSecurityDescriptorA");
+ Log(("VBoxTray: pfnConvertStringSecurityDescriptorToSecurityDescriptorA = %x\n", pfnConvertStringSecurityDescriptorToSecurityDescriptorA));
+ if (pfnConvertStringSecurityDescriptorToSecurityDescriptorA)
{
PSECURITY_DESCRIPTOR pSD;
PACL pSacl = NULL;
BOOL fSaclPresent = FALSE;
BOOL fSaclDefaulted = FALSE;
- *(uintptr_t *)&pfnConvertStringSecurityDescriptorToSecurityDescriptorA = (uintptr_t)GetProcAddress(hModule, "ConvertStringSecurityDescriptorToSecurityDescriptorA");
-
- Log(("VBoxTray: pfnConvertStringSecurityDescriptorToSecurityDescriptorA = %x\n", pfnConvertStringSecurityDescriptorToSecurityDescriptorA));
- if (pfnConvertStringSecurityDescriptorToSecurityDescriptorA)
+ fRC = pfnConvertStringSecurityDescriptorToSecurityDescriptorA("S:(ML;;NW;;;LW)", /* this means "low integrity" */
+ SDDL_REVISION_1, &pSD, NULL);
+ if (!fRC)
+ {
+ dwErr = GetLastError();
+ Log(("VBoxTray: ConvertStringSecurityDescriptorToSecurityDescriptorA failed with last error = %08X\n", dwErr));
+ }
+ else
{
- fRC = pfnConvertStringSecurityDescriptorToSecurityDescriptorA("S:(ML;;NW;;;LW)", /* this means "low integrity" */
- SDDL_REVISION_1, &pSD, NULL);
+ fRC = GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted);
if (!fRC)
{
dwErr = GetLastError();
- Log(("VBoxTray: ConvertStringSecurityDescriptorToSecurityDescriptorA failed with last error = %08X\n", dwErr));
+ Log(("VBoxTray: GetSecurityDescriptorSacl failed with last error = %08X\n", dwErr));
}
else
{
- fRC = GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted);
+ fRC = SetSecurityDescriptorSacl(SecAttr.lpSecurityDescriptor, TRUE, pSacl, FALSE);
if (!fRC)
{
dwErr = GetLastError();
- Log(("VBoxTray: GetSecurityDescriptorSacl failed with last error = %08X\n", dwErr));
- }
- else
- {
- fRC = SetSecurityDescriptorSacl(SecAttr.lpSecurityDescriptor, TRUE, pSacl, FALSE);
- if (!fRC)
- {
- dwErr = GetLastError();
- Log(("VBoxTray: SetSecurityDescriptorSacl failed with last error = %08X\n", dwErr));
- }
+ Log(("VBoxTray: SetSecurityDescriptorSacl failed with last error = %08X\n", dwErr));
}
}
}
@@ -515,8 +612,15 @@ static int vboxTraySetupSeamless(void)
if ( dwErr == ERROR_SUCCESS
&& gMajorVersion >= 5) /* Only for W2K and up ... */
{
- ghSeamlessNotifyEvent = CreateEvent(&SecAttr, FALSE, FALSE, VBOXHOOK_GLOBAL_EVENT_NAME);
- if (ghSeamlessNotifyEvent == NULL)
+ ghSeamlessWtNotifyEvent = CreateEvent(&SecAttr, FALSE, FALSE, VBOXHOOK_GLOBAL_WT_EVENT_NAME);
+ if (ghSeamlessWtNotifyEvent == NULL)
+ {
+ dwErr = GetLastError();
+ Log(("VBoxTray: CreateEvent for Seamless failed, last error = %08X\n", dwErr));
+ }
+
+ ghSeamlessKmNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (ghSeamlessKmNotifyEvent == NULL)
{
dwErr = GetLastError();
Log(("VBoxTray: CreateEvent for Seamless failed, last error = %08X\n", dwErr));
@@ -528,10 +632,26 @@ static int vboxTraySetupSeamless(void)
static void vboxTrayShutdownSeamless(void)
{
- if (ghSeamlessNotifyEvent)
+ if (ghSeamlessWtNotifyEvent)
+ {
+ CloseHandle(ghSeamlessWtNotifyEvent);
+ ghSeamlessWtNotifyEvent = NULL;
+ }
+
+ if (ghSeamlessKmNotifyEvent)
+ {
+ CloseHandle(ghSeamlessKmNotifyEvent);
+ ghSeamlessKmNotifyEvent = NULL;
+ }
+}
+
+static void VBoxTrayCheckDt()
+{
+ BOOL fOldAllowedState = VBoxConsoleIsAllowed();
+ if (vboxDtHandleEvent())
{
- CloseHandle(ghSeamlessNotifyEvent);
- ghSeamlessNotifyEvent = NULL;
+ if (!VBoxConsoleIsAllowed() != !fOldAllowedState)
+ VBoxConsoleEnable(!fOldAllowedState);
}
}
@@ -607,11 +727,26 @@ static int vboxTrayServiceMain(void)
* Wait for the stop semaphore to be posted or a window event to arrive
*/
- DWORD dwEventCount = 2;
- HANDLE hWaitEvent[2] = { ghStopSem, ghSeamlessNotifyEvent };
+ HANDLE hWaitEvent[4] = {0};
+ DWORD dwEventCount = 0;
- if (0 == ghSeamlessNotifyEvent) /* If seamless mode is not active / supported, reduce event array count. */
- dwEventCount = 1;
+ hWaitEvent[dwEventCount++] = ghStopSem;
+
+ /* Check if seamless mode is not active and add seamless event to the list */
+ if (0 != ghSeamlessWtNotifyEvent)
+ {
+ hWaitEvent[dwEventCount++] = ghSeamlessWtNotifyEvent;
+ }
+
+ if (0 != ghSeamlessKmNotifyEvent)
+ {
+ hWaitEvent[dwEventCount++] = ghSeamlessKmNotifyEvent;
+ }
+
+ if (0 != vboxDtGetNotifyEvent())
+ {
+ hWaitEvent[dwEventCount++] = vboxDtGetNotifyEvent();
+ }
Log(("VBoxTray: Number of events to wait in main loop: %ld\n", dwEventCount));
while (true)
@@ -628,29 +763,53 @@ static int vboxTrayServiceMain(void)
/* exit */
break;
}
- else if ( waitResult == 1
- && ghSeamlessNotifyEvent != 0) /* Only jump in, if seamless is active! */
- {
- Log(("VBoxTray: Event 'Seamless' triggered\n"));
-
- /* seamless window notification */
- VBoxSeamlessCheckWindows();
- }
else
{
- /* timeout or a window message, handle it */
- MSG msg;
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ BOOL fHandled = FALSE;
+ if (waitResult < RT_ELEMENTS(hWaitEvent))
{
- Log(("VBoxTray: msg %p\n", msg.message));
- if (msg.message == WM_QUIT)
+ if (hWaitEvent[waitResult])
{
- Log(("VBoxTray: WM_QUIT!\n"));
- SetEvent(ghStopSem);
- continue;
+ if (hWaitEvent[waitResult] == ghSeamlessWtNotifyEvent)
+ {
+ Log(("VBoxTray: Event 'Seamless' triggered\n"));
+
+ /* seamless window notification */
+ VBoxSeamlessCheckWindows(false);
+ fHandled = TRUE;
+ }
+ else if (hWaitEvent[waitResult] == ghSeamlessKmNotifyEvent)
+ {
+ Log(("VBoxTray: Event 'Km Seamless' triggered\n"));
+
+ /* seamless window notification */
+ VBoxSeamlessCheckWindows(true);
+ fHandled = TRUE;
+ }
+ else if (hWaitEvent[waitResult] == vboxDtGetNotifyEvent())
+ {
+ Log(("VBoxTray: Event 'Dt' triggered\n"));
+ VBoxTrayCheckDt();
+ fHandled = TRUE;
+ }
+ }
+ }
+
+ if (!fHandled)
+ {
+ /* timeout or a window message, handle it */
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ Log(("VBoxTray: msg %p\n", msg.message));
+ if (msg.message == WM_QUIT)
+ {
+ Log(("VBoxTray: WM_QUIT!\n"));
+ SetEvent(ghStopSem);
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
}
- TranslateMessage(&msg);
- DispatchMessage(&msg);
}
}
}
@@ -703,6 +862,34 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
rc = vboxTrayCreateToolWindow();
if (RT_SUCCESS(rc))
{
+ VBoxCapsInit();
+
+ rc = vboxStInit(ghwndToolWindow);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxTray: vboxStInit failed, rc %d\n"));
+ /* ignore the St Init failure. this can happen for < XP win that do not support WTS API
+ * in that case the session is treated as active connected to the physical console
+ * (i.e. fallback to the old behavior that was before introduction of VBoxSt) */
+ Assert(vboxStIsActiveConsole());
+ }
+
+ rc = vboxDtInit();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxTray: vboxDtInit failed, rc %d\n"));
+ /* ignore the Dt Init failure. this can happen for < XP win that do not support WTS API
+ * in that case the session is treated as active connected to the physical console
+ * (i.e. fallback to the old behavior that was before introduction of VBoxSt) */
+ Assert(vboxDtIsInputDesktop());
+ }
+
+ rc = VBoxAcquireGuestCaps(VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0, true);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxAcquireGuestCaps cfg failed rc %d, ignoring..\n", rc));
+ }
+
rc = vboxTraySetupSeamless();
if (RT_SUCCESS(rc))
{
@@ -712,6 +899,15 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
hlpReportStatus(VBoxGuestFacilityStatus_Terminating);
vboxTrayShutdownSeamless();
}
+
+ /* it should be safe to call vboxDtTerm even if vboxStInit above failed */
+ vboxDtTerm();
+
+ /* it should be safe to call vboxStTerm even if vboxStInit above failed */
+ vboxStTerm();
+
+ VBoxCapsTerm();
+
vboxTrayDestroyToolWindow();
}
if (RT_SUCCESS(rc))
@@ -763,6 +959,13 @@ static LRESULT CALLBACK vboxToolWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
return 0;
case WM_TIMER:
+ if (VBoxCapsCheckTimer(wParam))
+ return 0;
+ if (vboxDtCheckTimer(wParam))
+ return 0;
+ if (vboxStCheckTimer(wParam))
+ return 0;
+
switch (wParam)
{
case TIMERID_VBOXTRAY_CHECK_HOSTVERSION:
@@ -789,16 +992,26 @@ static LRESULT CALLBACK vboxToolWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
}
return 0;
- case WM_VBOX_INSTALL_SEAMLESS_HOOK:
- VBoxSeamlessInstallHook();
+ case WM_VBOX_SEAMLESS_ENABLE:
+ VBoxCapsEntryFuncStateSet(VBOXCAPS_ENTRY_IDX_SEAMLESS, VBOXCAPS_ENTRY_FUNCSTATE_STARTED);
return 0;
- case WM_VBOX_REMOVE_SEAMLESS_HOOK:
- VBoxSeamlessRemoveHook();
+ case WM_VBOX_SEAMLESS_DISABLE:
+ VBoxCapsEntryFuncStateSet(VBOXCAPS_ENTRY_IDX_SEAMLESS, VBOXCAPS_ENTRY_FUNCSTATE_SUPPORTED);
return 0;
+ case WM_DISPLAYCHANGE:
case WM_VBOX_SEAMLESS_UPDATE:
- VBoxSeamlessCheckWindows();
+ if (VBoxCapsEntryIsEnabled(VBOXCAPS_ENTRY_IDX_SEAMLESS))
+ VBoxSeamlessCheckWindows(true);
+ return 0;
+
+ case WM_VBOX_GRAPHICS_SUPPORTED:
+ VBoxGrapicsSetSupported(TRUE);
+ return 0;
+
+ case WM_VBOX_GRAPHICS_UNSUPPORTED:
+ VBoxGrapicsSetSupported(FALSE);
return 0;
case WM_VBOXTRAY_VM_RESTORED:
@@ -809,6 +1022,16 @@ static LRESULT CALLBACK vboxToolWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
VBoxRestoreCheckVRDP();
return 0;
+ case WM_WTSSESSION_CHANGE:
+ {
+ BOOL fOldAllowedState = VBoxConsoleIsAllowed();
+ if (vboxStHandleEvent(wParam, lParam))
+ {
+ if (!VBoxConsoleIsAllowed() != !fOldAllowedState)
+ VBoxConsoleEnable(!fOldAllowedState);
+ }
+ return 0;
+ }
default:
/* Handle all globally registered window messages. */
@@ -825,3 +1048,771 @@ static LRESULT CALLBACK vboxToolWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
+/* St (session [state] tracking) functionality API impl */
+
+typedef struct VBOXST
+{
+ HWND hWTSAPIWnd;
+ RTLDRMOD hLdrModWTSAPI32;
+ BOOL fIsConsole;
+ WTS_CONNECTSTATE_CLASS enmConnectState;
+ UINT_PTR idDelayedInitTimer;
+ BOOL (WINAPI * pfnWTSRegisterSessionNotification)(HWND hWnd, DWORD dwFlags);
+ BOOL (WINAPI * pfnWTSUnRegisterSessionNotification)(HWND hWnd);
+ BOOL (WINAPI * pfnWTSQuerySessionInformationA)(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR *ppBuffer, DWORD *pBytesReturned);
+} VBOXST;
+
+static VBOXST gVBoxSt;
+
+static int vboxStCheckState()
+{
+ int rc = VINF_SUCCESS;
+ WTS_CONNECTSTATE_CLASS *penmConnectState = NULL;
+ USHORT *pProtocolType = NULL;
+ DWORD cbBuf = 0;
+ if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState,
+ (LPTSTR *)&penmConnectState, &cbBuf))
+ {
+ if (gVBoxSt.pfnWTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSClientProtocolType,
+ (LPTSTR *)&pProtocolType, &cbBuf))
+ {
+ gVBoxSt.fIsConsole = (*pProtocolType == 0);
+ gVBoxSt.enmConnectState = *penmConnectState;
+ return VINF_SUCCESS;
+ }
+
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: WTSQuerySessionInformationA WTSClientProtocolType failed, error = %08X\n", dwErr));
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: WTSQuerySessionInformationA WTSConnectState failed, error = %08X\n", dwErr));
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+
+ /* failure branch, set to "console-active" state */
+ gVBoxSt.fIsConsole = TRUE;
+ gVBoxSt.enmConnectState = WTSActive;
+
+ return rc;
+}
+
+static int vboxStInit(HWND hWnd)
+{
+ RT_ZERO(gVBoxSt);
+ int rc = RTLdrLoadSystem("WTSAPI32.DLL", false /*fNoUnload*/, &gVBoxSt.hLdrModWTSAPI32);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSRegisterSessionNotification",
+ (void **)&gVBoxSt.pfnWTSRegisterSessionNotification);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSUnRegisterSessionNotification",
+ (void **)&gVBoxSt.pfnWTSUnRegisterSessionNotification);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(gVBoxSt.hLdrModWTSAPI32, "WTSQuerySessionInformationA",
+ (void **)&gVBoxSt.pfnWTSQuerySessionInformationA);
+ if (RT_FAILURE(rc))
+ WARN(("VBoxTray: WTSQuerySessionInformationA not found\n"));
+ }
+ else
+ WARN(("VBoxTray: WTSUnRegisterSessionNotification not found\n"));
+ }
+ else
+ WARN(("VBoxTray: WTSRegisterSessionNotification not found\n"));
+ if (RT_SUCCESS(rc))
+ {
+ gVBoxSt.hWTSAPIWnd = hWnd;
+ if (gVBoxSt.pfnWTSRegisterSessionNotification(gVBoxSt.hWTSAPIWnd, NOTIFY_FOR_THIS_SESSION))
+ vboxStCheckState();
+ else
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: WTSRegisterSessionNotification failed, error = %08X\n", dwErr));
+ if (dwErr == RPC_S_INVALID_BINDING)
+ {
+ gVBoxSt.idDelayedInitTimer = SetTimer(gVBoxSt.hWTSAPIWnd, TIMERID_VBOXTRAY_ST_DELAYED_INIT_TIMER,
+ 2000, (TIMERPROC)NULL);
+ gVBoxSt.fIsConsole = TRUE;
+ gVBoxSt.enmConnectState = WTSActive;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ }
+
+ RTLdrClose(gVBoxSt.hLdrModWTSAPI32);
+ }
+ else
+ WARN(("VBoxTray: WTSAPI32 load failed, rc = %Rrc\n", rc));
+
+ RT_ZERO(gVBoxSt);
+ gVBoxSt.fIsConsole = TRUE;
+ gVBoxSt.enmConnectState = WTSActive;
+ return rc;
+}
+
+static void vboxStTerm(void)
+{
+ if (!gVBoxSt.hWTSAPIWnd)
+ {
+ WARN(("VBoxTray: vboxStTerm called for non-initialized St\n"));
+ return;
+ }
+
+ if (gVBoxSt.idDelayedInitTimer)
+ {
+ /* notification is not registered, just kill timer */
+ KillTimer(gVBoxSt.hWTSAPIWnd, gVBoxSt.idDelayedInitTimer);
+ gVBoxSt.idDelayedInitTimer = 0;
+ }
+ else
+ {
+ if (!gVBoxSt.pfnWTSUnRegisterSessionNotification(gVBoxSt.hWTSAPIWnd))
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: WTSAPI32 load failed, error = %08X\n", dwErr));
+ }
+ }
+
+ RTLdrClose(gVBoxSt.hLdrModWTSAPI32);
+ RT_ZERO(gVBoxSt);
+}
+
+#define VBOXST_DBG_MAKECASE(_val) case _val: return #_val;
+
+static const char* vboxStDbgGetString(DWORD val)
+{
+ switch (val)
+ {
+ VBOXST_DBG_MAKECASE(WTS_CONSOLE_CONNECT);
+ VBOXST_DBG_MAKECASE(WTS_CONSOLE_DISCONNECT);
+ VBOXST_DBG_MAKECASE(WTS_REMOTE_CONNECT);
+ VBOXST_DBG_MAKECASE(WTS_REMOTE_DISCONNECT);
+ VBOXST_DBG_MAKECASE(WTS_SESSION_LOGON);
+ VBOXST_DBG_MAKECASE(WTS_SESSION_LOGOFF);
+ VBOXST_DBG_MAKECASE(WTS_SESSION_LOCK);
+ VBOXST_DBG_MAKECASE(WTS_SESSION_UNLOCK);
+ VBOXST_DBG_MAKECASE(WTS_SESSION_REMOTE_CONTROL);
+ default:
+ WARN(("VBoxTray: invalid WTS state %d\n", val));
+ return "Unknown";
+ }
+}
+
+static BOOL vboxStCheckTimer(WPARAM wEvent)
+{
+ if (wEvent != gVBoxSt.idDelayedInitTimer)
+ return FALSE;
+
+ if (gVBoxSt.pfnWTSRegisterSessionNotification(gVBoxSt.hWTSAPIWnd, NOTIFY_FOR_THIS_SESSION))
+ {
+ KillTimer(gVBoxSt.hWTSAPIWnd, gVBoxSt.idDelayedInitTimer);
+ gVBoxSt.idDelayedInitTimer = 0;
+ vboxStCheckState();
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: timer WTSRegisterSessionNotification failed, error = %08X\n", dwErr));
+ Assert(gVBoxSt.fIsConsole == TRUE);
+ Assert(gVBoxSt.enmConnectState == WTSActive);
+ }
+
+ return TRUE;
+}
+
+
+static BOOL vboxStHandleEvent(WPARAM wEvent, LPARAM SessionID)
+{
+ WARN(("VBoxTray: WTS Event: %s\n", vboxStDbgGetString(wEvent)));
+ BOOL fOldIsActiveConsole = vboxStIsActiveConsole();
+
+ vboxStCheckState();
+
+ return !vboxStIsActiveConsole() != !fOldIsActiveConsole;
+}
+
+static BOOL vboxStIsActiveConsole()
+{
+ return (gVBoxSt.enmConnectState == WTSActive && gVBoxSt.fIsConsole);
+}
+
+/*
+ * Dt (desktop [state] tracking) functionality API impl
+ *
+ * !!!NOTE: this API is NOT thread-safe!!!
+ * */
+
+typedef struct VBOXDT
+{
+ HANDLE hNotifyEvent;
+ BOOL fIsInputDesktop;
+ UINT_PTR idTimer;
+ RTLDRMOD hLdrModHook;
+ BOOL (* pfnVBoxHookInstallActiveDesktopTracker)(HMODULE hDll);
+ BOOL (* pfnVBoxHookRemoveActiveDesktopTracker)();
+ HDESK (WINAPI * pfnGetThreadDesktop)(DWORD dwThreadId);
+ HDESK (WINAPI * pfnOpenInputDesktop)(DWORD dwFlags, BOOL fInherit, ACCESS_MASK dwDesiredAccess);
+ BOOL (WINAPI * pfnCloseDesktop)(HDESK hDesktop);
+} VBOXDT;
+
+static VBOXDT gVBoxDt;
+
+static BOOL vboxDtCalculateIsInputDesktop()
+{
+ BOOL fIsInputDt = FALSE;
+ HDESK hInput = gVBoxDt.pfnOpenInputDesktop(0, FALSE, DESKTOP_CREATEWINDOW);
+ if (hInput)
+ {
+// DWORD dwThreadId = GetCurrentThreadId();
+// HDESK hThreadDt = gVBoxDt.pfnGetThreadDesktop(dwThreadId);
+// if (hThreadDt)
+// {
+ fIsInputDt = TRUE;
+// }
+// else
+// {
+// DWORD dwErr = GetLastError();
+// WARN(("VBoxTray: pfnGetThreadDesktop for Seamless failed, last error = %08X\n", dwErr));
+// }
+
+ gVBoxDt.pfnCloseDesktop(hInput);
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+// WARN(("VBoxTray: pfnOpenInputDesktop for Seamless failed, last error = %08X\n", dwErr));
+ }
+ return fIsInputDt;
+}
+
+static BOOL vboxDtCheckTimer(WPARAM wParam)
+{
+ if (wParam != gVBoxDt.idTimer)
+ return FALSE;
+
+ VBoxTrayCheckDt();
+
+ return TRUE;
+}
+
+static int vboxDtInit()
+{
+ int rc = VINF_SUCCESS;
+ OSVERSIONINFO info;
+ gMajorVersion = 5; /* Default to Windows XP. */
+ info.dwOSVersionInfoSize = sizeof(info);
+ if (GetVersionEx(&info))
+ {
+ LogRel(("VBoxTray: Windows version %ld.%ld\n", info.dwMajorVersion, info.dwMinorVersion));
+ gMajorVersion = info.dwMajorVersion;
+ }
+
+ RT_ZERO(gVBoxDt);
+
+ gVBoxDt.hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, VBOXHOOK_GLOBAL_DT_EVENT_NAME);
+ if (gVBoxDt.hNotifyEvent != NULL)
+ {
+ /* Load the hook dll and resolve the necessary entry points. */
+ rc = RTLdrLoadAppPriv(VBOXHOOK_DLL_NAME, &gVBoxDt.hLdrModHook);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(gVBoxDt.hLdrModHook, "VBoxHookInstallActiveDesktopTracker",
+ (void **)&gVBoxDt.pfnVBoxHookInstallActiveDesktopTracker);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(gVBoxDt.hLdrModHook, "VBoxHookRemoveActiveDesktopTracker",
+ (void **)&gVBoxDt.pfnVBoxHookRemoveActiveDesktopTracker);
+ if (RT_FAILURE(rc))
+ WARN(("VBoxTray: VBoxHookRemoveActiveDesktopTracker not found\n"));
+ }
+ else
+ WARN(("VBoxTray: VBoxHookInstallActiveDesktopTracker not found\n"));
+ if (RT_SUCCESS(rc))
+ {
+ /* Try get the system APIs we need. */
+ *(void **)&gVBoxDt.pfnGetThreadDesktop = RTLdrGetSystemSymbol("user32.dll", "GetThreadDesktop");
+ if (!gVBoxDt.pfnGetThreadDesktop)
+ {
+ WARN(("VBoxTray: GetThreadDesktop not found\n"));
+ rc = VERR_NOT_SUPPORTED;
+ }
+
+ *(void **)&gVBoxDt.pfnOpenInputDesktop = RTLdrGetSystemSymbol("user32.dll", "OpenInputDesktop");
+ if (!gVBoxDt.pfnOpenInputDesktop)
+ {
+ WARN(("VBoxTray: OpenInputDesktop not found\n"));
+ rc = VERR_NOT_SUPPORTED;
+ }
+
+ *(void **)&gVBoxDt.pfnCloseDesktop = RTLdrGetSystemSymbol("user32.dll", "CloseDesktop");
+ if (!gVBoxDt.pfnCloseDesktop)
+ {
+ WARN(("VBoxTray: CloseDesktop not found\n"));
+ rc = VERR_NOT_SUPPORTED;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ BOOL fRc = FALSE;
+ /* For Vista and up we need to change the integrity of the security descriptor, too. */
+ if (gMajorVersion >= 6)
+ {
+ HMODULE hModHook = (HMODULE)RTLdrGetNativeHandle(gVBoxDt.hLdrModHook);
+ Assert((uintptr_t)hModHook != ~(uintptr_t)0);
+ fRc = gVBoxDt.pfnVBoxHookInstallActiveDesktopTracker(hModHook);
+ if (!fRc)
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: pfnVBoxHookInstallActiveDesktopTracker failed, last error = %08X\n", dwErr));
+ }
+ }
+
+ if (!fRc)
+ {
+ gVBoxDt.idTimer = SetTimer(ghwndToolWindow, TIMERID_VBOXTRAY_DT_TIMER, 500, (TIMERPROC)NULL);
+ if (!gVBoxDt.idTimer)
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: SetTimer error %08X\n", dwErr));
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ gVBoxDt.fIsInputDesktop = vboxDtCalculateIsInputDesktop();
+ return VINF_SUCCESS;
+ }
+ }
+ }
+
+ RTLdrClose(gVBoxDt.hLdrModHook);
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: CreateEvent for Seamless failed, last error = %08X\n", dwErr));
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+
+ CloseHandle(gVBoxDt.hNotifyEvent);
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: CreateEvent for Seamless failed, last error = %08X\n", dwErr));
+ rc = RTErrConvertFromWin32(dwErr);
+ }
+
+
+ RT_ZERO(gVBoxDt);
+ gVBoxDt.fIsInputDesktop = TRUE;
+
+ return rc;
+}
+
+static void vboxDtTerm()
+{
+ if (!gVBoxDt.hLdrModHook)
+ return;
+
+ gVBoxDt.pfnVBoxHookRemoveActiveDesktopTracker();
+
+ RTLdrClose(gVBoxDt.hLdrModHook);
+ CloseHandle(gVBoxDt.hNotifyEvent);
+
+ RT_ZERO(gVBoxDt);
+}
+/* @returns true on "IsInputDesktop" state change */
+static BOOL vboxDtHandleEvent()
+{
+ BOOL fIsInputDesktop = gVBoxDt.fIsInputDesktop;
+ gVBoxDt.fIsInputDesktop = vboxDtCalculateIsInputDesktop();
+ return !fIsInputDesktop != !gVBoxDt.fIsInputDesktop;
+}
+
+static HANDLE vboxDtGetNotifyEvent()
+{
+ return gVBoxDt.hNotifyEvent;
+}
+
+/* @returns true iff the application (VBoxTray) desktop is input */
+static BOOL vboxDtIsInputDesktop()
+{
+ return gVBoxDt.fIsInputDesktop;
+}
+
+
+/* we need to perform Acquire/Release using the file handled we use for rewuesting events from VBoxGuest
+ * otherwise Acquisition mechanism will treat us as different client and will not propagate necessary requests
+ * */
+static int VBoxAcquireGuestCaps(uint32_t fOr, uint32_t fNot, bool fCfg)
+{
+ DWORD cbReturned = 0;
+ VBoxGuestCapsAquire Info;
+ Log(("VBoxTray: VBoxAcquireGuestCaps or(0x%x), not(0x%x), cfx(%d)\n", fOr, fNot, fCfg));
+ Info.enmFlags = fCfg ? VBOXGUESTCAPSACQUIRE_FLAGS_CONFIG_ACQUIRE_MODE : VBOXGUESTCAPSACQUIRE_FLAGS_NONE;
+ Info.rc = VERR_NOT_IMPLEMENTED;
+ Info.u32OrMask = fOr;
+ Info.u32NotMask = fNot;
+ if (!DeviceIoControl(ghVBoxDriver, VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE, &Info, sizeof(Info), &Info, sizeof(Info), &cbReturned, NULL))
+ {
+ DWORD LastErr = GetLastError();
+ WARN(("VBoxTray: DeviceIoControl VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE failed LastErr %d\n", LastErr));
+ return RTErrConvertFromWin32(LastErr);
+ }
+
+ int rc = Info.rc;
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxTray: VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE failed rc %d\n", rc));
+ return rc;
+ }
+
+ return rc;
+}
+
+typedef enum VBOXCAPS_ENTRY_ACSTATE
+{
+ /* the given cap is released */
+ VBOXCAPS_ENTRY_ACSTATE_RELEASED = 0,
+ /* the given cap acquisition is in progress */
+ VBOXCAPS_ENTRY_ACSTATE_ACQUIRING,
+ /* the given cap is acquired */
+ VBOXCAPS_ENTRY_ACSTATE_ACQUIRED
+} VBOXCAPS_ENTRY_ACSTATE;
+
+
+struct VBOXCAPS_ENTRY;
+struct VBOXCAPS;
+
+typedef DECLCALLBACKPTR(void, PFNVBOXCAPS_ENTRY_ON_ENABLE)(struct VBOXCAPS *pConsole, struct VBOXCAPS_ENTRY *pCap, BOOL fEnabled);
+
+typedef struct VBOXCAPS_ENTRY
+{
+ uint32_t fCap;
+ uint32_t iCap;
+ VBOXCAPS_ENTRY_FUNCSTATE enmFuncState;
+ VBOXCAPS_ENTRY_ACSTATE enmAcState;
+ PFNVBOXCAPS_ENTRY_ON_ENABLE pfnOnEnable;
+} VBOXCAPS_ENTRY;
+
+
+typedef struct VBOXCAPS
+{
+ UINT_PTR idTimer;
+ VBOXCAPS_ENTRY aCaps[VBOXCAPS_ENTRY_IDX_COUNT];
+} VBOXCAPS;
+
+static VBOXCAPS gVBoxCaps;
+
+static DECLCALLBACK(void) vboxCapsOnEnableSeamles(struct VBOXCAPS *pConsole, struct VBOXCAPS_ENTRY *pCap, BOOL fEnabled)
+{
+ if (fEnabled)
+ {
+ Log(("VBoxTray: vboxCapsOnEnableSeamles: ENABLED\n"));
+ Assert(pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED);
+ Assert(pCap->enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED);
+ VBoxSeamlessEnable();
+ }
+ else
+ {
+ Log(("VBoxTray: vboxCapsOnEnableSeamles: DISABLED\n"));
+ Assert(pCap->enmAcState != VBOXCAPS_ENTRY_ACSTATE_ACQUIRED || pCap->enmFuncState != VBOXCAPS_ENTRY_FUNCSTATE_STARTED);
+ VBoxSeamlessDisable();
+ }
+}
+
+static void vboxCapsEntryAcStateSet(VBOXCAPS_ENTRY *pCap, VBOXCAPS_ENTRY_ACSTATE enmAcState)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+
+ Log(("VBoxTray: vboxCapsEntryAcStateSet: new state enmAcState(%d); pCap: fCap(%d), iCap(%d), enmFuncState(%d), enmAcState(%d)\n",
+ enmAcState, pCap->fCap, pCap->iCap, pCap->enmFuncState, pCap->enmAcState));
+
+ if (pCap->enmAcState == enmAcState)
+ return;
+
+ VBOXCAPS_ENTRY_ACSTATE enmOldAcState = pCap->enmAcState;
+ pCap->enmAcState = enmAcState;
+
+ if (enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED)
+ {
+ if (pCap->enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
+ {
+ if (pCap->pfnOnEnable)
+ pCap->pfnOnEnable(pConsole, pCap, TRUE);
+ }
+ }
+ else if (enmOldAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED && pCap->enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
+ {
+ if (pCap->pfnOnEnable)
+ pCap->pfnOnEnable(pConsole, pCap, FALSE);
+ }
+}
+
+static void vboxCapsEntryFuncStateSet(VBOXCAPS_ENTRY *pCap, VBOXCAPS_ENTRY_FUNCSTATE enmFuncState)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+
+ Log(("VBoxTray: vboxCapsEntryFuncStateSet: new state enmAcState(%d); pCap: fCap(%d), iCap(%d), enmFuncState(%d), enmAcState(%d)\n",
+ enmFuncState, pCap->fCap, pCap->iCap, pCap->enmFuncState, pCap->enmAcState));
+
+ if (pCap->enmFuncState == enmFuncState)
+ return;
+
+ VBOXCAPS_ENTRY_FUNCSTATE enmOldFuncState = pCap->enmFuncState;
+
+ pCap->enmFuncState = enmFuncState;
+
+ if (enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
+ {
+ Assert(enmOldFuncState == VBOXCAPS_ENTRY_FUNCSTATE_SUPPORTED);
+ if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED)
+ {
+ if (pCap->pfnOnEnable)
+ pCap->pfnOnEnable(pConsole, pCap, TRUE);
+ }
+ }
+ else if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED && enmOldFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
+ {
+ if (pCap->pfnOnEnable)
+ pCap->pfnOnEnable(pConsole, pCap, FALSE);
+ }
+}
+
+static void VBoxCapsEntryFuncStateSet(uint32_t iCup, VBOXCAPS_ENTRY_FUNCSTATE enmFuncState)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[iCup];
+ vboxCapsEntryFuncStateSet(pCap, enmFuncState);
+}
+
+static int VBoxCapsInit()
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ memset(pConsole, 0, sizeof (*pConsole));
+ pConsole->aCaps[VBOXCAPS_ENTRY_IDX_SEAMLESS].fCap = VMMDEV_GUEST_SUPPORTS_SEAMLESS;
+ pConsole->aCaps[VBOXCAPS_ENTRY_IDX_SEAMLESS].iCap = VBOXCAPS_ENTRY_IDX_SEAMLESS;
+ pConsole->aCaps[VBOXCAPS_ENTRY_IDX_SEAMLESS].pfnOnEnable = vboxCapsOnEnableSeamles;
+ pConsole->aCaps[VBOXCAPS_ENTRY_IDX_GRAPHICS].fCap = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
+ pConsole->aCaps[VBOXCAPS_ENTRY_IDX_GRAPHICS].iCap = VBOXCAPS_ENTRY_IDX_GRAPHICS;
+ return VINF_SUCCESS;
+}
+
+static int VBoxCapsReleaseAll()
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ Log(("VBoxTray: VBoxCapsReleaseAll\n"));
+ int rc = VBoxAcquireGuestCaps(0, VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GRAPHICS, false);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxTray: vboxCapsEntryReleaseAll VBoxAcquireGuestCaps failed rc %d\n", rc));
+ return rc;
+ }
+
+ if (pConsole->idTimer)
+ {
+ Log(("VBoxTray: killing console timer\n"));
+ KillTimer(ghwndToolWindow, pConsole->idTimer);
+ pConsole->idTimer = 0;
+ }
+
+ for (int i = 0; i < RT_ELEMENTS(pConsole->aCaps); ++i)
+ {
+ vboxCapsEntryAcStateSet(&pConsole->aCaps[i], VBOXCAPS_ENTRY_ACSTATE_RELEASED);
+ }
+
+ return rc;
+}
+
+static void VBoxCapsTerm()
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ VBoxCapsReleaseAll();
+ memset(pConsole, 0, sizeof (*pConsole));
+}
+
+static BOOL VBoxCapsEntryIsAcquired(uint32_t iCap)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ return pConsole->aCaps[iCap].enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED;
+}
+
+static BOOL VBoxCapsEntryIsEnabled(uint32_t iCap)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ return pConsole->aCaps[iCap].enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED
+ && pConsole->aCaps[iCap].enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED;
+}
+
+static BOOL VBoxCapsCheckTimer(WPARAM wParam)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ if (wParam != pConsole->idTimer)
+ return FALSE;
+
+ uint32_t u32AcquiredCaps = 0;
+ BOOL fNeedNewTimer = FALSE;
+
+ for (int i = 0; i < RT_ELEMENTS(pConsole->aCaps); ++i)
+ {
+ VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[i];
+ if (pCap->enmAcState != VBOXCAPS_ENTRY_ACSTATE_ACQUIRING)
+ continue;
+
+ int rc = VBoxAcquireGuestCaps(pCap->fCap, 0, false);
+ if (RT_SUCCESS(rc))
+ {
+ vboxCapsEntryAcStateSet(&pConsole->aCaps[i], VBOXCAPS_ENTRY_ACSTATE_ACQUIRED);
+ u32AcquiredCaps |= pCap->fCap;
+ }
+ else
+ {
+ Assert(rc == VERR_RESOURCE_BUSY);
+ fNeedNewTimer = TRUE;
+ }
+ }
+
+ if (!fNeedNewTimer)
+ {
+ KillTimer(ghwndToolWindow, pConsole->idTimer);
+ /* cleanup timer data */
+ pConsole->idTimer = 0;
+ }
+
+ return TRUE;
+}
+
+static int VBoxCapsEntryRelease(uint32_t iCap)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[iCap];
+ if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_RELEASED)
+ {
+ WARN(("VBoxTray: invalid cap[%d] state[%d] on release\n", iCap, pCap->enmAcState));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED)
+ {
+ int rc = VBoxAcquireGuestCaps(0, pCap->fCap, false);
+ AssertRC(rc);
+ }
+
+ vboxCapsEntryAcStateSet(pCap, VBOXCAPS_ENTRY_ACSTATE_RELEASED);
+
+ return VINF_SUCCESS;
+}
+
+static int VBoxCapsEntryAcquire(uint32_t iCap)
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ Assert(VBoxConsoleIsAllowed());
+ VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[iCap];
+ Log(("VBoxTray: VBoxCapsEntryAcquire %d\n", iCap));
+ if (pCap->enmAcState != VBOXCAPS_ENTRY_ACSTATE_RELEASED)
+ {
+ WARN(("VBoxTray: invalid cap[%d] state[%d] on acquire\n", iCap, pCap->enmAcState));
+ return VERR_INVALID_STATE;
+ }
+
+ vboxCapsEntryAcStateSet(pCap, VBOXCAPS_ENTRY_ACSTATE_ACQUIRING);
+ int rc = VBoxAcquireGuestCaps(pCap->fCap, 0, false);
+ if (RT_SUCCESS(rc))
+ {
+ vboxCapsEntryAcStateSet(pCap, VBOXCAPS_ENTRY_ACSTATE_ACQUIRED);
+ return VINF_SUCCESS;
+ }
+
+ if (rc != VERR_RESOURCE_BUSY)
+ {
+ WARN(("VBoxTray: vboxCapsEntryReleaseAll VBoxAcquireGuestCaps failed rc %d\n", rc));
+ return rc;
+ }
+
+ WARN(("VBoxTray: iCap %d is busy!\n", iCap));
+
+ /* the cap was busy, most likely it is still used by other VBoxTray instance running in another session,
+ * queue the retry timer */
+ if (!pConsole->idTimer)
+ {
+ pConsole->idTimer = SetTimer(ghwndToolWindow, TIMERID_VBOXTRAY_CAPS_TIMER, 100, (TIMERPROC)NULL);
+ if (!pConsole->idTimer)
+ {
+ DWORD dwErr = GetLastError();
+ WARN(("VBoxTray: SetTimer error %08X\n", dwErr));
+ return RTErrConvertFromWin32(dwErr);
+ }
+ }
+
+ return rc;
+}
+
+static int VBoxCapsAcquireAllSupported()
+{
+ VBOXCAPS *pConsole = &gVBoxCaps;
+ Log(("VBoxTray: VBoxCapsAcquireAllSupported\n"));
+ for (int i = 0; i < RT_ELEMENTS(pConsole->aCaps); ++i)
+ {
+ if (pConsole->aCaps[i].enmFuncState >= VBOXCAPS_ENTRY_FUNCSTATE_SUPPORTED)
+ {
+ Log(("VBoxTray: VBoxCapsAcquireAllSupported acquiring cap %d, state %d\n", i, pConsole->aCaps[i].enmFuncState));
+ VBoxCapsEntryAcquire(i);
+ }
+ else
+ {
+ WARN(("VBoxTray: VBoxCapsAcquireAllSupported: WARN: cap %d not supported, state %d\n", i, pConsole->aCaps[i].enmFuncState));
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+static BOOL VBoxConsoleIsAllowed()
+{
+ return vboxDtIsInputDesktop() && vboxStIsActiveConsole();
+}
+
+static void VBoxConsoleEnable(BOOL fEnable)
+{
+ if (fEnable)
+ VBoxCapsAcquireAllSupported();
+ else
+ VBoxCapsReleaseAll();
+}
+
+static void VBoxConsoleCapSetSupported(uint32_t iCap, BOOL fSupported)
+{
+ if (fSupported)
+ {
+ VBoxCapsEntryFuncStateSet(iCap, VBOXCAPS_ENTRY_FUNCSTATE_SUPPORTED);
+
+ if (VBoxConsoleIsAllowed())
+ VBoxCapsEntryAcquire(iCap);
+ }
+ else
+ {
+ VBoxCapsEntryFuncStateSet(iCap, VBOXCAPS_ENTRY_FUNCSTATE_UNSUPPORTED);
+
+ VBoxCapsEntryRelease(iCap);
+ }
+}
+
+void VBoxSeamlessSetSupported(BOOL fSupported)
+{
+ VBoxConsoleCapSetSupported(VBOXCAPS_ENTRY_IDX_SEAMLESS, fSupported);
+}
+
+static void VBoxGrapicsSetSupported(BOOL fSupported)
+{
+ VBoxConsoleCapSetSupported(VBOXCAPS_ENTRY_IDX_GRAPHICS, fSupported);
+}
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.h
index 132c74f8..139f962f 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -54,6 +54,17 @@
#include "VBoxDispIf.h"
+#ifdef DEBUG_misha
+#define WARN(_m) do { \
+ Assert(0); \
+ Log(_m); \
+ } while (0)
+#else
+#define WARN(_m) do { \
+ Log(_m); \
+ } while (0)
+#endif
+
/*
* Windows messsages.
*/
@@ -80,6 +91,9 @@
* Timer IDs.
*/
#define TIMERID_VBOXTRAY_CHECK_HOSTVERSION 1000
+#define TIMERID_VBOXTRAY_CAPS_TIMER 1001
+#define TIMERID_VBOXTRAY_DT_TIMER 1002
+#define TIMERID_VBOXTRAY_ST_DELAYED_INIT_TIMER 1003
/* The environment information for services. */
typedef struct _VBOXSERVICEENV
@@ -97,6 +111,7 @@ typedef struct _VBOXSERVICEINFO
char *pszName;
int (* pfnInit) (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
unsigned (__stdcall * pfnThread) (void *pInstance);
+ void (* pfnStop) (const VBOXSERVICEENV *pEnv, void *pInstance);
void (* pfnDestroy) (const VBOXSERVICEENV *pEnv, void *pInstance);
/* Variables. */
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxTrayMsg.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxTrayMsg.h
index 27d86752..bef94983 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxTrayMsg.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxTrayMsg.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -18,48 +18,81 @@
#ifndef ___VBOXTRAY_MSG_H
#define ___VBOXTRAY_MSG_H
-#define VBOXTRAY_PIPE_IPC "\\\\.\\pipe\\VBoxTrayIPC"
-#define VBOXTRAY_PIPE_IPC_BUFSIZE 64 * 1024
+/** The IPC pipe's prefix. Will be followed by the
+ * username VBoxTray runs under. */
+#define VBOXTRAY_IPC_PIPE_PREFIX "VBoxTrayIPC-"
+/** The IPC header's magic. */
+#define VBOXTRAY_IPC_HDR_MAGIC 0x19840804
enum VBOXTRAYIPCMSGTYPE
{
/** Restarts VBoxTray. */
VBOXTRAYIPCMSGTYPE_RESTART = 10,
-
- /** Asks the IPC thread to quit. */
- VBOXTRAYIPCMSGTYPE_IPC_QUIT = 50,
-
/** Shows a balloon message in the tray area. */
- VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG = 100
+ VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG = 100,
+ /** Retrieves the current user's last input
+ * time. This will be the user VBoxTray is running
+ * under. No actual message for this command
+ * required. */
+ VBOXTRAYIPCMSGTYPE_USERLASTINPUT = 120
};
/* VBoxTray's IPC header. */
-typedef struct _VBOXTRAYIPCHEADER
+typedef struct VBOXTRAYIPCHEADER
{
- /** Message type. */
- ULONG ulMsg;
- /** Size of message body
- * (without this header). */
- ULONG cbBody;
- /** User-supplied wParam. */
- ULONG wParam;
- /** User-supplied lParam. */
- ULONG lParam;
+ /** The header's magic. */
+ uint32_t uMagic;
+ /** Header version, must be 0 by now. */
+ uint32_t uHdrVersion;
+ /** Message type. Specifies a message
+ * of VBOXTRAYIPCMSGTYPE. */
+ uint32_t uMsgType;
+ /** Message length (in bytes). This must
+ * include the overall message length, including
+ * (eventual) dynamically allocated areas which
+ * are passed into the message structure.
+ */
+ uint32_t uMsgLen;
+
} VBOXTRAYIPCHEADER, *PVBOXTRAYIPCHEADER;
-typedef struct _VBOXTRAYIPCMSG_SHOWBALLOONMSG
+/**
+ * Tells VBoxTray to show a balloon message in Windows'
+ * tray area. This may or may not work depending on the
+ * system's configuration / set user preference.
+ */
+typedef struct VBOXTRAYIPCMSG_SHOWBALLOONMSG
{
- /** Message content. */
- TCHAR szContent[256];
- /** Message title. */
- TCHAR szTitle[64];
+ /** Length of message body (in bytes). */
+ uint32_t cbMsgContent;
+ /** Length of message title (in bytes). */
+ uint32_t cbMsgTitle;
/** Message type. */
- ULONG ulType;
- /** Flags; not used yet. */
- ULONG ulFlags;
- /** Time to show the message (in msec). */
- ULONG ulShowMS;
+ uint32_t uType;
+ /** Time to show the message (in ms). */
+ uint32_t uShowMS;
+ /** Dynamically allocated stuff.
+ *
+ * Note: These must come at the end of the
+ * structure to not overwrite any important
+ * stuff above.
+ */
+ /** Message body. Can be up to 256 chars
+ * long. */
+ char szMsgContent[1];
+ /** Message title. Can be up to 73 chars
+ * long. */
+ char szMsgTitle[1];
} VBOXTRAYIPCMSG_SHOWBALLOONMSG, *PVBOXTRAYIPCMSG_SHOWBALLOONMSG;
+/**
+ * Response telling the last input of the current user.
+ */
+typedef struct VBOXTRAYIPCRES_USERLASTINPUT
+{
+ /** Last occurred user input event (in seconds). */
+ uint32_t uLastInput;
+} VBOXTRAYIPCRES_USERLASTINPUT, *PVBOXTRAYIPCRES_USERLASTINPUT;
+
#endif /* !___VBOXTRAY_MSG_H */
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.cpp b/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.cpp
index 9f3cef91..9435a9f1 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.cpp
@@ -24,6 +24,7 @@
#include <VBox/VMMDev.h>
#include <VBoxGuestInternal.h>
#include <iprt/assert.h>
+#include <iprt/ldr.h>
/* The guest receives VRDP_ACTIVE/VRDP_INACTIVE notifications.
@@ -255,7 +256,7 @@ typedef struct _VBOXVRDPCONTEXT
uint32_t level;
BOOL fSavedThemeEnabled;
- HMODULE hModule;
+ RTLDRMOD hModUxTheme;
HRESULT (* pfnEnableTheming)(BOOL fEnable);
BOOL (* pfnIsThemeActive)(VOID);
@@ -273,16 +274,17 @@ int VBoxVRDPInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThr
gCtx.level = VRDP_EXPERIENCE_LEVEL_FULL;
gCtx.fSavedThemeEnabled = FALSE;
- gCtx.hModule = LoadLibrary("UxTheme");
-
- if (gCtx.hModule)
+ int rc = RTLdrLoadSystem("UxTheme.dll", false /*fNoUnload*/, &gCtx.hModUxTheme);
+ if (RT_SUCCESS(rc))
{
- *(uintptr_t *)&gCtx.pfnEnableTheming = (uintptr_t)GetProcAddress(gCtx.hModule, "EnableTheming");
- *(uintptr_t *)&gCtx.pfnIsThemeActive = (uintptr_t)GetProcAddress(gCtx.hModule, "IsThemeActive");
+ *(PFNRT *)&gCtx.pfnEnableTheming = RTLdrGetFunction(gCtx.hModUxTheme, "EnableTheming");
+ *(PFNRT *)&gCtx.pfnIsThemeActive = RTLdrGetFunction(gCtx.hModUxTheme, "IsThemeActive");
}
else
{
- gCtx.pfnEnableTheming = 0;
+ gCtx.hModUxTheme = NIL_RTLDRMOD;
+ gCtx.pfnEnableTheming = NULL;
+ gCtx.pfnIsThemeActive = NULL;
}
*pfStartThread = true;
@@ -296,9 +298,11 @@ void VBoxVRDPDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
Log(("VBoxTray: VBoxVRDPDestroy\n"));
VBOXVRDPCONTEXT *pCtx = (VBOXVRDPCONTEXT *)pInstance;
vboxExperienceRestore (pCtx->level);
- if (gCtx.hModule)
- FreeLibrary(gCtx.hModule);
- gCtx.hModule = 0;
+ if (gCtx.hModUxTheme != NIL_RTLDRMOD)
+ {
+ RTLdrClose(gCtx.hModUxTheme);
+ gCtx.hModUxTheme = NIL_RTLDRMOD;
+ }
return;
}
diff --git a/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.h b/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.h
index dbb63439..f6c8aa3c 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/VBoxVRDP.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/WINNT/VBoxTray/resource.h b/src/VBox/Additions/WINNT/VBoxTray/resource.h
index e01df6df..04c1f0ce 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/resource.h
+++ b/src/VBox/Additions/WINNT/VBoxTray/resource.h
@@ -2,7 +2,7 @@
*
* VBoxService - Guest Additions Service
*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Additions/WINNT/VBoxTray/testcase/tstSessionHack.cpp b/src/VBox/Additions/WINNT/VBoxTray/testcase/tstSessionHack.cpp
index b0df40a9..8e160b96 100644
--- a/src/VBox/Additions/WINNT/VBoxTray/testcase/tstSessionHack.cpp
+++ b/src/VBox/Additions/WINNT/VBoxTray/testcase/tstSessionHack.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;