VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/wddm/VBoxScreen.cpp@ 37845

Last change on this file since 37845 was 36867, checked in by vboxsync, 14 years ago

Additions/Video: display/miniport drivers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.1 KB
Line 
1/* $Id: VBoxScreen.cpp 36867 2011-04-28 07:27:03Z vboxsync $ */
2
3/** @file
4 * VBoxVideo Display D3D User mode dll
5 */
6
7/*
8 * Copyright (C) 2011 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxScreen.h"
20
21#include <iprt/log.h>
22
23
24typedef struct VBOXSCREENMONENUM
25{
26 PVBOXSCREENMON pMon;
27 UINT iCur;
28 HRESULT hr;
29 BOOL bChanged;
30} VBOXSCREENMONENUM, *PVBOXSCREENMONENUM;
31
32static VBOXSCREENMON g_VBoxScreenMon;
33
34
35#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
36#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
37
38typedef DECLCALLBACK(BOOLEAN) FNVBOXSCREENMON_ADAPTEROP(PVBOXSCREENMON pMon, D3DKMT_HANDLE hAdapter, LPCWSTR pDevName, PVOID pContext);
39typedef FNVBOXSCREENMON_ADAPTEROP *PFNVBOXSCREENMON_ADAPTEROP;
40static HRESULT vboxScreenMonWDDMAdapterOp(PVBOXSCREENMON pMon, LPCWSTR pDevName, PFNVBOXSCREENMON_ADAPTEROP pfnOp, PVOID pContext)
41{
42 D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME OpenAdapterData = {0};
43 wcsncpy(OpenAdapterData.DeviceName, pDevName, RT_ELEMENTS(OpenAdapterData.DeviceName) - 1 /* the last one is always \0 */);
44 HRESULT hr = S_OK;
45 NTSTATUS Status = pMon->pfnD3DKMTOpenAdapterFromGdiDisplayName(&OpenAdapterData);
46 Assert(!Status);
47 if (!Status)
48 {
49 BOOLEAN bCloseAdapter = pfnOp(pMon, OpenAdapterData.hAdapter, OpenAdapterData.DeviceName, pContext);
50
51 if (bCloseAdapter)
52 {
53 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
54 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
55 Status = pMon->pfnD3DKMTCloseAdapter(&ClosaAdapterData);
56 if (Status)
57 {
58 Log((__FUNCTION__": pfnD3DKMTCloseAdapter failed, Status (0x%x)\n", Status));
59 /* ignore */
60 Status = 0;
61 }
62 }
63 }
64 else
65 {
66 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName failed, Status (0x%x)\n", Status));
67 hr = E_FAIL;
68 }
69
70 return hr;
71}
72
73typedef struct
74{
75 NTSTATUS Status;
76 PVBOXDISPIFESCAPE pEscape;
77 int cbData;
78} VBOXDISPIFWDDM_ESCAPEOP_CONTEXT, *PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT;
79
80DECLCALLBACK(BOOLEAN) vboxScreenMonEscapeOp(PVBOXSCREENMON pMon, D3DKMT_HANDLE hAdapter, LPCWSTR pDevName, PVOID pContext)
81{
82 PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT pCtx = (PVBOXDISPIFWDDM_ESCAPEOP_CONTEXT)pContext;
83
84 D3DKMT_ESCAPE EscapeData = {0};
85 EscapeData.hAdapter = hAdapter;
86 //EscapeData.hDevice = NULL;
87 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
88 EscapeData.Flags.HardwareAccess = 1;
89 EscapeData.pPrivateDriverData = pCtx->pEscape;
90 EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(pCtx->cbData);
91 //EscapeData.hContext = NULL;
92
93 pCtx->Status = pMon->pfnD3DKMTEscape(&EscapeData);
94
95 return TRUE;
96}
97
98static HRESULT vboxScreenMonEscape(PVBOXSCREENMON pMon, PVBOXDISPIFESCAPE pEscape, int cbData)
99{
100 VBOXDISPIFWDDM_ESCAPEOP_CONTEXT Ctx = {0};
101 Ctx.pEscape = pEscape;
102 Ctx.cbData = cbData;
103 HRESULT hr = vboxScreenMonWDDMAdapterOp(pMon, L"\\\\.\\DISPLAY1", vboxScreenMonEscapeOp, &Ctx);
104 Assert(hr == S_OK);
105 if (hr == S_OK)
106 {
107 Assert(!Ctx.Status);
108 if (Ctx.Status)
109 {
110 if (Ctx.Status == 0xC00000BBL) /* not supported */
111 hr = VBOX_E_NOT_SUPPORTED;
112 else
113 hr = E_FAIL;
114 Log((__FUNCTION__": pfnD3DKMTEscape failed, Status (0x%x)\n", Ctx.Status));
115 }
116 }
117 else
118 Log((__FUNCTION__": vboxScreenMRunnerWDDMAdapterOp failed, hr (0x%x)\n", hr));
119
120 return hr;
121}
122
123static BOOL CALLBACK vboxScreenMonEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
124{
125 PVBOXSCREENMONENUM pEnum = (PVBOXSCREENMONENUM)dwData;
126 PVBOXSCREENMON pMon = pEnum->pMon;
127 UINT cbRequired = RT_OFFSETOF(VBOXSCREENLAYOUT, aScreens[pEnum->iCur]);
128 if (pEnum->hr == S_OK)
129 {
130 Assert(pEnum->iCur < VBOX_VIDEO_MAX_SCREENS);
131 if (pEnum->iCur < VBOX_VIDEO_MAX_SCREENS)
132 {
133 MONITORINFOEX minfo;
134 minfo.cbSize = sizeof (minfo);
135 if (GetMonitorInfo(hMonitor, (LPMONITORINFO)&minfo))
136 {
137 D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME OpenAdapterData = {0};
138 wcsncpy(OpenAdapterData.DeviceName, minfo.szDevice, RT_ELEMENTS(OpenAdapterData.DeviceName) - 1 /* the last one is always \0 */);
139 NTSTATUS Status = pMon->pfnD3DKMTOpenAdapterFromGdiDisplayName(&OpenAdapterData);
140 Assert(!Status);
141 if (!Status)
142 {
143 if (pMon->LoData.ScreenLayout.ScreenLayout.cScreens <= pEnum->iCur
144 || pMon->LoData.ScreenLayout.ScreenLayout.aScreens[pEnum->iCur].VidPnSourceId != OpenAdapterData.VidPnSourceId
145 || pMon->LoData.ScreenLayout.ScreenLayout.aScreens[pEnum->iCur].pos.x != lprcMonitor->left
146 || pMon->LoData.ScreenLayout.ScreenLayout.aScreens[pEnum->iCur].pos.y != lprcMonitor->top)
147 {
148 pMon->LoData.ScreenLayout.ScreenLayout.aScreens[pEnum->iCur].VidPnSourceId = OpenAdapterData.VidPnSourceId;
149 pMon->LoData.ScreenLayout.ScreenLayout.aScreens[pEnum->iCur].pos.x = lprcMonitor->left;
150 pMon->LoData.ScreenLayout.ScreenLayout.aScreens[pEnum->iCur].pos.y = lprcMonitor->top;
151 pEnum->bChanged = true;
152 }
153
154 D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
155 ClosaAdapterData.hAdapter = OpenAdapterData.hAdapter;
156 HRESULT tmpHr = pMon->pfnD3DKMTCloseAdapter(&ClosaAdapterData);
157 Assert(tmpHr == S_OK);
158 }
159 else
160 {
161 pEnum->hr = E_FAIL;
162 }
163 }
164 else
165 {
166 DWORD winEr = GetLastError();
167 HRESULT hr = HRESULT_FROM_WIN32(winEr);
168 Assert(0);
169 Assert(hr != S_OK);
170 Assert(hr != S_FALSE);
171 if (hr == S_OK || hr == S_FALSE)
172 hr = E_FAIL;
173 pEnum->hr = hr;
174 }
175
176// D3DKMT_OPENADAPTERFROMHDC Oa;
177// memset(&Oa, 0, sizeof (D3DKMT_OPENADAPTERFROMHDC));
178// Oa.hDc = hdcMonitor;
179// HRESULT hr = pMon->pfnD3DKMTOpenAdapterFromHdc(&Oa);
180// Assert(hr == S_OK);
181// if (hr == S_OK)
182// {
183// if (pEnum->pScreenInfo->cScreens <= pEnum->iCur
184// || pEnum->pScreenInfo->aScreens[pEnum->iCur].VidPnSourceId != Oa.VidPnSourceId
185// || pEnum->pScreenInfo->aScreens[pEnum->iCur].pos.x != lprcMonitor->left
186// || pEnum->pScreenInfo->aScreens[pEnum->iCur].pos.y == lprcMonitor->top)
187// {
188// pEnum->pScreenInfo->aScreens[pEnum->iCur].VidPnSourceId = Oa.VidPnSourceId;
189// pEnum->pScreenInfo->aScreens[pEnum->iCur].pos.x = lprcMonitor->left;
190// pEnum->pScreenInfo->aScreens[pEnum->iCur].pos.y = lprcMonitor->top;
191// pEnum->bChanged = true;
192// }
193//
194// D3DKMT_CLOSEADAPTER ClosaAdapterData = {0};
195// ClosaAdapterData.hAdapter = Oa.hAdapter;
196// HRESULT tmpHr = pMon->pfnD3DKMTCloseAdapter(&ClosaAdapterData);
197// Assert(tmpHr == S_OK);
198// pEnum->hr = hr;
199// }
200 }
201 else
202 {
203 pEnum->hr = VBOX_E_INSUFFICIENT_BUFFER;
204 }
205 }
206
207 ++pEnum->iCur;
208
209 return TRUE;
210}
211
212
213//static HRESULT vboxScreenMonCheckUpdateChange(PVBOXSCREENMON pMon)
214static HRESULT vboxScreenMonCheckUpdateChange()
215{
216 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
217 VBOXSCREENMONENUM monEnum = {0};
218 monEnum.pMon = pMon;
219
220 BOOL bResult = EnumDisplayMonitors(NULL, NULL, vboxScreenMonEnumProc, (LPARAM)&monEnum);
221 if (bResult)
222 {
223 Assert(monEnum.hr == S_OK);
224 if (monEnum.hr == S_OK && monEnum.bChanged)
225 {
226 Assert(monEnum.iCur);
227 pMon->LoData.ScreenLayout.ScreenLayout.cScreens = monEnum.iCur;
228
229 UINT cbSize = RT_OFFSETOF(VBOXSCREENLAYOUT, aScreens[pMon->LoData.ScreenLayout.ScreenLayout.cScreens]);
230 HRESULT hr = vboxScreenMonEscape(pMon, &pMon->LoData.ScreenLayout.EscapeHdr, cbSize);
231 Assert(hr == S_OK);
232 return hr;
233 }
234 return monEnum.hr;
235 }
236
237 DWORD winEr = GetLastError();
238 HRESULT hr = HRESULT_FROM_WIN32(winEr);
239 Assert(0);
240 Assert(hr != S_OK);
241 Assert(hr != S_FALSE);
242 if (hr == S_OK || hr == S_FALSE)
243 hr = E_FAIL;
244 return hr;
245}
246
247static LRESULT CALLBACK vboxScreenMonWndProc(HWND hwnd,
248 UINT uMsg,
249 WPARAM wParam,
250 LPARAM lParam
251)
252{
253 switch(uMsg)
254 {
255 case WM_DISPLAYCHANGE:
256 {
257 HRESULT hr = vboxScreenMonCheckUpdateChange();
258 Assert(hr == S_OK);
259 }
260 case WM_CLOSE:
261 Log((__FUNCTION__": got WM_CLOSE for hwnd(0x%x)", hwnd));
262 return 0;
263 case WM_DESTROY:
264 Log((__FUNCTION__": got WM_DESTROY for hwnd(0x%x)", hwnd));
265 return 0;
266 case WM_NCHITTEST:
267 Log((__FUNCTION__": got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
268 return HTNOWHERE;
269 }
270
271 return DefWindowProc(hwnd, uMsg, wParam, lParam);
272}
273
274#define VBOXSCREENMONWND_NAME L"VboxScreenMonWnd"
275
276HRESULT vboxScreenMonWndCreate(HWND *phWnd)
277{
278 HRESULT hr = S_OK;
279 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
280 /* Register the Window Class. */
281 WNDCLASS wc;
282 if (!GetClassInfo(hInstance, VBOXSCREENMONWND_NAME, &wc))
283 {
284 wc.style = CS_OWNDC;
285 wc.lpfnWndProc = vboxScreenMonWndProc;
286 wc.cbClsExtra = 0;
287 wc.cbWndExtra = 0;
288 wc.hInstance = hInstance;
289 wc.hIcon = NULL;
290 wc.hCursor = NULL;
291 wc.hbrBackground = NULL;
292 wc.lpszMenuName = NULL;
293 wc.lpszClassName = VBOXSCREENMONWND_NAME;
294 if (!RegisterClass(&wc))
295 {
296 DWORD winErr = GetLastError();
297 Log((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
298 hr = E_FAIL;
299 }
300 }
301
302 if (hr == S_OK)
303 {
304 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
305 VBOXSCREENMONWND_NAME, VBOXSCREENMONWND_NAME,
306 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
307 -100, -100,
308 10, 10,
309 NULL, //GetDesktopWindow() /* hWndParent */,
310 NULL /* hMenu */,
311 hInstance,
312 NULL /* lpParam */);
313 Assert(hWnd);
314 if (hWnd)
315 {
316 *phWnd = hWnd;
317 }
318 else
319 {
320 DWORD winErr = GetLastError();
321 Log((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
322 hr = E_FAIL;
323 }
324 }
325
326 return hr;
327}
328
329static HRESULT vboxScreenMonWndDestroy(HWND hWnd)
330{
331 BOOL bResult = DestroyWindow(hWnd);
332 if (bResult)
333 return S_OK;
334
335 DWORD winErr = GetLastError();
336 Log((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));
337 Assert(0);
338
339 return HRESULT_FROM_WIN32(winErr);
340}
341
342//HRESULT vboxScreenMonInit(PVBOXSCREENMON pMon)
343HRESULT vboxScreenMonInit()
344{
345 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
346 HRESULT hr = S_OK;
347
348 memset(pMon, 0, sizeof (VBOXSCREENMON));
349
350 pMon->LoData.ScreenLayout.EscapeHdr.escapeCode = VBOXESC_SCREENLAYOUT;
351
352 pMon->hGdi32 = LoadLibraryW(L"gdi32.dll");
353 if (pMon->hGdi32 != NULL)
354 {
355 bool bSupported = true;
356 pMon->pfnD3DKMTOpenAdapterFromHdc = (PFND3DKMT_OPENADAPTERFROMHDC)GetProcAddress(pMon->hGdi32, "D3DKMTOpenAdapterFromHdc");
357 Log((__FUNCTION__"pfnD3DKMTOpenAdapterFromHdc = %p\n", pMon->pfnD3DKMTOpenAdapterFromHdc));
358 bSupported &= !!(pMon->pfnD3DKMTOpenAdapterFromHdc);
359
360 pMon->pfnD3DKMTOpenAdapterFromGdiDisplayName = (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)GetProcAddress(pMon->hGdi32, "D3DKMTOpenAdapterFromGdiDisplayName");
361 Log((__FUNCTION__": pfnD3DKMTOpenAdapterFromGdiDisplayName = %p\n", pMon->pfnD3DKMTOpenAdapterFromGdiDisplayName));
362 bSupported &= !!(pMon->pfnD3DKMTOpenAdapterFromGdiDisplayName);
363
364 pMon->pfnD3DKMTCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(pMon->hGdi32, "D3DKMTCloseAdapter");
365 Log((__FUNCTION__": pfnD3DKMTCloseAdapter = %p\n", pMon->pfnD3DKMTCloseAdapter));
366 bSupported &= !!(pMon->pfnD3DKMTCloseAdapter);
367
368 pMon->pfnD3DKMTEscape = (PFND3DKMT_ESCAPE)GetProcAddress(pMon->hGdi32, "D3DKMTEscape");
369 Log((__FUNCTION__": pfnD3DKMTEscape = %p\n", pMon->pfnD3DKMTEscape));
370 bSupported &= !!(pMon->pfnD3DKMTEscape);
371
372 Assert(bSupported);
373 if (bSupported)
374 {
375 hr = vboxScreenMonWndCreate(&pMon->hWnd);
376 Assert(hr == S_OK);
377 if (hr == S_OK)
378 return S_OK;
379 }
380 else
381 {
382 Log((__FUNCTION__": one of pfnD3DKMT function pointers failed to initialize\n"));
383 hr = VBOX_E_NOT_SUPPORTED;
384 }
385
386 FreeLibrary(pMon->hGdi32);
387 }
388 else
389 {
390 DWORD winEr = GetLastError();
391 hr = HRESULT_FROM_WIN32(winEr);
392 Assert(0);
393 Assert(hr != S_OK);
394 Assert(hr != S_FALSE);
395 if (hr == S_OK || hr == S_FALSE)
396 hr = E_FAIL;
397 }
398
399 return hr;
400}
401
402//HRESULT vboxScreenMonTerm(PVBOXSCREENMON pMon)
403HRESULT vboxScreenMonTerm()
404{
405 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
406 HRESULT tmpHr = vboxScreenMonWndDestroy(pMon->hWnd);
407 Assert(tmpHr == S_OK);
408
409 FreeLibrary(pMon->hGdi32);
410
411 pMon->bInited = FALSE;
412 return S_OK;
413}
414
415HRESULT vboxScreenMonRun()
416{
417 PVBOXSCREENMON pMon = &g_VBoxScreenMon;
418 MSG Msg;
419
420 HRESULT hr = S_FALSE;
421
422 if (!pMon->bInited)
423 {
424 PeekMessage(&Msg,
425 NULL /* HWND hWnd */,
426 WM_USER /* UINT wMsgFilterMin */,
427 WM_USER /* UINT wMsgFilterMax */,
428 PM_NOREMOVE);
429
430 pMon->bInited = TRUE;
431 }
432
433 BOOL bCheck = TRUE;
434 do
435 {
436 if (bCheck)
437 {
438 hr = vboxScreenMonCheckUpdateChange();
439 Assert(hr == S_OK);
440
441 bCheck = FALSE;
442 }
443
444 BOOL bResult = GetMessage(&Msg,
445 0 /*HWND hWnd*/,
446 0 /*UINT wMsgFilterMin*/,
447 0 /*UINT wMsgFilterMax*/
448 );
449
450 if(!bResult) /* WM_QUIT was posted */
451 {
452 hr = S_FALSE;
453 break;
454 }
455
456 if(bResult == -1) /* error occurred */
457 {
458 DWORD winEr = GetLastError();
459 hr = HRESULT_FROM_WIN32(winEr);
460 Assert(0);
461 /* just ensure we never return success in this case */
462 Assert(hr != S_OK);
463 Assert(hr != S_FALSE);
464 if (hr == S_OK || hr == S_FALSE)
465 hr = E_FAIL;
466 break;
467 }
468
469 switch (Msg.message)
470 {
471 case WM_DISPLAYCHANGE:
472 bCheck = TRUE;
473 default:
474 TranslateMessage(&Msg);
475 DispatchMessage(&Msg);
476 break;
477 }
478 } while (1);
479 return 0;
480}
481
482static DWORD WINAPI vboxScreenMRunnerThread(void *pvUser)
483{
484 PVBOXSCREENMONRUNNER pRunner = (PVBOXSCREENMONRUNNER)pvUser;
485 Assert(0);
486
487 BOOL bRc = SetEvent(pRunner->hEvent);
488 if (!bRc)
489 {
490 DWORD winErr = GetLastError();
491 Log((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
492 HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
493 Assert(0);
494 Assert(tmpHr != S_OK);
495 }
496
497 HRESULT hr = vboxScreenMonInit();
498 Assert(hr == S_OK);
499 if (hr == S_OK)
500 {
501 hr = vboxScreenMonRun();
502 Assert(hr == S_OK);
503
504 vboxScreenMonTerm();
505 }
506 return 0;
507}
508
509HRESULT VBoxScreenMRunnerStart(PVBOXSCREENMONRUNNER pMon)
510{
511 HRESULT hr = E_FAIL;
512 memset(pMon, 0, sizeof (VBOXSCREENMONRUNNER));
513
514 pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
515 FALSE, /* BOOL bManualReset*/
516 FALSE, /* BOOL bInitialState */
517 NULL /* LPCTSTR lpName */
518 );
519 if (pMon->hEvent)
520 {
521 pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
522 0 /* SIZE_T dwStackSize */,
523 vboxScreenMRunnerThread,
524 pMon,
525 0 /* DWORD dwCreationFlags */,
526 &pMon->idThread);
527 if (pMon->hThread)
528 {
529 Assert(0);
530 return S_OK;
531 }
532 else
533 {
534 DWORD winErr = GetLastError();
535 Log((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
536 hr = HRESULT_FROM_WIN32(winErr);
537 Assert(0);
538 Assert(hr != S_OK);
539 }
540 CloseHandle(pMon->hEvent);
541 }
542 else
543 {
544 DWORD winErr = GetLastError();
545 Log((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
546 hr = HRESULT_FROM_WIN32(winErr);
547 Assert(0);
548 Assert(hr != S_OK);
549 }
550
551 return hr;
552}
553
554HRESULT VBoxScreenMRunnerStop(PVBOXSCREENMONRUNNER pMon)
555{
556 if (!pMon->hThread)
557 return S_OK;
558
559 Assert(0);
560
561 HANDLE ahHandles[2];
562 ahHandles[0] = pMon->hThread;
563 ahHandles[1] = pMon->hEvent;
564 DWORD dwResult = WaitForMultipleObjects(2, ahHandles,
565 FALSE, /* BOOL bWaitAll */
566 INFINITE /* DWORD dwMilliseconds */
567 );
568 HRESULT hr = E_FAIL;
569 if (dwResult == WAIT_OBJECT_0 + 1) /* Event is signaled */
570 {
571 BOOL bResult = PostThreadMessage(pMon->idThread, WM_QUIT, 0, 0);
572 if (bResult)
573 {
574 DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
575 if (dwErr == WAIT_OBJECT_0)
576 {
577 hr = S_OK;
578 }
579 else
580 {
581 DWORD winErr = GetLastError();
582 hr = HRESULT_FROM_WIN32(winErr);
583 Assert(0);
584 }
585 }
586 else
587 {
588 DWORD winErr = GetLastError();
589 Assert(winErr != ERROR_SUCCESS);
590 if (winErr == ERROR_INVALID_THREAD_ID)
591 {
592 hr = S_OK;
593 }
594 else
595 {
596 hr = HRESULT_FROM_WIN32(winErr);
597 Assert(0);
598 }
599 }
600 }
601 else if (dwResult == WAIT_OBJECT_0)
602 {
603 /* thread has terminated already */
604 hr = S_OK;
605 }
606 else
607 {
608 Assert(0);
609 }
610
611 if (hr == S_OK)
612 {
613 CloseHandle(pMon->hThread);
614 pMon->hThread = 0;
615 CloseHandle(pMon->hEvent);
616 pMon->hThread = 0;
617 }
618
619 return hr;
620}
621
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