VirtualBox

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

Last change on this file since 42224 was 42224, checked in by vboxsync, 13 years ago

vboxtray: 64bit build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.9 KB
Line 
1/** @file
2 * VBoxTray - Display Settings Interface abstraction for XPDM & WDDM
3 */
4
5/*
6 * Copyright (C) 2006-2010 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
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/* display driver interface abstraction for XPDM & WDDM
30 * with WDDM we can not use ExtEscape to communicate with our driver
31 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
32 * that knows nothing about us */
33DWORD VBoxDispIfInit(PVBOXDISPIF pIf)
34{
35 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
36 return NO_ERROR;
37}
38
39#ifdef VBOX_WITH_WDDM
40static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf);
41static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf);
42#endif
43
44DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
45{
46#ifdef VBOX_WITH_WDDM
47 if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
48 {
49 vboxDispIfWddmTerm(pIf);
50 }
51#endif
52
53 pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
54 return NO_ERROR;
55}
56
57static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
58{
59 HDC hdc = GetDC(HWND_DESKTOP);
60 VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
61 int iRet = ExtEscape(hdc, pEscape->escapeCode, cbData, (LPCSTR)pvData, 0, NULL);
62 ReleaseDC(HWND_DESKTOP, hdc);
63 if (iRet > 0)
64 return VINF_SUCCESS;
65 else if (iRet == 0)
66 return ERROR_NOT_SUPPORTED;
67 /* else */
68 return ERROR_GEN_FAILURE;
69}
70
71#ifdef VBOX_WITH_WDDM
72static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
73{
74 DWORD err = NO_ERROR;
75 OSVERSIONINFO OSinfo;
76 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
77 GetVersionEx (&OSinfo);
78 bool bSupported = true;
79
80 if (OSinfo.dwMajorVersion >= 6)
81 {
82 Log((__FUNCTION__": this is vista and up\n"));
83 HMODULE hUser = GetModuleHandle("USER32");
84 if (hUser)
85 {
86 *(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
87 Log((__FUNCTION__": VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.wddm.pfnChangeDisplaySettingsEx));
88 bSupported &= !!(pIf->modeData.wddm.pfnChangeDisplaySettingsEx);
89
90 *(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
91 Log((__FUNCTION__": VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
92 bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
93
94 /* this is vista and up */
95 HMODULE hGdi32 = GetModuleHandle("gdi32");
96 if (hGdi32 != NULL)
97 {
98 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromHdc");
99 Log((__FUNCTION__"pfnD3DKMTOpenAdapterFromHdc = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc));
100 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc);
101
102 pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
103 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName));
104 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromGdiDisplayName);
105
106 pIf->modeData.wddm.pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
107 Log((__FUNCTION__": pfnD3DKMTCloseAdapter = %p\n", pIf->modeData.wddm.pfnD3DKMTCloseAdapter));
108 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
109
110 pIf->modeData.wddm.pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(hGdi32, "D3DKMTEscape");
111 Log((__FUNCTION__": pfnD3DKMTEscape = %p\n", pIf->modeData.wddm.pfnD3DKMTEscape));
112 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTCloseAdapter);
113
114 pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn = (PFND3DKMT_INVALIDATEACTIVEVIDPN)GetProcAddress(hGdi32, "D3DKMTInvalidateActiveVidPn");
115 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn = %p\n", pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn));
116 bSupported &= !!(pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn);
117
118 if (!bSupported)
119 {
120 Log((__FUNCTION__": one of pfnD3DKMT function pointers failed to initialize\n"));
121 err = ERROR_NOT_SUPPORTED;
122 }
123 }
124 else
125 {
126 Log((__FUNCTION__": GetModuleHandle(gdi32) failed, err(%d)\n", GetLastError()));
127 err = ERROR_NOT_SUPPORTED;
128 }
129
130 }
131 else
132 {
133 Log((__FUNCTION__": GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
134 err = ERROR_NOT_SUPPORTED;
135 }
136 }
137 else
138 {
139 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
140 err = ERROR_NOT_SUPPORTED;
141 }
142
143 if (err == ERROR_SUCCESS)
144 {
145 err = vboxDispIfWddmInit(pIf);
146 }
147
148 return err;
149}
150
151static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
152{
153 DWORD winEr = ERROR_INVALID_STATE;
154 memset(pDev, 0, sizeof (*pDev));
155 pDev->cb = sizeof (*pDev);
156
157 for (int i = 0; ; ++i)
158 {
159 if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
160 pDev, 0 /* DWORD dwFlags*/))
161 {
162 if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
163 {
164 HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
165 if (hDc)
166 {
167 *phDc = hDc;
168 return NO_ERROR;
169 }
170 else
171 {
172 winEr = GetLastError();
173 Assert(0);
174 break;
175 }
176 }
177 }
178 else
179 {
180 winEr = GetLastError();
181 Assert(0);
182 break;
183 }
184 }
185
186 return winEr;
187}
188
189
190typedef DECLCALLBACK(BOOLEAN) FNVBOXDISPIFWDDM_ADAPTEROP(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext);
191typedef FNVBOXDISPIFWDDM_ADAPTEROP *PFNVBOXDISPIFWDDM_ADAPTEROP;
192static DWORD vboxDispIfWDDMAdapterOp(PCVBOXDISPIF pIf, int iDisplay, PFNVBOXDISPIFWDDM_ADAPTEROP pfnOp, PVOID pContext)
193{
194 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
195 DISPLAY_DEVICE DDev;
196 DWORD err = vboxDispIfWDDMAdpHdcCreate(iDisplay, &OpenAdapterData.hDc, &DDev);
197 Assert(err == NO_ERROR);
198 if (err == NO_ERROR)
199 {
200 NTSTATUS Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
201 Assert(!Status);
202 if (!Status)
203 {
204 BOOLEAN bCloseAdapter = pfnOp(pIf, OpenAdapterData.hAdapter, &DDev, pContext);
205
206 if (bCloseAdapter)
207 {
208 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
209 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
210 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
211 if (Status)
212 {
213 Log((__FUNCTION__": pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
214 }
215 }
216 }
217 else
218 {
219 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
220 err = ERROR_GEN_FAILURE;
221 }
222
223 DeleteDC(OpenAdapterData.hDc);
224 }
225
226 return err;
227}
228
229typedef struct
230{
231 NTSTATUS Status;
232 PVBOXDISPIFESCAPE pEscape;
233 int cbData;
234 D3DDDI_ESCAPEFLAGS EscapeFlags;
235} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
236
237DECLCALLBACK(BOOLEAN) vboxDispIfEscapeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
238{
239 PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
240
241 D3DKMT_ESCAPE EscapeData = {0};
242 EscapeData.hAdapter = hAdapter;
243 //EscapeData.hDevice = NULL;
244 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
245 EscapeData.Flags = pCtx->EscapeFlags;
246 EscapeData.pPrivateDriverData = pCtx->pEscape;
247 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
248 //EscapeData.hContext = NULL;
249
250 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTEscape(&EscapeData);
251
252 return TRUE;
253}
254
255static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
256{
257 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
258 Ctx.pEscape = pEscape;
259 Ctx.cbData = cbData;
260 if (fHwAccess)
261 Ctx.EscapeFlags.HardwareAccess = 1;
262 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1 /* iDisplay, -1 means primary */, vboxDispIfEscapeWDDMOp, &Ctx);
263 if (err == NO_ERROR)
264 {
265 if (!Ctx.Status)
266 err = NO_ERROR;
267 else
268 {
269 if (Ctx.Status == 0xC00000BBL) /* not supported */
270 err = ERROR_NOT_SUPPORTED;
271 else
272 err = ERROR_GEN_FAILURE;
273 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
274 }
275 }
276 else
277 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
278
279 return err;
280}
281
282typedef struct
283{
284 NTSTATUS Status;
285 VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO Info;
286} VBOXDISPIFWDDM_RESIZEOP_CONTEXT, *PVBOXDISPIFWDDM_RESIZEOP_CONTEXT;
287
288DECLCALLBACK(BOOLEAN) vboxDispIfResizeWDDMOp(PCVBOXDISPIF pIf, D3DKMT_HANDLE hAdapter, DISPLAY_DEVICE *pDev, PVOID pContext)
289{
290 PVBOXDISPIFWDDM_RESIZEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_RESIZEOP_CONTEXT)pContext;
291 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
292 uint32_t cbData = VBOXWDDM_RECOMMENDVIDPN_SIZE(1);
293 PVBOXWDDM_RECOMMENDVIDPN pData = (PVBOXWDDM_RECOMMENDVIDPN)malloc(cbData);
294 if (pData)
295 {
296 memset(pData, 0, cbData);
297 pData->cScreenInfos = 1;
298 memcpy(&pData->aScreenInfos[0], &pCtx->Info, sizeof (VBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO));
299
300 IAVidPnData.hAdapter = hAdapter;
301 IAVidPnData.pPrivateDriverData = pData;
302 IAVidPnData.PrivateDriverDataSize = cbData;
303
304 pCtx->Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
305 Assert(!pCtx->Status);
306 if (pCtx->Status)
307 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", pCtx->Status));
308
309 free(pData);
310 }
311 else
312 {
313 Log((__FUNCTION__": malloc failed\n"));
314 pCtx->Status = -1;
315 }
316
317 return TRUE;
318}
319
320static DWORD vboxDispIfResizeWDDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
321{
322 VBOXDISPIFWDDM_RESIZEOP_CONTEXT Ctx = {0};
323 Ctx.Info.Id = Id;
324 Ctx.Info.Width = Width;
325 Ctx.Info.Height = Height;
326 Ctx.Info.BitsPerPixel = BitsPerPixel;
327 DWORD err = vboxDispIfWDDMAdapterOp(pIf, -1, /* (int)Id - always say -1 to use primary display since the display does not really matter here */
328 vboxDispIfResizeWDDMOp, &Ctx);
329 if (err == NO_ERROR)
330 {
331 if (!Ctx.Status)
332 err = NO_ERROR;
333 else
334 {
335 if (Ctx.Status == 0xC00000BBL) /* not supported */
336 err = ERROR_NOT_SUPPORTED;
337 else
338 err = ERROR_GEN_FAILURE;
339 Log((__FUNCTION__": vboxDispIfResizeWDDMOp failed, Status (0x%x)\n", Ctx.Status));
340 }
341 }
342 else
343 Log((__FUNCTION__": vboxDispIfWDDMAdapterOp failed, err (%d)\n", err));
344
345 return err;
346}
347#endif
348
349DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
350{
351 switch (pIf->enmMode)
352 {
353 case VBOXDISPIF_MODE_XPDM_NT4:
354 case VBOXDISPIF_MODE_XPDM:
355 return vboxDispIfEscapeXPDM(pIf, pEscape, cbData);
356#ifdef VBOX_WITH_WDDM
357 case VBOXDISPIF_MODE_WDDM:
358 return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
359#endif
360 default:
361 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
362 return ERROR_INVALID_PARAMETER;
363 }
364}
365
366static DWORD vboxDispIfResizeXPDM(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
367{
368 return ERROR_NOT_SUPPORTED;
369}
370
371DWORD VBoxDispIfResize(PCVBOXDISPIF const pIf, ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
372{
373 switch (pIf->enmMode)
374 {
375 case VBOXDISPIF_MODE_XPDM_NT4:
376 return ERROR_NOT_SUPPORTED;
377 case VBOXDISPIF_MODE_XPDM:
378 return vboxDispIfResizeXPDM(pIf, Id, Width, Height, BitsPerPixel);
379#ifdef VBOX_WITH_WDDM
380 case VBOXDISPIF_MODE_WDDM:
381 return vboxDispIfResizeWDDM(pIf, Id, Width, Height, BitsPerPixel);
382#endif
383 default:
384 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
385 return ERROR_INVALID_PARAMETER;
386 }
387}
388
389
390#ifdef VBOX_WITH_WDDM
391/**/
392typedef DECLCALLBACK(VOID) FNVBOXSCREENMONRUNNER_CB(void *pvCb);
393typedef FNVBOXSCREENMONRUNNER_CB *PFNVBOXSCREENMONRUNNER_CB;
394
395typedef struct VBOXSCREENMON
396{
397 HANDLE hThread;
398 DWORD idThread;
399 HANDLE hEvent;
400 HWND hWnd;
401 PFNVBOXSCREENMONRUNNER_CB pfnCb;
402 void *pvCb;
403} VBOXSCREENMON, *PVBOXSCREENMON;
404
405
406static VBOXSCREENMON g_VBoxScreenMon;
407
408
409#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
410#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
411
412
413static void vboxScreenMonOnChange()
414{
415 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
416 pMon->pfnCb(pMon->pvCb);
417}
418
419static LRESULT CALLBACK vboxScreenMonWndProc(HWND hwnd,
420 UINT uMsg,
421 WPARAM wParam,
422 LPARAM lParam
423)
424{
425 switch(uMsg)
426 {
427 case WM_DISPLAYCHANGE:
428 {
429 vboxScreenMonOnChange();
430 }
431 case WM_CLOSE:
432 Log((__FUNCTION__": got WM_CLOSE for hwnd(0x%x)", hwnd));
433 return 0;
434 case WM_DESTROY:
435 Log((__FUNCTION__": got WM_DESTROY for hwnd(0x%x)", hwnd));
436 return 0;
437 case WM_NCHITTEST:
438 Log((__FUNCTION__": got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
439 return HTNOWHERE;
440 }
441
442 return DefWindowProc(hwnd, uMsg, wParam, lParam);
443}
444
445#define VBOXSCREENMONWND_NAME "VboxScreenMonWnd"
446
447static HRESULT vboxScreenMonWndCreate(HWND *phWnd)
448{
449 HRESULT hr = S_OK;
450 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
451 /* Register the Window Class. */
452 WNDCLASS wc;
453 if (!GetClassInfo(hInstance, VBOXSCREENMONWND_NAME, &wc))
454 {
455 wc.style = 0;//CS_OWNDC;
456 wc.lpfnWndProc = vboxScreenMonWndProc;
457 wc.cbClsExtra = 0;
458 wc.cbWndExtra = 0;
459 wc.hInstance = hInstance;
460 wc.hIcon = NULL;
461 wc.hCursor = NULL;
462 wc.hbrBackground = NULL;
463 wc.lpszMenuName = NULL;
464 wc.lpszClassName = VBOXSCREENMONWND_NAME;
465 if (!RegisterClass(&wc))
466 {
467 DWORD winErr = GetLastError();
468 Log((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
469 hr = E_FAIL;
470 }
471 }
472
473 if (hr == S_OK)
474 {
475 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
476 VBOXSCREENMONWND_NAME, VBOXSCREENMONWND_NAME,
477 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
478 -100, -100,
479 10, 10,
480 NULL, //GetDesktopWindow() /* hWndParent */,
481 NULL /* hMenu */,
482 hInstance,
483 NULL /* lpParam */);
484 Assert(hWnd);
485 if (hWnd)
486 {
487 *phWnd = hWnd;
488 }
489 else
490 {
491 DWORD winErr = GetLastError();
492 Log((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
493 hr = E_FAIL;
494 }
495 }
496
497 return hr;
498}
499
500static HRESULT vboxScreenMonWndDestroy(HWND hWnd)
501{
502 BOOL bResult = DestroyWindow(hWnd);
503 if (bResult)
504 return S_OK;
505
506 DWORD winErr = GetLastError();
507 Log((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
508 Assert(0);
509
510 return HRESULT_FROM_WIN32(winErr);
511}
512
513static HRESULT vboxScreenMonWndInit()
514{
515 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
516 return vboxScreenMonWndCreate(&pMon->hWnd);
517}
518
519HRESULT vboxScreenMonWndTerm()
520{
521 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
522 HRESULT tmpHr = vboxScreenMonWndDestroy(pMon->hWnd);
523 Assert(tmpHr == S_OK);
524
525 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
526 UnregisterClass(VBOXSCREENMONWND_NAME, hInstance);
527
528 return S_OK;
529}
530
531#define WM_VBOXSCREENMON_INIT_QUIT (WM_APP+2)
532
533HRESULT vboxScreenMonRun()
534{
535 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
536 MSG Msg;
537
538 HRESULT hr = S_FALSE;
539
540 PeekMessage(&Msg,
541 NULL /* HWND hWnd */,
542 WM_USER /* UINT wMsgFilterMin */,
543 WM_USER /* UINT wMsgFilterMax */,
544 PM_NOREMOVE);
545
546 BOOL bCheck = TRUE;
547
548 do
549 {
550 if (bCheck)
551 {
552 vboxScreenMonOnChange();
553
554 bCheck = FALSE;
555 }
556
557 BOOL bResult = GetMessage(&Msg,
558 0 /*HWND hWnd*/,
559 0 /*UINT wMsgFilterMin*/,
560 0 /*UINT wMsgFilterMax*/
561 );
562
563 if(!bResult) /* WM_QUIT was posted */
564 {
565 hr = S_FALSE;
566 break;
567 }
568
569 if(bResult == -1) /* error occurred */
570 {
571 DWORD winEr = GetLastError();
572 hr = HRESULT_FROM_WIN32(winEr);
573 Assert(0);
574 /* just ensure we never return success in this case */
575 Assert(hr != S_OK);
576 Assert(hr != S_FALSE);
577 if (hr == S_OK || hr == S_FALSE)
578 hr = E_FAIL;
579 break;
580 }
581
582 switch (Msg.message)
583 {
584 case WM_VBOXSCREENMON_INIT_QUIT:
585 case WM_CLOSE:
586 {
587 PostQuitMessage(0);
588 break;
589 }
590 case WM_DISPLAYCHANGE:
591 bCheck = TRUE;
592 default:
593 TranslateMessage(&Msg);
594 DispatchMessage(&Msg);
595 break;
596 }
597 } while (1);
598 return 0;
599}
600
601static DWORD WINAPI vboxScreenMonRunnerThread(void *pvUser)
602{
603 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
604
605 BOOL bRc = SetEvent(pMon->hEvent);
606 if (!bRc)
607 {
608 DWORD winErr = GetLastError();
609 Log((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
610 HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
611 Assert(0);
612 Assert(tmpHr != S_OK);
613 }
614
615 HRESULT hr = vboxScreenMonWndInit();
616 Assert(hr == S_OK);
617 if (hr == S_OK)
618 {
619 hr = vboxScreenMonRun();
620 Assert(hr == S_OK);
621
622 vboxScreenMonWndTerm();
623 }
624
625 return 0;
626}
627
628HRESULT VBoxScreenMonInit(PFNVBOXSCREENMONRUNNER_CB pfnCb, void *pvCb)
629{
630 HRESULT hr = E_FAIL;
631 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
632 memset(pMon, 0, sizeof (*pMon));
633
634 pMon->pfnCb = pfnCb;
635 pMon->pvCb = pvCb;
636
637 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
638 TRUE, /* BOOL bManualReset*/
639 FALSE, /* BOOL bInitialState */
640 NULL /* LPCTSTR lpName */
641 );
642 if (pMon->hEvent)
643 {
644 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
645 0 /* SIZE_T dwStackSize */,
646 vboxScreenMonRunnerThread,
647 pMon,
648 0 /* DWORD dwCreationFlags */,
649 &pMon->idThread);
650 if (pMon->hThread)
651 {
652 DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
653 if (dwResult == WAIT_OBJECT_0)
654 return S_OK;
655 else
656 {
657 Log(("WaitForSingleObject failed!"));
658 hr = E_FAIL;
659 }
660 }
661 else
662 {
663 DWORD winErr = GetLastError();
664 Log((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
665 hr = HRESULT_FROM_WIN32(winErr);
666 Assert(0);
667 Assert(hr != S_OK);
668 }
669 CloseHandle(pMon->hEvent);
670 }
671 else
672 {
673 DWORD winErr = GetLastError();
674 Log((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
675 hr = HRESULT_FROM_WIN32(winErr);
676 Assert(0);
677 Assert(hr != S_OK);
678 }
679
680 return hr;
681}
682
683VOID VBoxScreenMonTerm()
684{
685 HRESULT hr;
686 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
687 if (!pMon->hThread)
688 return;
689
690 BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXSCREENMON_INIT_QUIT, 0, 0);
691 DWORD winErr;
692 if (bResult
693 || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
694 {
695 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
696 if (dwErr == WAIT_OBJECT_0)
697 {
698 hr = S_OK;
699 }
700 else
701 {
702 winErr = GetLastError();
703 hr = HRESULT_FROM_WIN32(winErr);
704 Assert(0);
705 }
706 }
707 else
708 {
709 hr = HRESULT_FROM_WIN32(winErr);
710 Assert(0);
711 }
712
713 CloseHandle(pMon->hThread);
714 pMon->hThread = 0;
715 CloseHandle(pMon->hEvent);
716 pMon->hThread = 0;
717}
718/**/
719
720typedef struct VBOXDISPIF_WDDM_INTERNAL
721{
722 PCVBOXDISPIF pIf;
723
724 HANDLE hResizeEvent;
725} VBOXDISPIF_WDDM_INTERNAL, *PVBOXDISPIF_WDDM_INTERNAL;
726
727static VBOXDISPIF_WDDM_INTERNAL g_VBoxDispIfWddm;
728
729static BOOL vboxDispIfWddmValidateResize(DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
730{
731 DISPLAY_DEVICE DisplayDevice;
732 int i = 0;
733 UINT cMatched = 0;
734 DEVMODE DeviceMode;
735 for (int i = 0; ; ++i)
736 {
737 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
738 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
739
740 if (!EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
741 break;
742
743 Log(("VBoxTray: vboxDispIfValidateResize: [%d(%d)] %s\n", i, cMatched, DisplayDevice.DeviceName));
744
745 BOOL bFetchDevice = FALSE;
746
747 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
748 {
749 Log(("VBoxTray: vboxDispIfValidateResize: Found primary device. err %d\n", GetLastError ()));
750 bFetchDevice = TRUE;
751 }
752 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
753 {
754
755 Log(("VBoxTray: vboxDispIfValidateResize: Found secondary device. err %d\n", GetLastError ()));
756 bFetchDevice = TRUE;
757 }
758
759 if (bFetchDevice)
760 {
761 if (cMatched >= cDevModes)
762 {
763 Log(("VBoxTray: vboxDispIfValidateResize: %d >= %d\n", cDevModes, cMatched));
764 return FALSE;
765 }
766
767 /* First try to get the video mode stored in registry (ENUM_REGISTRY_SETTINGS).
768 * A secondary display could be not active at the moment and would not have
769 * a current video mode (ENUM_CURRENT_SETTINGS).
770 */
771 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
772 DeviceMode.dmSize = sizeof(DEVMODE);
773 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
774 ENUM_REGISTRY_SETTINGS, &DeviceMode))
775 {
776 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings error %d\n", GetLastError ()));
777 return FALSE;
778 }
779
780 if ( DeviceMode.dmPelsWidth == 0
781 || DeviceMode.dmPelsHeight == 0)
782 {
783 /* No ENUM_REGISTRY_SETTINGS yet. Seen on Vista after installation.
784 * Get the current video mode then.
785 */
786 ZeroMemory(&DeviceMode, sizeof(DeviceMode));
787 DeviceMode.dmSize = sizeof(DeviceMode);
788 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
789 ENUM_CURRENT_SETTINGS, &DeviceMode))
790 {
791 /* ENUM_CURRENT_SETTINGS returns FALSE when the display is not active:
792 * for example a disabled secondary display */
793 Log(("VBoxTray: vboxDispIfValidateResize: EnumDisplaySettings(ENUM_CURRENT_SETTINGS) error %d\n", GetLastError ()));
794 return FALSE;
795 }
796 }
797
798 UINT j = 0;
799 for (; j < cDevModes; ++j)
800 {
801 if (!strncmp(DisplayDevice.DeviceName, paDisplayDevices[j].DeviceName, RT_ELEMENTS(DeviceMode.dmDeviceName)))
802 {
803 if (paDeviceModes[j].dmBitsPerPel != DeviceMode.dmBitsPerPel
804 || (paDeviceModes[j].dmPelsWidth & 0xfff8) != (DeviceMode.dmPelsWidth & 0xfff8)
805 || (paDeviceModes[j].dmPelsHeight & 0xfff8) != (DeviceMode.dmPelsHeight & 0xfff8)
806 || (paDeviceModes[j].dmPosition.x & 0xfff8) != (DeviceMode.dmPosition.x & 0xfff8)
807 || (paDeviceModes[j].dmPosition.y & 0xfff8) != (DeviceMode.dmPosition.y & 0xfff8)
808 || (paDisplayDevices[j].StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
809 {
810 return FALSE;
811 }
812 break;
813 }
814 }
815
816 if (j == cDevModes)
817 return FALSE;
818
819 ++cMatched;
820 }
821 }
822
823 return cMatched == cDevModes;
824}
825
826static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
827{
828 if (vboxDispIfWddmValidateResize(paDisplayDevices, paDeviceModes, cDevModes))
829 return NO_ERROR;
830
831 DWORD winEr;
832 LONG status = DISP_CHANGE_SUCCESSFUL;
833
834 /* now try to resize in a "regular" way */
835 /* Assign the new rectangles to displays. */
836 for (UINT i = 0; i < cDevModes; i++)
837 {
838 /* On Vista one must specify DM_BITSPERPEL.
839 * Note that the current mode dmBitsPerPel is already in the DEVMODE structure.
840 */
841 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH | DM_BITSPERPEL;
842
843 Log(("VBoxTray: ResizeDisplayDevice: pfnChangeDisplaySettingsEx %x: %dx%dx%d at %d,%d\n",
844 pIf->modeData.wddm.pfnChangeDisplaySettingsEx,
845 paDeviceModes[i].dmPelsWidth,
846 paDeviceModes[i].dmPelsHeight,
847 paDeviceModes[i].dmBitsPerPel,
848 paDeviceModes[i].dmPosition.x,
849 paDeviceModes[i].dmPosition.y));
850
851 /* the miniport might have been adjusted the display mode stuff,
852 * adjust the paDeviceModes[i] by picking the closest available one */
853// DEVMODE AdjustedMode = paDeviceModes[i];
854// vboxDispIfAdjustMode(&paDisplayDevices[i], &AdjustedMode);
855
856 LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
857 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
858 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettingsEx position status %d, err %d\n", tmpStatus, GetLastError ()));
859
860 if (tmpStatus != DISP_CHANGE_SUCCESSFUL)
861 {
862 status = tmpStatus;
863 }
864 }
865
866 /* A second call to ChangeDisplaySettings updates the monitor. */
867 LONG tmpStatus = pIf->modeData.wddm.pfnChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
868 Log(("VBoxTray: ResizeDisplayDevice: ChangeDisplaySettings update status %d\n", status));
869 if (tmpStatus == DISP_CHANGE_SUCCESSFUL)
870 {
871 if (status == DISP_CHANGE_SUCCESSFUL)
872 {
873 return NO_ERROR;
874 }
875 tmpStatus = status;
876 }
877
878 winEr = ERROR_GEN_FAILURE;
879 return winEr;
880}
881
882static DECLCALLBACK(VOID) vboxDispIfWddmScreenMonCb(void *pvCb)
883{
884 PVBOXDISPIF_WDDM_INTERNAL pData = (PVBOXDISPIF_WDDM_INTERNAL)pvCb;
885
886 SetEvent(pData->hResizeEvent);
887}
888
889static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
890{
891 memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
892 g_VBoxDispIfWddm.pIf = pIf;
893 g_VBoxDispIfWddm.hResizeEvent = CreateEvent(NULL,
894 FALSE, /* BOOL bManualReset */
895 FALSE, /* BOOL bInitialState */
896 NULL /* LPCTSTR lpName */
897 );
898 if (g_VBoxDispIfWddm.hResizeEvent)
899 {
900 HRESULT hr = VBoxScreenMonInit(vboxDispIfWddmScreenMonCb, &g_VBoxDispIfWddm);
901 if (SUCCEEDED(hr))
902 {
903 /* ensure event is reset */
904 WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 0);
905 return ERROR_SUCCESS;
906 }
907 CloseHandle(g_VBoxDispIfWddm.hResizeEvent);
908 }
909 return ERROR_GEN_FAILURE;
910}
911
912static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
913{
914 VBoxScreenMonTerm();
915 CloseHandle(g_VBoxDispIfWddm.hResizeEvent);
916 memset(&g_VBoxDispIfWddm, 0, sizeof (g_VBoxDispIfWddm));
917}
918
919static DWORD vboxDispIfReninitModesWDDM(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
920{
921 VBOXDISPIFESCAPE_REINITVIDEOMODESBYMASK Data = {0};
922 Data.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
923 if (fReconnectDisplaysOnChange)
924 Data.EscapeHdr.u32CmdSpecific = VBOXWDDM_REINITVIDEOMODESBYMASK_F_RECONNECT_DISPLAYS_ON_CHANGE;
925
926 memcpy(Data.ScreenMask, pScreenIdMask, sizeof (Data.ScreenMask));
927
928 DWORD err = vboxDispIfEscapeWDDM(pIf, &Data.EscapeHdr, sizeof (Data) - sizeof (Data.EscapeHdr), fReconnectDisplaysOnChange ? FALSE /* hw access must be false here,
929 * otherwise the miniport driver would fail
930 * request to prevent a deadlock */
931 : TRUE);
932 if (err != NO_ERROR)
933 {
934 Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
935 }
936 return err;
937}
938
939static DWORD vboxDispIfAdjustMode(DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
940{
941 DEVMODE CurMode;
942 DEVMODE BestMatchMode;
943 DWORD i = 0;
944 int64_t diffWH = INT64_MAX;
945 int diffBpp = INT32_MAX;
946 for (; ; ++i)
947 {
948 CurMode.dmSize = sizeof (CurMode);
949 CurMode.dmDriverExtra = 0;
950
951 if (!EnumDisplaySettings(pDisplayDevice->DeviceName, i, &CurMode))
952 break;
953
954 if (CurMode.dmPelsWidth == pDeviceMode->dmPelsWidth
955 && CurMode.dmPelsHeight == pDeviceMode->dmPelsHeight
956 && CurMode.dmBitsPerPel == pDeviceMode->dmBitsPerPel)
957 {
958 Log(("Exact match found"));
959 *pDeviceMode = CurMode;
960 return NO_ERROR;
961 }
962
963 int diffCurrW = RT_ABS((int)(CurMode.dmPelsWidth - pDeviceMode->dmPelsWidth));
964 int diffCurrH = RT_ABS((int)(CurMode.dmPelsHeight - pDeviceMode->dmPelsHeight));
965 int diffCurrBpp = RT_ABS((int)(CurMode.dmBitsPerPel - pDeviceMode->dmBitsPerPel)
966 - 1 /* <- to make higher bpp take precedence over lower ones */
967 );
968
969 int64_t diffCurrHW = (int64_t)diffCurrW*diffCurrW + (int64_t)diffCurrH*diffCurrH;
970
971 if (i == 0
972 || diffCurrHW < diffWH
973 || (diffCurrHW == diffWH && diffCurrBpp < diffBpp))
974 {
975 /* first run */
976 BestMatchMode = CurMode;
977 diffWH = diffCurrHW;
978 diffBpp = diffCurrBpp;
979 continue;
980 }
981 }
982
983 if (i == 0)
984 {
985 Log(("No modes found!"));
986 return NO_ERROR;
987 }
988
989 *pDeviceMode = BestMatchMode;
990 return NO_ERROR;
991}
992
993static DWORD vboxDispIfAdjustModeValues(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *pDisplayDevice, DEVMODE *pDeviceMode)
994{
995 VBOXDISPIFESCAPE_ADJUSTVIDEOMODES Data = {0};
996 Data.EscapeHdr.escapeCode = VBOXESC_REINITVIDEOMODESBYMASK;
997 Data.EscapeHdr.u32CmdSpecific = 1;
998 Data.aScreenInfos[0].Mode.Id =
999 Data.aScreenInfos[0].Mode.Width = pDeviceMode->dmPelsWidth;
1000 Data.aScreenInfos[0].Mode.Height = pDeviceMode->dmPelsHeight;
1001 Data.aScreenInfos[0].Mode.BitsPerPixel = pDeviceMode->dmBitsPerPel;
1002 DWORD err = vboxDispIfEscapeWDDM(pIf, &Data.EscapeHdr, sizeof (Data) - sizeof (Data.EscapeHdr), TRUE);
1003 if (err != NO_ERROR)
1004 {
1005 Log((__FUNCTION__": VBoxDispIfEscape failed with err (%d)\n", err));
1006 }
1007 return err;
1008}
1009
1010DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1011{
1012 UINT cbVidPnInfo = VBOXWDDM_RECOMMENDVIDPN_SIZE(cDevModes);
1013 PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo = (PVBOXWDDM_RECOMMENDVIDPN)alloca(cbVidPnInfo);
1014 pVidPnInfo->cScreenInfos = cDevModes;
1015 D3DKMT_HANDLE hAdapter = NULL;
1016 NTSTATUS Status;
1017 DWORD winEr = NO_ERROR;
1018 UINT i = 0;
1019
1020 for (; i < cDevModes; i++)
1021 {
1022 PVBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO pInfo = &pVidPnInfo->aScreenInfos[i];
1023 D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = {0};
1024 OpenAdapterData.hDc = CreateDC(NULL, paDisplayDevices[i].DeviceName, NULL, NULL);
1025 if (!OpenAdapterData.hDc)
1026 {
1027 winEr = GetLastError();
1028 Assert(0);
1029 break;
1030 }
1031
1032 Status = pIf->modeData.wddm.pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
1033 Assert(!Status);
1034 if (Status)
1035 {
1036 winEr = ERROR_GEN_FAILURE;
1037 Assert(0);
1038 break;
1039 }
1040
1041 pInfo->Id = OpenAdapterData.VidPnSourceId;
1042 pInfo->Width = paDeviceModes[i].dmPelsWidth;
1043 pInfo->Height = paDeviceModes[i].dmPelsHeight;
1044 pInfo->BitsPerPixel = paDeviceModes[i].dmBitsPerPel;
1045
1046 if (!hAdapter)
1047 {
1048 hAdapter = OpenAdapterData.hAdapter;
1049 }
1050 else
1051 {
1052 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
1053 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
1054 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
1055 Assert(!Status);
1056 }
1057 }
1058
1059 BOOL fAbleToInvalidateVidPn = FALSE;
1060
1061 if (winEr == NO_ERROR)
1062 {
1063 Assert(hAdapter);
1064
1065 D3DKMT_INVALIDATEACTIVEVIDPN IAVidPnData = {0};
1066 IAVidPnData.hAdapter = hAdapter;
1067 IAVidPnData.pPrivateDriverData = pVidPnInfo;
1068 IAVidPnData.PrivateDriverDataSize = cbVidPnInfo;
1069
1070 DWORD winEr = NO_ERROR;
1071 Status = pIf->modeData.wddm.pfnD3DKMTInvalidateActiveVidPn(&IAVidPnData);
1072 Assert(!Status);
1073 if (Status)
1074 {
1075 Log((__FUNCTION__": pfnD3DKMTInvalidateActiveVidPn failed, Status (0x%x)\n", Status));
1076 winEr = ERROR_GEN_FAILURE;
1077 }
1078 else
1079 {
1080 fAbleToInvalidateVidPn = TRUE;
1081 }
1082 }
1083
1084 if (hAdapter)
1085 {
1086 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
1087 ClosaAdapterData.hAdapter = hAdapter;
1088 Status = pIf->modeData.wddm.pfnD3DKMTCloseAdapter(&ClosaAdapterData);
1089 Assert(!Status);
1090 }
1091
1092// for (i = 0; i < cDevModes; i++)
1093// {
1094// vboxDispIfAdjustMode(&paDisplayDevices[i], &paDeviceModes[i]);
1095// }
1096
1097 if (fAbleToInvalidateVidPn)
1098 {
1099 winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1100 }
1101 else
1102 {
1103 /* fallback impl needed for display-only driver
1104 * since D3DKMTInvalidateActiveVidPn is not available for WDDM > 1.0:
1105 * make the driver invalidate VidPn,
1106 * which is done by emulating a monitor re-plug currently */
1107 /* ensure event is reset */
1108 WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 0);
1109
1110 uint8_t ScreenMask[VBOXWDDM_SCREENMASK_SIZE] = {0};
1111 ASMBitSet(ScreenMask, iChangedMode);
1112 vboxDispIfReninitModesWDDM(pIf, ScreenMask, TRUE);
1113
1114 for (UINT i = 0; i < 4; ++i)
1115 {
1116 WaitForSingleObject(g_VBoxDispIfWddm.hResizeEvent, 500);
1117 winEr = vboxDispIfWddmValidateFixResize(pIf, paDisplayDevices, paDeviceModes, cDevModes);
1118 if (winEr == NO_ERROR)
1119 break;
1120 }
1121
1122 Assert(winEr == NO_ERROR);
1123 }
1124
1125 return winEr;
1126}
1127#endif /* VBOX_WITH_WDDM */
1128
1129DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
1130{
1131 switch (pIf->enmMode)
1132 {
1133 case VBOXDISPIF_MODE_XPDM_NT4:
1134 return ERROR_NOT_SUPPORTED;
1135 case VBOXDISPIF_MODE_XPDM:
1136 return ERROR_NOT_SUPPORTED;
1137#ifdef VBOX_WITH_WDDM
1138 case VBOXDISPIF_MODE_WDDM:
1139 return vboxDispIfResizeModesWDDM(pIf, iChangedMode, paDisplayDevices, paDeviceModes, cDevModes);
1140#endif
1141 default:
1142 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1143 return ERROR_INVALID_PARAMETER;
1144 }
1145}
1146
1147DWORD VBoxDispIfReninitModes(PCVBOXDISPIF const pIf, uint8_t *pScreenIdMask, BOOL fReconnectDisplaysOnChange)
1148{
1149 switch (pIf->enmMode)
1150 {
1151 case VBOXDISPIF_MODE_XPDM_NT4:
1152 return ERROR_NOT_SUPPORTED;
1153 case VBOXDISPIF_MODE_XPDM:
1154 return ERROR_NOT_SUPPORTED;
1155#ifdef VBOX_WITH_WDDM
1156 case VBOXDISPIF_MODE_WDDM:
1157 return vboxDispIfReninitModesWDDM(pIf, pScreenIdMask, fReconnectDisplaysOnChange);
1158#endif
1159 default:
1160 Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
1161 return ERROR_INVALID_PARAMETER;
1162 }
1163}
1164
1165static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
1166{
1167 return NO_ERROR;
1168}
1169
1170static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
1171{
1172 DWORD err = NO_ERROR;
1173 AssertBreakpoint();
1174 OSVERSIONINFO OSinfo;
1175 OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
1176 GetVersionEx (&OSinfo);
1177 if (OSinfo.dwMajorVersion >= 5)
1178 {
1179 HMODULE hUser = GetModuleHandle("USER32");
1180 if (NULL != hUser)
1181 {
1182 bool bSupported = true;
1183 *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
1184 Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
1185 bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);
1186
1187 if (!bSupported)
1188 {
1189 Log((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
1190 err = ERROR_NOT_SUPPORTED;
1191 }
1192 }
1193 else
1194 {
1195 Log((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
1196 err = ERROR_NOT_SUPPORTED;
1197 }
1198 }
1199 else
1200 {
1201 Log((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
1202 err = ERROR_NOT_SUPPORTED;
1203 }
1204
1205 return err;
1206}
1207
1208DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
1209{
1210 /* @todo: may need to addd synchronization in case we want to change modes dynamically
1211 * i.e. currently the mode is supposed to be initialized once on service initialization */
1212 if (penmOldMode)
1213 *penmOldMode = pIf->enmMode;
1214
1215 if (enmMode == pIf->enmMode)
1216 return NO_ERROR;
1217
1218#ifdef VBOX_WITH_WDDM
1219 if (pIf->enmMode == VBOXDISPIF_MODE_WDDM)
1220 {
1221 vboxDispIfWddmTerm(pIf);
1222 }
1223#endif
1224
1225 DWORD err = NO_ERROR;
1226 switch (enmMode)
1227 {
1228 case VBOXDISPIF_MODE_XPDM_NT4:
1229 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
1230 err = vboxDispIfSwitchToXPDM_NT4(pIf);
1231 if (err == NO_ERROR)
1232 {
1233 Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
1234 pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
1235 }
1236 else
1237 Log((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
1238 break;
1239 case VBOXDISPIF_MODE_XPDM:
1240 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
1241 err = vboxDispIfSwitchToXPDM(pIf);
1242 if (err == NO_ERROR)
1243 {
1244 Log((__FUNCTION__": successfully switched to XPDM mode\n"));
1245 pIf->enmMode = VBOXDISPIF_MODE_XPDM;
1246 }
1247 else
1248 Log((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
1249 break;
1250#ifdef VBOX_WITH_WDDM
1251 case VBOXDISPIF_MODE_WDDM:
1252 {
1253 Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
1254 err = vboxDispIfSwitchToWDDM(pIf);
1255 if (err == NO_ERROR)
1256 {
1257 Log((__FUNCTION__": successfully switched to WDDM mode\n"));
1258 pIf->enmMode = VBOXDISPIF_MODE_WDDM;
1259 }
1260 else
1261 Log((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
1262 break;
1263 }
1264#endif
1265 default:
1266 err = ERROR_INVALID_PARAMETER;
1267 break;
1268 }
1269 return err;
1270}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette