VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDispIf.cpp@ 72372

Last change on this file since 72372 was 72372, checked in by vboxsync, 7 years ago

WDDM/VBoxTray: bugref:8444: fix trailing whitespace from previous commit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.3 KB
Line 
1/* $Id: VBoxDispIf.cpp 72372 2018-05-29 05:50:52Z vboxsync $ */
2/** @file
3 * VBoxTray - Display Settings Interface abstraction for XPDM & WDDM
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxTray.h"
19#define _WIN32_WINNT 0x0601
20#include <iprt/log.h>
21#include <iprt/err.h>
22#include <iprt/assert.h>
23
24#include <malloc.h>
25
26
27/*********************************************************************************************************************************
28* Defined Constants And Macros *
29*********************************************************************************************************************************/
30#ifdef DEBUG_misha
31# define WARN(_m) do { \
32 Assert(0); \
33 Log(_m); \
34 } while (0)
35# define WARN_FUNC(_m) do { \
36 Assert(0); \
37 LogFunc(_m); \
38 } while (0)
39#else
40# define WARN(_m) do { \
41 Log(_m); \
42 } while (0)
43# define WARN_FUNC(_m) do { \
44 LogFunc(_m); \
45 } while (0)
46#endif
47
48#ifdef VBOX_WITH_WDDM
49#include <iprt/asm.h>
50#endif
51
52#include "VBoxDisplay.h"
53
54#ifndef NT_SUCCESS
55# define NT_SUCCESS(_Status) ((_Status) >= 0)
56#endif
57
58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
62typedef struct VBOXDISPIF_OP
63{
64 PCVBOXDISPIF pIf;
65 VBOXDISPKMT_ADAPTER Adapter;
66 VBOXDISPKMT_DEVICE Device;
67 VBOXDISPKMT_CONTEXT Context;
68} VBOXDISPIF_OP;
69
70/*
71 * APIs specific to Win7 and above WDDM architecture. Not available for Vista WDDM.
72 * This is the reason they have not been put in the VBOXDISPIF struct in VBoxDispIf.h.
73 */
74typedef struct _VBOXDISPLAYWDDMAPICONTEXT
75{
76 LONG (WINAPI * pfnSetDisplayConfig)(UINT numPathArrayElements,DISPLAYCONFIG_PATH_INFO *pathArray,UINT numModeInfoArrayElements,
77 DISPLAYCONFIG_MODE_INFO *modeInfoArray, UINT Flags);
78 LONG (WINAPI * pfnQueryDisplayConfig)(UINT Flags,UINT *pNumPathArrayElements, DISPLAYCONFIG_PATH_INFO *pPathInfoArray,
79 UINT *pNumModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *pModeInfoArray,
80 DISPLAYCONFIG_TOPOLOGY_ID *pCurrentTopologyId);
81 LONG (WINAPI * pfnGetDisplayConfigBufferSizes)(UINT Flags, UINT *pNumPathArrayElements, UINT *pNumModeInfoArrayElements);
82} _VBOXDISPLAYWDDMAPICONTEXT;
83
84static _VBOXDISPLAYWDDMAPICONTEXT gCtx = {0};
85
86typedef struct VBOXDISPIF_WDDM_DISPCFG
87{
88 UINT32 cPathInfoArray;
89 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
90 UINT32 cModeInfoArray;
91 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
92} VBOXDISPIF_WDDM_DISPCFG;
93
94
95/*********************************************************************************************************************************
96* Internal Functions *
97*********************************************************************************************************************************/
98static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices,
99 DEVMODE *paDeviceModes, UINT devModes);
100
101static DWORD vboxDispIfWddmResizeDisplay2(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT devModes);
102
103static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup,
104 DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
105static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable);
106static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp);
107
108
109static DWORD vboxDispIfWddmDcCreate(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT32 fFlags)
110{
111 UINT32 cPathInfoArray = 0;
112 UINT32 cModeInfoArray = 0;
113 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
114 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
115 DWORD winEr = gCtx.pfnGetDisplayConfigBufferSizes(fFlags, &cPathInfoArray, &cModeInfoArray);
116 if (winEr != ERROR_SUCCESS)
117 {
118 WARN(("VBoxTray: (WDDM) Failed GetDisplayConfigBufferSizes\n"));
119 return winEr;
120 }
121
122 pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cPathInfoArray * sizeof(DISPLAYCONFIG_PATH_INFO));
123 if (!pPathInfoArray)
124 {
125 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
126 return ERROR_OUTOFMEMORY;
127 }
128 pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
129 if (!pModeInfoArray)
130 {
131 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
132 free(pPathInfoArray);
133 return ERROR_OUTOFMEMORY;
134 }
135
136 winEr = gCtx.pfnQueryDisplayConfig(fFlags, &cPathInfoArray, pPathInfoArray, &cModeInfoArray, pModeInfoArray, NULL);
137 if (winEr != ERROR_SUCCESS)
138 {
139 WARN(("VBoxTray: (WDDM) Failed QueryDisplayConfig\n"));
140 free(pPathInfoArray);
141 free(pModeInfoArray);
142 return winEr;
143 }
144
145 pCfg->cPathInfoArray = cPathInfoArray;
146 pCfg->pPathInfoArray = pPathInfoArray;
147 pCfg->cModeInfoArray = cModeInfoArray;
148 pCfg->pModeInfoArray = pModeInfoArray;
149 return ERROR_SUCCESS;
150}
151
152static DWORD vboxDispIfWddmDcClone(VBOXDISPIF_WDDM_DISPCFG *pCfg, VBOXDISPIF_WDDM_DISPCFG *pCfgDst)
153{
154 memset(pCfgDst, 0, sizeof (*pCfgDst));
155
156 if (pCfg->cPathInfoArray)
157 {
158 pCfgDst->pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
159 if (!pCfgDst->pPathInfoArray)
160 {
161 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
162 return ERROR_OUTOFMEMORY;
163 }
164
165 memcpy(pCfgDst->pPathInfoArray, pCfg->pPathInfoArray, pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
166
167 pCfgDst->cPathInfoArray = pCfg->cPathInfoArray;
168 }
169
170 if (pCfg->cModeInfoArray)
171 {
172 pCfgDst->pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
173 if (!pCfgDst->pModeInfoArray)
174 {
175 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
176 if (pCfgDst->pPathInfoArray)
177 {
178 free(pCfgDst->pPathInfoArray);
179 pCfgDst->pPathInfoArray = NULL;
180 }
181 return ERROR_OUTOFMEMORY;
182 }
183
184 memcpy(pCfgDst->pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
185
186 pCfgDst->cModeInfoArray = pCfg->cModeInfoArray;
187 }
188
189 return ERROR_SUCCESS;
190}
191
192
193static VOID vboxDispIfWddmDcTerm(VBOXDISPIF_WDDM_DISPCFG *pCfg)
194{
195 if (pCfg->pPathInfoArray)
196 free(pCfg->pPathInfoArray);
197 if (pCfg->pModeInfoArray)
198 free(pCfg->pModeInfoArray);
199 /* sanity */
200 memset(pCfg, 0, sizeof (*pCfg));
201}
202
203static UINT32 g_cVBoxDispIfWddmDisplays = 0;
204static DWORD vboxDispIfWddmDcQueryNumDisplays(UINT32 *pcDisplays)
205{
206 if (!g_cVBoxDispIfWddmDisplays)
207 {
208 VBOXDISPIF_WDDM_DISPCFG DispCfg;
209 *pcDisplays = 0;
210 DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
211 if (winEr != ERROR_SUCCESS)
212 {
213 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
214 return winEr;
215 }
216
217 int cDisplays = -1;
218
219 for (UINT iter = 0; iter < DispCfg.cPathInfoArray; ++iter)
220 {
221 if (cDisplays < (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id))
222 cDisplays = (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id);
223 }
224
225 cDisplays++;
226
227 g_cVBoxDispIfWddmDisplays = cDisplays;
228 Assert(g_cVBoxDispIfWddmDisplays);
229
230 vboxDispIfWddmDcTerm(&DispCfg);
231 }
232
233 *pcDisplays = g_cVBoxDispIfWddmDisplays;
234 return ERROR_SUCCESS;
235}
236
237#define VBOX_WDDM_DC_SEARCH_PATH_ANY (~(UINT)0)
238static int vboxDispIfWddmDcSearchPath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
239{
240 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
241 {
242 if ( (srcId == VBOX_WDDM_DC_SEARCH_PATH_ANY || pCfg->pPathInfoArray[iter].sourceInfo.id == srcId)
243 && (trgId == VBOX_WDDM_DC_SEARCH_PATH_ANY || pCfg->pPathInfoArray[iter].targetInfo.id == trgId))
244 {
245 return (int)iter;
246 }
247 }
248 return -1;
249}
250
251static int vboxDispIfWddmDcSearchActivePath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
252{
253 int idx = vboxDispIfWddmDcSearchPath(pCfg, srcId, trgId);
254 if (idx < 0)
255 return idx;
256
257 if (!(pCfg->pPathInfoArray[idx].flags & DISPLAYCONFIG_PATH_ACTIVE))
258 return -1;
259
260 return idx;
261}
262
263static VOID vboxDispIfWddmDcSettingsInvalidateModeIndex(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx)
264{
265 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
266 pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
267}
268
269static VOID vboxDispIfWddmDcSettingsInvalidateModeIndeces(VBOXDISPIF_WDDM_DISPCFG *pCfg)
270{
271 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
272 {
273 vboxDispIfWddmDcSettingsInvalidateModeIndex(pCfg, (int)iter);
274 }
275
276 if (pCfg->pModeInfoArray)
277 {
278 free(pCfg->pModeInfoArray);
279 pCfg->pModeInfoArray = NULL;
280 }
281 pCfg->cModeInfoArray = 0;
282}
283
284static DWORD vboxDispIfWddmDcSettingsModeAdd(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT *pIdx)
285{
286 UINT32 cModeInfoArray = pCfg->cModeInfoArray + 1;
287 DISPLAYCONFIG_MODE_INFO *pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
288 if (!pModeInfoArray)
289 {
290 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
291 return ERROR_OUTOFMEMORY;
292 }
293
294 memcpy (pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
295 memset(&pModeInfoArray[cModeInfoArray-1], 0, sizeof (pModeInfoArray[0]));
296 free(pCfg->pModeInfoArray);
297 *pIdx = cModeInfoArray-1;
298 pCfg->pModeInfoArray = pModeInfoArray;
299 pCfg->cModeInfoArray = cModeInfoArray;
300 return ERROR_SUCCESS;
301}
302
303static DWORD vboxDispIfWddmDcSettingsUpdate(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx, DEVMODE *pDeviceMode, BOOL fInvalidateSrcMode, BOOL fEnable)
304{
305 if (fInvalidateSrcMode)
306 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
307 else if (pDeviceMode)
308 {
309 UINT iSrcMode = pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx;
310 if (iSrcMode == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)
311 {
312
313 WARN(("VBoxTray: (WDDM) no source mode index specified"));
314 DWORD winEr = vboxDispIfWddmDcSettingsModeAdd(pCfg, &iSrcMode);
315 if (winEr != ERROR_SUCCESS)
316 {
317 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcSettingsModeAdd Failed winEr %d\n", winEr));
318 return winEr;
319 }
320 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = iSrcMode;
321 }
322
323 for (int i = 0; i < (int)pCfg->cPathInfoArray; ++i)
324 {
325 if (i == idx)
326 continue;
327
328 if (pCfg->pPathInfoArray[i].sourceInfo.modeInfoIdx == iSrcMode)
329 {
330 /* this is something we're not expecting/supporting */
331 WARN(("VBoxTray: (WDDM) multiple paths have the same mode index"));
332 return ERROR_NOT_SUPPORTED;
333 }
334 }
335
336 if (pDeviceMode->dmFields & DM_PELSWIDTH)
337 pCfg->pModeInfoArray[iSrcMode].sourceMode.width = pDeviceMode->dmPelsWidth;
338 if (pDeviceMode->dmFields & DM_PELSHEIGHT)
339 pCfg->pModeInfoArray[iSrcMode].sourceMode.height = pDeviceMode->dmPelsHeight;
340 if (pDeviceMode->dmFields & DM_POSITION)
341 {
342 LogFlowFunc(("DM_POSITION %d,%d -> %d,%d\n",
343 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x,
344 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y,
345 pDeviceMode->dmPosition.x, pDeviceMode->dmPosition.y));
346 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x = pDeviceMode->dmPosition.x;
347 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y = pDeviceMode->dmPosition.y;
348 }
349 if (pDeviceMode->dmFields & DM_BITSPERPEL)
350 {
351 switch (pDeviceMode->dmBitsPerPel)
352 {
353 case 32:
354 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
355 break;
356 case 24:
357 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_24BPP;
358 break;
359 case 16:
360 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_16BPP;
361 break;
362 case 8:
363 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_8BPP;
364 break;
365 default:
366 LogRel(("VBoxTray: (WDDM) invalid bpp %d, using 32\n", pDeviceMode->dmBitsPerPel));
367 pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
368 break;
369 }
370 }
371 }
372
373 pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
374
375 /* "A refresh rate with both the numerator and denominator set to zero indicates that
376 * the caller does not specify a refresh rate and the operating system should use
377 * the most optimal refresh rate available. For this case, in a call to the SetDisplayConfig
378 * function, the caller must set the scanLineOrdering member to the
379 * DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED value; otherwise, SetDisplayConfig fails."
380 *
381 * If a refresh rate is set to a value, then the resize will fail if miniport driver
382 * does not support VSync, i.e. with display-only driver on Win8+ (@bugref{8440}).
383 */
384 pCfg->pPathInfoArray[idx].targetInfo.refreshRate.Numerator = 0;
385 pCfg->pPathInfoArray[idx].targetInfo.refreshRate.Denominator = 0;
386 pCfg->pPathInfoArray[idx].targetInfo.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
387
388 /* Make sure that "The output can be forced on this target even if a monitor is not detected." */
389 pCfg->pPathInfoArray[idx].targetInfo.targetAvailable = TRUE;
390 pCfg->pPathInfoArray[idx].targetInfo.statusFlags |= DISPLAYCONFIG_TARGET_FORCIBLE;
391
392 if (fEnable)
393 pCfg->pPathInfoArray[idx].flags |= DISPLAYCONFIG_PATH_ACTIVE;
394 else
395 pCfg->pPathInfoArray[idx].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
396
397 return ERROR_SUCCESS;
398}
399
400static DWORD vboxDispIfWddmDcSet(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT fFlags)
401{
402 DWORD winEr = gCtx.pfnSetDisplayConfig(pCfg->cPathInfoArray, pCfg->pPathInfoArray, pCfg->cModeInfoArray, pCfg->pModeInfoArray, fFlags);
403 if (winEr != ERROR_SUCCESS)
404 Log(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed for Flags 0x%x\n", fFlags));
405 return winEr;
406}
407
408static BOOL vboxDispIfWddmDcSettingsAdjustSupportedPaths(VBOXDISPIF_WDDM_DISPCFG *pCfg)
409{
410 BOOL fAdjusted = FALSE;
411 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
412 {
413 if (pCfg->pPathInfoArray[iter].sourceInfo.id == pCfg->pPathInfoArray[iter].targetInfo.id)
414 continue;
415
416 if (!(pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
417 continue;
418
419 pCfg->pPathInfoArray[iter].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
420 fAdjusted = TRUE;
421 }
422
423 return fAdjusted;
424}
425
426static void vboxDispIfWddmDcSettingsAttachDisbledToPrimary(VBOXDISPIF_WDDM_DISPCFG *pCfg)
427{
428 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
429 {
430 if ((pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
431 continue;
432
433 pCfg->pPathInfoArray[iter].sourceInfo.id = 0;
434 pCfg->pPathInfoArray[iter].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
435 pCfg->pPathInfoArray[iter].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
436 }
437}
438
439static DWORD vboxDispIfWddmDcSettingsIncludeAllTargets(VBOXDISPIF_WDDM_DISPCFG *pCfg)
440{
441 UINT32 cDisplays = 0;
442 VBOXDISPIF_WDDM_DISPCFG AllCfg;
443 BOOL fAllCfgInited = FALSE;
444
445 DWORD winEr = vboxDispIfWddmDcQueryNumDisplays(&cDisplays);
446 if (winEr != ERROR_SUCCESS)
447 {
448 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcQueryNumDisplays Failed winEr %d\n", winEr));
449 return winEr;
450 }
451
452 DISPLAYCONFIG_PATH_INFO *pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cDisplays * sizeof(DISPLAYCONFIG_PATH_INFO));
453 if (!pPathInfoArray)
454 {
455 WARN(("malloc failed\n"));
456 return ERROR_OUTOFMEMORY;
457 }
458
459 for (UINT i = 0; i < cDisplays; ++i)
460 {
461 int idx = vboxDispIfWddmDcSearchPath(pCfg, i, i);
462 if (idx < 0)
463 {
464 idx = vboxDispIfWddmDcSearchPath(pCfg, VBOX_WDDM_DC_SEARCH_PATH_ANY, i);
465 if (idx >= 0)
466 {
467 WARN(("VBoxTray:(WDDM) different source and target paare enabled, this is something we would not expect\n"));
468 }
469 }
470
471 if (idx >= 0)
472 pPathInfoArray[i] = pCfg->pPathInfoArray[idx];
473 else
474 {
475 if (!fAllCfgInited)
476 {
477 winEr = vboxDispIfWddmDcCreate(&AllCfg, QDC_ALL_PATHS);
478 if (winEr != ERROR_SUCCESS)
479 {
480 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
481 free(pPathInfoArray);
482 return winEr;
483 }
484 fAllCfgInited = TRUE;
485 }
486
487 idx = vboxDispIfWddmDcSearchPath(&AllCfg, i, i);
488 if (idx < 0)
489 {
490 WARN(("VBoxTray:(WDDM) %d %d path not supported\n", i, i));
491 idx = vboxDispIfWddmDcSearchPath(pCfg, VBOX_WDDM_DC_SEARCH_PATH_ANY, i);
492 if (idx < 0)
493 {
494 WARN(("VBoxTray:(WDDM) %d %d path not supported\n", -1, i));
495 }
496 }
497
498 if (idx >= 0)
499 {
500 pPathInfoArray[i] = AllCfg.pPathInfoArray[idx];
501
502 if (pPathInfoArray[i].flags & DISPLAYCONFIG_PATH_ACTIVE)
503 {
504 WARN(("VBoxTray:(WDDM) disabled path %d %d is marked active\n",
505 pPathInfoArray[i].sourceInfo.id, pPathInfoArray[i].targetInfo.id));
506 pPathInfoArray[i].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
507 }
508
509 Assert(pPathInfoArray[i].sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
510 Assert(pPathInfoArray[i].sourceInfo.statusFlags == 0);
511
512 Assert(pPathInfoArray[i].targetInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
513 Assert(pPathInfoArray[i].targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15);
514 Assert(pPathInfoArray[i].targetInfo.rotation == DISPLAYCONFIG_ROTATION_IDENTITY);
515 Assert(pPathInfoArray[i].targetInfo.scaling == DISPLAYCONFIG_SCALING_PREFERRED);
516 Assert(pPathInfoArray[i].targetInfo.refreshRate.Numerator == 0);
517 Assert(pPathInfoArray[i].targetInfo.refreshRate.Denominator == 0);
518 Assert(pPathInfoArray[i].targetInfo.scanLineOrdering == DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED);
519 Assert(pPathInfoArray[i].targetInfo.targetAvailable == TRUE);
520 Assert(pPathInfoArray[i].targetInfo.statusFlags == DISPLAYCONFIG_TARGET_FORCIBLE);
521
522 Assert(pPathInfoArray[i].flags == 0);
523 }
524 else
525 {
526 pPathInfoArray[i].sourceInfo.adapterId = pCfg->pPathInfoArray[0].sourceInfo.adapterId;
527 pPathInfoArray[i].sourceInfo.id = i;
528 pPathInfoArray[i].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
529 pPathInfoArray[i].sourceInfo.statusFlags = 0;
530
531 pPathInfoArray[i].targetInfo.adapterId = pPathInfoArray[i].sourceInfo.adapterId;
532 pPathInfoArray[i].targetInfo.id = i;
533 pPathInfoArray[i].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
534 pPathInfoArray[i].targetInfo.outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15;
535 pPathInfoArray[i].targetInfo.rotation = DISPLAYCONFIG_ROTATION_IDENTITY;
536 pPathInfoArray[i].targetInfo.scaling = DISPLAYCONFIG_SCALING_PREFERRED;
537 pPathInfoArray[i].targetInfo.refreshRate.Numerator = 0;
538 pPathInfoArray[i].targetInfo.refreshRate.Denominator = 0;
539 pPathInfoArray[i].targetInfo.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
540 pPathInfoArray[i].targetInfo.targetAvailable = TRUE;
541 pPathInfoArray[i].targetInfo.statusFlags = DISPLAYCONFIG_TARGET_FORCIBLE;
542
543 pPathInfoArray[i].flags = 0;
544 }
545 }
546 }
547
548 free(pCfg->pPathInfoArray);
549 pCfg->pPathInfoArray = pPathInfoArray;
550 pCfg->cPathInfoArray = cDisplays;
551 if (fAllCfgInited)
552 vboxDispIfWddmDcTerm(&AllCfg);
553
554 return ERROR_SUCCESS;
555}
556
557static DWORD vboxDispIfOpBegin(PCVBOXDISPIF pIf, VBOXDISPIF_OP *pOp)
558{
559 pOp->pIf = pIf;
560
561 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pOp->Adapter);
562 if (SUCCEEDED(hr))
563 {
564 hr = vboxDispKmtCreateDevice(&pOp->Adapter, &pOp->Device);
565 if (SUCCEEDED(hr))
566 {
567 hr = vboxDispKmtCreateContext(&pOp->Device, &pOp->Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE,
568 0, 0, NULL, 0ULL);
569 if (SUCCEEDED(hr))
570 return ERROR_SUCCESS;
571 else
572 WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
573
574 vboxDispKmtDestroyDevice(&pOp->Device);
575 }
576 else
577 WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
578
579 vboxDispKmtCloseAdapter(&pOp->Adapter);
580 }
581
582 return hr;
583}
584
585static VOID vboxDispIfOpEnd(VBOXDISPIF_OP *pOp)
586{
587 vboxDispKmtDestroyContext(&pOp->Context);
588 vboxDispKmtDestroyDevice(&pOp->Device);
589 vboxDispKmtCloseAdapter(&pOp->Adapter);
590}
591
592/* display driver interface abstraction for XPDM & WDDM
593 * with WDDM we can not use ExtEscape to communicate with our driver
594 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
595 * that knows nothing about us */
596DWORD VBoxDispIfInit(PVBOXDISPIF pDispIf)
597{
598 VBoxDispIfSwitchMode(pDispIf, VBOXDISPIF_MODE_XPDM, NULL);
599
600 return NO_ERROR;
601}
602
603#ifdef VBOX_WITH_WDDM
604static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf);
605static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf);
606#endif
607
608DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
609{
610#ifdef VBOX_WITH_WDDM
611 if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
612 {
613 vboxDispIfWddmTerm(pIf);
614
615 vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
616 }
617#endif
618
619 pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
620 return NO_ERROR;
621}
622
623static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, int iDirection)
624{
625 RT_NOREF(pIf);
626 HDC hdc = GetDC(HWND_DESKTOP);
627 VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
628 int iRet = ExtEscape(hdc, pEscape->escapeCode,
629 iDirection >= 0 ? cbData : 0,
630 iDirection >= 0 ? (LPSTR)pvData : NULL,
631 iDirection <= 0 ? cbData : 0,
632 iDirection <= 0 ? (LPSTR)pvData : NULL);
633 ReleaseDC(HWND_DESKTOP, hdc);
634 if (iRet > 0)
635 return VINF_SUCCESS;
636 if (iRet == 0)
637 return ERROR_NOT_SUPPORTED;
638 /* else */
639 return ERROR_GEN_FAILURE;
640}
641
642#ifdef VBOX_WITH_WDDM
643static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
644{
645 DWORD err = NO_ERROR;
646 OSVERSIONINFO OSinfo;
647 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
648 GetVersionEx (&OSinfo);
649 bool bSupported = true;
650
651 if (OSinfo.dwMajorVersion >= 6)
652 {
653 LogFunc(("this is vista and up\n"));
654 HMODULE hUser = GetModuleHandle("user32.dll");
655 if (hUser)
656 {
657 *(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
658 LogFunc(("VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.wddm.pfnChangeDisplaySettingsEx));
659 bSupported &= !!(pIf->modeData.wddm.pfnChangeDisplaySettingsEx);
660
661 *(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
662 LogFunc(("VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
663 bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
664 /* for win 7 and above */
665 if (OSinfo.dwMinorVersion >= 1)
666 {
667 *(uintptr_t *)&gCtx.pfnSetDisplayConfig = (uintptr_t)GetProcAddress(hUser, "SetDisplayConfig");
668 LogFunc(("VBoxDisplayInit: pfnSetDisplayConfig = %p\n", gCtx.pfnSetDisplayConfig));
669 bSupported &= !!(gCtx.pfnSetDisplayConfig);
670
671 *(uintptr_t *)&gCtx.pfnQueryDisplayConfig = (uintptr_t)GetProcAddress(hUser, "QueryDisplayConfig");
672 LogFunc(("VBoxDisplayInit: pfnQueryDisplayConfig = %p\n", gCtx.pfnQueryDisplayConfig));
673 bSupported &= !!(gCtx.pfnQueryDisplayConfig);
674
675 *(uintptr_t *)&gCtx.pfnGetDisplayConfigBufferSizes = (uintptr_t)GetProcAddress(hUser, "GetDisplayConfigBufferSizes");
676 LogFunc(("VBoxDisplayInit: pfnGetDisplayConfigBufferSizes = %p\n", gCtx.pfnGetDisplayConfigBufferSizes));
677 bSupported &= !!(gCtx.pfnGetDisplayConfigBufferSizes);
678 }
679
680 /* this is vista and up */
681 HRESULT hr = vboxDispKmtCallbacksInit(&pIf->modeData.wddm.KmtCallbacks);
682 if (FAILED(hr))
683 {
684 WARN(("VBoxTray: vboxDispKmtCallbacksInit failed hr 0x%x\n", hr));
685 err = hr;
686 }
687 }
688 else
689 {
690 WARN_FUNC(("GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
691 err = ERROR_NOT_SUPPORTED;
692 }
693 }
694 else
695 {
696 WARN_FUNC(("can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
697 err = ERROR_NOT_SUPPORTED;
698 }
699
700 if (err == ERROR_SUCCESS)
701 {
702 err = vboxDispIfWddmInit(pIf);
703 }
704
705 return err;
706}
707
708static DWORD vboxDispIfSwitchToWDDM_W7(PVBOXDISPIF pIf)
709{
710 return vboxDispIfSwitchToWDDM(pIf);
711}
712
713static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
714{
715 DWORD winEr = ERROR_INVALID_STATE;
716 memset(pDev, 0, sizeof (*pDev));
717 pDev->cb = sizeof (*pDev);
718
719 for (int i = 0; ; ++i)
720 {
721 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
722 pDev, 0 /* DWORD dwFlags*/))
723 {
724 if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
725 {
726 HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
727 if (hDc)
728 {
729 *phDc = hDc;
730 return NO_ERROR;
731 }
732 else
733 {
734 winEr = GetLastError();
735 WARN(("CreateDC failed %d", winEr));
736 break;
737 }
738 }
739 Log(("display data no match display(%d): i(%d), flags(%d)", iDisplay, i, pDev->StateFlags));
740 }
741 else
742 {
743 winEr = GetLastError();
744 WARN(("EnumDisplayDevices failed %d", winEr));
745 break;
746 }
747 }
748
749 WARN(("vboxDispIfWDDMAdpHdcCreate failure branch %d", winEr));
750 return winEr;
751}
752
753static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
754{
755 DWORD winEr = ERROR_SUCCESS;
756 VBOXDISPKMT_ADAPTER Adapter;
757 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &Adapter);
758 if (!SUCCEEDED(hr))
759 {
760 WARN(("VBoxTray: vboxDispKmtOpenAdapter failed hr 0x%x\n", hr));
761 return hr;
762 }
763
764 D3DKMT_ESCAPE EscapeData = {0};
765 EscapeData.hAdapter = Adapter.hAdapter;
766 //EscapeData.hDevice = NULL;
767 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
768 if (fHwAccess)
769 EscapeData.Flags.HardwareAccess = 1;
770 EscapeData.pPrivateDriverData = pEscape;
771 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
772 //EscapeData.hContext = NULL;
773
774 NTSTATUS Status = pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
775 if (NT_SUCCESS(Status))
776 winEr = ERROR_SUCCESS;
777 else
778 {
779 WARN(("VBoxTray: pfnD3DKMTEscape failed Status 0x%x\n", Status));
780 winEr = ERROR_GEN_FAILURE;
781 }
782
783 vboxDispKmtCloseAdapter(&Adapter);
784
785 return winEr;
786}
787#endif
788
789DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
790{
791 switch (pIf->enmMode)
792 {
793 case VBOXDISPIF_MODE_XPDM_NT4:
794 case VBOXDISPIF_MODE_XPDM:
795 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 1);
796#ifdef VBOX_WITH_WDDM
797 case VBOXDISPIF_MODE_WDDM:
798 case VBOXDISPIF_MODE_WDDM_W7:
799 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
800#endif
801 default:
802 LogFunc(("unknown mode (%d)\n", pIf->enmMode));
803 return ERROR_INVALID_PARAMETER;
804 }
805}
806
807DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
808{
809 switch (pIf->enmMode)
810 {
811 case VBOXDISPIF_MODE_XPDM_NT4:
812 case VBOXDISPIF_MODE_XPDM:
813 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 0);
814#ifdef VBOX_WITH_WDDM
815 case VBOXDISPIF_MODE_WDDM:
816 case VBOXDISPIF_MODE_WDDM_W7:
817 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
818#endif
819 default:
820 LogFunc(("unknown mode (%d)\n", pIf->enmMode));
821 return ERROR_INVALID_PARAMETER;
822 }
823}
824
825#ifdef VBOX_WITH_WDDM
826
827#define VBOXRR_TIMER_ID 1234
828
829typedef struct VBOXRR
830{
831 HANDLE hThread;
832 DWORD idThread;
833 HANDLE hEvent;
834 HWND hWnd;
835 CRITICAL_SECTION CritSect;
836 UINT_PTR idTimer;
837 PCVBOXDISPIF pIf;
838 UINT iChangedMode;
839 BOOL fEnable;
840 BOOL fExtDispSup;
841 DISPLAY_DEVICE *paDisplayDevices;
842 DEVMODE *paDeviceModes;
843 UINT cDevModes;
844} VBOXRR, *PVBOXRR;
845
846static VBOXRR g_VBoxRr = {0};
847
848#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
849#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
850
851static void vboxRrRetryStopLocked()
852{
853 PVBOXRR pMon = &g_VBoxRr;
854 if (pMon->pIf)
855 {
856 if (pMon->paDisplayDevices)
857 {
858 free(pMon->paDisplayDevices);
859 pMon->paDisplayDevices = NULL;
860 }
861
862 if (pMon->paDeviceModes)
863 {
864 free(pMon->paDeviceModes);
865 pMon->paDeviceModes = NULL;
866 }
867
868 if (pMon->idTimer)
869 {
870 KillTimer(pMon->hWnd, pMon->idTimer);
871 pMon->idTimer = 0;
872 }
873
874 pMon->cDevModes = 0;
875 pMon->pIf = NULL;
876 }
877}
878
879static void VBoxRrRetryStop()
880{
881 PVBOXRR pMon = &g_VBoxRr;
882 EnterCriticalSection(&pMon->CritSect);
883 vboxRrRetryStopLocked();
884 LeaveCriticalSection(&pMon->CritSect);
885}
886
887//static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
888
889static void vboxRrRetryReschedule()
890{
891}
892
893static void VBoxRrRetrySchedule(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
894{
895 PVBOXRR pMon = &g_VBoxRr;
896 EnterCriticalSection(&pMon->CritSect);
897 vboxRrRetryStopLocked();
898
899 pMon->pIf = pIf;
900 pMon->iChangedMode = iChangedMode;
901 pMon->fEnable = fEnable;
902 pMon->fExtDispSup = fExtDispSup;
903
904 if (cDevModes)
905 {
906 pMon->paDisplayDevices = (DISPLAY_DEVICE*)malloc(sizeof (*paDisplayDevices) * cDevModes);
907 Assert(pMon->paDisplayDevices);
908 if (!pMon->paDisplayDevices)
909 {
910 Log(("malloc failed!"));
911 vboxRrRetryStopLocked();
912 LeaveCriticalSection(&pMon->CritSect);
913 return;
914 }
915 memcpy(pMon->paDisplayDevices, paDisplayDevices, sizeof (*paDisplayDevices) * cDevModes);
916
917 pMon->paDeviceModes = (DEVMODE*)malloc(sizeof (*paDeviceModes) * cDevModes);
918 Assert(pMon->paDeviceModes);
919 if (!pMon->paDeviceModes)
920 {
921 Log(("malloc failed!"));
922 vboxRrRetryStopLocked();
923 LeaveCriticalSection(&pMon->CritSect);
924 return;
925 }
926 memcpy(pMon->paDeviceModes, paDeviceModes, sizeof (*paDeviceModes) * cDevModes);
927 }
928 pMon->cDevModes = cDevModes;
929
930 pMon->idTimer = SetTimer(pMon->hWnd, VBOXRR_TIMER_ID, 1000, (TIMERPROC)NULL);
931 Assert(pMon->idTimer);
932 if (!pMon->idTimer)
933 {
934 WARN(("VBoxTray: SetTimer failed!, err %d\n", GetLastError()));
935 vboxRrRetryStopLocked();
936 }
937
938 LeaveCriticalSection(&pMon->CritSect);
939}
940
941static void vboxRrRetryPerform()
942{
943 PVBOXRR pMon = &g_VBoxRr;
944 EnterCriticalSection(&pMon->CritSect);
945 if (pMon->pIf)
946 {
947 DWORD dwErr = vboxDispIfResizePerform(pMon->pIf, pMon->iChangedMode, pMon->fEnable, pMon->fExtDispSup, pMon->paDisplayDevices, pMon->paDeviceModes, pMon->cDevModes);
948 if (ERROR_RETRY != dwErr)
949 VBoxRrRetryStop();
950 else
951 vboxRrRetryReschedule();
952 }
953 LeaveCriticalSection(&pMon->CritSect);
954}
955
956static LRESULT CALLBACK vboxRrWndProc(HWND hwnd,
957 UINT uMsg,
958 WPARAM wParam,
959 LPARAM lParam
960)
961{
962 switch(uMsg)
963 {
964 case WM_DISPLAYCHANGE:
965 {
966 Log(("VBoxTray: WM_DISPLAYCHANGE\n"));
967 VBoxRrRetryStop();
968 return 0;
969 }
970 case WM_TIMER:
971 {
972 if (wParam == VBOXRR_TIMER_ID)
973 {
974 Log(("VBoxTray: VBOXRR_TIMER_ID\n"));
975 vboxRrRetryPerform();
976 return 0;
977 }
978 break;
979 }
980 case WM_NCHITTEST:
981 LogFunc(("got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
982 return HTNOWHERE;
983 default:
984 break;
985 }
986
987 return DefWindowProc(hwnd, uMsg, wParam, lParam);
988}
989
990#define VBOXRRWND_NAME "VBoxRrWnd"
991
992static HRESULT vboxRrWndCreate(HWND *phWnd)
993{
994 HRESULT hr = S_OK;
995
996 /** @todo r=andy Use VBOXSERVICEENV::hInstance. */
997 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
998
999 /* Register the Window Class. */
1000 WNDCLASSEX wc = { 0 };
1001 wc.cbSize = sizeof(WNDCLASSEX);
1002
1003 if (!GetClassInfoEx(hInstance, VBOXRRWND_NAME, &wc))
1004 {
1005 wc.lpfnWndProc = vboxRrWndProc;
1006 wc.hInstance = hInstance;
1007 wc.lpszClassName = VBOXRRWND_NAME;
1008
1009 if (!RegisterClassEx(&wc))
1010 {
1011 WARN_FUNC(("RegisterClass failed, winErr(%d)\n", GetLastError()));
1012 hr = E_FAIL;
1013 }
1014 }
1015
1016 if (hr == S_OK)
1017 {
1018 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
1019 VBOXRRWND_NAME, VBOXRRWND_NAME,
1020 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
1021 -100, -100,
1022 10, 10,
1023 NULL, //GetDesktopWindow() /* hWndParent */,
1024 NULL /* hMenu */,
1025 hInstance,
1026 NULL /* lpParam */);
1027 Assert(hWnd);
1028 if (hWnd)
1029 {
1030 *phWnd = hWnd;
1031 }
1032 else
1033 {
1034 WARN_FUNC(("CreateWindowEx failed, winErr(%d)\n", GetLastError()));
1035 hr = E_FAIL;
1036 }
1037 }
1038
1039 return hr;
1040}
1041
1042static HRESULT vboxRrWndDestroy(HWND hWnd)
1043{
1044 BOOL bResult = DestroyWindow(hWnd);
1045 if (bResult)
1046 return S_OK;
1047
1048 DWORD winErr = GetLastError();
1049 WARN_FUNC(("DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
1050
1051 return HRESULT_FROM_WIN32(winErr);
1052}
1053
1054static HRESULT vboxRrWndInit()
1055{
1056 PVBOXRR pMon = &g_VBoxRr;
1057 return vboxRrWndCreate(&pMon->hWnd);
1058}
1059
1060HRESULT vboxRrWndTerm()
1061{
1062 PVBOXRR pMon = &g_VBoxRr;
1063 HRESULT hrTmp = vboxRrWndDestroy(pMon->hWnd);
1064 Assert(hrTmp == S_OK); NOREF(hrTmp);
1065
1066 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
1067 UnregisterClass(VBOXRRWND_NAME, hInstance);
1068
1069 return S_OK;
1070}
1071
1072#define WM_VBOXRR_INIT_QUIT (WM_APP+2)
1073
1074HRESULT vboxRrRun()
1075{
1076 PVBOXRR pMon = &g_VBoxRr;
1077 MSG Msg;
1078
1079 HRESULT hr = S_FALSE;
1080
1081 /* Create the thread message queue*/
1082 PeekMessage(&Msg,
1083 NULL /* HWND hWnd */,
1084 WM_USER /* UINT wMsgFilterMin */,
1085 WM_USER /* UINT wMsgFilterMax */,
1086 PM_NOREMOVE);
1087
1088 /*
1089 * Send signal that message queue is ready.
1090 * From this moment only the thread is ready to receive messages.
1091 */
1092 BOOL bRc = SetEvent(pMon->hEvent);
1093 if (!bRc)
1094 {
1095 DWORD winErr = GetLastError();
1096 WARN_FUNC(("SetEvent failed, winErr = (%d)", winErr));
1097 HRESULT hrTmp = HRESULT_FROM_WIN32(winErr);
1098 Assert(hrTmp != S_OK); NOREF(hrTmp);
1099 }
1100
1101 do
1102 {
1103 BOOL bResult = GetMessage(&Msg,
1104 0 /*HWND hWnd*/,
1105 0 /*UINT wMsgFilterMin*/,
1106 0 /*UINT wMsgFilterMax*/
1107 );
1108
1109 if (bResult == -1) /* error occurred */
1110 {
1111 DWORD winEr = GetLastError();
1112 hr = HRESULT_FROM_WIN32(winEr);
1113 /* just ensure we never return success in this case */
1114 Assert(hr != S_OK);
1115 Assert(hr != S_FALSE);
1116 if (hr == S_OK || hr == S_FALSE)
1117 hr = E_FAIL;
1118 WARN(("VBoxTray: GetMessage returned -1, err %d\n", winEr));
1119 VBoxRrRetryStop();
1120 break;
1121 }
1122
1123 if(!bResult) /* WM_QUIT was posted */
1124 {
1125 hr = S_FALSE;
1126 Log(("VBoxTray: GetMessage returned FALSE\n"));
1127 VBoxRrRetryStop();
1128 break;
1129 }
1130
1131 switch (Msg.message)
1132 {
1133 case WM_VBOXRR_INIT_QUIT:
1134 case WM_CLOSE:
1135 {
1136 Log(("VBoxTray: closing Rr %d\n", Msg.message));
1137 VBoxRrRetryStop();
1138 PostQuitMessage(0);
1139 break;
1140 }
1141 default:
1142 TranslateMessage(&Msg);
1143 DispatchMessage(&Msg);
1144 break;
1145 }
1146 } while (1);
1147 return 0;
1148}
1149
1150static DWORD WINAPI vboxRrRunnerThread(void *pvUser)
1151{
1152 RT_NOREF(pvUser);
1153 HRESULT hr = vboxRrWndInit();
1154 Assert(hr == S_OK);
1155 if (hr == S_OK)
1156 {
1157 hr = vboxRrRun();
1158 Assert(hr == S_OK);
1159
1160 vboxRrWndTerm();
1161 }
1162
1163 return 0;
1164}
1165
1166HRESULT VBoxRrInit()
1167{
1168 HRESULT hr = E_FAIL;
1169 PVBOXRR pMon = &g_VBoxRr;
1170 memset(pMon, 0, sizeof (*pMon));
1171
1172 InitializeCriticalSection(&pMon->CritSect);
1173
1174 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
1175 TRUE, /* BOOL bManualReset*/
1176 FALSE, /* BOOL bInitialState */
1177 NULL /* LPCTSTR lpName */
1178 );
1179 if (pMon->hEvent)
1180 {
1181 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
1182 0 /* SIZE_T dwStackSize */,
1183 vboxRrRunnerThread,
1184 pMon,
1185 0 /* DWORD dwCreationFlags */,
1186 &pMon->idThread);
1187 if (pMon->hThread)
1188 {
1189 DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
1190 if (dwResult == WAIT_OBJECT_0)
1191 return S_OK;
1192 else
1193 {
1194 Log(("WaitForSingleObject failed!"));
1195 hr = E_FAIL;
1196 }
1197 }
1198 else
1199 {
1200 DWORD winErr = GetLastError();
1201 WARN_FUNC(("CreateThread failed, winErr = (%d)", winErr));
1202 hr = HRESULT_FROM_WIN32(winErr);
1203 Assert(hr != S_OK);
1204 }
1205 CloseHandle(pMon->hEvent);
1206 }
1207 else
1208 {
1209 DWORD winErr = GetLastError();
1210 WARN_FUNC(("CreateEvent failed, winErr = (%d)", winErr));
1211 hr = HRESULT_FROM_WIN32(winErr);
1212 Assert(hr != S_OK);
1213 }
1214
1215 DeleteCriticalSection(&pMon->CritSect);
1216
1217 return hr;
1218}
1219
1220VOID VBoxRrTerm()
1221{
1222 HRESULT hr;
1223 PVBOXRR pMon = &g_VBoxRr;
1224 if (!pMon->hThread)
1225 return;
1226
1227 BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXRR_INIT_QUIT, 0, 0);
1228 DWORD winErr;
1229 if (bResult
1230 || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
1231 {
1232 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
1233 if (dwErr == WAIT_OBJECT_0)
1234 {
1235 hr = S_OK;
1236 }
1237 else
1238 {
1239 winErr = GetLastError();
1240 hr = HRESULT_FROM_WIN32(winErr);
1241 }
1242 }
1243 else
1244 {
1245 hr = HRESULT_FROM_WIN32(winErr);
1246 }
1247
1248 DeleteCriticalSection(&pMon->CritSect);
1249
1250 CloseHandle(pMon->hThread);
1251 pMon->hThread = 0;
1252 CloseHandle(pMon->hEvent);
1253 pMon->hThread = 0;
1254}
1255
1256static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
1257{
1258 RT_NOREF(pIf);
1259 HRESULT hr = VBoxRrInit();
1260 if (SUCCEEDED(hr))
1261 return ERROR_SUCCESS;
1262 WARN(("VBoxTray: VBoxRrInit failed hr 0x%x\n", hr));
1263 return hr;
1264}
1265
1266static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
1267{
1268 RT_NOREF(pIf);
1269 VBoxRrTerm();
1270}
1271
1272static DWORD vboxDispIfQueryDisplayConnection(VBOXDISPIF_OP *pOp, UINT32 iDisplay, BOOL *pfConnected)
1273{
1274 if (pOp->pIf->enmMode == VBOXDISPIF_MODE_WDDM)
1275 {
1276 /** @todo do we need ti impl it? */
1277 *pfConnected = TRUE;
1278 return ERROR_SUCCESS;
1279 }
1280
1281 *pfConnected = FALSE;
1282
1283 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1284 DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
1285 if (winEr != ERROR_SUCCESS)
1286 {
1287 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1288 return winEr;
1289 }
1290
1291 int idx = vboxDispIfWddmDcSearchPath(&DispCfg, iDisplay, iDisplay);
1292 *pfConnected = (idx >= 0);
1293
1294 vboxDispIfWddmDcTerm(&DispCfg);
1295
1296 return ERROR_SUCCESS;
1297}
1298
1299static DWORD vboxDispIfWaitDisplayDataInited(VBOXDISPIF_OP *pOp)
1300{
1301 DWORD winEr = ERROR_SUCCESS;
1302 do
1303 {
1304 Sleep(100);
1305
1306 D3DKMT_POLLDISPLAYCHILDREN PollData = {0};
1307 PollData.hAdapter = pOp->Adapter.hAdapter;
1308 PollData.NonDestructiveOnly = 1;
1309 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTPollDisplayChildren(&PollData);
1310 if (Status != 0)
1311 {
1312 Log(("VBoxTray: (WDDM) pfnD3DKMTPollDisplayChildren failed, Status (0x%x)\n", Status));
1313 continue;
1314 }
1315
1316 BOOL fFound = FALSE;
1317#if 0
1318 for (UINT i = 0; i < VBOXWDDM_SCREENMASK_SIZE; ++i)
1319 {
1320 if (pu8DisplayMask && !ASMBitTest(pu8DisplayMask, i))
1321 continue;
1322
1323 BOOL fConnected = FALSE;
1324 winEr = vboxDispIfQueryDisplayConnection(pOp, i, &fConnected);
1325 if (winEr != ERROR_SUCCESS)
1326 {
1327 WARN(("VBoxTray: (WDDM) Failed vboxDispIfQueryDisplayConnection winEr %d\n", winEr));
1328 return winEr;
1329 }
1330
1331 if (!fConnected)
1332 {
1333 WARN(("VBoxTray: (WDDM) Display %d not connected, not expected\n", i));
1334 fFound = TRUE;
1335 break;
1336 }
1337 }
1338#endif
1339 if (!fFound)
1340 break;
1341 } while (1);
1342
1343 return winEr;
1344}
1345
1346static DWORD vboxDispIfUpdateModesWDDM(VBOXDISPIF_OP *pOp, uint32_t u32TargetId, const RTRECTSIZE *pSize)
1347{
1348 DWORD winEr = ERROR_SUCCESS;
1349 VBOXDISPIFESCAPE_UPDATEMODES EscData = {0};
1350 EscData.EscapeHdr.escapeCode = VBOXESC_UPDATEMODES;
1351 EscData.u32TargetId = u32TargetId;
1352 EscData.Size = *pSize;
1353
1354 D3DKMT_ESCAPE EscapeData = {0};
1355 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1356#ifdef VBOX_DISPIF_WITH_OPCONTEXT
1357 /* win8.1 does not allow context-based escapes for display-only mode */
1358 EscapeData.hDevice = pOp->Device.hDevice;
1359 EscapeData.hContext = pOp->Context.hContext;
1360#endif
1361 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1362 EscapeData.Flags.HardwareAccess = 1;
1363 EscapeData.pPrivateDriverData = &EscData;
1364 EscapeData.PrivateDriverDataSize = sizeof (EscData);
1365
1366 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1367 if (NT_SUCCESS(Status))
1368 winEr = ERROR_SUCCESS;
1369 else
1370 {
1371 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_UPDATEMODES failed Status 0x%x\n", Status));
1372 winEr = ERROR_GEN_FAILURE;
1373 }
1374
1375#ifdef VBOX_WDDM_REPLUG_ON_MODE_CHANGE
1376 /* The code was disabled because VBOXESC_UPDATEMODES should not cause (un)plugging virtual displays. */
1377 winEr = vboxDispIfWaitDisplayDataInited(pOp);
1378 if (winEr != NO_ERROR)
1379 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWaitDisplayDataInited winEr %d\n", winEr));
1380#endif
1381
1382 return winEr;
1383}
1384
1385static DWORD vboxDispIfTargetConnectivityWDDM(VBOXDISPIF_OP *pOp, uint32_t u32TargetId, uint32_t fu32Connect)
1386{
1387 VBOXDISPIFESCAPE_TARGETCONNECTIVITY PrivateData;
1388 RT_ZERO(PrivateData);
1389 PrivateData.EscapeHdr.escapeCode = VBOXESC_TARGET_CONNECTIVITY;
1390 PrivateData.u32TargetId = u32TargetId;
1391 PrivateData.fu32Connect = fu32Connect;
1392
1393 D3DKMT_ESCAPE EscapeData;
1394 RT_ZERO(EscapeData);
1395 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1396 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1397 EscapeData.Flags.HardwareAccess = 1;
1398 EscapeData.pPrivateDriverData = &PrivateData;
1399 EscapeData.PrivateDriverDataSize = sizeof(PrivateData);
1400
1401 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1402 if (NT_SUCCESS(Status))
1403 return ERROR_SUCCESS;
1404
1405 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_TARGETCONNECTIVITY failed Status 0x%x\n", Status));
1406 return ERROR_GEN_FAILURE;
1407}
1408
1409DWORD vboxDispIfCancelPendingResizeWDDM(PCVBOXDISPIF const pIf)
1410{
1411 RT_NOREF(pIf);
1412 Log(("VBoxTray: cancelling pending resize\n"));
1413 VBoxRrRetryStop();
1414 return NO_ERROR;
1415}
1416
1417static DWORD vboxDispIfWddmResizeDisplayVista(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD cDevModes, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup)
1418{
1419 /* Without this, Windows will not ask the miniport for its
1420 * mode table but uses an internal cache instead.
1421 */
1422 for (DWORD i = 0; i < cDevModes; i++)
1423 {
1424 DEVMODE tempDevMode;
1425 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
1426 tempDevMode.dmSize = sizeof(DEVMODE);
1427 EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
1428 Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
1429 }
1430
1431 DWORD winEr = EnableAndResizeDispDev(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, paDeviceModes[iChangedMode].dmPelsWidth, paDeviceModes[iChangedMode].dmPelsHeight,
1432 paDeviceModes[iChangedMode].dmBitsPerPel, paDeviceModes[iChangedMode].dmPosition.x, paDeviceModes[iChangedMode].dmPosition.y, fEnable, fExtDispSup);
1433 if (winEr != NO_ERROR)
1434 WARN(("VBoxTray: (WDDM) Failed EnableAndResizeDispDev winEr %d\n", winEr));
1435
1436 return winEr;
1437}
1438
1439static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1440{
1441 LogFunc((" ENTER"));
1442 DWORD winEr;
1443
1444 if (pIf->enmMode > VBOXDISPIF_MODE_WDDM)
1445 {
1446 if (fEnable)
1447 paDisplayDevices[iChangedMode].StateFlags |= DISPLAY_DEVICE_ACTIVE;
1448 else
1449 paDisplayDevices[iChangedMode].StateFlags &= ~DISPLAY_DEVICE_ACTIVE;
1450
1451 winEr = vboxDispIfWddmResizeDisplay2(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1452
1453 if (winEr != NO_ERROR)
1454 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplay winEr %d\n", winEr));
1455 }
1456 else
1457 {
1458 winEr = vboxDispIfWddmResizeDisplayVista(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, fEnable, fExtDispSup);
1459 if (winEr != NO_ERROR)
1460 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplayVista winEr %d\n", winEr));
1461 }
1462
1463 LogFunc((" LEAVE"));
1464 return winEr;
1465}
1466
1467DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1468{
1469 DWORD winEr = NO_ERROR;
1470
1471 Log(("VBoxTray: vboxDispIfResizeModesWDDM iChanged %d cDevModes %d fEnable %d fExtDispSup %d\n", iChangedMode, cDevModes, fEnable, fExtDispSup));
1472 VBoxRrRetryStop();
1473
1474 VBOXDISPIF_OP Op;
1475
1476 winEr = vboxDispIfOpBegin(pIf, &Op);
1477 if (winEr != NO_ERROR)
1478 {
1479 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x", winEr));
1480 return winEr;
1481 }
1482
1483/* The pfnD3DKMTInvalidateActiveVidPn was deprecated since Win7 and causes deadlocks since Win10 TH2.
1484 Instead, the VidPn Manager can replace an old VidPn as soon as SetDisplayConfig or ChangeDisplaySettingsEx will try to set a new display mode.
1485 On Vista D3DKMTInvalidateActiveVidPn is still required. TBD: Get rid of it. */
1486 if (Op.pIf->enmMode < VBOXDISPIF_MODE_WDDM_W7)
1487 {
1488 D3DKMT_INVALIDATEACTIVEVIDPN ddiArgInvalidateVidPN;
1489 VBOXWDDM_RECOMMENDVIDPN vboxRecommendVidPN;
1490
1491 memset(&ddiArgInvalidateVidPN, 0, sizeof(ddiArgInvalidateVidPN));
1492 memset(&vboxRecommendVidPN, 0, sizeof(vboxRecommendVidPN));
1493
1494 uint32_t cElements = 0;
1495
1496 for (uint32_t i = 0; i < cDevModes; ++i)
1497 {
1498 if ((i == iChangedMode) ? fEnable : (paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
1499 {
1500 vboxRecommendVidPN.aSources[cElements].Size.cx = paDeviceModes[i].dmPelsWidth;
1501 vboxRecommendVidPN.aSources[cElements].Size.cy = paDeviceModes[i].dmPelsHeight;
1502 vboxRecommendVidPN.aTargets[cElements].iSource = cElements;
1503 ++cElements;
1504 }
1505 else
1506 vboxRecommendVidPN.aTargets[cElements].iSource = -1;
1507 }
1508
1509 ddiArgInvalidateVidPN.hAdapter = Op.Adapter.hAdapter;
1510 ddiArgInvalidateVidPN.pPrivateDriverData = &vboxRecommendVidPN;
1511 ddiArgInvalidateVidPN.PrivateDriverDataSize = sizeof (vboxRecommendVidPN);
1512
1513 NTSTATUS Status;
1514 Status = Op.pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTInvalidateActiveVidPn(&ddiArgInvalidateVidPN);
1515 LogFunc(("D3DKMTInvalidateActiveVidPn returned %d)\n", Status));
1516 }
1517
1518 vboxDispIfTargetConnectivityWDDM(&Op, iChangedMode, fEnable? 1: 0);
1519
1520 /* Whether the current display is already or should be enabled. */
1521 BOOL fChangedEnable = fEnable || RT_BOOL(paDisplayDevices[iChangedMode].StateFlags & DISPLAY_DEVICE_ACTIVE);
1522
1523 if (fChangedEnable)
1524 {
1525 RTRECTSIZE Size;
1526
1527 Size.cx = paDeviceModes[iChangedMode].dmPelsWidth;
1528 Size.cy = paDeviceModes[iChangedMode].dmPelsHeight;
1529
1530 LogFunc(("Calling vboxDispIfUpdateModesWDDM to change target %d mode to (%d x %d)\n", iChangedMode, Size.cx, Size.cy));
1531 winEr = vboxDispIfUpdateModesWDDM(&Op, iChangedMode, &Size);
1532 }
1533
1534 winEr = vboxDispIfResizePerform(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1535
1536 if (winEr == ERROR_RETRY)
1537 {
1538 VBoxRrRetrySchedule(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1539
1540 winEr = NO_ERROR;
1541 }
1542
1543 vboxDispIfOpEnd(&Op);
1544
1545 return winEr;
1546}
1547
1548static DWORD vboxDispIfWddmEnableDisplays(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnabled, BOOL fSetTopology, DEVMODE *pDeviceMode)
1549{
1550 RT_NOREF(pIf);
1551 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1552
1553 DWORD winEr;
1554 int iPath;
1555
1556 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1557 if (winEr != ERROR_SUCCESS)
1558 {
1559 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1560 return winEr;
1561 }
1562
1563 UINT cChangeIds = 0;
1564 UINT *pChangeIds = (UINT*)alloca(cIds * sizeof (*pChangeIds));
1565 if (!pChangeIds)
1566 {
1567 WARN(("VBoxTray: (WDDM) Failed to alloc change ids\n"));
1568 winEr = ERROR_OUTOFMEMORY;
1569 goto done;
1570 }
1571
1572 for (UINT i = 0; i < cIds; ++i)
1573 {
1574 UINT Id = pIds[i];
1575 bool fIsDup = false;
1576 for (UINT j = 0; j < cChangeIds; ++j)
1577 {
1578 if (pChangeIds[j] == Id)
1579 {
1580 fIsDup = true;
1581 break;
1582 }
1583 }
1584
1585 if (fIsDup)
1586 continue;
1587
1588 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
1589
1590 if (!((iPath >= 0) && (DispCfg.pPathInfoArray[iPath].flags & DISPLAYCONFIG_PATH_ACTIVE)) != !fEnabled)
1591 {
1592 pChangeIds[cChangeIds] = Id;
1593 ++cChangeIds;
1594 }
1595 }
1596
1597 if (cChangeIds == 0)
1598 {
1599 Log(("VBoxTray: (WDDM) vboxDispIfWddmEnableDisplay: settings are up to date\n"));
1600 winEr = ERROR_SUCCESS;
1601 goto done;
1602 }
1603
1604 /* we want to set primary for every disabled for non-topoly mode only */
1605 winEr = vboxDispIfWddmDcSettingsIncludeAllTargets(&DispCfg);
1606 if (winEr != ERROR_SUCCESS)
1607 {
1608 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsIncludeAllTargets winEr %d\n", winEr));
1609 return winEr;
1610 }
1611
1612 if (fSetTopology)
1613 vboxDispIfWddmDcSettingsInvalidateModeIndeces(&DispCfg);
1614
1615 for (UINT i = 0; i < cChangeIds; ++i)
1616 {
1617 UINT Id = pChangeIds[i];
1618 /* re-query paths */
1619 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, VBOX_WDDM_DC_SEARCH_PATH_ANY, Id);
1620 if (iPath < 0)
1621 {
1622 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1623 winEr = ERROR_GEN_FAILURE;
1624 goto done;
1625 }
1626
1627 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, pDeviceMode, !fEnabled || fSetTopology, fEnabled);
1628 if (winEr != ERROR_SUCCESS)
1629 {
1630 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1631 goto done;
1632 }
1633 }
1634
1635 if (!fSetTopology)
1636 vboxDispIfWddmDcSettingsAttachDisbledToPrimary(&DispCfg);
1637
1638#if 0
1639 /* ensure the zero-index (primary) screen is enabled */
1640 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, 0, 0);
1641 if (iPath < 0)
1642 {
1643 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1644 winEr = ERROR_GEN_FAILURE;
1645 goto done;
1646 }
1647
1648 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, /* just re-use device node here*/ pDeviceMode, fSetTopology, TRUE);
1649 if (winEr != ERROR_SUCCESS)
1650 {
1651 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1652 goto done;
1653 }
1654#endif
1655
1656 UINT fSetFlags = !fSetTopology ? (SDC_USE_SUPPLIED_DISPLAY_CONFIG) : (SDC_ALLOW_PATH_ORDER_CHANGES | SDC_TOPOLOGY_SUPPLIED);
1657 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1658 if (winEr != ERROR_SUCCESS)
1659 {
1660 if (!fSetTopology)
1661 {
1662 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet validation failed winEr, trying with changes %d\n", winEr));
1663 fSetFlags |= SDC_ALLOW_CHANGES;
1664 }
1665 else
1666 {
1667 Log(("VBoxTray: (WDDM) vboxDispIfWddmDcSet topology validation failed winEr %d\n", winEr));
1668 goto done;
1669 }
1670 }
1671
1672 if (!fSetTopology)
1673 fSetFlags |= SDC_SAVE_TO_DATABASE;
1674
1675 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_APPLY);
1676 if (winEr != ERROR_SUCCESS)
1677 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet apply failed winEr %d\n", winEr));
1678
1679done:
1680 vboxDispIfWddmDcTerm(&DispCfg);
1681
1682 return winEr;
1683}
1684
1685static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable)
1686{
1687 DWORD winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, FALSE, NULL);
1688 if (winEr != ERROR_SUCCESS)
1689 {
1690 if (fEnable)
1691 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1692 else
1693 Log(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1694 winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, TRUE, NULL);
1695 if (winEr != ERROR_SUCCESS)
1696 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1697 }
1698
1699 return winEr;
1700}
1701
1702BOOL vboxDispIfWddmResizeDisplayWin7(PCVBOXDISPIF const pIf, uint32_t cDispDef, const VMMDevDisplayDef *paDispDef)
1703{
1704 const VMMDevDisplayDef* pDispDef;
1705 VBOXDISPIF_OP Op;
1706 DWORD winEr = ERROR_SUCCESS;
1707 uint32_t id;
1708 int iPath;
1709
1710 vboxDispIfOpBegin(pIf, &Op);
1711
1712 for (id = 0; id < cDispDef; ++id)
1713 {
1714 pDispDef = &paDispDef[id];
1715
1716 if (!(pDispDef->fDisplayFlags & VMMDEV_DISPLAY_DISABLED) &&
1717 (pDispDef->fDisplayFlags | VMMDEV_DISPLAY_CX) ||
1718 (pDispDef->fDisplayFlags | VMMDEV_DISPLAY_CY))
1719 {
1720 RTRECTSIZE Size;
1721
1722 Size.cx = pDispDef->cx;
1723 Size.cy = pDispDef->cy;
1724
1725 vboxDispIfUpdateModesWDDM(&Op, id, &Size);
1726 }
1727 }
1728
1729 vboxDispIfOpEnd(&Op);
1730
1731 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1732
1733 vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
1734
1735 for (id = 0; id < cDispDef; ++id)
1736 {
1737 DISPLAYCONFIG_PATH_INFO *pPathInfo;
1738
1739 pDispDef = &paDispDef[id];
1740 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, id, id);
1741
1742 if (iPath < 0)
1743 {
1744 WARN(("VBoxTray:(WDDM) Unexpected iPath(%d) between src(%d) and tgt(%d)\n", iPath, id, id));
1745 continue;
1746 }
1747
1748 if (!(pDispDef->fDisplayFlags & VMMDEV_DISPLAY_DISABLED))
1749 {
1750 DISPLAYCONFIG_SOURCE_MODE *pSrcMode;
1751 DISPLAYCONFIG_TARGET_MODE *pTgtMode;
1752
1753 pPathInfo = &DispCfg.pPathInfoArray[iPath];
1754
1755 if (pPathInfo->flags & DISPLAYCONFIG_PATH_ACTIVE)
1756 {
1757 UINT iSrcMode, iTgtMode;
1758
1759 iSrcMode = pPathInfo->sourceInfo.modeInfoIdx;
1760 iTgtMode = pPathInfo->targetInfo.modeInfoIdx;
1761
1762 if (iSrcMode >= DispCfg.cModeInfoArray || iTgtMode >= DispCfg.cModeInfoArray)
1763 {
1764 WARN(("VBoxTray:(WDDM) Unexpected iSrcMode(%d) and/or iTgtMode(%d)\n", iSrcMode, iTgtMode));
1765 continue;
1766 }
1767
1768 pSrcMode = &DispCfg.pModeInfoArray[iSrcMode].sourceMode;
1769 pTgtMode = &DispCfg.pModeInfoArray[iTgtMode].targetMode;
1770
1771 pSrcMode->width =
1772 pTgtMode->targetVideoSignalInfo.activeSize.cx =
1773 pTgtMode->targetVideoSignalInfo.totalSize.cx = pDispDef->cx;
1774
1775 pSrcMode->height =
1776 pTgtMode->targetVideoSignalInfo.activeSize.cy =
1777 pTgtMode->targetVideoSignalInfo.totalSize.cy = pDispDef->cy;
1778
1779 pSrcMode->position.x = pDispDef->xOrigin;
1780 pSrcMode->position.y = pDispDef->yOrigin;
1781
1782 switch (pDispDef->cBitsPerPixel)
1783 {
1784 case 32:
1785 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
1786 break;
1787 case 24:
1788 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_24BPP;
1789 break;
1790 case 16:
1791 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_16BPP;
1792 break;
1793 case 8:
1794 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_8BPP;
1795 break;
1796 default:
1797 LogRel(("VBoxTray: (WDDM) invalid bpp %d, using 32bpp instead\n", pDispDef->cBitsPerPixel));
1798 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
1799 break;
1800 }
1801 }
1802 else
1803 {
1804 DISPLAYCONFIG_MODE_INFO *pModeInfo, *pModeInfoNew;
1805
1806 pModeInfo = (DISPLAYCONFIG_MODE_INFO *)realloc(DispCfg.pModeInfoArray, (DispCfg.cModeInfoArray + 2) * sizeof(DISPLAYCONFIG_MODE_INFO));
1807
1808 if (!pModeInfo)
1809 {
1810 WARN(("VBoxTray:(WDDM) Unable to re-allocate DispCfg.pModeInfoArray\n"));
1811 continue;
1812 }
1813
1814 DispCfg.pModeInfoArray = pModeInfo;
1815
1816 *pPathInfo = DispCfg.pPathInfoArray[0];
1817 pPathInfo->sourceInfo.id = id;
1818 pPathInfo->targetInfo.id = id;
1819
1820 pModeInfoNew = &pModeInfo[DispCfg.cModeInfoArray];
1821 pModeInfoNew->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE;
1822 pModeInfoNew->id = id;
1823 pModeInfoNew->adapterId = pModeInfo[0].adapterId;
1824 pSrcMode = &pModeInfoNew->sourceMode;
1825 pSrcMode->width = pDispDef->cx;
1826 pSrcMode->height = pDispDef->cy;
1827 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
1828 pSrcMode->position.x = pDispDef->xOrigin;
1829 pSrcMode->position.y = pDispDef->yOrigin;
1830 pPathInfo->sourceInfo.modeInfoIdx = DispCfg.cModeInfoArray;
1831
1832 pModeInfoNew++;
1833 pModeInfoNew->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET;
1834 pModeInfoNew->id = id;
1835 pModeInfoNew->adapterId = pModeInfo[0].adapterId;
1836 pModeInfoNew->targetMode = pModeInfo[0].targetMode;
1837 pTgtMode = &pModeInfoNew->targetMode;
1838 pTgtMode->targetVideoSignalInfo.activeSize.cx =
1839 pTgtMode->targetVideoSignalInfo.totalSize.cx = pDispDef->cx;
1840 pTgtMode->targetVideoSignalInfo.activeSize.cy =
1841 pTgtMode->targetVideoSignalInfo.totalSize.cy = pDispDef->cy;
1842 pPathInfo->targetInfo.modeInfoIdx = DispCfg.cModeInfoArray + 1;
1843
1844 DispCfg.cModeInfoArray += 2;
1845 }
1846 }
1847 else
1848 {
1849 DispCfg.pPathInfoArray[id].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
1850 }
1851 }
1852
1853 UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
1854 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1855 if (winEr != ERROR_SUCCESS)
1856 {
1857 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1858 fSetFlags |= SDC_ALLOW_CHANGES;
1859 }
1860
1861 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
1862 if (winEr != ERROR_SUCCESS)
1863 {
1864 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1865 }
1866
1867 vboxDispIfWddmDcTerm(&DispCfg);
1868
1869 return (winEr == ERROR_SUCCESS);
1870}
1871
1872static DWORD vboxDispIfWddmResizeDisplay2(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT devModes)
1873{
1874 RT_NOREF(pIf, paDeviceModes);
1875 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1876 DWORD winEr = ERROR_SUCCESS;
1877 UINT idx;
1878 int iPath;
1879
1880 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
1881
1882 if (winEr != ERROR_SUCCESS)
1883 {
1884 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate\n"));
1885 return winEr;
1886 }
1887
1888 for (idx = 0; idx < devModes; idx++)
1889 {
1890 DEVMODE *pDeviceMode = &paDeviceModes[idx];
1891
1892 if (paDisplayDevices[idx].StateFlags & DISPLAY_DEVICE_ACTIVE)
1893 {
1894 DISPLAYCONFIG_PATH_INFO *pPathInfo;
1895
1896 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, idx, idx);
1897
1898 if (iPath < 0)
1899 {
1900 WARN(("VBoxTray:(WDDM) Unexpected iPath(%d) between src(%d) and tgt(%d)\n", iPath, idx, idx));
1901 continue;
1902 }
1903
1904 pPathInfo = &DispCfg.pPathInfoArray[iPath];
1905
1906 if (pPathInfo->flags & DISPLAYCONFIG_PATH_ACTIVE)
1907 {
1908 UINT iSrcMode, iTgtMode;
1909 DISPLAYCONFIG_SOURCE_MODE *pSrcMode;
1910 DISPLAYCONFIG_TARGET_MODE *pTgtMode;
1911
1912 iSrcMode = pPathInfo->sourceInfo.modeInfoIdx;
1913 iTgtMode = pPathInfo->targetInfo.modeInfoIdx;
1914
1915 if (iSrcMode >= DispCfg.cModeInfoArray || iTgtMode >= DispCfg.cModeInfoArray)
1916 {
1917 WARN(("VBoxTray:(WDDM) Unexpected iSrcMode(%d) and/or iTgtMode(%d)\n", iSrcMode, iTgtMode));
1918 continue;
1919 }
1920
1921 pSrcMode = &DispCfg.pModeInfoArray[iSrcMode].sourceMode;
1922 pTgtMode = &DispCfg.pModeInfoArray[iTgtMode].targetMode;
1923
1924 if (pDeviceMode->dmFields & DM_PELSWIDTH)
1925 {
1926 pSrcMode->width = pDeviceMode->dmPelsWidth;
1927 pTgtMode->targetVideoSignalInfo.activeSize.cx = pDeviceMode->dmPelsWidth;
1928 pTgtMode->targetVideoSignalInfo.totalSize.cx = pDeviceMode->dmPelsWidth;
1929 }
1930
1931 if (pDeviceMode->dmFields & DM_PELSHEIGHT)
1932 {
1933 pSrcMode->height = pDeviceMode->dmPelsHeight;
1934 pTgtMode->targetVideoSignalInfo.activeSize.cy = pDeviceMode->dmPelsHeight;
1935 pTgtMode->targetVideoSignalInfo.totalSize.cy = pDeviceMode->dmPelsHeight;
1936 }
1937
1938 if (pDeviceMode->dmFields & DM_POSITION)
1939 {
1940 pSrcMode->position.x = pDeviceMode->dmPosition.x;
1941 pSrcMode->position.y = pDeviceMode->dmPosition.y;
1942 }
1943
1944 if (pDeviceMode->dmFields & DM_BITSPERPEL)
1945 {
1946 switch (pDeviceMode->dmBitsPerPel)
1947 {
1948 case 32:
1949 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
1950 break;
1951 case 24:
1952 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_24BPP;
1953 break;
1954 case 16:
1955 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_16BPP;
1956 break;
1957 case 8:
1958 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_8BPP;
1959 break;
1960 default:
1961 LogRel(("VBoxTray: (WDDM) invalid bpp %d, using 32bpp instead\n", pDeviceMode->dmBitsPerPel));
1962 pSrcMode->pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
1963 break;
1964 }
1965 }
1966 }
1967 else
1968 {
1969 DISPLAYCONFIG_MODE_INFO *pModeInfo, *pModeInfoNew;
1970
1971 pModeInfo = (DISPLAYCONFIG_MODE_INFO *)realloc(DispCfg.pModeInfoArray, (DispCfg.cModeInfoArray + 2) * sizeof(DISPLAYCONFIG_MODE_INFO));
1972
1973 if (!pModeInfo)
1974 {
1975 WARN(("VBoxTray:(WDDM) Unable to re-allocate DispCfg.pModeInfoArray\n"));
1976 continue;
1977 }
1978
1979 DispCfg.pModeInfoArray = pModeInfo;
1980
1981 *pPathInfo = DispCfg.pPathInfoArray[0];
1982 pPathInfo->sourceInfo.id = idx;
1983 pPathInfo->targetInfo.id = idx;
1984
1985 pModeInfoNew = &pModeInfo[DispCfg.cModeInfoArray];
1986
1987 pModeInfoNew->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE;
1988 pModeInfoNew->id = idx;
1989 pModeInfoNew->adapterId = pModeInfo[0].adapterId;
1990 pModeInfoNew->sourceMode.width = pDeviceMode->dmPelsWidth;
1991 pModeInfoNew->sourceMode.height = pDeviceMode->dmPelsHeight;
1992 pModeInfoNew->sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
1993 pModeInfoNew->sourceMode.position.x = pDeviceMode->dmPosition.x;
1994 pModeInfoNew->sourceMode.position.y = pDeviceMode->dmPosition.y;
1995 pPathInfo->sourceInfo.modeInfoIdx = DispCfg.cModeInfoArray;
1996
1997 pModeInfoNew++;
1998 pModeInfoNew->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET;
1999 pModeInfoNew->id = idx;
2000 pModeInfoNew->adapterId = pModeInfo[0].adapterId;
2001 pModeInfoNew->targetMode = pModeInfo[0].targetMode;
2002 pModeInfoNew->targetMode.targetVideoSignalInfo.activeSize.cx = pDeviceMode->dmPelsWidth;
2003 pModeInfoNew->targetMode.targetVideoSignalInfo.totalSize.cx = pDeviceMode->dmPelsWidth;
2004 pModeInfoNew->targetMode.targetVideoSignalInfo.activeSize.cy = pDeviceMode->dmPelsHeight;
2005 pModeInfoNew->targetMode.targetVideoSignalInfo.totalSize.cy = pDeviceMode->dmPelsHeight;
2006 pPathInfo->targetInfo.modeInfoIdx = DispCfg.cModeInfoArray + 1;
2007
2008 DispCfg.cModeInfoArray += 2;
2009 }
2010 }
2011 else
2012 {
2013 iPath = vboxDispIfWddmDcSearchActivePath(&DispCfg, idx, idx);
2014
2015 if (iPath >= 0)
2016 {
2017 DispCfg.pPathInfoArray[idx].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
2018 }
2019 }
2020 }
2021
2022 UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
2023 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
2024 if (winEr != ERROR_SUCCESS)
2025 {
2026 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
2027 fSetFlags |= SDC_ALLOW_CHANGES;
2028 }
2029
2030 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
2031 if (winEr != ERROR_SUCCESS)
2032 {
2033 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
2034 }
2035
2036 vboxDispIfWddmDcTerm(&DispCfg);
2037
2038 return winEr;
2039}
2040
2041static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE *paDisplayDevices,
2042 DEVMODE *paDeviceModes, UINT devModes)
2043{
2044 RT_NOREF(paDisplayDevices, devModes);
2045 VBOXDISPIF_WDDM_DISPCFG DispCfg;
2046 DWORD winEr;
2047 int iPath;
2048
2049 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
2050 if (winEr != ERROR_SUCCESS)
2051 {
2052 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate\n"));
2053 return winEr;
2054 }
2055
2056 iPath = vboxDispIfWddmDcSearchActivePath(&DispCfg, Id, Id);
2057
2058 if (iPath < 0)
2059 {
2060 vboxDispIfWddmDcTerm(&DispCfg);
2061
2062 if (!fEnable)
2063 {
2064 /* nothing to be done here, just leave */
2065 return ERROR_SUCCESS;
2066 }
2067
2068 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
2069 if (winEr != ERROR_SUCCESS)
2070 {
2071 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
2072 return winEr;
2073 }
2074
2075 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
2076 if (winEr != ERROR_SUCCESS)
2077 {
2078 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
2079 return winEr;
2080 }
2081
2082 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
2083 if (iPath < 0)
2084 {
2085 WARN(("VBoxTray: (WDDM) path (%d) is still disabled, going to retry winEr %d\n", winEr));
2086 vboxDispIfWddmDcTerm(&DispCfg);
2087 return ERROR_RETRY;
2088 }
2089 }
2090
2091 Assert(iPath >= 0);
2092
2093 if (!fEnable)
2094 {
2095 /* need to disable it, and we are done */
2096 vboxDispIfWddmDcTerm(&DispCfg);
2097
2098 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
2099 if (winEr != ERROR_SUCCESS)
2100 {
2101 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
2102 return winEr;
2103 }
2104
2105 return winEr;
2106 }
2107
2108 Assert(fEnable);
2109
2110 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, &paDeviceModes[Id], FALSE, fEnable);
2111 if (winEr != ERROR_SUCCESS)
2112 {
2113 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate\n"));
2114 vboxDispIfWddmDcTerm(&DispCfg);
2115 return winEr;
2116 }
2117
2118 UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
2119 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
2120 if (winEr != ERROR_SUCCESS)
2121 {
2122 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
2123 fSetFlags |= SDC_ALLOW_CHANGES;
2124 }
2125
2126 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
2127 if (winEr != ERROR_SUCCESS)
2128 {
2129 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
2130 }
2131
2132 vboxDispIfWddmDcTerm(&DispCfg);
2133
2134 return winEr;
2135}
2136
2137#endif /* VBOX_WITH_WDDM */
2138
2139DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
2140{
2141 switch (pIf->enmMode)
2142 {
2143 case VBOXDISPIF_MODE_XPDM_NT4:
2144 return ERROR_NOT_SUPPORTED;
2145 case VBOXDISPIF_MODE_XPDM:
2146 return ERROR_NOT_SUPPORTED;
2147#ifdef VBOX_WITH_WDDM
2148 case VBOXDISPIF_MODE_WDDM:
2149 case VBOXDISPIF_MODE_WDDM_W7:
2150 return vboxDispIfResizeModesWDDM(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
2151#endif
2152 default:
2153 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
2154 return ERROR_INVALID_PARAMETER;
2155 }
2156}
2157
2158DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf)
2159{
2160 switch (pIf->enmMode)
2161 {
2162 case VBOXDISPIF_MODE_XPDM_NT4:
2163 return NO_ERROR;
2164 case VBOXDISPIF_MODE_XPDM:
2165 return NO_ERROR;
2166#ifdef VBOX_WITH_WDDM
2167 case VBOXDISPIF_MODE_WDDM:
2168 case VBOXDISPIF_MODE_WDDM_W7:
2169 return vboxDispIfCancelPendingResizeWDDM(pIf);
2170#endif
2171 default:
2172 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
2173 return ERROR_INVALID_PARAMETER;
2174 }
2175}
2176
2177static DWORD vboxDispIfConfigureTargetsWDDM(VBOXDISPIF_OP *pOp, uint32_t *pcConnected)
2178{
2179 VBOXDISPIFESCAPE EscapeHdr = {0};
2180 EscapeHdr.escapeCode = VBOXESC_CONFIGURETARGETS;
2181 EscapeHdr.u32CmdSpecific = 0;
2182
2183 D3DKMT_ESCAPE EscapeData = {0};
2184 EscapeData.hAdapter = pOp->Adapter.hAdapter;
2185#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2186 /* win8.1 does not allow context-based escapes for display-only mode */
2187 EscapeData.hDevice = pOp->Device.hDevice;
2188 EscapeData.hContext = pOp->Context.hContext;
2189#endif
2190 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
2191 EscapeData.Flags.HardwareAccess = 1;
2192 EscapeData.pPrivateDriverData = &EscapeHdr;
2193 EscapeData.PrivateDriverDataSize = sizeof (EscapeHdr);
2194
2195 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
2196 if (NT_SUCCESS(Status))
2197 {
2198 if (pcConnected)
2199 *pcConnected = EscapeHdr.u32CmdSpecific;
2200 return NO_ERROR;
2201 }
2202 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_CONFIGURETARGETS failed Status 0x%x\n", Status));
2203 return Status;
2204}
2205
2206static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp)
2207{
2208 DWORD NumDevices = VBoxDisplayGetCount();
2209 if (NumDevices == 0)
2210 {
2211 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
2212 return ERROR_GEN_FAILURE;
2213 }
2214
2215 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
2216 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
2217 DWORD DevNum = 0;
2218 DWORD DevPrimaryNum = 0;
2219
2220 DWORD winEr = VBoxDisplayGetConfig(NumDevices, &DevPrimaryNum, &DevNum, paDisplayDevices, paDeviceModes);
2221 if (winEr != NO_ERROR)
2222 {
2223 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed, %d\n", winEr));
2224 return winEr;
2225 }
2226
2227 if (NumDevices != DevNum)
2228 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != DevNum(%d)\n", NumDevices, DevNum));
2229
2230
2231 uint32_t cConnected = 0;
2232 winEr = vboxDispIfConfigureTargetsWDDM(pOp, &cConnected);
2233 if (winEr != NO_ERROR)
2234 {
2235 WARN(("VBoxTray: vboxDispIfConfigureTargetsWDDM failed winEr 0x%x\n", winEr));
2236 return winEr;
2237 }
2238
2239 if (!cConnected)
2240 {
2241 Log(("VBoxTray: all targets already connected, nothing to do\n"));
2242 return NO_ERROR;
2243 }
2244
2245 winEr = vboxDispIfWaitDisplayDataInited(pOp);
2246 if (winEr != NO_ERROR)
2247 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWaitDisplayDataInited failed winEr 0x%x\n", winEr));
2248
2249 DWORD NewNumDevices = VBoxDisplayGetCount();
2250 if (NewNumDevices == 0)
2251 {
2252 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
2253 return ERROR_GEN_FAILURE;
2254 }
2255
2256 if (NewNumDevices != NumDevices)
2257 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != NewNumDevices(%d)\n", NumDevices, NewNumDevices));
2258
2259 DISPLAY_DEVICE *paNewDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NewNumDevices);
2260 DEVMODE *paNewDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NewNumDevices);
2261 DWORD NewDevNum = 0;
2262 DWORD NewDevPrimaryNum = 0;
2263
2264 winEr = VBoxDisplayGetConfig(NewNumDevices, &NewDevPrimaryNum, &NewDevNum, paNewDisplayDevices, paNewDeviceModes);
2265 if (winEr != NO_ERROR)
2266 {
2267 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed for new devices, %d\n", winEr));
2268 return winEr;
2269 }
2270
2271 if (NewNumDevices != NewDevNum)
2272 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NewNumDevices(%d) != NewDevNum(%d)\n", NewNumDevices, NewDevNum));
2273
2274 DWORD minDevNum = RT_MIN(DevNum, NewDevNum);
2275 UINT *pIds = (UINT*)alloca (sizeof (UINT) * minDevNum);
2276 UINT cIds = 0;
2277 for (DWORD i = 0; i < minDevNum; ++i)
2278 {
2279 if ((paNewDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE)
2280 && !(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
2281 {
2282 pIds[cIds] = i;
2283 ++cIds;
2284 }
2285 }
2286
2287 if (!cIds)
2288 {
2289 /* this is something we would not regularly expect */
2290 WARN(("VBoxTray: all targets already have proper config, nothing to do\n"));
2291 return NO_ERROR;
2292 }
2293
2294 if (pOp->pIf->enmMode > VBOXDISPIF_MODE_WDDM)
2295 {
2296 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pOp->pIf, cIds, pIds, FALSE);
2297 if (winEr != NO_ERROR)
2298 WARN(("VBoxTray: vboxDispIfWddmEnableDisplaysTryingTopology failed to record current settings, %d, ignoring\n", winEr));
2299 }
2300 else
2301 {
2302 for (DWORD i = 0; i < cIds; ++i)
2303 {
2304 winEr = vboxDispIfWddmResizeDisplayVista(paNewDeviceModes, paNewDisplayDevices, NewDevNum, i, FALSE, TRUE);
2305 if (winEr != NO_ERROR)
2306 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWddmResizeDisplayVista failed winEr 0x%x\n", winEr));
2307 }
2308 }
2309
2310 return winEr;
2311}
2312
2313
2314static DWORD vboxDispIfResizeStartedWDDM(PCVBOXDISPIF const pIf)
2315{
2316 VBOXDISPIF_OP Op;
2317
2318 DWORD winEr = vboxDispIfOpBegin(pIf, &Op);
2319 if (winEr != NO_ERROR)
2320 {
2321 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x\n", winEr));
2322 return winEr;
2323 }
2324
2325 winEr = vboxDispIfResizeStartedWDDMOp(&Op);
2326 if (winEr != NO_ERROR)
2327 {
2328 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp failed winEr 0x%x\n", winEr));
2329 }
2330
2331 vboxDispIfOpEnd(&Op);
2332
2333 return winEr;
2334}
2335
2336DWORD VBoxDispIfResizeStarted(PCVBOXDISPIF const pIf)
2337{
2338 switch (pIf->enmMode)
2339 {
2340 case VBOXDISPIF_MODE_XPDM_NT4:
2341 return NO_ERROR;
2342 case VBOXDISPIF_MODE_XPDM:
2343 return NO_ERROR;
2344#ifdef VBOX_WITH_WDDM
2345 case VBOXDISPIF_MODE_WDDM:
2346 case VBOXDISPIF_MODE_WDDM_W7:
2347 return vboxDispIfResizeStartedWDDM(pIf);
2348#endif
2349 default:
2350 WARN_FUNC(("unknown mode (%d)\n", pIf->enmMode));
2351 return ERROR_INVALID_PARAMETER;
2352 }
2353}
2354
2355static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
2356{
2357 RT_NOREF(pIf);
2358 return NO_ERROR;
2359}
2360
2361static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
2362{
2363 DWORD err = NO_ERROR;
2364
2365 OSVERSIONINFO OSinfo;
2366 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
2367 GetVersionEx (&OSinfo);
2368 if (OSinfo.dwMajorVersion >= 5)
2369 {
2370 HMODULE hUser = GetModuleHandle("user32.dll");
2371 if (NULL != hUser)
2372 {
2373 bool bSupported = true;
2374 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
2375 LogFunc(("pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
2376 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
2377
2378 if (!bSupported)
2379 {
2380 WARN_FUNC(("pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
2381 err = ERROR_NOT_SUPPORTED;
2382 }
2383 }
2384 else
2385 {
2386 WARN_FUNC(("failed to get USER32 handle, err (%d)\n", GetLastError()));
2387 err = ERROR_NOT_SUPPORTED;
2388 }
2389 }
2390 else
2391 {
2392 WARN_FUNC(("can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
2393 err = ERROR_NOT_SUPPORTED;
2394 }
2395
2396 return err;
2397}
2398
2399DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
2400{
2401 /** @todo may need to addd synchronization in case we want to change modes dynamically
2402 * i.e. currently the mode is supposed to be initialized once on service initialization */
2403 if (penmOldMode)
2404 *penmOldMode = pIf->enmMode;
2405
2406 if (enmMode == pIf->enmMode)
2407 return NO_ERROR;
2408
2409#ifdef VBOX_WITH_WDDM
2410 if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
2411 {
2412 vboxDispIfWddmTerm(pIf);
2413
2414 vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
2415 }
2416#endif
2417
2418 DWORD err = NO_ERROR;
2419 switch (enmMode)
2420 {
2421 case VBOXDISPIF_MODE_XPDM_NT4:
2422 LogFunc(("request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
2423 err = vboxDispIfSwitchToXPDM_NT4(pIf);
2424 if (err == NO_ERROR)
2425 {
2426 LogFunc(("successfully switched to XPDM_NT4 mode\n"));
2427 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
2428 }
2429 else
2430 WARN_FUNC(("failed to switch to XPDM_NT4 mode, err (%d)\n", err));
2431 break;
2432 case VBOXDISPIF_MODE_XPDM:
2433 LogFunc(("request to switch to VBOXDISPIF_MODE_XPDM\n"));
2434 err = vboxDispIfSwitchToXPDM(pIf);
2435 if (err == NO_ERROR)
2436 {
2437 LogFunc(("successfully switched to XPDM mode\n"));
2438 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
2439 }
2440 else
2441 WARN_FUNC(("failed to switch to XPDM mode, err (%d)\n", err));
2442 break;
2443#ifdef VBOX_WITH_WDDM
2444 case VBOXDISPIF_MODE_WDDM:
2445 {
2446 LogFunc(("request to switch to VBOXDISPIF_MODE_WDDM\n"));
2447 err = vboxDispIfSwitchToWDDM(pIf);
2448 if (err == NO_ERROR)
2449 {
2450 LogFunc(("successfully switched to WDDM mode\n"));
2451 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
2452 }
2453 else
2454 WARN_FUNC(("failed to switch to WDDM mode, err (%d)\n", err));
2455 break;
2456 }
2457 case VBOXDISPIF_MODE_WDDM_W7:
2458 {
2459 LogFunc(("request to switch to VBOXDISPIF_MODE_WDDM_W7\n"));
2460 err = vboxDispIfSwitchToWDDM_W7(pIf);
2461 if (err == NO_ERROR)
2462 {
2463 LogFunc(("successfully switched to WDDM mode\n"));
2464 pIf->enmMode = VBOXDISPIF_MODE_WDDM_W7;
2465 }
2466 else
2467 WARN_FUNC(("failed to switch to WDDM mode, err (%d)\n", err));
2468 break;
2469 }
2470#endif
2471 default:
2472 err = ERROR_INVALID_PARAMETER;
2473 break;
2474 }
2475 return err;
2476}
2477
2478static DWORD vboxDispIfSeamlessCreateWDDM(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2479{
2480 RT_NOREF(hEvent);
2481 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pSeamless->modeData.wddm.Adapter);
2482 if (SUCCEEDED(hr))
2483 {
2484#ifndef VBOX_DISPIF_WITH_OPCONTEXT
2485 return ERROR_SUCCESS;
2486#else
2487 hr = vboxDispKmtCreateDevice(&pSeamless->modeData.wddm.Adapter, &pSeamless->modeData.wddm.Device);
2488 if (SUCCEEDED(hr))
2489 {
2490 hr = vboxDispKmtCreateContext(&pSeamless->modeData.wddm.Device, &pSeamless->modeData.wddm.Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS,
2491 0, 0, hEvent, 0ULL);
2492 if (SUCCEEDED(hr))
2493 return ERROR_SUCCESS;
2494 WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
2495
2496 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2497 }
2498 else
2499 WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
2500
2501 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2502#endif /* VBOX_DISPIF_WITH_OPCONTEXT */
2503 }
2504
2505 return hr;
2506}
2507
2508static DWORD vboxDispIfSeamlessTermWDDM(VBOXDISPIF_SEAMLESS *pSeamless)
2509{
2510#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2511 vboxDispKmtDestroyContext(&pSeamless->modeData.wddm.Context);
2512 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2513#endif
2514 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2515
2516 return NO_ERROR;
2517}
2518
2519static DWORD vboxDispIfSeamlessSubmitWDDM(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2520{
2521 D3DKMT_ESCAPE EscapeData = {0};
2522 EscapeData.hAdapter = pSeamless->modeData.wddm.Adapter.hAdapter;
2523#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2524 EscapeData.hDevice = pSeamless->modeData.wddm.Device.hDevice;
2525 EscapeData.hContext = pSeamless->modeData.wddm.Context.hContext;
2526#endif
2527 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
2528 /*EscapeData.Flags.HardwareAccess = 1;*/
2529 EscapeData.pPrivateDriverData = pData;
2530 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
2531
2532 NTSTATUS Status = pSeamless->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
2533 if (NT_SUCCESS(Status))
2534 return ERROR_SUCCESS;
2535
2536 WARN(("VBoxTray: pfnD3DKMTEscape Seamless failed Status 0x%x\n", Status));
2537 return Status;
2538}
2539
2540DWORD VBoxDispIfSeamlessCreate(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2541{
2542 memset(pSeamless, 0, sizeof (*pSeamless));
2543 pSeamless->pIf = pIf;
2544
2545 switch (pIf->enmMode)
2546 {
2547 case VBOXDISPIF_MODE_XPDM_NT4:
2548 case VBOXDISPIF_MODE_XPDM:
2549 return NO_ERROR;
2550#ifdef VBOX_WITH_WDDM
2551 case VBOXDISPIF_MODE_WDDM:
2552 case VBOXDISPIF_MODE_WDDM_W7:
2553 return vboxDispIfSeamlessCreateWDDM(pIf, pSeamless, hEvent);
2554#endif
2555 default:
2556 break;
2557 }
2558
2559 WARN(("VBoxTray: VBoxDispIfSeamlessCreate: invalid mode %d\n", pIf->enmMode));
2560 return ERROR_INVALID_PARAMETER;
2561}
2562
2563DWORD VBoxDispIfSeamlessTerm(VBOXDISPIF_SEAMLESS *pSeamless)
2564{
2565 PCVBOXDISPIF const pIf = pSeamless->pIf;
2566 DWORD winEr;
2567 switch (pIf->enmMode)
2568 {
2569 case VBOXDISPIF_MODE_XPDM_NT4:
2570 case VBOXDISPIF_MODE_XPDM:
2571 winEr = NO_ERROR;
2572 break;
2573#ifdef VBOX_WITH_WDDM
2574 case VBOXDISPIF_MODE_WDDM:
2575 case VBOXDISPIF_MODE_WDDM_W7:
2576 winEr = vboxDispIfSeamlessTermWDDM(pSeamless);
2577 break;
2578#endif
2579 default:
2580 WARN(("VBoxTray: VBoxDispIfSeamlessTerm: invalid mode %d\n", pIf->enmMode));
2581 winEr = ERROR_INVALID_PARAMETER;
2582 break;
2583 }
2584
2585 if (winEr == NO_ERROR)
2586 memset(pSeamless, 0, sizeof (*pSeamless));
2587
2588 return winEr;
2589}
2590
2591DWORD VBoxDispIfSeamlessSubmit(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2592{
2593 PCVBOXDISPIF const pIf = pSeamless->pIf;
2594
2595 if (pData->escapeCode != VBOXESC_SETVISIBLEREGION)
2596 {
2597 WARN(("VBoxTray: invalid escape code for Seamless submit %d\n", pData->escapeCode));
2598 return ERROR_INVALID_PARAMETER;
2599 }
2600
2601 switch (pIf->enmMode)
2602 {
2603 case VBOXDISPIF_MODE_XPDM_NT4:
2604 case VBOXDISPIF_MODE_XPDM:
2605 return VBoxDispIfEscape(pIf, pData, cbData);
2606#ifdef VBOX_WITH_WDDM
2607 case VBOXDISPIF_MODE_WDDM:
2608 case VBOXDISPIF_MODE_WDDM_W7:
2609 return vboxDispIfSeamlessSubmitWDDM(pSeamless, pData, cbData);
2610#endif
2611 default:
2612 WARN(("VBoxTray: VBoxDispIfSeamlessSubmit: invalid mode %d\n", pIf->enmMode));
2613 return ERROR_INVALID_PARAMETER;
2614 }
2615}
2616
Note: See TracBrowser for help on using the repository browser.

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