VirtualBox

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

Last change on this file since 44931 was 44931, checked in by vboxsync, 12 years ago

Additions/WINNT: Code improvement. Fix for WDDM multimonitor.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.7 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/* APIs specific to win7 and above WDDM architecture. Not available for Vista WDDM.
30 * This is the reason they have not been put in the VBOXDISPIF struct in VBoxDispIf.h
31 */
32typedef struct _VBOXDISPLAYWDDMAPICONTEXT
33{
34 LONG (WINAPI * pfnSetDisplayConfig)(UINT numPathArrayElements,DISPLAYCONFIG_PATH_INFO *pathArray,UINT numModeInfoArrayElements,
35 DISPLAYCONFIG_MODE_INFO *modeInfoArray, UINT Flags);
36 LONG (WINAPI * pfnQueryDisplayConfig)(UINT Flags,UINT *pNumPathArrayElements, DISPLAYCONFIG_PATH_INFO *pPathInfoArray,
37 UINT *pNumModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *pModeInfoArray,
38 DISPLAYCONFIG_TOPOLOGY_ID *pCurrentTopologyId);
39 LONG (WINAPI * pfnGetDisplayConfigBufferSizes)(UINT Flags, UINT *pNumPathArrayElements, UINT *pNumModeInfoArrayElements);
40} _VBOXDISPLAYWDDMAPICONTEXT;
41
42static _VBOXDISPLAYWDDMAPICONTEXT gCtx = {0};
43
44/* display driver interface abstraction for XPDM & WDDM
45 * with WDDM we can not use ExtEscape to communicate with our driver
46 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
47 * that knows nothing about us */
48DWORD VBoxDispIfInit(PVBOXDISPIF pIf)
49{
50 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
51 return NO_ERROR;
52}
53
54#ifdef VBOX_WITH_WDDM
55static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf);
56static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf);
57#endif
58
59DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
60{
61#ifdef VBOX_WITH_WDDM
62 if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
63 {
64 vboxDispIfWddmTerm(pIf);
65 }
66#endif
67
68 pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
69 return NO_ERROR;
70}
71
72static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, int iDirection)
73{
74 HDC hdc = GetDC(HWND_DESKTOP);
75 VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
76 int iRet = ExtEscape(hdc, pEscape->escapeCode,
77 iDirection >= 0 ? cbData : 0,
78 iDirection >= 0 ? (LPSTR)pvData : NULL,
79 iDirection <= 0 ? cbData : 0,
80 iDirection <= 0 ? (LPSTR)pvData : NULL);
81 ReleaseDC(HWND_DESKTOP, hdc);
82 if (iRet > 0)
83 return VINF_SUCCESS;
84 else if (iRet == 0)
85 return ERROR_NOT_SUPPORTED;
86 /* else */
87 return ERROR_GEN_FAILURE;
88}
89
90#ifdef VBOX_WITH_WDDM
91static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
92{
93 DWORD err = NO_ERROR;
94 OSVERSIONINFO OSinfo;
95 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
96 GetVersionEx (&OSinfo);
97 bool bSupported = true;
98
99 if (OSinfo.dwMajorVersion >= 6)
100 {
101 Log((__FUNCTION__": this is vista and up\n"));
102 HMODULE hUser = GetModuleHandle("USER32");
103 if (hUser)
104 {
105 *(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
106 Log((__FUNCTION__": VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.wddm.pfnChangeDisplaySettingsEx));
107 bSupported &= !!(pIf->modeData.wddm.pfnChangeDisplaySettingsEx);
108
109 *(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
110 Log((__FUNCTION__": VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
111 bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
112 /* for win 7 and above */
113 if (OSinfo.dwMinorVersion >= 1)
114 {
115 *(uintptr_t *)&gCtx.pfnSetDisplayConfig = (uintptr_t)GetProcAddress(hUser, "SetDisplayConfig");
116 Log((__FUNCTION__": VBoxDisplayInit: pfnSetDisplayConfig = %p\n", gCtx.pfnSetDisplayConfig));
117 bSupported &= !!(gCtx.pfnSetDisplayConfig);
118
119 *(uintptr_t *)&gCtx.pfnQueryDisplayConfig = (uintptr_t)GetProcAddress(hUser, "QueryDisplayConfig");
120 Log((__FUNCTION__": VBoxDisplayInit: pfnQueryDisplayConfig = %p\n", gCtx.pfnQueryDisplayConfig));
121 bSupported &= !!(gCtx.pfnQueryDisplayConfig);
122
123 *(uintptr_t *)&gCtx.pfnGetDisplayConfigBufferSizes = (uintptr_t)GetProcAddress(hUser, "GetDisplayConfigBufferSizes");
124 Log((__FUNCTION__": VBoxDisplayInit: pfnGetDisplayConfigBufferSizes = %p\n", gCtx.pfnGetDisplayConfigBufferSizes));
125 bSupported &= !!(gCtx.pfnGetDisplayConfigBufferSizes);
126 }
127
128 /* this is vista and up */
129 HMODULE hGdi32 = GetModuleHandle("gdi32");
130 if (hGdi32 != NULL)
131 {
132 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromHdc");
133 Log((__FUNCTION__"pfnD3DKMTOpenAdapterFromHdc = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc));
134 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc);
135
136 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
137 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName));
138 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName);
139
140 pIf->modeData.wddm.pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
141 Log((__FUNCTION__": pfnD3DKMTCloseAdapter = %p\n", pIf->modeData.wddm.pfnD3DKMTCloseAdapter));
142 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
143
144 pIf->modeData.wddm.pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(hGdi32, "D3DKMTEscape");
145 Log((__FUNCTION__": pfnD3DKMTEscape = %p\n", pIf->modeData.wddm.pfnD3DKMTEscape));
146 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
147
148 pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn = (PFND3DKMT_INVALIDATEACTIVEVIDPN)GetProcAddress(hGdi32, "D3DKMTInvalidateActiveVidPn");
149 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn = %p\n", pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn));
150 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn);
151
152 pIf->modeData.wddm.pfnD3DKMTPollDisplayChildren = (PFND3DKMT_POLLDISPLAYCHILDREN)GetProcAddress(hGdi32, "D3DKMTPollDisplayChildren");
153 Log((__FUNCTION__": pfnD3DKMTPollDisplayChildren = %p\n", pIf->modeData.wddm.pfnD3DKMTPollDisplayChildren));
154 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTPollDisplayChildren);
155
156 if (!bSupported)
157 {
158 Log((__FUNCTION__": one of pfnD3DKMT function pointers failed to initialize\n"));
159 err = ERROR_NOT_SUPPORTED;
160 }
161 }
162 else
163 {
164 Log((__FUNCTION__": GetModuleHandle(gdi32) failed, err(%d)\n", GetLastError()));
165 err = ERROR_NOT_SUPPORTED;
166 }
167
168 }
169 else
170 {
171 Log((__FUNCTION__": GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
172 err = ERROR_NOT_SUPPORTED;
173 }
174 }
175 else
176 {
177 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
178 err = ERROR_NOT_SUPPORTED;
179 }
180
181 if (err == ERROR_SUCCESS)
182 {
183 err = vboxDispIfWddmInit(pIf);
184 }
185
186 return err;
187}
188
189static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
190{
191 DWORD winEr = ERROR_INVALID_STATE;
192 memset(pDev, 0, sizeof (*pDev));
193 pDev->cb = sizeof (*pDev);
194
195 for (int i = 0; ; ++i)
196 {
197 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
198 pDev, 0 /* DWORD dwFlags*/))
199 {
200 if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
201 {
202 HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
203 if (hDc)
204 {
205 *phDc = hDc;
206 return NO_ERROR;
207 }
208 else
209 {
210 winEr = GetLastError();
211 Log(("CreateDC failed %d", winEr));
212 break;
213 }
214 }
215 Log(("display data no match display(%d): i(%d), flags(%d)", iDisplay, i, pDev->StateFlags));
216 }
217 else
218 {
219 winEr = GetLastError();
220 Log(("EnumDisplayDevices failed %d", winEr));
221 break;
222 }
223 }
224
225 Log(("vboxDispIfWDDMAdpHdcCreate failure branch %d", winEr));
226 return winEr;
227}
228
229
230typedef DECLCALLBACK(BOOLEAN) FNVBOXDISPIFWDDM_ADAPTEROP(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext);
231typedef FNVBOXDISPIFWDDM_ADAPTEROP *PFNVBOXDISPIFWDDM_ADAPTEROP;
232static DWORD vboxDispIfWDDMAdapterOp(PCVBOXDISPIF pIf, int iDisplay, PFNVBOXDISPIFWDDM_ADAPTEROP pfnOp, PVOID pContext)
233{
234 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
235 DISPLAY_DEVICE DDev;
236 DWORD err = vboxDispIfWDDMAdpHdcCreate(iDisplay, &OpenAdapterData.hDc, &DDev);
237 Assert(err == NO_ERROR);
238 if (err == NO_ERROR)
239 {
240 NTSTATUS Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
241 Assert(!Status);
242 if (!Status)
243 {
244 BOOLEAN bCloseAdapter = pfnOp(pIf, OpenAdapterData.hAdapter, &DDev, pContext);
245
246 if (bCloseAdapter)
247 {
248 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
249 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
250 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
251 if (Status)
252 {
253 Log((__FUNCTION__": pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
254 }
255 }
256 }
257 else
258 {
259 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
260 err = ERROR_GEN_FAILURE;
261 }
262
263 DeleteDC(OpenAdapterData.hDc);
264 }
265 else
266 Log((__FUNCTION__": vboxDispIfWDDMAdpHdcCreate failed, winEr (%d)\n", err));
267
268 return err;
269}
270
271typedef struct
272{
273 NTSTATUS Status;
274 PVBOXDISPIFESCAPE pEscape;
275 int cbData;
276 D3DDDI_ESCAPEFLAGS EscapeFlags;
277} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
278
279DECLCALLBACK(BOOLEAN) vboxDispIfEscapeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
280{
281 PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
282
283 D3DKMT_ESCAPE EscapeData = {0};
284 EscapeData.hAdapter = hAdapter;
285 //EscapeData.hDevice = NULL;
286 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
287 EscapeData.Flags = pCtx->EscapeFlags;
288 EscapeData.pPrivateDriverData = pCtx->pEscape;
289 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
290 //EscapeData.hContext = NULL;
291
292 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTEscape(&EscapeData);
293
294 return TRUE;
295}
296
297static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
298{
299 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
300 Ctx.pEscape = pEscape;
301 Ctx.cbData = cbData;
302 if (fHwAccess)
303 Ctx.EscapeFlags.HardwareAccess = 1;
304 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
305 if (err == NO_ERROR)
306 {
307 if (!Ctx.Status)
308 err = NO_ERROR;
309 else
310 {
311 if (Ctx.Status == 0xC00000BBL) /* not supported */
312 err = ERROR_NOT_SUPPORTED;
313 else
314 err = ERROR_GEN_FAILURE;
315 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
316 }
317 }
318 else
319 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
320
321 return err;
322}
323
324typedef struct
325{
326 NTSTATUS Status;
327 VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO Info;
328} VBOXDISPIFWDDM_RESIZEOP_CONTEXT, *PVBOXDISPIFWDDM_RESIZEOP_CONTEXT;
329
330DECLCALLBACK(BOOLEAN) vboxDispIfResizeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
331{
332 PVBOXDISPIFWDDM_RESIZEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_RESIZEOP_CONTEXT)pContext;
333 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
334 uint32_t cbData = VBOXWDDM_RECOMMENDVIDPN_SIZE(1);
335 PVBOXWDDM_RECOMMENDVIDPN pData = (PVBOXWDDM_RECOMMENDVIDPN)malloc(cbData);
336 if (pData)
337 {
338 memset(pData, 0, cbData);
339 pData->cScreenInfos = 1;
340 memcpy(&pData->aScreenInfos[0], &pCtx->Info, sizeof (VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO));
341
342 IAVidPnData.hAdapter = hAdapter;
343 IAVidPnData.pPrivateDriverData = pData;
344 IAVidPnData.PrivateDriverDataSize = cbData;
345
346 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
347 Assert(!pCtx->Status);
348 if (pCtx->Status)
349 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", pCtx->Status));
350
351 free(pData);
352 }
353 else
354 {
355 Log((__FUNCTION__": malloc failed\n"));
356 pCtx->Status = -1;
357 }
358
359 return TRUE;
360}
361
362static DWORD vboxDispIfResizeWDDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
363{
364 VBOXDISPIFWDDM_RESIZEOP_CONTEXT Ctx = {0};
365 Ctx.Info.Id = Id;
366 Ctx.Info.Width = Width;
367 Ctx.Info.Height = Height;
368 Ctx.Info.BitsPerPixel = BitsPerPixel;
369 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1, /* (int)Id - always say -1 to use primary display since the display does not really matter here */
370 vboxDispIfResizeWDDMOp, &Ctx);
371 if (err == NO_ERROR)
372 {
373 if (!Ctx.Status)
374 err = NO_ERROR;
375 else
376 {
377 if (Ctx.Status == 0xC00000BBL) /* not supported */
378 err = ERROR_NOT_SUPPORTED;
379 else
380 err = ERROR_GEN_FAILURE;
381 Log((__FUNCTION__": vboxDispIfResizeWDDMOp failed, Status (0x%x)\n", Ctx.Status));
382 }
383 }
384 else
385 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
386
387 return err;
388}
389#endif
390
391DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
392{
393 switch (pIf->enmMode)
394 {
395 case VBOXDISPIF_MODE_XPDM_NT4:
396 case VBOXDISPIF_MODE_XPDM:
397 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 1);
398#ifdef VBOX_WITH_WDDM
399 case VBOXDISPIF_MODE_WDDM:
400 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
401#endif
402 default:
403 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
404 return ERROR_INVALID_PARAMETER;
405 }
406}
407
408DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
409{
410 switch (pIf->enmMode)
411 {
412 case VBOXDISPIF_MODE_XPDM_NT4:
413 case VBOXDISPIF_MODE_XPDM:
414 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 0);
415#ifdef VBOX_WITH_WDDM
416 case VBOXDISPIF_MODE_WDDM:
417 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
418#endif
419 default:
420 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
421 return ERROR_INVALID_PARAMETER;
422 }
423}
424
425static DWORD vboxDispIfResizeXPDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
426{
427 return ERROR_NOT_SUPPORTED;
428}
429
430DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
431{
432 switch (pIf->enmMode)
433 {
434 case VBOXDISPIF_MODE_XPDM_NT4:
435 return ERROR_NOT_SUPPORTED;
436 case VBOXDISPIF_MODE_XPDM:
437 return vboxDispIfResizeXPDM(pIf, Id, Width, Height, BitsPerPixel);
438#ifdef VBOX_WITH_WDDM
439 case VBOXDISPIF_MODE_WDDM:
440 return vboxDispIfResizeWDDM(pIf, Id, Width, Height, BitsPerPixel);
441#endif
442 default:
443 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
444 return ERROR_INVALID_PARAMETER;
445 }
446}
447
448
449#ifdef VBOX_WITH_WDDM
450
451#define VBOXRR_TIMER_ID 1234
452
453typedef struct VBOXRR
454{
455 HANDLE hThread;
456 DWORD idThread;
457 HANDLE hEvent;
458 HWND hWnd;
459 CRITICAL_SECTION CritSect;
460 UINT_PTR idTimer;
461 PCVBOXDISPIF pIf;
462 DISPLAY_DEVICE *paDisplayDevices;
463 DEVMODE *paDeviceModes;
464 UINT cDevModes;
465} VBOXRR, *PVBOXRR;
466
467static VBOXRR g_VBoxRr = {0};
468
469#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
470#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
471
472static void vboxRrRetryStopLocked()
473{
474 PVBOXRR pMon = &g_VBoxRr;
475 if (pMon->pIf)
476 {
477 if (pMon->paDisplayDevices)
478 {
479 free(pMon->paDisplayDevices);
480 pMon->paDisplayDevices = NULL;
481 }
482
483 if (pMon->paDeviceModes)
484 {
485 free(pMon->paDeviceModes);
486 pMon->paDeviceModes = NULL;
487 }
488
489 if (pMon->idTimer)
490 {
491 KillTimer(pMon->hWnd, pMon->idTimer);
492 pMon->idTimer = 0;
493 }
494
495 pMon->cDevModes = 0;
496 pMon->pIf = NULL;
497 }
498}
499
500static void VBoxRrRetryStop()
501{
502 PVBOXRR pMon = &g_VBoxRr;
503 EnterCriticalSection(&pMon->CritSect);
504 vboxRrRetryStopLocked();
505 LeaveCriticalSection(&pMon->CritSect);
506}
507
508static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);
509
510static void vboxRrRetryReschedule()
511{
512}
513
514static void VBoxRrRetrySchedule(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
515{
516 PVBOXRR pMon = &g_VBoxRr;
517 EnterCriticalSection(&pMon->CritSect);
518 vboxRrRetryStopLocked();
519
520 pMon->pIf = pIf;
521 if (cDevModes)
522 {
523 pMon->paDisplayDevices = (DISPLAY_DEVICE*)malloc(sizeof (*paDisplayDevices) * cDevModes);
524 Assert(pMon->paDisplayDevices);
525 if (!pMon->paDisplayDevices)
526 {
527 Log(("malloc failed!"));
528 vboxRrRetryStopLocked();
529 LeaveCriticalSection(&pMon->CritSect);
530 return;
531 }
532 memcpy(pMon->paDisplayDevices, paDisplayDevices, sizeof (*paDisplayDevices) * cDevModes);
533
534 pMon->paDeviceModes = (DEVMODE*)malloc(sizeof (*paDeviceModes) * cDevModes);
535 Assert(pMon->paDeviceModes);
536 if (!pMon->paDeviceModes)
537 {
538 Log(("malloc failed!"));
539 vboxRrRetryStopLocked();
540 LeaveCriticalSection(&pMon->CritSect);
541 return;
542 }
543 memcpy(pMon->paDeviceModes, paDeviceModes, sizeof (*paDeviceModes) * cDevModes);
544 }
545 pMon->cDevModes = cDevModes;
546
547 pMon->idTimer = SetTimer(pMon->hWnd, VBOXRR_TIMER_ID, 1000, (TIMERPROC)NULL);
548 Assert(pMon->idTimer);
549 if (!pMon->idTimer)
550 {
551 Log(("VBoxTray: SetTimer failed!, err %d\n", GetLastError()));
552 vboxRrRetryStopLocked();
553 }
554
555 LeaveCriticalSection(&pMon->CritSect);
556}
557
558static void vboxRrRetryPerform()
559{
560 PVBOXRR pMon = &g_VBoxRr;
561 EnterCriticalSection(&pMon->CritSect);
562 if (pMon->pIf)
563 {
564 DWORD dwErr = vboxDispIfWddmValidateFixResize(pMon->pIf, pMon->paDisplayDevices, pMon->paDeviceModes, pMon->cDevModes);
565 if (ERROR_RETRY != dwErr)
566 VBoxRrRetryStop();
567 else
568 vboxRrRetryReschedule();
569 }
570 LeaveCriticalSection(&pMon->CritSect);
571}
572
573static LRESULT CALLBACK vboxRrWndProc(HWND hwnd,
574 UINT uMsg,
575 WPARAM wParam,
576 LPARAM lParam
577)
578{
579 switch(uMsg)
580 {
581 case WM_DISPLAYCHANGE:
582 {
583 Log(("VBoxTray: WM_DISPLAYCHANGE\n"));
584 VBoxRrRetryStop();
585 return 0;
586 }
587 case WM_TIMER:
588 {
589 if (wParam == VBOXRR_TIMER_ID)
590 {
591 Log(("VBoxTray: VBOXRR_TIMER_ID\n"));
592 vboxRrRetryPerform();
593 return 0;
594 }
595 break;
596 }
597 case WM_CLOSE:
598 Log((__FUNCTION__": got WM_CLOSE for hwnd(0x%x)", hwnd));
599 return 0;
600 case WM_DESTROY:
601 Log((__FUNCTION__": got WM_DESTROY for hwnd(0x%x)", hwnd));
602 return 0;
603 case WM_NCHITTEST:
604 Log((__FUNCTION__": got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
605 return HTNOWHERE;
606 default:
607 break;
608 }
609
610 return DefWindowProc(hwnd, uMsg, wParam, lParam);
611}
612
613#define VBOXRRWND_NAME "VBoxRrWnd"
614
615static HRESULT vboxRrWndCreate(HWND *phWnd)
616{
617 HRESULT hr = S_OK;
618 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
619 /* Register the Window Class. */
620 WNDCLASS wc;
621 if (!GetClassInfo(hInstance, VBOXRRWND_NAME, &wc))
622 {
623 wc.style = 0;//CS_OWNDC;
624 wc.lpfnWndProc = vboxRrWndProc;
625 wc.cbClsExtra = 0;
626 wc.cbWndExtra = 0;
627 wc.hInstance = hInstance;
628 wc.hIcon = NULL;
629 wc.hCursor = NULL;
630 wc.hbrBackground = NULL;
631 wc.lpszMenuName = NULL;
632 wc.lpszClassName = VBOXRRWND_NAME;
633 if (!RegisterClass(&wc))
634 {
635 DWORD winErr = GetLastError();
636 Log((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
637 hr = E_FAIL;
638 }
639 }
640
641 if (hr == S_OK)
642 {
643 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
644 VBOXRRWND_NAME, VBOXRRWND_NAME,
645 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
646 -100, -100,
647 10, 10,
648 NULL, //GetDesktopWindow() /* hWndParent */,
649 NULL /* hMenu */,
650 hInstance,
651 NULL /* lpParam */);
652 Assert(hWnd);
653 if (hWnd)
654 {
655 *phWnd = hWnd;
656 }
657 else
658 {
659 DWORD winErr = GetLastError();
660 Log((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
661 hr = E_FAIL;
662 }
663 }
664
665 return hr;
666}
667
668static HRESULT vboxRrWndDestroy(HWND hWnd)
669{
670 BOOL bResult = DestroyWindow(hWnd);
671 if (bResult)
672 return S_OK;
673
674 DWORD winErr = GetLastError();
675 Log((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
676
677 return HRESULT_FROM_WIN32(winErr);
678}
679
680static HRESULT vboxRrWndInit()
681{
682 PVBOXRR pMon = &g_VBoxRr;
683 return vboxRrWndCreate(&pMon->hWnd);
684}
685
686HRESULT vboxRrWndTerm()
687{
688 PVBOXRR pMon = &g_VBoxRr;
689 HRESULT tmpHr = vboxRrWndDestroy(pMon->hWnd);
690 Assert(tmpHr == S_OK);
691
692 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
693 UnregisterClass(VBOXRRWND_NAME, hInstance);
694
695 return S_OK;
696}
697
698#define WM_VBOXRR_INIT_QUIT (WM_APP+2)
699
700HRESULT vboxRrRun()
701{
702 PVBOXRR pMon = &g_VBoxRr;
703 MSG Msg;
704
705 HRESULT hr = S_FALSE;
706
707 PeekMessage(&Msg,
708 NULL /* HWND hWnd */,
709 WM_USER /* UINT wMsgFilterMin */,
710 WM_USER /* UINT wMsgFilterMax */,
711 PM_NOREMOVE);
712
713 do
714 {
715 BOOL bResult = GetMessage(&Msg,
716 0 /*HWND hWnd*/,
717 0 /*UINT wMsgFilterMin*/,
718 0 /*UINT wMsgFilterMax*/
719 );
720
721 if(!bResult) /* WM_QUIT was posted */
722 {
723 hr = S_FALSE;
724 Log(("VBoxTray: GetMessage returned FALSE\n"));
725 VBoxRrRetryStop();
726 break;
727 }
728
729 if(bResult == -1) /* error occurred */
730 {
731 DWORD winEr = GetLastError();
732 hr = HRESULT_FROM_WIN32(winEr);
733 Assert(0);
734 /* just ensure we never return success in this case */
735 Assert(hr != S_OK);
736 Assert(hr != S_FALSE);
737 if (hr == S_OK || hr == S_FALSE)
738 hr = E_FAIL;
739 Log(("VBoxTray: GetMessage returned -1, err %d\n", winEr));
740 VBoxRrRetryStop();
741 break;
742 }
743
744 switch (Msg.message)
745 {
746 case WM_VBOXRR_INIT_QUIT:
747 case WM_CLOSE:
748 {
749 Log(("VBoxTray: closing Rr %d\n", Msg.message));
750 VBoxRrRetryStop();
751 PostQuitMessage(0);
752 break;
753 }
754 default:
755 TranslateMessage(&Msg);
756 DispatchMessage(&Msg);
757 break;
758 }
759 } while (1);
760 return 0;
761}
762
763static DWORD WINAPI vboxRrRunnerThread(void *pvUser)
764{
765 PVBOXRR pMon = &g_VBoxRr;
766
767 BOOL bRc = SetEvent(pMon->hEvent);
768 if (!bRc)
769 {
770 DWORD winErr = GetLastError();
771 Log((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
772 HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
773 Assert(tmpHr != S_OK);
774 }
775
776 HRESULT hr = vboxRrWndInit();
777 Assert(hr == S_OK);
778 if (hr == S_OK)
779 {
780 hr = vboxRrRun();
781 Assert(hr == S_OK);
782
783 vboxRrWndTerm();
784 }
785
786 return 0;
787}
788
789HRESULT VBoxRrInit()
790{
791 HRESULT hr = E_FAIL;
792 PVBOXRR pMon = &g_VBoxRr;
793 memset(pMon, 0, sizeof (*pMon));
794
795 InitializeCriticalSection(&pMon->CritSect);
796
797 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
798 TRUE, /* BOOL bManualReset*/
799 FALSE, /* BOOL bInitialState */
800 NULL /* LPCTSTR lpName */
801 );
802 if (pMon->hEvent)
803 {
804 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
805 0 /* SIZE_T dwStackSize */,
806 vboxRrRunnerThread,
807 pMon,
808 0 /* DWORD dwCreationFlags */,
809 &pMon->idThread);
810 if (pMon->hThread)
811 {
812 DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
813 if (dwResult == WAIT_OBJECT_0)
814 return S_OK;
815 else
816 {
817 Log(("WaitForSingleObject failed!"));
818 hr = E_FAIL;
819 }
820 }
821 else
822 {
823 DWORD winErr = GetLastError();
824 Log((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
825 hr = HRESULT_FROM_WIN32(winErr);
826 Assert(hr != S_OK);
827 }
828 CloseHandle(pMon->hEvent);
829 }
830 else
831 {
832 DWORD winErr = GetLastError();
833 Log((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
834 hr = HRESULT_FROM_WIN32(winErr);
835 Assert(hr != S_OK);
836 }
837
838 DeleteCriticalSection(&pMon->CritSect);
839
840 return hr;
841}
842
843VOID VBoxRrTerm()
844{
845 HRESULT hr;
846 PVBOXRR pMon = &g_VBoxRr;
847 if (!pMon->hThread)
848 return;
849
850 BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXRR_INIT_QUIT, 0, 0);
851 DWORD winErr;
852 if (bResult
853 || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
854 {
855 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
856 if (dwErr == WAIT_OBJECT_0)
857 {
858 hr = S_OK;
859 }
860 else
861 {
862 winErr = GetLastError();
863 hr = HRESULT_FROM_WIN32(winErr);
864 }
865 }
866 else
867 {
868 hr = HRESULT_FROM_WIN32(winErr);
869 }
870
871 DeleteCriticalSection(&pMon->CritSect);
872
873 CloseHandle(pMon->hThread);
874 pMon->hThread = 0;
875 CloseHandle(pMon->hEvent);
876 pMon->hThread = 0;
877}
878
879
880typedef struct VBOXDISPIF_WDDM_INTERNAL
881{
882 PCVBOXDISPIF pIf;
883} VBOXDISPIF_WDDM_INTERNAL, *PVBOXDISPIF_WDDM_INTERNAL;
884
885static VBOXDISPIF_WDDM_INTERNAL g_VBoxDispIfWddm;
886
887static BOOL vboxDispIfWddmValidateResize(DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
888{
889 DISPLAY_DEVICE DisplayDevice;
890 int i = 0;
891 UINT cMatched = 0;
892 DEVMODE CurDevMode, RegDevMode;
893 for (int i = 0; ; ++i)
894 {
895 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
896 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
897
898 if (!EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
899 break;
900
901 Log(("VBoxTray: vboxDispIfValidateResize: [%d(%d)] %s\n", i, cMatched, DisplayDevice.DeviceName));
902
903 BOOL bFetchDevice = FALSE;
904
905 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
906 {
907 Log(("VBoxTray: vboxDispIfValidateResize: Found primary device. err %d\n", GetLastError ()));
908 bFetchDevice = TRUE;
909 }
910 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
911 {
912
913 Log(("VBoxTray: vboxDispIfValidateResize: Found secondary device. err %d\n", GetLastError ()));
914 bFetchDevice = TRUE;
915 }
916
917 if (bFetchDevice)
918 {
919 if (cMatched >= cDevModes)
920 {
921 Log(("VBoxTray: vboxDispIfValidateResize: %d >= %d\n", cDevModes, cMatched));
922 return FALSE;
923 }
924
925 /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
926 * A secondary display could be not active at the moment and would not have
927 * a current video mode (ENUM_CURRENT_SETTINGS).
928 */
929 ZeroMemory(&RegDevMode, sizeof(RegDevMode));
930 RegDevMode.dmSize = sizeof(DEVMODE);
931 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
932 ENUM_REGISTRY_SETTINGS, &RegDevMode))
933 {
934 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings error %d\n", GetLastError ()));
935 return FALSE;
936 }
937
938 /* with Win8 WDDM Display-only driver, it seems like sometimes we get an auto-resize setting being stored in registry, although current settings do not match */
939 ZeroMemory(&CurDevMode, sizeof(CurDevMode));
940 CurDevMode.dmSize = sizeof(CurDevMode);
941 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
942 ENUM_CURRENT_SETTINGS, &CurDevMode))
943 {
944 /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
945 * for example a disabled secondary display */
946 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
947 return FALSE;
948 }
949
950 /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
951 * Get the current video mode then.
952 */
953 if ( RegDevMode.dmPelsWidth != 0
954 && RegDevMode.dmPelsHeight == 0)
955 {
956 if (CurDevMode.dmBitsPerPel != RegDevMode.dmBitsPerPel
957 || CurDevMode.dmPelsWidth != RegDevMode.dmPelsWidth
958 || CurDevMode.dmPelsHeight != RegDevMode.dmPelsHeight
959 || CurDevMode.dmPosition.x != RegDevMode.dmPosition.x
960 || CurDevMode.dmPosition.y != RegDevMode.dmPosition.y)
961 {
962 Log(("VBoxTray: vboxDispIfValidateResize: current settings do not match registry settings, trating as no-match"));
963 return FALSE;
964 }
965 }
966
967 UINT j = 0;
968 for (; j < cDevModes; ++j)
969 {
970 if (!strncmp(DisplayDevice.DeviceName, paDisplayDevices[j].DeviceName, RT_ELEMENTS(CurDevMode.dmDeviceName)))
971 {
972 if (paDeviceModes[j].dmBitsPerPel != CurDevMode.dmBitsPerPel
973 || (paDeviceModes[j].dmPelsWidth & 0xfff8) != (CurDevMode.dmPelsWidth & 0xfff8)
974 || (paDeviceModes[j].dmPelsHeight & 0xfff8) != (CurDevMode.dmPelsHeight & 0xfff8)
975 || (paDeviceModes[j].dmPosition.x & 0xfff8) != (CurDevMode.dmPosition.x & 0xfff8)
976 || (paDeviceModes[j].dmPosition.y & 0xfff8) != (CurDevMode.dmPosition.y & 0xfff8)
977 || (paDisplayDevices[j].StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
978 {
979 return FALSE;
980 }
981 break;
982 }
983 }
984
985 if (j == cDevModes)
986 return FALSE;
987
988 ++cMatched;
989 }
990 }
991
992 return cMatched == cDevModes;
993}
994
995static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
996{
997 if (vboxDispIfWddmValidateResize(paDisplayDevices, paDeviceModes, cDevModes))
998 return NO_ERROR;
999
1000 LONG status = DISP_CHANGE_SUCCESSFUL;
1001
1002 /* now try to resize in a "regular" way */
1003 /* Assign the new rectangles to displays. */
1004 for (UINT i = 0; i < cDevModes; i++)
1005 {
1006 /* On Vista one must specify DM_BITSPERPEL.
1007 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
1008 */
1009 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
1010
1011 Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
1012 pIf->modeData.wddm.pfnChangeDisplaySettingsEx,
1013 paDeviceModes[i].dmPelsWidth,
1014 paDeviceModes[i].dmPelsHeight,
1015 paDeviceModes[i].dmBitsPerPel,
1016 paDeviceModes[i].dmPosition.x,
1017 paDeviceModes[i].dmPosition.y));
1018
1019 /* the miniport might have been adjusted the display mode stuff,
1020 * adjust the paDeviceModes[i] by picking the closest available one */
1021// DEVMODE AdjustedMode = paDeviceModes[i];
1022// vboxDispIfAdjustMode(&paDisplayDevices[i], &AdjustedMode);
1023
1024 LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
1025 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
1026 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", tmpStatus, GetLastError ()));
1027 if (tmpStatus != DISP_CHANGE_SUCCESSFUL)
1028 {
1029 status = tmpStatus;
1030 }
1031 }
1032
1033 /* A second call to ChangeDisplaySettings updates the monitor. */
1034 LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
1035 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
1036 if (tmpStatus == DISP_CHANGE_SUCCESSFUL)
1037 {
1038 if (status == DISP_CHANGE_SUCCESSFUL)
1039 {
1040 Log(("VBoxTray: resize succeeded\n"));
1041 return NO_ERROR;
1042 }
1043 }
1044 else
1045 {
1046 if (status == DISP_CHANGE_SUCCESSFUL)
1047 status = tmpStatus;
1048 }
1049
1050 if (status == DISP_CHANGE_FAILED)
1051 {
1052 Log(("VBoxTray: DISP_CHANGE_FAILED, retrying..\n"));
1053 return ERROR_RETRY;
1054 }
1055
1056 Log(("VBoxTray: resize failed with status %d\n", status));
1057
1058 return ERROR_GEN_FAILURE;
1059}
1060
1061static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
1062{
1063 memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
1064 g_VBoxDispIfWddm.pIf = pIf;
1065 HRESULT hr = VBoxRrInit();
1066 if (SUCCEEDED(hr))
1067 {
1068 return ERROR_SUCCESS;
1069 }
1070 return ERROR_GEN_FAILURE;
1071}
1072
1073static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
1074{
1075 VBoxRrTerm();
1076 memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
1077}
1078
1079typedef struct VBOXDISPIF_REINITMODES_OP
1080{
1081 VBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK EscData;
1082} VBOXDISPIF_REINITMODES_OP, *PVBOXDISPIF_REINITMODES_OP;
1083
1084static DECLCALLBACK(BOOLEAN) vboxDispIfReninitModesWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
1085{
1086 PVBOXDISPIF_REINITMODES_OP pData = (PVBOXDISPIF_REINITMODES_OP)pContext;
1087 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
1088 Ctx.pEscape = &pData->EscData.EscapeHdr;
1089 Ctx.cbData = sizeof (pData->EscData) - sizeof (pData->EscData.EscapeHdr);
1090// Ctx.EscapeFlags.HardwareAccess = 0;
1091 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
1092 if (err == NO_ERROR)
1093 {
1094 if (!Ctx.Status)
1095 err = NO_ERROR;
1096 else
1097 {
1098 if (Ctx.Status == 0xC00000BBL) /* not supported */
1099 err = ERROR_NOT_SUPPORTED;
1100 else
1101 err = ERROR_GEN_FAILURE;
1102 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
1103 }
1104 }
1105 else
1106 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
1107
1108 D3DKMT_POLLDISPLAYCHILDREN PollData = {0};
1109 PollData.hAdapter = hAdapter;
1110 PollData.NonDestructiveOnly = 1;
1111 NTSTATUS Status = pIf->modeData.wddm.pfnD3DKMTPollDisplayChildren(&PollData);
1112 if (Status != 0)
1113 {
1114 Log((__FUNCTION__": pfnD3DKMTPollDisplayChildren failed, Status (0x%x)\n", Status));
1115 }
1116 return TRUE;
1117}
1118
1119static DWORD vboxDispIfReninitModesWDDM(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
1120{
1121 VBOXDISPIF_REINITMODES_OP OpData = {0};
1122 OpData.EscData.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
1123 if (fReconnectDisplaysOnChange)
1124 OpData.EscData.EscapeHdr.u32CmdSpecific = VBOXWDDM_REINITVIDEOMODESBYMASK_F_RECONNECT_DISPLAYS_ON_CHANGE;
1125
1126 memcpy(OpData.EscData.ScreenMask, pScreenIdMask, sizeof (OpData.EscData.ScreenMask));
1127
1128 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfReninitModesWDDMOp, &OpData);
1129 return err;
1130}
1131
1132DWORD vboxDispIfCancelPendingResizeWDDM(PCVBOXDISPIF const pIf)
1133{
1134 Log(("VBoxTray: cancelling pending resize\n"));
1135 VBoxRrRetryStop();
1136 return NO_ERROR;
1137}
1138
1139static DWORD vboxDispIfAdjustMode(DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
1140{
1141 DEVMODE CurMode;
1142 DEVMODE BestMatchMode;
1143 DWORD i = 0;
1144 int64_t diffWH = INT64_MAX;
1145 int diffBpp = INT32_MAX;
1146 for (; ; ++i)
1147 {
1148 CurMode.dmSize = sizeof (CurMode);
1149 CurMode.dmDriverExtra = 0;
1150
1151 if (!EnumDisplaySettings(pDisplayDevice->DeviceName, i, &CurMode))
1152 break;
1153
1154 if (CurMode.dmPelsWidth == pDeviceMode->dmPelsWidth
1155 && CurMode.dmPelsHeight == pDeviceMode->dmPelsHeight
1156 && CurMode.dmBitsPerPel == pDeviceMode->dmBitsPerPel)
1157 {
1158 Log(("Exact match found"));
1159 *pDeviceMode = CurMode;
1160 return NO_ERROR;
1161 }
1162
1163 int diffCurrW = RT_ABS((int)(CurMode.dmPelsWidth - pDeviceMode->dmPelsWidth));
1164 int diffCurrH = RT_ABS((int)(CurMode.dmPelsHeight - pDeviceMode->dmPelsHeight));
1165 int diffCurrBpp = RT_ABS((int)(CurMode.dmBitsPerPel - pDeviceMode->dmBitsPerPel)
1166 - 1 /* <- to make higher bpp take precedence over lower ones */
1167 );
1168
1169 int64_t diffCurrHW = (int64_t)diffCurrW*diffCurrW + (int64_t)diffCurrH*diffCurrH;
1170
1171 if (i == 0
1172 || diffCurrHW < diffWH
1173 || (diffCurrHW == diffWH && diffCurrBpp < diffBpp))
1174 {
1175 /* first run */
1176 BestMatchMode = CurMode;
1177 diffWH = diffCurrHW;
1178 diffBpp = diffCurrBpp;
1179 continue;
1180 }
1181 }
1182
1183 if (i == 0)
1184 {
1185 Log(("No modes found!"));
1186 return NO_ERROR;
1187 }
1188
1189 *pDeviceMode = BestMatchMode;
1190 return NO_ERROR;
1191}
1192
1193static DWORD vboxDispIfAdjustModeValues(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
1194{
1195 VBOXDISPIFESCAPE_ADJUSTVIDEOMODES Data = {0};
1196 Data.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
1197 Data.EscapeHdr.u32CmdSpecific = 1;
1198 Data.aScreenInfos[0].Mode.Id =
1199 Data.aScreenInfos[0].Mode.Width = pDeviceMode->dmPelsWidth;
1200 Data.aScreenInfos[0].Mode.Height = pDeviceMode->dmPelsHeight;
1201 Data.aScreenInfos[0].Mode.BitsPerPixel = pDeviceMode->dmBitsPerPel;
1202 if (pDeviceMode->dmPosition.x != 0 || pDeviceMode->dmPosition.y != 0) {
1203 Data.aScreenInfos[0].Mode.PosX = pDeviceMode->dmPosition.x;
1204 Data.aScreenInfos[0].Mode.PosY = pDeviceMode->dmPosition.y;
1205 }
1206 DWORD err = vboxDispIfEscapeWDDM(pIf, &Data.EscapeHdr, sizeof (Data) - sizeof (Data.EscapeHdr), TRUE);
1207 if (err != NO_ERROR)
1208 {
1209 Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
1210 }
1211 return err;
1212}
1213
1214DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1215{
1216 UINT cbVidPnInfo = VBOXWDDM_RECOMMENDVIDPN_SIZE(cDevModes);
1217 PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = (PVBOXWDDM_RECOMMENDVIDPN)alloca(cbVidPnInfo);
1218 pVidPnInfo->cScreenInfos = cDevModes;
1219 D3DKMT_HANDLE hAdapter = NULL;
1220 NTSTATUS Status;
1221 DWORD winEr = NO_ERROR;
1222 UINT i = 0;
1223
1224 Log(("VBoxTray: vboxDispIfResizeModesWDDM\n"));
1225 VBoxRrRetryStop();
1226
1227 for (; i < cDevModes; i++)
1228 {
1229 PVBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO pInfo = &pVidPnInfo->aScreenInfos[i];
1230 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
1231 OpenAdapterData.hDc = CreateDC(NULL, paDisplayDevices[i].DeviceName, NULL, NULL);
1232 if (!OpenAdapterData.hDc)
1233 {
1234 winEr = GetLastError();
1235 Log(("VBoxTray: WARNING: Failed to get dc for display device %s, winEr %d\n", paDisplayDevices[i].DeviceName, winEr));
1236 break;
1237 }
1238
1239 Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
1240 Assert(!Status);
1241 if (Status)
1242 {
1243 winEr = ERROR_GEN_FAILURE;
1244 Log(("VBoxTray: WARNING: Failed to open adapter from dc, Status 0x%x\n", Status));
1245 break;
1246 }
1247
1248 pInfo->Id = OpenAdapterData.VidPnSourceId;
1249 pInfo->Width = paDeviceModes[i].dmPelsWidth;
1250 pInfo->Height = paDeviceModes[i].dmPelsHeight;
1251 pInfo->BitsPerPixel = paDeviceModes[i].dmBitsPerPel;
1252
1253 if (i == iChangedMode && (paDeviceModes[i].dmPosition.x != 0 || paDeviceModes[i].dmPosition.y != 0) )
1254 {
1255 /* change position values only if not equal to 0*/
1256 LogRel(("VBoxTray: (WDDM) Change Position x=%d*y=%d Display Device ID=%d\n", paDeviceModes[i].dmPosition.x, paDeviceModes[i].dmPosition.y, i));
1257 pInfo->PosX = paDeviceModes[i].dmPosition.x;
1258 pInfo->PosY = paDeviceModes[i].dmPosition.y;
1259 }
1260
1261 if (!hAdapter)
1262 {
1263 hAdapter = OpenAdapterData.hAdapter;
1264 }
1265 else
1266 {
1267 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
1268 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
1269 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
1270 if (Status)
1271 Log(("VBoxTray: WARNING: Failed to close adapter, Status 0x%x\n", Status));
1272 }
1273 }
1274
1275 BOOL fAbleToInvalidateVidPn = FALSE;
1276
1277 if (0 && winEr == NO_ERROR)
1278 {
1279 Assert(hAdapter);
1280
1281 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
1282 IAVidPnData.hAdapter = hAdapter;
1283 IAVidPnData.pPrivateDriverData = pVidPnInfo;
1284 IAVidPnData.PrivateDriverDataSize = cbVidPnInfo;
1285
1286 DWORD winEr = NO_ERROR;
1287 Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
1288 Assert(!Status);
1289 if (Status)
1290 {
1291 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", Status));
1292 winEr = ERROR_GEN_FAILURE;
1293 }
1294 else
1295 {
1296 fAbleToInvalidateVidPn = TRUE;
1297 }
1298 }
1299
1300 if (hAdapter)
1301 {
1302 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
1303 ClosaAdapterData.hAdapter = hAdapter;
1304 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
1305 if (Status)
1306 Log(("VBoxTray: WARNING: Failed to close adapter[2], Status 0x%x\n", Status));
1307 }
1308
1309// for (i = 0; i < cDevModes; i++)
1310// {
1311// vboxDispIfAdjustMode(&paDisplayDevices[i], &paDeviceModes[i]);
1312// }
1313
1314 if (fAbleToInvalidateVidPn)
1315 {
1316 Log(("VBoxTray: Invalidating VidPn Worked!\n"));
1317 OSVERSIONINFO OSinfo;
1318 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
1319 GetVersionEx (&OSinfo);
1320 /* for win 7 and above calling ChangeDisplaySettingsEx to resize a specific display, is having
1321 * a side affect for enabling all the monitors including the disabled ones. So using
1322 * WDDM win 7 APIs to resize the display for OSes Win7 and above.
1323 */
1324 if (OSinfo.dwMajorVersion >= 6 && OSinfo.dwMinorVersion >= 1)
1325 winEr = vboxDispIfWddmResizeDisplay(pIf, iChangedMode, paDisplayDevices, paDeviceModes, cDevModes);
1326 else
1327 winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1328
1329 }
1330 else
1331 {
1332 Log(("VBoxTray: Falling back to monitor mode reinit\n"));
1333 /* fallback impl needed for display-only driver
1334 * since D3DKMTInvalidateActiveVidPn is not available for WDDM > 1.0:
1335 * make the driver invalidate VidPn,
1336 * which is done by emulating a monitor re-plug currently */
1337 uint8_t ScreenMask[VBOXWDDM_SCREENMASK_SIZE] = {0};
1338 ASMBitSet(ScreenMask, iChangedMode);
1339 vboxDispIfReninitModesWDDM(pIf, ScreenMask, TRUE);
1340
1341 OSVERSIONINFO OSinfo;
1342 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
1343 GetVersionEx (&OSinfo);
1344 if (OSinfo.dwMajorVersion >= 6 && OSinfo.dwMinorVersion >= 1)
1345 winEr = vboxDispIfWddmResizeDisplay(pIf, iChangedMode, paDisplayDevices, paDeviceModes, cDevModes);
1346 else
1347 winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1348 Assert(winEr == NO_ERROR);
1349 }
1350
1351 if (winEr == ERROR_RETRY)
1352 {
1353 VBoxRrRetrySchedule(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1354 /* just pretend everything is fine so far */
1355 winEr = NO_ERROR;
1356 }
1357
1358 return winEr;
1359}
1360
1361DWORD vboxDispIfWddmEnableDisplay(PCVBOXDISPIF const pIf, UINT Id, bool fEnabled)
1362{
1363 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
1364 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
1365 UINT numPathArrayElements = 0;
1366 UINT numModeInfoArrayElements = 0;
1367 ULONG dwStatus;
1368
1369 dwStatus = gCtx.pfnGetDisplayConfigBufferSizes(fEnabled ? QDC_ALL_PATHS : QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, &numModeInfoArrayElements);
1370 if (dwStatus != ERROR_SUCCESS)
1371 {
1372 LogFlow(("VBoxTray: (WDDM) Failed GetDisplayConfigBufferSizes \n"));
1373 return dwStatus;
1374 }
1375 pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(numPathArrayElements * sizeof(DISPLAYCONFIG_PATH_INFO));
1376 if (!pPathInfoArray)
1377 return ERROR_OUTOFMEMORY;
1378 pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(numModeInfoArrayElements * sizeof(DISPLAYCONFIG_MODE_INFO));
1379 if (!pModeInfoArray )
1380 {
1381 if (pPathInfoArray)
1382 {
1383 free(pPathInfoArray);
1384 }
1385 return ERROR_OUTOFMEMORY;
1386 }
1387 dwStatus = gCtx.pfnQueryDisplayConfig(fEnabled ? QDC_ALL_PATHS : QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pPathInfoArray,&numModeInfoArrayElements, pModeInfoArray, NULL);
1388 if (dwStatus != ERROR_SUCCESS)
1389 {
1390 LogFlow(("VBoxTray: (WDDM) Failed QueryDisplayConfig \n"));
1391 free(pPathInfoArray);
1392 free(pModeInfoArray);
1393 return dwStatus;
1394 }
1395 for (unsigned int i=0; i < numPathArrayElements; ++i)
1396 {
1397 LogRel(("Sourceid= %d and targetid = %d\n", pPathInfoArray[i].sourceInfo.id, pPathInfoArray[i].targetInfo.id));
1398 if (pPathInfoArray[i].sourceInfo.id == Id)
1399 {
1400 if (fEnabled)
1401 {
1402 LogRel(("VBoxTray: (WDDM) Enable the Display Device i =%d \n", i));
1403 pPathInfoArray[i].flags=DISPLAYCONFIG_PATH_ACTIVE;
1404 break;
1405 }
1406 else
1407 {
1408 LogRel(("VBoxTray: (WDDM) Disable the Display Device Path ID=%d and Sourceid=%d\n", i, pPathInfoArray[i].sourceInfo.id));
1409 pPathInfoArray[i].flags=0;
1410 break;
1411 }
1412 }
1413 }
1414 dwStatus = gCtx.pfnSetDisplayConfig(numPathArrayElements, pPathInfoArray, numModeInfoArrayElements, pModeInfoArray, (SDC_APPLY | SDC_SAVE_TO_DATABASE| SDC_ALLOW_CHANGES | SDC_USE_SUPPLIED_DISPLAY_CONFIG));
1415 if (dwStatus != ERROR_SUCCESS)
1416 {
1417 free(pPathInfoArray);
1418 free(pModeInfoArray);
1419 LogRel(("VBoxTray:(WDDM) Failed to Enable/ disable the monitor."));
1420 return dwStatus;
1421 }
1422 free(pPathInfoArray);
1423 free(pModeInfoArray);
1424 return ERROR_SUCCESS;
1425}
1426
1427DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes)
1428{
1429 DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
1430 DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
1431 UINT numPathArrayElements = 0;
1432 UINT numModeInfoArrayElements = 0;
1433 ULONG dwStatus;
1434 bool fFoundDisplay = false;
1435
1436 dwStatus = gCtx.pfnGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, &numModeInfoArrayElements);
1437 if (dwStatus != ERROR_SUCCESS)
1438 {
1439 LogFlow(("VBoxTray: (WDDM) Failed GetDisplayConfigBufferSizes \n"));
1440 return dwStatus;
1441 }
1442 pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(numPathArrayElements * sizeof(DISPLAYCONFIG_PATH_INFO));
1443 if (!pPathInfoArray)
1444 return ERROR_OUTOFMEMORY;
1445 pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(numModeInfoArrayElements * sizeof(DISPLAYCONFIG_MODE_INFO));
1446 if (!pModeInfoArray )
1447 {
1448 if (pPathInfoArray)
1449 {
1450 free(pPathInfoArray);
1451 }
1452 return ERROR_OUTOFMEMORY;
1453 }
1454 dwStatus = gCtx.pfnQueryDisplayConfig( QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pPathInfoArray,&numModeInfoArrayElements, pModeInfoArray, NULL);
1455 if (dwStatus != ERROR_SUCCESS)
1456 {
1457 LogFlow(("VBoxTray: (WDDM) Failed QueryDisplayConfig \n"));
1458 free(pPathInfoArray);
1459 free(pModeInfoArray);
1460 return dwStatus;
1461 }
1462 LogFlow(("VBoxTray: NumPath =%d and NumMod=%d\n", numPathArrayElements, numModeInfoArrayElements));
1463 for (UINT iter = 0; iter < numPathArrayElements; ++iter)
1464 {
1465 LogFlow(("Sourceid= %d and targetid = %d iter =%d and id = %d\n", pPathInfoArray[iter].sourceInfo.id, pPathInfoArray[iter].targetInfo.id, iter, Id));
1466 if (pPathInfoArray[iter].sourceInfo.id == Id)
1467 {
1468 UINT iModIdx = pPathInfoArray[iter].sourceInfo.modeInfoIdx;
1469 LogFlow(("VBoxTray: Mode Index = %d\n", iModIdx));
1470 pModeInfoArray[iModIdx].sourceMode.width = paDeviceMode[Id].dmPelsWidth;
1471 pModeInfoArray[iModIdx].sourceMode.height = paDeviceMode[Id].dmPelsHeight;
1472 if(paDeviceMode[Id].dmPosition.x != 0 || paDeviceMode[Id].dmPosition.y != 0)
1473 {
1474 pModeInfoArray[iModIdx].sourceMode.position.x = paDeviceMode[Id].dmPosition.x;
1475 pModeInfoArray[iModIdx].sourceMode.position.y = paDeviceMode[Id].dmPosition.y;
1476 }
1477 fFoundDisplay = true;
1478 break;
1479 }
1480 }
1481 if (fFoundDisplay)
1482 {
1483 /* Call SetDisplayConfig only if displaywith ID=Id has been found. */
1484 LogFlow(("VBoxTray: Found Display with Id=%d\n", Id));
1485 dwStatus = gCtx.pfnSetDisplayConfig(numPathArrayElements, pPathInfoArray, numModeInfoArrayElements, pModeInfoArray,(SDC_APPLY | SDC_SAVE_TO_DATABASE| SDC_ALLOW_CHANGES | SDC_USE_SUPPLIED_DISPLAY_CONFIG));
1486 if (dwStatus != ERROR_SUCCESS)
1487 {
1488 LogRel(("VBoxTray:(WDDM) Failed to resize the monitor."));
1489 free(pPathInfoArray);
1490 free(pModeInfoArray);
1491 return dwStatus;
1492 }
1493 }
1494 free(pPathInfoArray);
1495 free(pModeInfoArray);
1496 return ERROR_SUCCESS;
1497}
1498
1499#endif /* VBOX_WITH_WDDM */
1500
1501DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1502{
1503 switch (pIf->enmMode)
1504 {
1505 case VBOXDISPIF_MODE_XPDM_NT4:
1506 return ERROR_NOT_SUPPORTED;
1507 case VBOXDISPIF_MODE_XPDM:
1508 return ERROR_NOT_SUPPORTED;
1509#ifdef VBOX_WITH_WDDM
1510 case VBOXDISPIF_MODE_WDDM:
1511 return vboxDispIfResizeModesWDDM(pIf, iChangedMode, paDisplayDevices, paDeviceModes, cDevModes);
1512#endif
1513 default:
1514 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1515 return ERROR_INVALID_PARAMETER;
1516 }
1517}
1518
1519DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf)
1520{
1521 switch (pIf->enmMode)
1522 {
1523 case VBOXDISPIF_MODE_XPDM_NT4:
1524 return NO_ERROR;
1525 case VBOXDISPIF_MODE_XPDM:
1526 return NO_ERROR;
1527#ifdef VBOX_WITH_WDDM
1528 case VBOXDISPIF_MODE_WDDM:
1529 return vboxDispIfCancelPendingResizeWDDM(pIf);
1530#endif
1531 default:
1532 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1533 return ERROR_INVALID_PARAMETER;
1534 }
1535}
1536
1537DWORD VBoxDispIfReninitModes(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
1538{
1539 switch (pIf->enmMode)
1540 {
1541 case VBOXDISPIF_MODE_XPDM_NT4:
1542 return ERROR_NOT_SUPPORTED;
1543 case VBOXDISPIF_MODE_XPDM:
1544 return ERROR_NOT_SUPPORTED;
1545#ifdef VBOX_WITH_WDDM
1546 case VBOXDISPIF_MODE_WDDM:
1547 return vboxDispIfReninitModesWDDM(pIf, pScreenIdMask, fReconnectDisplaysOnChange);
1548#endif
1549 default:
1550 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1551 return ERROR_INVALID_PARAMETER;
1552 }
1553}
1554
1555static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
1556{
1557 return NO_ERROR;
1558}
1559
1560static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
1561{
1562 DWORD err = NO_ERROR;
1563 AssertBreakpoint();
1564 OSVERSIONINFO OSinfo;
1565 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
1566 GetVersionEx (&OSinfo);
1567 if (OSinfo.dwMajorVersion >= 5)
1568 {
1569 HMODULE hUser = GetModuleHandle("USER32");
1570 if (NULL != hUser)
1571 {
1572 bool bSupported = true;
1573 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
1574 Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
1575 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
1576
1577 if (!bSupported)
1578 {
1579 Log((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
1580 err = ERROR_NOT_SUPPORTED;
1581 }
1582 }
1583 else
1584 {
1585 Log((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
1586 err = ERROR_NOT_SUPPORTED;
1587 }
1588 }
1589 else
1590 {
1591 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
1592 err = ERROR_NOT_SUPPORTED;
1593 }
1594
1595 return err;
1596}
1597
1598DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
1599{
1600 /* @todo: may need to addd synchronization in case we want to change modes dynamically
1601 * i.e. currently the mode is supposed to be initialized once on service initialization */
1602 if (penmOldMode)
1603 *penmOldMode = pIf->enmMode;
1604
1605 if (enmMode == pIf->enmMode)
1606 return NO_ERROR;
1607
1608#ifdef VBOX_WITH_WDDM
1609 if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
1610 {
1611 vboxDispIfWddmTerm(pIf);
1612 }
1613#endif
1614
1615 DWORD err = NO_ERROR;
1616 switch (enmMode)
1617 {
1618 case VBOXDISPIF_MODE_XPDM_NT4:
1619 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
1620 err = vboxDispIfSwitchToXPDM_NT4(pIf);
1621 if (err == NO_ERROR)
1622 {
1623 Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
1624 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
1625 }
1626 else
1627 Log((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
1628 break;
1629 case VBOXDISPIF_MODE_XPDM:
1630 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
1631 err = vboxDispIfSwitchToXPDM(pIf);
1632 if (err == NO_ERROR)
1633 {
1634 Log((__FUNCTION__": successfully switched to XPDM mode\n"));
1635 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
1636 }
1637 else
1638 Log((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
1639 break;
1640#ifdef VBOX_WITH_WDDM
1641 case VBOXDISPIF_MODE_WDDM:
1642 {
1643 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
1644 err = vboxDispIfSwitchToWDDM(pIf);
1645 if (err == NO_ERROR)
1646 {
1647 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
1648 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
1649 }
1650 else
1651 Log((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
1652 break;
1653 }
1654#endif
1655 default:
1656 err = ERROR_INVALID_PARAMETER;
1657 break;
1658 }
1659 return err;
1660}
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