VirtualBox

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

Last change on this file since 51287 was 49010, checked in by vboxsync, 11 years ago

VBoxTray/wddm: fix autoresize

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