VirtualBox

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

Last change on this file since 60274 was 60274, checked in by vboxsync, 9 years ago

Additions: try to purge all ocurrences of __FUNCTION__

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