VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/vboxext.c@ 39570

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

wddm/wine: missing CloseHandle & lock init/term

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* $Id: vboxext.c 39257 2011-11-09 15:30:48Z vboxsync $ */
2/** @file
3 *
4 * VBox extension to Wine D3D
5 *
6 * Copyright (C) 2011 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#include "config.h"
17#include "wined3d_private.h"
18#include "vboxext.h"
19
20WINE_DEFAULT_DEBUG_CHANNEL(d3d_vbox);
21
22typedef DECLCALLBACK(void) FNVBOXEXTWORKERCB(void *pvUser);
23typedef FNVBOXEXTWORKERCB *PFNVBOXEXTWORKERCB;
24
25HRESULT VBoxExtDwSubmitProc(PFNVBOXEXTWORKERCB pfnCb, void *pvCb);
26
27/*******************************/
28#if defined(VBOX_WDDM_WOW64)
29# define VBOXEXT_WINE_MODULE_NAME "wined3dwddm-x86.dll"
30#else
31# define VBOXEXT_WINE_MODULE_NAME "wined3dwddm.dll"
32#endif
33
34typedef struct VBOXEXT_WORKER
35{
36 CRITICAL_SECTION CritSect;
37
38 HANDLE hEvent;
39
40 HANDLE hThread;
41 DWORD idThread;
42 /* wine does not seem to guarantie the dll is not unloaded in case FreeLibrary is used
43 * while d3d object is not terminated, keep an extra reference to ensure we're not unloaded
44 * while we are active */
45 HMODULE hSelf;
46} VBOXEXT_WORKER, *PVBOXEXT_WORKER;
47
48
49
50HRESULT VBoxExtWorkerCreate(PVBOXEXT_WORKER pWorker);
51HRESULT VBoxExtWorkerDestroy(PVBOXEXT_WORKER pWorker);
52HRESULT VBoxExtWorkerSubmitProc(PVBOXEXT_WORKER pWorker, PFNVBOXEXTWORKERCB pfnCb, void *pvCb);
53
54
55/*******************************/
56typedef struct VBOXEXT_GLOBAL
57{
58 VBOXEXT_WORKER Worker;
59} VBOXEXT_GLOBAL, *PVBOXEXT_GLOBAL;
60
61static VBOXEXT_GLOBAL g_VBoxExtGlobal;
62
63#define WM_VBOXEXT_CALLPROC (WM_APP+1)
64
65typedef struct VBOXEXT_CALLPROC
66{
67 PFNVBOXEXTWORKERCB pfnCb;
68 void *pvCb;
69} VBOXEXT_CALLPROC, *PVBOXEXT_CALLPROC;
70
71static DWORD WINAPI vboxExtWorkerThread(void *pvUser)
72{
73 PVBOXEXT_WORKER pWorker = (PVBOXEXT_WORKER)pvUser;
74 MSG Msg;
75
76 PeekMessage(&Msg,
77 NULL /* HWND hWnd */,
78 WM_USER /* UINT wMsgFilterMin */,
79 WM_USER /* UINT wMsgFilterMax */,
80 PM_NOREMOVE);
81 SetEvent(pWorker->hEvent);
82
83 do
84 {
85 BOOL bResult = GetMessage(&Msg,
86 0 /*HWND hWnd*/,
87 0 /*UINT wMsgFilterMin*/,
88 0 /*UINT wMsgFilterMax*/
89 );
90
91 if(!bResult) /* WM_QUIT was posted */
92 break;
93
94 Assert(bResult != -1);
95 if(bResult == -1) /* error occurred */
96 break;
97
98 switch (Msg.message)
99 {
100 case WM_VBOXEXT_CALLPROC:
101 {
102 VBOXEXT_CALLPROC* pData = (VBOXEXT_CALLPROC*)Msg.lParam;
103 pData->pfnCb(pData->pvCb);
104 SetEvent(pWorker->hEvent);
105 break;
106 }
107 default:
108 TranslateMessage(&Msg);
109 DispatchMessage(&Msg);
110 }
111 } while (1);
112 return 0;
113}
114
115HRESULT VBoxExtWorkerCreate(PVBOXEXT_WORKER pWorker)
116{
117 if(!GetModuleHandleEx(0, VBOXEXT_WINE_MODULE_NAME, &pWorker->hSelf))
118 {
119 DWORD dwEr = GetLastError();
120 ERR("GetModuleHandleEx failed, %d", dwEr);
121 return E_FAIL;
122 }
123
124 InitializeCriticalSection(&pWorker->CritSect);
125 pWorker->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
126 FALSE, /* BOOL bManualReset */
127 FALSE, /* BOOL bInitialState */
128 NULL /* LPCTSTR lpName */
129 );
130 if (pWorker->hEvent)
131 {
132 pWorker->hThread = CreateThread(
133 NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
134 0 /* SIZE_T dwStackSize */,
135 vboxExtWorkerThread,
136 pWorker,
137 0 /* DWORD dwCreationFlags */,
138 &pWorker->idThread);
139 if (pWorker->hThread)
140 {
141 DWORD dwResult = WaitForSingleObject(pWorker->hEvent, INFINITE);
142 if (WAIT_OBJECT_0 == dwResult)
143 return S_OK;
144 ERR("WaitForSingleObject returned %d\n", dwResult);
145 }
146 else
147 {
148 DWORD winErr = GetLastError();
149 ERR("CreateThread failed, winErr = (%d)", winErr);
150 }
151
152 DeleteCriticalSection(&pWorker->CritSect);
153 }
154 else
155 {
156 DWORD winErr = GetLastError();
157 ERR("CreateEvent failed, winErr = (%d)", winErr);
158 }
159
160 FreeLibrary(pWorker->hSelf);
161
162 return E_FAIL;
163}
164
165HRESULT VBoxExtWorkerDestroy(PVBOXEXT_WORKER pWorker)
166{
167 BOOL bResult = PostThreadMessage(pWorker->idThread, WM_QUIT, 0, 0);
168 DWORD dwErr;
169 if (!bResult)
170 {
171 DWORD winErr = GetLastError();
172 ERR("PostThreadMessage failed, winErr = (%d)", winErr);
173 return E_FAIL;
174 }
175
176 dwErr = WaitForSingleObject(pWorker->hThread, INFINITE);
177 if (dwErr != WAIT_OBJECT_0)
178 {
179 ERR("WaitForSingleObject returned (%d)", dwErr);
180 return E_FAIL;
181 }
182
183 CloseHandle(pWorker->hEvent);
184 DeleteCriticalSection(&pWorker->CritSect);
185
186 FreeLibrary(pWorker->hSelf);
187
188 CloseHandle(pWorker->hThread);
189
190 return S_OK;
191}
192
193static HRESULT vboxExtWorkerSubmit(VBOXEXT_WORKER *pWorker, UINT Msg, LPARAM lParam)
194{
195 HRESULT hr = E_FAIL;
196 BOOL bResult;
197 /* need to serialize since vboxExtWorkerThread is using one pWorker->hEvent
198 * to signal job completion */
199 EnterCriticalSection(&pWorker->CritSect);
200 bResult = PostThreadMessage(pWorker->idThread, Msg, 0, lParam);
201 if (bResult)
202 {
203 DWORD dwErr = WaitForSingleObject(pWorker->hEvent, INFINITE);
204 if (dwErr == WAIT_OBJECT_0)
205 {
206 hr = S_OK;
207 }
208 else
209 {
210 ERR("WaitForSingleObject returned (%d)", dwErr);
211 }
212 }
213 else
214 {
215 DWORD winErr = GetLastError();
216 ERR("PostThreadMessage failed, winErr = (%d)", winErr);
217 return E_FAIL;
218 }
219 LeaveCriticalSection(&pWorker->CritSect);
220 return hr;
221}
222
223HRESULT VBoxExtWorkerSubmitProc(PVBOXEXT_WORKER pWorker, PFNVBOXEXTWORKERCB pfnCb, void *pvCb)
224{
225 VBOXEXT_CALLPROC Ctx;
226 Ctx.pfnCb = pfnCb;
227 Ctx.pvCb = pvCb;
228 return vboxExtWorkerSubmit(pWorker, WM_VBOXEXT_CALLPROC, (LPARAM)&Ctx);
229}
230
231static HRESULT vboxExtInit()
232{
233 HRESULT hr = S_OK;
234 memset(&g_VBoxExtGlobal, 0, sizeof (g_VBoxExtGlobal));
235 hr = VBoxExtWorkerCreate(&g_VBoxExtGlobal.Worker);
236 return hr;
237}
238
239static HRESULT vboxExtTerm()
240{
241 HRESULT hr = VBoxExtWorkerDestroy(&g_VBoxExtGlobal.Worker);
242 return hr;
243}
244
245/* wine serializes all calls to us, so no need for any synchronization here */
246static DWORD g_cVBoxExtInits = 0;
247
248static DWORD vboxExtAddRef()
249{
250 return ++g_cVBoxExtInits;
251}
252
253static DWORD vboxExtRelease()
254{
255 DWORD cVBoxExtInits = --g_cVBoxExtInits;
256 Assert(cVBoxExtInits < UINT32_MAX/2);
257 return cVBoxExtInits;
258}
259
260static DWORD vboxExtGetRef()
261{
262 return g_cVBoxExtInits;
263}
264
265HRESULT VBoxExtCheckInit()
266{
267 HRESULT hr = S_OK;
268 if (!vboxExtGetRef())
269 {
270 hr = vboxExtInit();
271 if (FAILED(hr))
272 {
273 ERR("vboxExtInit failed, hr (0x%x)", hr);
274 return hr;
275 }
276 }
277 vboxExtAddRef();
278 return S_OK;
279}
280
281HRESULT VBoxExtCheckTerm()
282{
283 HRESULT hr = S_OK;
284 if (vboxExtGetRef() == 1)
285 {
286 hr = vboxExtTerm();
287 if (FAILED(hr))
288 {
289 ERR("vboxExtTerm failed, hr (0x%x)", hr);
290 return hr;
291 }
292 }
293 vboxExtRelease();
294 return S_OK;
295}
296
297HRESULT VBoxExtDwSubmitProc(PFNVBOXEXTWORKERCB pfnCb, void *pvCb)
298{
299 return VBoxExtWorkerSubmitProc(&g_VBoxExtGlobal.Worker, pfnCb, pvCb);
300}
301
302typedef struct VBOXEXT_GETDC_CB
303{
304 HWND hWnd;
305 HDC hDC;
306} VBOXEXT_GETDC_CB, *PVBOXEXT_GETDC_CB;
307
308static DECLCALLBACK(void) vboxExtGetDCWorker(void *pvUser)
309{
310 PVBOXEXT_GETDC_CB pData = (PVBOXEXT_GETDC_CB)pvUser;
311 pData->hDC = GetDC(pData->hWnd);
312}
313
314typedef struct VBOXEXT_RELEASEDC_CB
315{
316 HWND hWnd;
317 HDC hDC;
318 int ret;
319} VBOXEXT_RELEASEDC_CB, *PVBOXEXT_RELEASEDC_CB;
320
321static DECLCALLBACK(void) vboxExtReleaseDCWorker(void *pvUser)
322{
323 PVBOXEXT_RELEASEDC_CB pData = (PVBOXEXT_RELEASEDC_CB)pvUser;
324 pData->ret = ReleaseDC(pData->hWnd, pData->hDC);
325}
326#if 0
327HDC VBoxExtGetDC(HWND hWnd)
328{
329#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
330 HRESULT hr;
331 VBOXEXT_GETDC_CB Data = {0};
332 Data.hWnd = hWnd;
333 Data.hDC = NULL;
334
335 hr = VBoxExtDwSubmitProc(vboxExtGetDCWorker, &Data);
336 if (FAILED(hr))
337 {
338 ERR("VBoxExtDwSubmitProc feiled, hr (0x%x)\n", hr);
339 return NULL;
340 }
341
342 return Data.hDC;
343#else
344 return GetDC(hWnd);
345#endif
346}
347
348int VBoxExtReleaseDC(HWND hWnd, HDC hDC)
349{
350#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
351 HRESULT hr;
352 VBOXEXT_RELEASEDC_CB Data = {0};
353 Data.hWnd = hWnd;
354 Data.hDC = hDC;
355 Data.ret = 0;
356
357 hr = VBoxExtDwSubmitProc(vboxExtReleaseDCWorker, &Data);
358 if (FAILED(hr))
359 {
360 ERR("VBoxExtDwSubmitProc feiled, hr (0x%x)\n", hr);
361 return -1;
362 }
363
364 return Data.ret;
365#else
366 return ReleaseDC(hWnd, hDC);
367#endif
368}
369#endif
370
371/* window creation API */
372static LRESULT CALLBACK vboxExtWndProc(HWND hwnd,
373 UINT uMsg,
374 WPARAM wParam,
375 LPARAM lParam
376)
377{
378 switch(uMsg)
379 {
380 case WM_CLOSE:
381 TRACE("got WM_CLOSE for hwnd(0x%x)", hwnd);
382 return 0;
383 case WM_DESTROY:
384 TRACE("got WM_DESTROY for hwnd(0x%x)", hwnd);
385 return 0;
386 case WM_NCHITTEST:
387 TRACE("got WM_NCHITTEST for hwnd(0x%x)\n", hwnd);
388 return HTNOWHERE;
389 }
390
391 return DefWindowProc(hwnd, uMsg, wParam, lParam);
392}
393
394#define VBOXEXTWND_NAME "VboxDispD3DWineWnd"
395
396HRESULT vboxExtWndDoCreate(DWORD w, DWORD h, HWND *phWnd, HDC *phDC)
397{
398 HRESULT hr = S_OK;
399 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
400 /* Register the Window Class. */
401 WNDCLASS wc;
402 if (!GetClassInfo(hInstance, VBOXEXTWND_NAME, &wc))
403 {
404 wc.style = 0;//CS_OWNDC;
405 wc.lpfnWndProc = vboxExtWndProc;
406 wc.cbClsExtra = 0;
407 wc.cbWndExtra = 0;
408 wc.hInstance = hInstance;
409 wc.hIcon = NULL;
410 wc.hCursor = NULL;
411 wc.hbrBackground = NULL;
412 wc.lpszMenuName = NULL;
413 wc.lpszClassName = VBOXEXTWND_NAME;
414 if (!RegisterClass(&wc))
415 {
416 DWORD winErr = GetLastError();
417 ERR("RegisterClass failed, winErr(%d)\n", winErr);
418 hr = E_FAIL;
419 }
420 }
421
422 if (hr == S_OK)
423 {
424 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
425 VBOXEXTWND_NAME, VBOXEXTWND_NAME,
426 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
427 0, 0,
428 w, h,
429 NULL, //GetDesktopWindow() /* hWndParent */,
430 NULL /* hMenu */,
431 hInstance,
432 NULL /* lpParam */);
433 Assert(hWnd);
434 if (hWnd)
435 {
436 *phWnd = hWnd;
437 *phDC = GetDC(hWnd);
438 /* make sure we keep inited until the window is active */
439 vboxExtAddRef();
440 }
441 else
442 {
443 DWORD winErr = GetLastError();
444 ERR("CreateWindowEx failed, winErr(%d)\n", winErr);
445 hr = E_FAIL;
446 }
447 }
448
449 return hr;
450}
451
452static HRESULT vboxExtWndDoDestroy(HWND hWnd, HDC hDC)
453{
454 BOOL bResult;
455 DWORD winErr;
456 ReleaseDC(hWnd, hDC);
457 bResult = DestroyWindow(hWnd);
458 Assert(bResult);
459 if (bResult)
460 {
461 /* release the reference we previously acquired on window creation */
462 vboxExtRelease();
463 return S_OK;
464 }
465
466 winErr = GetLastError();
467 ERR("DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd);
468
469 return E_FAIL;
470}
471
472typedef struct VBOXEXTWND_CREATE_INFO
473{
474 int hr;
475 HWND hWnd;
476 HDC hDC;
477 DWORD width;
478 DWORD height;
479} VBOXEXTWND_CREATE_INFO;
480
481typedef struct VBOXEXTWND_DESTROY_INFO
482{
483 int hr;
484 HWND hWnd;
485 HDC hDC;
486} VBOXEXTWND_DESTROY_INFO;
487
488DECLCALLBACK(void) vboxExtWndDestroyWorker(void *pvUser)
489{
490 VBOXEXTWND_DESTROY_INFO *pInfo = (VBOXEXTWND_DESTROY_INFO*)pvUser;
491 pInfo->hr = vboxExtWndDoDestroy(pInfo->hWnd, pInfo->hDC);
492 Assert(pInfo->hr == S_OK);
493}
494
495DECLCALLBACK(void) vboxExtWndCreateWorker(void *pvUser)
496{
497 VBOXEXTWND_CREATE_INFO *pInfo = (VBOXEXTWND_CREATE_INFO*)pvUser;
498 pInfo->hr = vboxExtWndDoCreate(pInfo->width, pInfo->height, &pInfo->hWnd, &pInfo->hDC);
499 Assert(pInfo->hr == S_OK);
500}
501
502HRESULT VBoxExtWndDestroy(HWND hWnd, HDC hDC)
503{
504 HRESULT hr;
505 VBOXEXTWND_DESTROY_INFO Info;
506 Info.hr = E_FAIL;
507 Info.hWnd = hWnd;
508 Info.hDC = hDC;
509 hr = VBoxExtDwSubmitProc(vboxExtWndDestroyWorker, &Info);
510 Assert(hr == S_OK);
511 if (hr == S_OK)
512 {
513 Assert(Info.hr == S_OK);
514 return Info.hr;
515 }
516 return hr;
517}
518
519HRESULT VBoxExtWndCreate(DWORD width, DWORD height, HWND *phWnd, HDC *phDC)
520{
521 HRESULT hr;
522 VBOXEXTWND_CREATE_INFO Info;
523 Info.hr = E_FAIL;
524 Info.width = width;
525 Info.height = height;
526 hr = VBoxExtDwSubmitProc(vboxExtWndCreateWorker, &Info);
527 Assert(hr == S_OK);
528 if (hr == S_OK)
529 {
530 Assert(Info.hr == S_OK);
531 if (Info.hr == S_OK)
532 {
533 *phWnd = Info.hWnd;
534 *phDC = Info.hDC;
535 }
536 return Info.hr;
537 }
538 return hr;
539}
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