VirtualBox

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

Last change on this file since 52560 was 52143, checked in by vboxsync, 10 years ago

build fix

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