VirtualBox

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

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

Additions/VBoxTray:

  • Refactored internal services to use the RTThread API.
  • First take on cleaning up VBoxTray, separating the services more and more. See @todos.
  • Updated some code areas where deprecated APIs were used.
  • A lot of log formatting fixes and renaming.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 70.1 KB
Line 
1/* $Id: VBoxDispIf.cpp 57741 2015-09-14 15:24:42Z 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#else
32#define WARN(_m) do { \
33 Log(_m); \
34 } while (0)
35#endif
36
37#ifdef VBOX_WITH_WDDM
38#include <iprt/asm.h>
39#endif
40
41#include "VBoxDisplay.h"
42
43#ifndef NT_SUCCESS
44# define NT_SUCCESS(_Status) ((_Status) >= 0)
45#endif
46
47typedef struct VBOXDISPIF_OP
48{
49 PCVBOXDISPIF pIf;
50 VBOXDISPKMT_ADAPTER Adapter;
51 VBOXDISPKMT_DEVICE Device;
52 VBOXDISPKMT_CONTEXT Context;
53} VBOXDISPIF_OP;
54
55static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes);
56static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
57static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable);
58static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp);
59
60/*
61 * APIs specific to Win7 and above WDDM architecture. Not available for Vista WDDM.
62 * This is the reason they have not been put in the VBOXDISPIF struct in VBoxDispIf.h.
63 */
64typedef struct _VBOXDISPLAYWDDMAPICONTEXT
65{
66 LONG (WINAPI * pfnSetDisplayConfig)(UINT numPathArrayElements,DISPLAYCONFIG_PATH_INFO *pathArray,UINT numModeInfoArrayElements,
67 DISPLAYCONFIG_MODE_INFO *modeInfoArray, UINT Flags);
68 LONG (WINAPI * pfnQueryDisplayConfig)(UINT Flags,UINT *pNumPathArrayElements, DISPLAYCONFIG_PATH_INFO *pPathInfoArray,
69 UINT *pNumModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *pModeInfoArray,
70 DISPLAYCONFIG_TOPOLOGY_ID *pCurrentTopologyId);
71 LONG (WINAPI * pfnGetDisplayConfigBufferSizes)(UINT Flags, UINT *pNumPathArrayElements, UINT *pNumModeInfoArrayElements);
72} _VBOXDISPLAYWDDMAPICONTEXT;
73
74static _VBOXDISPLAYWDDMAPICONTEXT gCtx = {0};
75
76typedef struct VBOXDISPIF_WDDM_DISPCFG
77{
78 UINT32 cPathInfoArray;
79 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
80 UINT32 cModeInfoArray;
81 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
82} VBOXDISPIF_WDDM_DISPCFG;
83
84static DWORD vboxDispIfWddmDcCreate(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT32 fFlags)
85{
86 UINT32 cPathInfoArray = 0;
87 UINT32 cModeInfoArray = 0;
88 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
89 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
90 DWORD winEr = gCtx.pfnGetDisplayConfigBufferSizes(fFlags, &cPathInfoArray, &cModeInfoArray);
91 if (winEr != ERROR_SUCCESS)
92 {
93 WARN(("VBoxTray: (WDDM) Failed GetDisplayConfigBufferSizes\n"));
94 return winEr;
95 }
96
97 pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cPathInfoArray * sizeof(DISPLAYCONFIG_PATH_INFO));
98 if (!pPathInfoArray)
99 {
100 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
101 return ERROR_OUTOFMEMORY;
102 }
103 pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
104 if (!pModeInfoArray)
105 {
106 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
107 free(pPathInfoArray);
108 return ERROR_OUTOFMEMORY;
109 }
110
111 winEr = gCtx.pfnQueryDisplayConfig(fFlags, &cPathInfoArray, pPathInfoArray, &cModeInfoArray, pModeInfoArray, NULL);
112 if (winEr != ERROR_SUCCESS)
113 {
114 WARN(("VBoxTray: (WDDM) Failed QueryDisplayConfig\n"));
115 free(pPathInfoArray);
116 free(pModeInfoArray);
117 return winEr;
118 }
119
120 pCfg->cPathInfoArray = cPathInfoArray;
121 pCfg->pPathInfoArray = pPathInfoArray;
122 pCfg->cModeInfoArray = cModeInfoArray;
123 pCfg->pModeInfoArray = pModeInfoArray;
124 return ERROR_SUCCESS;
125}
126
127static DWORD vboxDispIfWddmDcClone(VBOXDISPIF_WDDM_DISPCFG *pCfg, VBOXDISPIF_WDDM_DISPCFG *pCfgDst)
128{
129 memset(pCfgDst, 0, sizeof (*pCfgDst));
130
131 if (pCfg->cPathInfoArray)
132 {
133 pCfgDst->pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
134 if (!pCfgDst->pPathInfoArray)
135 {
136 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
137 return ERROR_OUTOFMEMORY;
138 }
139
140 memcpy(pCfgDst->pPathInfoArray, pCfg->pPathInfoArray, pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
141
142 pCfgDst->cPathInfoArray = pCfg->cPathInfoArray;
143 }
144
145 if (pCfg->cModeInfoArray)
146 {
147 pCfgDst->pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
148 if (!pCfgDst->pModeInfoArray)
149 {
150 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
151 if (pCfgDst->pPathInfoArray)
152 {
153 free(pCfgDst->pPathInfoArray);
154 pCfgDst->pPathInfoArray = NULL;
155 }
156 return ERROR_OUTOFMEMORY;
157 }
158
159 memcpy(pCfgDst->pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
160
161 pCfgDst->cModeInfoArray = pCfg->cModeInfoArray;
162 }
163
164 return ERROR_SUCCESS;
165}
166
167
168static VOID vboxDispIfWddmDcTerm(VBOXDISPIF_WDDM_DISPCFG *pCfg)
169{
170 if (pCfg->pPathInfoArray)
171 free(pCfg->pPathInfoArray);
172 if (pCfg->pModeInfoArray)
173 free(pCfg->pModeInfoArray);
174 /* sanity */
175 memset(pCfg, 0, sizeof (*pCfg));
176}
177
178static UINT32 g_cVBoxDispIfWddmDisplays = 0;
179static DWORD vboxDispIfWddmDcQueryNumDisplays(UINT32 *pcDisplays)
180{
181 if (!g_cVBoxDispIfWddmDisplays)
182 {
183 VBOXDISPIF_WDDM_DISPCFG DispCfg;
184 *pcDisplays = 0;
185 DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
186 if (winEr != ERROR_SUCCESS)
187 {
188 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
189 return winEr;
190 }
191
192 int cDisplays = -1;
193
194 for (UINT iter = 0; iter < DispCfg.cPathInfoArray; ++iter)
195 {
196 if (cDisplays < (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id))
197 cDisplays = (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id);
198 }
199
200 cDisplays++;
201
202 g_cVBoxDispIfWddmDisplays = cDisplays;
203 Assert(g_cVBoxDispIfWddmDisplays);
204
205 vboxDispIfWddmDcTerm(&DispCfg);
206 }
207
208 *pcDisplays = g_cVBoxDispIfWddmDisplays;
209 return ERROR_SUCCESS;
210}
211
212static int vboxDispIfWddmDcSearchPath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
213{
214 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
215 {
216 if ((srcId == ~0UL || pCfg->pPathInfoArray[iter].sourceInfo.id == srcId)
217 && (trgId == ~0UL || pCfg->pPathInfoArray[iter].targetInfo.id == trgId))
218 {
219 return (int)iter;
220 }
221 }
222 return -1;
223}
224
225static int vboxDispIfWddmDcSearchActivePath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
226{
227 int idx = vboxDispIfWddmDcSearchPath(pCfg, srcId, trgId);
228 if (idx < 0)
229 return idx;
230
231 if (!(pCfg->pPathInfoArray[idx].flags & DISPLAYCONFIG_PATH_ACTIVE))
232 return -1;
233
234 return idx;
235}
236
237static VOID vboxDispIfWddmDcSettingsInvalidateModeIndex(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx)
238{
239 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
240 pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
241}
242
243static VOID vboxDispIfWddmDcSettingsInvalidateModeIndeces(VBOXDISPIF_WDDM_DISPCFG *pCfg)
244{
245 for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
246 {
247 vboxDispIfWddmDcSettingsInvalidateModeIndex(pCfg, (int)iter);
248 }
249
250 if (pCfg->pModeInfoArray)
251 {
252 free(pCfg->pModeInfoArray);
253 pCfg->pModeInfoArray = NULL;
254 }
255 pCfg->cModeInfoArray = 0;
256}
257
258static DWORD vboxDispIfWddmDcSettingsModeAdd(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT *pIdx)
259{
260 UINT32 cModeInfoArray = pCfg->cModeInfoArray + 1;
261 DISPLAYCONFIG_MODE_INFO *pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
262 if (!pModeInfoArray)
263 {
264 WARN(("VBoxTray: (WDDM) malloc failed!\n"));
265 return ERROR_OUTOFMEMORY;
266 }
267
268 memcpy (pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
269 memset(&pModeInfoArray[cModeInfoArray-1], 0, sizeof (pModeInfoArray[0]));
270 free(pCfg->pModeInfoArray);
271 *pIdx = cModeInfoArray-1;
272 pCfg->pModeInfoArray = pModeInfoArray;
273 pCfg->cModeInfoArray = cModeInfoArray;
274 return ERROR_SUCCESS;
275}
276
277static DWORD vboxDispIfWddmDcSettingsUpdate(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx, DEVMODE *pDeviceMode, BOOL fInvalidateSrcMode, BOOL fEnable)
278{
279 UINT Id = pCfg->pPathInfoArray[idx].sourceInfo.id;
280
281 if (fInvalidateSrcMode)
282 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
283 else if (pDeviceMode)
284 {
285 UINT iSrcMode = pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx;
286 if (iSrcMode == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)
287 {
288
289 WARN(("VBoxTray: (WDDM) no source mode index specified"));
290 DWORD winEr = vboxDispIfWddmDcSettingsModeAdd(pCfg, &iSrcMode);
291 if (winEr != ERROR_SUCCESS)
292 {
293 WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcSettingsModeAdd Failed winEr %d\n", winEr));
294 return winEr;
295 }
296 pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = iSrcMode;
297 }
298
299 for (int i = 0; i < (int)pCfg->cPathInfoArray; ++i)
300 {
301 if (i == idx)
302 continue;
303
304 if (pCfg->pPathInfoArray[i].sourceInfo.modeInfoIdx == iSrcMode)
305 {
306 /* this is something we're not expecting/supporting */
307 WARN(("VBoxTray: (WDDM) multiple paths have the same mode index"));
308 return ERROR_NOT_SUPPORTED;
309 }
310 }
311
312 if (pDeviceMode->dmFields & DM_PELSWIDTH)
313 pCfg->pModeInfoArray[iSrcMode].sourceMode.width = pDeviceMode->dmPelsWidth;
314 if (pDeviceMode->dmFields & DM_PELSHEIGHT)
315 pCfg->pModeInfoArray[iSrcMode].sourceMode.height = pDeviceMode->dmPelsHeight;
316 if (pDeviceMode->dmFields & DM_POSITION)
317 {
318 LogFlowFunc(("DM_POSITION %d,%d -> %d,%d\n",
319 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x,
320 pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y,
321 pDeviceMode->dmPosition.x, pDeviceMode->dmPosition.y));
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
959 /** @todo r=andy Use VBOXSERVICEENV::hInstance. */
960 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
961
962 /* Register the Window Class. */
963 WNDCLASSEX wc = { 0 };
964 wc.cbSize = sizeof(WNDCLASSEX);
965
966 if (!GetClassInfoEx(hInstance, VBOXRRWND_NAME, &wc))
967 {
968 wc.lpfnWndProc = vboxRrWndProc;
969 wc.hInstance = hInstance;
970 wc.lpszClassName = VBOXRRWND_NAME;
971
972 if (!RegisterClassEx(&wc))
973 {
974 DWORD winErr = GetLastError();
975 WARN((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
976 hr = E_FAIL;
977 }
978 }
979
980 if (hr == S_OK)
981 {
982 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
983 VBOXRRWND_NAME, VBOXRRWND_NAME,
984 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
985 -100, -100,
986 10, 10,
987 NULL, //GetDesktopWindow() /* hWndParent */,
988 NULL /* hMenu */,
989 hInstance,
990 NULL /* lpParam */);
991 Assert(hWnd);
992 if (hWnd)
993 {
994 *phWnd = hWnd;
995 }
996 else
997 {
998 DWORD winErr = GetLastError();
999 WARN((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
1000 hr = E_FAIL;
1001 }
1002 }
1003
1004 return hr;
1005}
1006
1007static HRESULT vboxRrWndDestroy(HWND hWnd)
1008{
1009 BOOL bResult = DestroyWindow(hWnd);
1010 if (bResult)
1011 return S_OK;
1012
1013 DWORD winErr = GetLastError();
1014 WARN((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
1015
1016 return HRESULT_FROM_WIN32(winErr);
1017}
1018
1019static HRESULT vboxRrWndInit()
1020{
1021 PVBOXRR pMon = &g_VBoxRr;
1022 return vboxRrWndCreate(&pMon->hWnd);
1023}
1024
1025HRESULT vboxRrWndTerm()
1026{
1027 PVBOXRR pMon = &g_VBoxRr;
1028 HRESULT tmpHr = vboxRrWndDestroy(pMon->hWnd);
1029 Assert(tmpHr == S_OK);
1030
1031 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
1032 UnregisterClass(VBOXRRWND_NAME, hInstance);
1033
1034 return S_OK;
1035}
1036
1037#define WM_VBOXRR_INIT_QUIT (WM_APP+2)
1038
1039HRESULT vboxRrRun()
1040{
1041 PVBOXRR pMon = &g_VBoxRr;
1042 MSG Msg;
1043
1044 HRESULT hr = S_FALSE;
1045
1046 PeekMessage(&Msg,
1047 NULL /* HWND hWnd */,
1048 WM_USER /* UINT wMsgFilterMin */,
1049 WM_USER /* UINT wMsgFilterMax */,
1050 PM_NOREMOVE);
1051
1052 do
1053 {
1054 BOOL bResult = GetMessage(&Msg,
1055 0 /*HWND hWnd*/,
1056 0 /*UINT wMsgFilterMin*/,
1057 0 /*UINT wMsgFilterMax*/
1058 );
1059
1060 if(!bResult) /* WM_QUIT was posted */
1061 {
1062 hr = S_FALSE;
1063 Log(("VBoxTray: GetMessage returned FALSE\n"));
1064 VBoxRrRetryStop();
1065 break;
1066 }
1067
1068 if(bResult == -1) /* error occurred */
1069 {
1070 DWORD winEr = GetLastError();
1071 hr = HRESULT_FROM_WIN32(winEr);
1072 /* just ensure we never return success in this case */
1073 Assert(hr != S_OK);
1074 Assert(hr != S_FALSE);
1075 if (hr == S_OK || hr == S_FALSE)
1076 hr = E_FAIL;
1077 WARN(("VBoxTray: GetMessage returned -1, err %d\n", winEr));
1078 VBoxRrRetryStop();
1079 break;
1080 }
1081
1082 switch (Msg.message)
1083 {
1084 case WM_VBOXRR_INIT_QUIT:
1085 case WM_CLOSE:
1086 {
1087 Log(("VBoxTray: closing Rr %d\n", Msg.message));
1088 VBoxRrRetryStop();
1089 PostQuitMessage(0);
1090 break;
1091 }
1092 default:
1093 TranslateMessage(&Msg);
1094 DispatchMessage(&Msg);
1095 break;
1096 }
1097 } while (1);
1098 return 0;
1099}
1100
1101static DWORD WINAPI vboxRrRunnerThread(void *pvUser)
1102{
1103 PVBOXRR pMon = &g_VBoxRr;
1104
1105 BOOL bRc = SetEvent(pMon->hEvent);
1106 if (!bRc)
1107 {
1108 DWORD winErr = GetLastError();
1109 WARN((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
1110 HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
1111 Assert(tmpHr != S_OK);
1112 }
1113
1114 HRESULT hr = vboxRrWndInit();
1115 Assert(hr == S_OK);
1116 if (hr == S_OK)
1117 {
1118 hr = vboxRrRun();
1119 Assert(hr == S_OK);
1120
1121 vboxRrWndTerm();
1122 }
1123
1124 return 0;
1125}
1126
1127HRESULT VBoxRrInit()
1128{
1129 HRESULT hr = E_FAIL;
1130 PVBOXRR pMon = &g_VBoxRr;
1131 memset(pMon, 0, sizeof (*pMon));
1132
1133 InitializeCriticalSection(&pMon->CritSect);
1134
1135 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
1136 TRUE, /* BOOL bManualReset*/
1137 FALSE, /* BOOL bInitialState */
1138 NULL /* LPCTSTR lpName */
1139 );
1140 if (pMon->hEvent)
1141 {
1142 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
1143 0 /* SIZE_T dwStackSize */,
1144 vboxRrRunnerThread,
1145 pMon,
1146 0 /* DWORD dwCreationFlags */,
1147 &pMon->idThread);
1148 if (pMon->hThread)
1149 {
1150 DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
1151 if (dwResult == WAIT_OBJECT_0)
1152 return S_OK;
1153 else
1154 {
1155 Log(("WaitForSingleObject failed!"));
1156 hr = E_FAIL;
1157 }
1158 }
1159 else
1160 {
1161 DWORD winErr = GetLastError();
1162 WARN((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
1163 hr = HRESULT_FROM_WIN32(winErr);
1164 Assert(hr != S_OK);
1165 }
1166 CloseHandle(pMon->hEvent);
1167 }
1168 else
1169 {
1170 DWORD winErr = GetLastError();
1171 WARN((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
1172 hr = HRESULT_FROM_WIN32(winErr);
1173 Assert(hr != S_OK);
1174 }
1175
1176 DeleteCriticalSection(&pMon->CritSect);
1177
1178 return hr;
1179}
1180
1181VOID VBoxRrTerm()
1182{
1183 HRESULT hr;
1184 PVBOXRR pMon = &g_VBoxRr;
1185 if (!pMon->hThread)
1186 return;
1187
1188 BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXRR_INIT_QUIT, 0, 0);
1189 DWORD winErr;
1190 if (bResult
1191 || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
1192 {
1193 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
1194 if (dwErr == WAIT_OBJECT_0)
1195 {
1196 hr = S_OK;
1197 }
1198 else
1199 {
1200 winErr = GetLastError();
1201 hr = HRESULT_FROM_WIN32(winErr);
1202 }
1203 }
1204 else
1205 {
1206 hr = HRESULT_FROM_WIN32(winErr);
1207 }
1208
1209 DeleteCriticalSection(&pMon->CritSect);
1210
1211 CloseHandle(pMon->hThread);
1212 pMon->hThread = 0;
1213 CloseHandle(pMon->hEvent);
1214 pMon->hThread = 0;
1215}
1216
1217static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
1218{
1219 HRESULT hr = VBoxRrInit();
1220 if (SUCCEEDED(hr))
1221 {
1222 return ERROR_SUCCESS;
1223 }
1224 WARN(("VBoxTray: VBoxRrInit failed hr 0x%x\n", hr));
1225 return hr;
1226}
1227
1228static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
1229{
1230 VBoxRrTerm();
1231}
1232
1233static DWORD vboxDispIfQueryDisplayConnection(VBOXDISPIF_OP *pOp, UINT32 iDisplay, BOOL *pfConnected)
1234{
1235 if (pOp->pIf->enmMode == VBOXDISPIF_MODE_WDDM)
1236 {
1237 /* @todo: do we need ti impl it? */
1238 *pfConnected = TRUE;
1239 return ERROR_SUCCESS;
1240 }
1241
1242 *pfConnected = FALSE;
1243
1244 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1245 DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
1246 if (winEr != ERROR_SUCCESS)
1247 {
1248 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1249 return winEr;
1250 }
1251
1252 int idx = vboxDispIfWddmDcSearchPath(&DispCfg, iDisplay, iDisplay);
1253 *pfConnected = (idx >= 0);
1254
1255 vboxDispIfWddmDcTerm(&DispCfg);
1256
1257 return ERROR_SUCCESS;
1258}
1259
1260static DWORD vboxDispIfWaitDisplayDataInited(VBOXDISPIF_OP *pOp)
1261{
1262 DWORD winEr = ERROR_SUCCESS;
1263 do
1264 {
1265 Sleep(100);
1266
1267 D3DKMT_POLLDISPLAYCHILDREN PollData = {0};
1268 PollData.hAdapter = pOp->Adapter.hAdapter;
1269 PollData.NonDestructiveOnly = 1;
1270 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTPollDisplayChildren(&PollData);
1271 if (Status != 0)
1272 {
1273 Log(("VBoxTray: (WDDM) pfnD3DKMTPollDisplayChildren failed, Status (0x%x)\n", Status));
1274 continue;
1275 }
1276
1277 BOOL fFound = FALSE;
1278#if 0
1279 for (UINT i = 0; i < VBOXWDDM_SCREENMASK_SIZE; ++i)
1280 {
1281 if (pu8DisplayMask && !ASMBitTest(pu8DisplayMask, i))
1282 continue;
1283
1284 BOOL fConnected = FALSE;
1285 winEr = vboxDispIfQueryDisplayConnection(pOp, i, &fConnected);
1286 if (winEr != ERROR_SUCCESS)
1287 {
1288 WARN(("VBoxTray: (WDDM) Failed vboxDispIfQueryDisplayConnection winEr %d\n", winEr));
1289 return winEr;
1290 }
1291
1292 if (!fConnected)
1293 {
1294 WARN(("VBoxTray: (WDDM) Display %d not connected, not expected\n", i));
1295 fFound = TRUE;
1296 break;
1297 }
1298 }
1299#endif
1300 if (!fFound)
1301 break;
1302 } while (1);
1303
1304 return winEr;
1305}
1306
1307static DWORD vboxDispIfUpdateModesWDDM(VBOXDISPIF_OP *pOp, uint32_t u32TargetId, const RTRECTSIZE *pSize)
1308{
1309 DWORD winEr = ERROR_SUCCESS;
1310 VBOXDISPIFESCAPE_UPDATEMODES EscData = {0};
1311 EscData.EscapeHdr.escapeCode = VBOXESC_UPDATEMODES;
1312 EscData.u32TargetId = u32TargetId;
1313 EscData.Size = *pSize;
1314
1315 D3DKMT_ESCAPE EscapeData = {0};
1316 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1317#ifdef VBOX_DISPIF_WITH_OPCONTEXT
1318 /* win8.1 does not allow context-based escapes for display-only mode */
1319 EscapeData.hDevice = pOp->Device.hDevice;
1320 EscapeData.hContext = pOp->Context.hContext;
1321#endif
1322 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1323 EscapeData.Flags.HardwareAccess = 1;
1324 EscapeData.pPrivateDriverData = &EscData;
1325 EscapeData.PrivateDriverDataSize = sizeof (EscData);
1326
1327 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1328 if (NT_SUCCESS(Status))
1329 winEr = ERROR_SUCCESS;
1330 else
1331 {
1332 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_UPDATEMODES failed Status 0x%x\n", Status));
1333 winEr = ERROR_GEN_FAILURE;
1334 }
1335
1336 winEr = vboxDispIfWaitDisplayDataInited(pOp);
1337 if (winEr != NO_ERROR)
1338 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWaitDisplayDataInited winEr %d\n", winEr));
1339
1340 return winEr;
1341}
1342
1343DWORD vboxDispIfCancelPendingResizeWDDM(PCVBOXDISPIF const pIf)
1344{
1345 Log(("VBoxTray: cancelling pending resize\n"));
1346 VBoxRrRetryStop();
1347 return NO_ERROR;
1348}
1349
1350static DWORD vboxDispIfWddmResizeDisplayVista(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD cDevModes, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup)
1351{
1352 /* Without this, Windows will not ask the miniport for its
1353 * mode table but uses an internal cache instead.
1354 */
1355 for (DWORD i = 0; i < cDevModes; i++)
1356 {
1357 DEVMODE tempDevMode;
1358 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
1359 tempDevMode.dmSize = sizeof(DEVMODE);
1360 EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
1361 Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
1362 }
1363
1364 DWORD winEr = EnableAndResizeDispDev(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, paDeviceModes[iChangedMode].dmPelsWidth, paDeviceModes[iChangedMode].dmPelsHeight,
1365 paDeviceModes[iChangedMode].dmBitsPerPel, paDeviceModes[iChangedMode].dmPosition.x, paDeviceModes[iChangedMode].dmPosition.y, fEnable, fExtDispSup);
1366 if (winEr != NO_ERROR)
1367 WARN(("VBoxTray: (WDDM) Failed EnableAndResizeDispDev winEr %d\n", winEr));
1368
1369 return winEr;
1370}
1371
1372static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1373{
1374 DWORD winEr;
1375 if (pIf->enmMode > VBOXDISPIF_MODE_WDDM)
1376 {
1377 winEr = vboxDispIfWddmResizeDisplay(pIf, iChangedMode, fEnable, paDisplayDevices, paDeviceModes, cDevModes);
1378 if (winEr != NO_ERROR)
1379 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplay winEr %d\n", winEr));
1380 }
1381 else
1382 {
1383 winEr = vboxDispIfWddmResizeDisplayVista(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, fEnable, fExtDispSup);
1384 if (winEr != NO_ERROR)
1385 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplayVista winEr %d\n", winEr));
1386 }
1387 return winEr;
1388}
1389
1390DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1391{
1392 DWORD winEr = NO_ERROR;
1393
1394 Log(("VBoxTray: vboxDispIfResizeModesWDDM iChanged %d cDevModes %d\n", iChangedMode, cDevModes));
1395 VBoxRrRetryStop();
1396
1397 VBOXDISPIF_OP Op;
1398
1399 winEr = vboxDispIfOpBegin(pIf, &Op);
1400 if (winEr != NO_ERROR)
1401 {
1402 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x", winEr));
1403 return winEr;
1404 }
1405
1406 VBOXWDDM_RECOMMENDVIDPN VidPnData;
1407
1408 memset(&VidPnData, 0, sizeof (VidPnData));
1409
1410 uint32_t cElements = 0;
1411
1412 for (uint32_t i = 0; i < cDevModes; ++i)
1413 {
1414 if ((i == iChangedMode) ? fEnable : (paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
1415 {
1416 VidPnData.aSources[cElements].Size.cx = paDeviceModes[i].dmPelsWidth;
1417 VidPnData.aSources[cElements].Size.cy = paDeviceModes[i].dmPelsHeight;
1418 VidPnData.aTargets[cElements].iSource = cElements;
1419 ++cElements;
1420 }
1421 else
1422 VidPnData.aTargets[cElements].iSource = -1;
1423 }
1424
1425 D3DKMT_INVALIDATEACTIVEVIDPN DdiData = {0};
1426
1427 DdiData.hAdapter = Op.Adapter.hAdapter;
1428 DdiData.pPrivateDriverData = &VidPnData;
1429 DdiData.PrivateDriverDataSize = sizeof (VidPnData);
1430
1431 NTSTATUS Status = Op.pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTInvalidateActiveVidPn(&DdiData);
1432 LogFunc(("InvalidateActiveVidPn 0x%08x\n", Status));
1433
1434 /* Resize displays always to keep the display layout because
1435 * "the D3DKMTInvalidateActiveVidPn function always resets a multimonitor desktop to the default configuration".
1436 */
1437 {
1438 winEr = NO_ERROR;
1439
1440 if (fEnable)
1441 {
1442 RTRECTSIZE Size;
1443 Size.cx = paDeviceModes[iChangedMode].dmPelsWidth;
1444 Size.cy = paDeviceModes[iChangedMode].dmPelsHeight;
1445 winEr = vboxDispIfUpdateModesWDDM(&Op, iChangedMode, &Size);
1446 if (winEr != NO_ERROR)
1447 WARN(("vboxDispIfUpdateModesWDDM failed %d\n", winEr));
1448 }
1449
1450 if (winEr == NO_ERROR)
1451 {
1452 winEr = vboxDispIfResizePerform(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1453
1454 if (winEr == ERROR_RETRY)
1455 {
1456 VBoxRrRetrySchedule(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1457 /* just pretend everything is fine so far */
1458 winEr = NO_ERROR;
1459 }
1460 }
1461 }
1462
1463 vboxDispIfOpEnd(&Op);
1464
1465 return winEr;
1466}
1467
1468static DWORD vboxDispIfWddmEnableDisplays(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnabled, BOOL fSetTopology, DEVMODE *pDeviceMode)
1469{
1470 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1471
1472 DWORD winEr;
1473 int iPath;
1474
1475 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1476 if (winEr != ERROR_SUCCESS)
1477 {
1478 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1479 return winEr;
1480 }
1481
1482 UINT cChangeIds = 0;
1483 UINT *pChangeIds = (UINT*)alloca(cIds * sizeof (*pChangeIds));
1484 if (!pChangeIds)
1485 {
1486 WARN(("VBoxTray: (WDDM) Failed to alloc change ids\n"));
1487 winEr = ERROR_OUTOFMEMORY;
1488 goto done;
1489 }
1490
1491 for (UINT i = 0; i < cIds; ++i)
1492 {
1493 UINT Id = pIds[i];
1494 bool fIsDup = false;
1495 for (UINT j = 0; j < cChangeIds; ++j)
1496 {
1497 if (pChangeIds[j] == Id)
1498 {
1499 fIsDup = true;
1500 break;
1501 }
1502 }
1503
1504 if (fIsDup)
1505 continue;
1506
1507 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
1508
1509 if (!((iPath >= 0) && (DispCfg.pPathInfoArray[iPath].flags & DISPLAYCONFIG_PATH_ACTIVE)) != !fEnabled)
1510 {
1511 pChangeIds[cChangeIds] = Id;
1512 ++cChangeIds;
1513 }
1514 }
1515
1516 if (cChangeIds == 0)
1517 {
1518 Log(("VBoxTray: (WDDM) vboxDispIfWddmEnableDisplay: settings are up to date\n"));
1519 winEr = ERROR_SUCCESS;
1520 goto done;
1521 }
1522
1523 /* we want to set primary for every disabled for non-topoly mode only */
1524 winEr = vboxDispIfWddmDcSettingsIncludeAllTargets(&DispCfg);
1525 if (winEr != ERROR_SUCCESS)
1526 {
1527 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsIncludeAllTargets winEr %d\n", winEr));
1528 return winEr;
1529 }
1530
1531 if (fSetTopology)
1532 vboxDispIfWddmDcSettingsInvalidateModeIndeces(&DispCfg);
1533
1534 for (UINT i = 0; i < cChangeIds; ++i)
1535 {
1536 UINT Id = pChangeIds[i];
1537 /* re-query paths */
1538 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, -1, Id);
1539 if (iPath < 0)
1540 {
1541 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1542 winEr = ERROR_GEN_FAILURE;
1543 goto done;
1544 }
1545
1546 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, pDeviceMode, !fEnabled || fSetTopology, fEnabled);
1547 if (winEr != ERROR_SUCCESS)
1548 {
1549 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1550 goto done;
1551 }
1552 }
1553
1554 if (!fSetTopology)
1555 vboxDispIfWddmDcSettingsAttachDisbledToPrimary(&DispCfg);
1556
1557#if 0
1558 /* ensure the zero-index (primary) screen is enabled */
1559 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, 0, 0);
1560 if (iPath < 0)
1561 {
1562 WARN(("VBoxTray: (WDDM) path index not found while it should"));
1563 winEr = ERROR_GEN_FAILURE;
1564 goto done;
1565 }
1566
1567 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, /* just re-use device node here*/ pDeviceMode, fSetTopology, TRUE);
1568 if (winEr != ERROR_SUCCESS)
1569 {
1570 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
1571 goto done;
1572 }
1573#endif
1574
1575 UINT fSetFlags = !fSetTopology ? (SDC_USE_SUPPLIED_DISPLAY_CONFIG) : (SDC_ALLOW_PATH_ORDER_CHANGES | SDC_TOPOLOGY_SUPPLIED);
1576 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1577 if (winEr != ERROR_SUCCESS)
1578 {
1579 if (!fSetTopology)
1580 {
1581 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet validation failed winEr, trying with changes %d\n", winEr));
1582 fSetFlags |= SDC_ALLOW_CHANGES;
1583 }
1584 else
1585 {
1586 Log(("VBoxTray: (WDDM) vboxDispIfWddmDcSet topology validation failed winEr %d\n", winEr));
1587 goto done;
1588 }
1589 }
1590
1591 if (!fSetTopology)
1592 fSetFlags |= SDC_SAVE_TO_DATABASE;
1593
1594 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_APPLY);
1595 if (winEr != ERROR_SUCCESS)
1596 WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet apply failed winEr %d\n", winEr));
1597
1598done:
1599 vboxDispIfWddmDcTerm(&DispCfg);
1600
1601 return winEr;
1602}
1603
1604static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable)
1605{
1606 DWORD winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, FALSE, NULL);
1607 if (winEr != ERROR_SUCCESS)
1608 {
1609 if (fEnable)
1610 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1611 else
1612 Log(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1613 winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, TRUE, NULL);
1614 if (winEr != ERROR_SUCCESS)
1615 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
1616 }
1617
1618 return winEr;
1619}
1620
1621static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes)
1622{
1623 VBOXDISPIF_WDDM_DISPCFG DispCfg;
1624 DWORD winEr;
1625 int iPath;
1626
1627 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1628 if (winEr != ERROR_SUCCESS)
1629 {
1630 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate\n"));
1631 return winEr;
1632 }
1633
1634 iPath = vboxDispIfWddmDcSearchActivePath(&DispCfg, Id, Id);
1635
1636 if (iPath < 0)
1637 {
1638 vboxDispIfWddmDcTerm(&DispCfg);
1639
1640 if (!fEnable)
1641 {
1642 /* nothing to be done here, just leave */
1643 return ERROR_SUCCESS;
1644 }
1645
1646 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
1647 if (winEr != ERROR_SUCCESS)
1648 {
1649 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
1650 return winEr;
1651 }
1652
1653 winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
1654 if (winEr != ERROR_SUCCESS)
1655 {
1656 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
1657 return winEr;
1658 }
1659
1660 iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
1661 if (iPath < 0)
1662 {
1663 WARN(("VBoxTray: (WDDM) path (%d) is still disabled, going to retry winEr %d\n", winEr));
1664 vboxDispIfWddmDcTerm(&DispCfg);
1665 return ERROR_RETRY;
1666 }
1667 }
1668
1669 Assert(iPath >= 0);
1670
1671 if (!fEnable)
1672 {
1673 /* need to disable it, and we are done */
1674 vboxDispIfWddmDcTerm(&DispCfg);
1675
1676 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
1677 if (winEr != ERROR_SUCCESS)
1678 {
1679 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
1680 return winEr;
1681 }
1682
1683 return winEr;
1684 }
1685
1686 Assert(fEnable);
1687
1688 winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, &paDeviceMode[Id], FALSE, fEnable);
1689 if (winEr != ERROR_SUCCESS)
1690 {
1691 WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate\n"));
1692 vboxDispIfWddmDcTerm(&DispCfg);
1693 return winEr;
1694 }
1695
1696 UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
1697 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
1698 if (winEr != ERROR_SUCCESS)
1699 {
1700 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1701 fSetFlags |= SDC_ALLOW_CHANGES;
1702 }
1703
1704 winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
1705 if (winEr != ERROR_SUCCESS)
1706 {
1707 WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
1708 }
1709
1710 vboxDispIfWddmDcTerm(&DispCfg);
1711
1712 return winEr;
1713}
1714
1715#endif /* VBOX_WITH_WDDM */
1716
1717DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1718{
1719 switch (pIf->enmMode)
1720 {
1721 case VBOXDISPIF_MODE_XPDM_NT4:
1722 return ERROR_NOT_SUPPORTED;
1723 case VBOXDISPIF_MODE_XPDM:
1724 return ERROR_NOT_SUPPORTED;
1725#ifdef VBOX_WITH_WDDM
1726 case VBOXDISPIF_MODE_WDDM:
1727 case VBOXDISPIF_MODE_WDDM_W7:
1728 return vboxDispIfResizeModesWDDM(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
1729#endif
1730 default:
1731 WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1732 return ERROR_INVALID_PARAMETER;
1733 }
1734}
1735
1736DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf)
1737{
1738 switch (pIf->enmMode)
1739 {
1740 case VBOXDISPIF_MODE_XPDM_NT4:
1741 return NO_ERROR;
1742 case VBOXDISPIF_MODE_XPDM:
1743 return NO_ERROR;
1744#ifdef VBOX_WITH_WDDM
1745 case VBOXDISPIF_MODE_WDDM:
1746 case VBOXDISPIF_MODE_WDDM_W7:
1747 return vboxDispIfCancelPendingResizeWDDM(pIf);
1748#endif
1749 default:
1750 WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1751 return ERROR_INVALID_PARAMETER;
1752 }
1753}
1754
1755static DWORD vboxDispIfConfigureTargetsWDDM(VBOXDISPIF_OP *pOp, uint32_t *pcConnected)
1756{
1757 VBOXDISPIFESCAPE EscapeHdr = {0};
1758 EscapeHdr.escapeCode = VBOXESC_CONFIGURETARGETS;
1759 EscapeHdr.u32CmdSpecific = 0;
1760
1761 D3DKMT_ESCAPE EscapeData = {0};
1762 EscapeData.hAdapter = pOp->Adapter.hAdapter;
1763#ifdef VBOX_DISPIF_WITH_OPCONTEXT
1764 /* win8.1 does not allow context-based escapes for display-only mode */
1765 EscapeData.hDevice = pOp->Device.hDevice;
1766 EscapeData.hContext = pOp->Context.hContext;
1767#endif
1768 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
1769 EscapeData.Flags.HardwareAccess = 1;
1770 EscapeData.pPrivateDriverData = &EscapeHdr;
1771 EscapeData.PrivateDriverDataSize = sizeof (EscapeHdr);
1772
1773 NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
1774 if (NT_SUCCESS(Status))
1775 {
1776 if (pcConnected)
1777 *pcConnected = EscapeHdr.u32CmdSpecific;
1778 return NO_ERROR;
1779 }
1780 WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_CONFIGURETARGETS failed Status 0x%x\n", Status));
1781 return Status;
1782}
1783
1784static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp)
1785{
1786 DWORD NumDevices = VBoxDisplayGetCount();
1787 if (NumDevices == 0)
1788 {
1789 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
1790 return ERROR_GEN_FAILURE;
1791 }
1792
1793 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
1794 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
1795 DWORD DevNum = 0;
1796 DWORD DevPrimaryNum = 0;
1797
1798 DWORD winEr = VBoxDisplayGetConfig(NumDevices, &DevPrimaryNum, &DevNum, paDisplayDevices, paDeviceModes);
1799 if (winEr != NO_ERROR)
1800 {
1801 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed, %d\n", winEr));
1802 return winEr;
1803 }
1804
1805 if (NumDevices != DevNum)
1806 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != DevNum(%d)\n", NumDevices, DevNum));
1807
1808
1809 uint32_t cConnected = 0;
1810 winEr = vboxDispIfConfigureTargetsWDDM(pOp, &cConnected);
1811 if (winEr != NO_ERROR)
1812 {
1813 WARN(("VBoxTray: vboxDispIfConfigureTargetsWDDM failed winEr 0x%x\n", winEr));
1814 return winEr;
1815 }
1816
1817 if (!cConnected)
1818 {
1819 Log(("VBoxTray: all targets already connected, nothing to do\n"));
1820 return NO_ERROR;
1821 }
1822
1823 winEr = vboxDispIfWaitDisplayDataInited(pOp);
1824 if (winEr != NO_ERROR)
1825 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWaitDisplayDataInited failed winEr 0x%x\n", winEr));
1826
1827 DWORD NewNumDevices = VBoxDisplayGetCount();
1828 if (NewNumDevices == 0)
1829 {
1830 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
1831 return ERROR_GEN_FAILURE;
1832 }
1833
1834 if (NewNumDevices != NumDevices)
1835 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != NewNumDevices(%d)\n", NumDevices, NewNumDevices));
1836
1837 DISPLAY_DEVICE *paNewDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NewNumDevices);
1838 DEVMODE *paNewDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NewNumDevices);
1839 DWORD NewDevNum = 0;
1840 DWORD NewDevPrimaryNum = 0;
1841
1842 winEr = VBoxDisplayGetConfig(NewNumDevices, &NewDevPrimaryNum, &NewDevNum, paNewDisplayDevices, paNewDeviceModes);
1843 if (winEr != NO_ERROR)
1844 {
1845 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed for new devices, %d\n", winEr));
1846 return winEr;
1847 }
1848
1849 if (NewNumDevices != NewDevNum)
1850 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NewNumDevices(%d) != NewDevNum(%d)\n", NewNumDevices, NewDevNum));
1851
1852 DWORD minDevNum = RT_MIN(DevNum, NewDevNum);
1853 UINT *pIds = (UINT*)alloca (sizeof (UINT) * minDevNum);
1854 UINT cIds = 0;
1855 for (DWORD i = 0; i < minDevNum; ++i)
1856 {
1857 if ((paNewDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE)
1858 && !(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
1859 {
1860 pIds[cIds] = i;
1861 ++cIds;
1862 }
1863 }
1864
1865 if (!cIds)
1866 {
1867 /* this is something we would not regularly expect */
1868 WARN(("VBoxTray: all targets already have proper config, nothing to do\n"));
1869 return NO_ERROR;
1870 }
1871
1872 if (pOp->pIf->enmMode > VBOXDISPIF_MODE_WDDM)
1873 {
1874 winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pOp->pIf, cIds, pIds, FALSE);
1875 if (winEr != NO_ERROR)
1876 WARN(("VBoxTray: vboxDispIfWddmEnableDisplaysTryingTopology failed to record current settings, %d, ignoring\n", winEr));
1877 }
1878 else
1879 {
1880 for (DWORD i = 0; i < cIds; ++i)
1881 {
1882 winEr = vboxDispIfWddmResizeDisplayVista(paNewDeviceModes, paNewDisplayDevices, NewDevNum, i, FALSE, TRUE);
1883 if (winEr != NO_ERROR)
1884 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWddmResizeDisplayVista failed winEr 0x%x\n", winEr));
1885 }
1886 }
1887
1888 return winEr;
1889}
1890
1891
1892static DWORD vboxDispIfResizeStartedWDDM(PCVBOXDISPIF const pIf)
1893{
1894 VBOXDISPIF_OP Op;
1895
1896 DWORD winEr = vboxDispIfOpBegin(pIf, &Op);
1897 if (winEr != NO_ERROR)
1898 {
1899 WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x\n", winEr));
1900 return winEr;
1901 }
1902
1903 winEr = vboxDispIfResizeStartedWDDMOp(&Op);
1904 if (winEr != NO_ERROR)
1905 {
1906 WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp failed winEr 0x%x\n", winEr));
1907 }
1908
1909 vboxDispIfOpEnd(&Op);
1910
1911 return winEr;
1912}
1913
1914DWORD VBoxDispIfResizeStarted(PCVBOXDISPIF const pIf)
1915{
1916 switch (pIf->enmMode)
1917 {
1918 case VBOXDISPIF_MODE_XPDM_NT4:
1919 return NO_ERROR;
1920 case VBOXDISPIF_MODE_XPDM:
1921 return NO_ERROR;
1922#ifdef VBOX_WITH_WDDM
1923 case VBOXDISPIF_MODE_WDDM:
1924 case VBOXDISPIF_MODE_WDDM_W7:
1925 return vboxDispIfResizeStartedWDDM(pIf);
1926#endif
1927 default:
1928 WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1929 return ERROR_INVALID_PARAMETER;
1930 }
1931}
1932
1933static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
1934{
1935 return NO_ERROR;
1936}
1937
1938static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
1939{
1940 DWORD err = NO_ERROR;
1941
1942 OSVERSIONINFO OSinfo;
1943 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
1944 GetVersionEx (&OSinfo);
1945 if (OSinfo.dwMajorVersion >= 5)
1946 {
1947 HMODULE hUser = GetModuleHandle("user32.dll");
1948 if (NULL != hUser)
1949 {
1950 bool bSupported = true;
1951 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
1952 Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
1953 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
1954
1955 if (!bSupported)
1956 {
1957 WARN((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
1958 err = ERROR_NOT_SUPPORTED;
1959 }
1960 }
1961 else
1962 {
1963 WARN((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
1964 err = ERROR_NOT_SUPPORTED;
1965 }
1966 }
1967 else
1968 {
1969 WARN((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
1970 err = ERROR_NOT_SUPPORTED;
1971 }
1972
1973 return err;
1974}
1975
1976DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
1977{
1978 /* @todo: may need to addd synchronization in case we want to change modes dynamically
1979 * i.e. currently the mode is supposed to be initialized once on service initialization */
1980 if (penmOldMode)
1981 *penmOldMode = pIf->enmMode;
1982
1983 if (enmMode == pIf->enmMode)
1984 return NO_ERROR;
1985
1986#ifdef VBOX_WITH_WDDM
1987 if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
1988 {
1989 vboxDispIfWddmTerm(pIf);
1990
1991 vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
1992 }
1993#endif
1994
1995 DWORD err = NO_ERROR;
1996 switch (enmMode)
1997 {
1998 case VBOXDISPIF_MODE_XPDM_NT4:
1999 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
2000 err = vboxDispIfSwitchToXPDM_NT4(pIf);
2001 if (err == NO_ERROR)
2002 {
2003 Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
2004 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
2005 }
2006 else
2007 WARN((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
2008 break;
2009 case VBOXDISPIF_MODE_XPDM:
2010 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
2011 err = vboxDispIfSwitchToXPDM(pIf);
2012 if (err == NO_ERROR)
2013 {
2014 Log((__FUNCTION__": successfully switched to XPDM mode\n"));
2015 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
2016 }
2017 else
2018 WARN((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
2019 break;
2020#ifdef VBOX_WITH_WDDM
2021 case VBOXDISPIF_MODE_WDDM:
2022 {
2023 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
2024 err = vboxDispIfSwitchToWDDM(pIf);
2025 if (err == NO_ERROR)
2026 {
2027 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
2028 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
2029 }
2030 else
2031 WARN((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
2032 break;
2033 }
2034 case VBOXDISPIF_MODE_WDDM_W7:
2035 {
2036 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM_W7\n"));
2037 err = vboxDispIfSwitchToWDDM_W7(pIf);
2038 if (err == NO_ERROR)
2039 {
2040 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
2041 pIf->enmMode = VBOXDISPIF_MODE_WDDM_W7;
2042 }
2043 else
2044 WARN((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
2045 break;
2046 }
2047#endif
2048 default:
2049 err = ERROR_INVALID_PARAMETER;
2050 break;
2051 }
2052 return err;
2053}
2054
2055static DWORD vboxDispIfSeamlessCreateWDDM(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2056{
2057 HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pSeamless->modeData.wddm.Adapter);
2058 if (SUCCEEDED(hr))
2059 {
2060#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2061 hr = vboxDispKmtCreateDevice(&pSeamless->modeData.wddm.Adapter, &pSeamless->modeData.wddm.Device);
2062 if (SUCCEEDED(hr))
2063 {
2064 hr = vboxDispKmtCreateContext(&pSeamless->modeData.wddm.Device, &pSeamless->modeData.wddm.Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS,
2065 0, 0, hEvent, 0ULL);
2066 if (SUCCEEDED(hr))
2067#endif
2068 return ERROR_SUCCESS;
2069#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2070 else
2071 WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));
2072
2073 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2074 }
2075 else
2076 WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));
2077
2078 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2079#endif
2080 }
2081
2082 return hr;
2083}
2084
2085static DWORD vboxDispIfSeamlessTermWDDM(VBOXDISPIF_SEAMLESS *pSeamless)
2086{
2087#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2088 vboxDispKmtDestroyContext(&pSeamless->modeData.wddm.Context);
2089 vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
2090#endif
2091 vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
2092
2093 return NO_ERROR;
2094}
2095
2096static DWORD vboxDispIfSeamlessSubmitWDDM(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2097{
2098 D3DKMT_ESCAPE EscapeData = {0};
2099 EscapeData.hAdapter = pSeamless->modeData.wddm.Adapter.hAdapter;
2100#ifdef VBOX_DISPIF_WITH_OPCONTEXT
2101 EscapeData.hDevice = pSeamless->modeData.wddm.Device.hDevice;
2102 EscapeData.hContext = pSeamless->modeData.wddm.Context.hContext;
2103#endif
2104 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
2105 /*EscapeData.Flags.HardwareAccess = 1;*/
2106 EscapeData.pPrivateDriverData = pData;
2107 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
2108
2109 NTSTATUS Status = pSeamless->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
2110 if (NT_SUCCESS(Status))
2111 return ERROR_SUCCESS;
2112
2113 WARN(("VBoxTray: pfnD3DKMTEscape Seamless failed Status 0x%x\n", Status));
2114 return Status;
2115}
2116
2117DWORD VBoxDispIfSeamlessCreate(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
2118{
2119 memset(pSeamless, 0, sizeof (*pSeamless));
2120 pSeamless->pIf = pIf;
2121
2122 switch (pIf->enmMode)
2123 {
2124 case VBOXDISPIF_MODE_XPDM_NT4:
2125 case VBOXDISPIF_MODE_XPDM:
2126 return NO_ERROR;
2127#ifdef VBOX_WITH_WDDM
2128 case VBOXDISPIF_MODE_WDDM:
2129 case VBOXDISPIF_MODE_WDDM_W7:
2130 return vboxDispIfSeamlessCreateWDDM(pIf, pSeamless, hEvent);
2131#endif
2132 default:
2133 break;
2134 }
2135
2136 WARN(("VBoxTray: VBoxDispIfSeamlessCreate: invalid mode %d\n", pIf->enmMode));
2137 return ERROR_INVALID_PARAMETER;
2138}
2139
2140DWORD VBoxDispIfSeamlessTerm(VBOXDISPIF_SEAMLESS *pSeamless)
2141{
2142 PCVBOXDISPIF const pIf = pSeamless->pIf;
2143 DWORD winEr;
2144 switch (pIf->enmMode)
2145 {
2146 case VBOXDISPIF_MODE_XPDM_NT4:
2147 case VBOXDISPIF_MODE_XPDM:
2148 winEr = NO_ERROR;
2149 break;
2150#ifdef VBOX_WITH_WDDM
2151 case VBOXDISPIF_MODE_WDDM:
2152 case VBOXDISPIF_MODE_WDDM_W7:
2153 winEr = vboxDispIfSeamlessTermWDDM(pSeamless);
2154 break;
2155#endif
2156 default:
2157 WARN(("VBoxTray: VBoxDispIfSeamlessTerm: invalid mode %d\n", pIf->enmMode));
2158 winEr = ERROR_INVALID_PARAMETER;
2159 break;
2160 }
2161
2162 if (winEr == NO_ERROR)
2163 memset(pSeamless, 0, sizeof (*pSeamless));
2164
2165 return winEr;
2166}
2167
2168DWORD VBoxDispIfSeamlessSubmit(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
2169{
2170 PCVBOXDISPIF const pIf = pSeamless->pIf;
2171
2172 if (pData->escapeCode != VBOXESC_SETVISIBLEREGION)
2173 {
2174 WARN(("VBoxTray: invalid escape code for Seamless submit %d\n", pData->escapeCode));
2175 return ERROR_INVALID_PARAMETER;
2176 }
2177
2178 switch (pIf->enmMode)
2179 {
2180 case VBOXDISPIF_MODE_XPDM_NT4:
2181 case VBOXDISPIF_MODE_XPDM:
2182 return VBoxDispIfEscape(pIf, pData, cbData);
2183#ifdef VBOX_WITH_WDDM
2184 case VBOXDISPIF_MODE_WDDM:
2185 case VBOXDISPIF_MODE_WDDM_W7:
2186 return vboxDispIfSeamlessSubmitWDDM(pSeamless, pData, cbData);
2187#endif
2188 default:
2189 WARN(("VBoxTray: VBoxDispIfSeamlessSubmit: invalid mode %d\n", pIf->enmMode));
2190 return ERROR_INVALID_PARAMETER;
2191 }
2192}
2193
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