dinput: COM cleanup - return interface instead of typecasting This.
[wine] / dlls / dinput / dinput_main.c
1 /*              DirectInput
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2002 TransGaming Technologies Inc.
6  * Copyright 2007 Vitaliy Margolen
7  *
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 /* Status:
24  *
25  * - Tomb Raider 2 Demo:
26  *   Playable using keyboard only.
27  * - WingCommander Prophecy Demo:
28  *   Doesn't get Input Focus.
29  *
30  * - Fallout : works great in X and DGA mode
31  */
32
33 #include "config.h"
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <string.h>
37
38 #define COBJMACROS
39 #define NONAMELESSUNION
40
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winuser.h"
46 #include "winerror.h"
47 #include "objbase.h"
48 #include "rpcproxy.h"
49 #include "dinput_private.h"
50 #include "device_private.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
53
54 static const IDirectInput7AVtbl ddi7avt;
55 static const IDirectInput7WVtbl ddi7wvt;
56 static const IDirectInput8AVtbl ddi8avt;
57 static const IDirectInput8WVtbl ddi8wvt;
58
59 static inline IDirectInputImpl *impl_from_IDirectInput7A( IDirectInput7A *iface )
60 {
61     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7A_iface );
62 }
63
64 static inline IDirectInputImpl *impl_from_IDirectInput7W( IDirectInput7W *iface )
65 {
66     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7W_iface );
67 }
68
69 static inline IDirectInputImpl *impl_from_IDirectInput8A( IDirectInput8A *iface )
70 {
71     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8A_iface );
72 }
73
74 static inline IDirectInputImpl *impl_from_IDirectInput8W( IDirectInput8W *iface )
75 {
76     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8W_iface );
77 }
78
79 static const struct dinput_device *dinput_devices[] =
80 {
81     &mouse_device,
82     &keyboard_device,
83     &joystick_linuxinput_device,
84     &joystick_linux_device,
85     &joystick_osx_device
86 };
87 #define NB_DINPUT_DEVICES (sizeof(dinput_devices)/sizeof(dinput_devices[0]))
88
89 static HINSTANCE DINPUT_instance = NULL;
90
91 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv)
92 {
93     switch(reason)
94     {
95       case DLL_PROCESS_ATTACH:
96         DisableThreadLibraryCalls(inst);
97         DINPUT_instance = inst;
98         break;
99       case DLL_PROCESS_DETACH:
100         break;
101     }
102     return TRUE;
103 }
104
105 static BOOL check_hook_thread(void);
106 static CRITICAL_SECTION dinput_hook_crit;
107 static struct list direct_input_list = LIST_INIT( direct_input_list );
108
109 /******************************************************************************
110  *      DirectInputCreateEx (DINPUT.@)
111  */
112 HRESULT WINAPI DirectInputCreateEx(
113         HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
114         LPUNKNOWN punkOuter) 
115 {
116     IDirectInputImpl* This;
117
118     TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter);
119
120     if (IsEqualGUID( &IID_IUnknown,       riid ) ||
121         IsEqualGUID( &IID_IDirectInputA,  riid ) ||
122         IsEqualGUID( &IID_IDirectInput2A, riid ) ||
123         IsEqualGUID( &IID_IDirectInput7A, riid ) ||
124         IsEqualGUID( &IID_IDirectInputW,  riid ) ||
125         IsEqualGUID( &IID_IDirectInput2W, riid ) ||
126         IsEqualGUID( &IID_IDirectInput7W, riid ) ||
127         IsEqualGUID( &IID_IDirectInput8A, riid ) ||
128         IsEqualGUID( &IID_IDirectInput8W, riid ))
129     {
130         if (!(This = HeapAlloc( GetProcessHeap(), 0, sizeof(IDirectInputImpl) )))
131             return DIERR_OUTOFMEMORY;
132     }
133     else
134         return DIERR_OLDDIRECTINPUTVERSION;
135
136     This->IDirectInput7A_iface.lpVtbl = &ddi7avt;
137     This->IDirectInput7W_iface.lpVtbl = &ddi7wvt;
138     This->IDirectInput8A_iface.lpVtbl = &ddi8avt;
139     This->IDirectInput8W_iface.lpVtbl = &ddi8wvt;
140     This->ref         = 0;
141     This->dwVersion   = dwVersion;
142     This->evsequence  = 1;
143
144     InitializeCriticalSection(&This->crit);
145     This->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectInputImpl*->crit");
146
147     list_init( &This->devices_list );
148
149     /* Add self to the list of the IDirectInputs */
150     EnterCriticalSection( &dinput_hook_crit );
151     list_add_head( &direct_input_list, &This->entry );
152     LeaveCriticalSection( &dinput_hook_crit );
153
154     if (!check_hook_thread())
155     {
156         IUnknown_Release( &This->IDirectInput7A_iface );
157         return DIERR_GENERIC;
158     }
159
160     IDirectInput_QueryInterface( &This->IDirectInput7A_iface, riid, ppDI );
161     return DI_OK;
162 }
163
164 /******************************************************************************
165  *      DirectInputCreateA (DINPUT.@)
166  */
167 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
168 {
169     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter);
170 }
171
172 /******************************************************************************
173  *      DirectInputCreateW (DINPUT.@)
174  */
175 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter)
176 {
177     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter);
178 }
179
180 static const char *_dump_DIDEVTYPE_value(DWORD dwDevType) {
181     switch (dwDevType) {
182         case 0: return "All devices";
183         case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
184         case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
185         case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
186         case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
187         default: return "Unknown";
188     }
189 }
190
191 static void _dump_EnumDevices_dwFlags(DWORD dwFlags) {
192     if (TRACE_ON(dinput)) {
193         unsigned int   i;
194         static const struct {
195             DWORD       mask;
196             const char  *name;
197         } flags[] = {
198 #define FE(x) { x, #x}
199             FE(DIEDFL_ALLDEVICES),
200             FE(DIEDFL_ATTACHEDONLY),
201             FE(DIEDFL_FORCEFEEDBACK),
202             FE(DIEDFL_INCLUDEALIASES),
203             FE(DIEDFL_INCLUDEPHANTOMS)
204 #undef FE
205         };
206         TRACE(" flags: ");
207         if (dwFlags == 0) {
208             TRACE("DIEDFL_ALLDEVICES\n");
209             return;
210         }
211         for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
212             if (flags[i].mask & dwFlags)
213                 TRACE("%s ",flags[i].name);
214     }
215     TRACE("\n");
216 }
217
218 void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat) {
219     unsigned int i;
220
221     FIXME("diaf.dwSize = %d\n", lpdiActionFormat->dwSize);
222     FIXME("diaf.dwActionSize = %d\n", lpdiActionFormat->dwActionSize);
223     FIXME("diaf.dwDataSize = %d\n", lpdiActionFormat->dwDataSize);
224     FIXME("diaf.dwNumActions = %d\n", lpdiActionFormat->dwNumActions);
225     FIXME("diaf.rgoAction = %p\n", lpdiActionFormat->rgoAction);
226     FIXME("diaf.guidActionMap = %s\n", debugstr_guid(&lpdiActionFormat->guidActionMap));
227     FIXME("diaf.dwGenre = 0x%08x\n", lpdiActionFormat->dwGenre);
228     FIXME("diaf.dwBufferSize = %d\n", lpdiActionFormat->dwBufferSize);
229     FIXME("diaf.lAxisMin = %d\n", lpdiActionFormat->lAxisMin);
230     FIXME("diaf.lAxisMax = %d\n", lpdiActionFormat->lAxisMax);
231     FIXME("diaf.hInstString = %p\n", lpdiActionFormat->hInstString);
232     FIXME("diaf.ftTimeStamp ...\n");
233     FIXME("diaf.dwCRC = 0x%x\n", lpdiActionFormat->dwCRC);
234     FIXME("diaf.tszActionMap = %s\n", debugstr_a(lpdiActionFormat->tszActionMap));
235     for (i = 0; i < lpdiActionFormat->dwNumActions; i++)
236     {
237         FIXME("diaf.rgoAction[%u]:\n", i);
238         FIXME("\tuAppData=0x%lx\n", lpdiActionFormat->rgoAction[i].uAppData);
239         FIXME("\tdwSemantic=0x%08x\n", lpdiActionFormat->rgoAction[i].dwSemantic);
240         FIXME("\tdwFlags=0x%x\n", lpdiActionFormat->rgoAction[i].dwFlags);
241         FIXME("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName));
242         FIXME("\tguidInstance=%s\n", debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance));
243         FIXME("\tdwObjID=0x%x\n", lpdiActionFormat->rgoAction[i].dwObjID);
244         FIXME("\tdwHow=0x%x\n", lpdiActionFormat->rgoAction[i].dwHow);
245     }
246 }
247
248 /******************************************************************************
249  *      IDirectInputA_EnumDevices
250  */
251 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
252         LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
253         LPVOID pvRef, DWORD dwFlags)
254 {
255     IDirectInputImpl *This = impl_from_IDirectInput7A(iface);
256     DIDEVICEINSTANCEA devInstance;
257     unsigned int i;
258     int j, r;
259
260     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
261           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
262           lpCallback, pvRef, dwFlags);
263     _dump_EnumDevices_dwFlags(dwFlags);
264
265     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
266         if (!dinput_devices[i]->enum_deviceA) continue;
267         for (j = 0, r = -1; r != 0; j++) {
268             devInstance.dwSize = sizeof(devInstance);
269             TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
270             if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
271                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
272                     return 0;
273             }
274         }
275     }
276     
277     return 0;
278 }
279 /******************************************************************************
280  *      IDirectInputW_EnumDevices
281  */
282 static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
283         LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
284         LPVOID pvRef, DWORD dwFlags) 
285 {
286     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
287     DIDEVICEINSTANCEW devInstance;
288     unsigned int i;
289     int j, r;
290
291     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
292           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
293           lpCallback, pvRef, dwFlags);
294     _dump_EnumDevices_dwFlags(dwFlags);
295
296     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
297         if (!dinput_devices[i]->enum_deviceW) continue;
298         for (j = 0, r = -1; r != 0; j++) {
299             devInstance.dwSize = sizeof(devInstance);
300             TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
301             if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
302                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
303                     return 0;
304             }
305         }
306     }
307     
308     return 0;
309 }
310
311 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
312 {
313     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
314     ULONG ref = InterlockedIncrement(&This->ref);
315
316     TRACE( "(%p) incrementing from %d\n", This, ref - 1);
317     return ref;
318 }
319
320 static ULONG WINAPI IDirectInputWImpl_AddRef(LPDIRECTINPUT7W iface)
321 {
322     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
323     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
324 }
325
326 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
327 {
328     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
329     ULONG ref = InterlockedDecrement( &This->ref );
330
331     TRACE( "(%p) releasing from %d\n", This, ref + 1 );
332
333     if (ref) return ref;
334
335     /* Remove self from the list of the IDirectInputs */
336     EnterCriticalSection( &dinput_hook_crit );
337     list_remove( &This->entry );
338     LeaveCriticalSection( &dinput_hook_crit );
339
340     check_hook_thread();
341
342     This->crit.DebugInfo->Spare[0] = 0;
343     DeleteCriticalSection( &This->crit );
344     HeapFree( GetProcessHeap(), 0, This );
345
346     return 0;
347 }
348
349 static ULONG WINAPI IDirectInputWImpl_Release(LPDIRECTINPUT7W iface)
350 {
351     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
352     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
353 }
354
355 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj)
356 {
357     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
358
359     TRACE( "(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj );
360
361     if (IsEqualGUID( &IID_IUnknown, riid ) ||
362         IsEqualGUID( &IID_IDirectInputA,  riid ) ||
363         IsEqualGUID( &IID_IDirectInput2A, riid ) ||
364         IsEqualGUID( &IID_IDirectInput7A, riid ))
365     {
366         *ppobj = &This->IDirectInput7A_iface;
367         IUnknown_AddRef( (IUnknown*)*ppobj );
368
369         return DI_OK;
370     }
371
372     if (IsEqualGUID( &IID_IDirectInputW,  riid ) ||
373         IsEqualGUID( &IID_IDirectInput2W, riid ) ||
374         IsEqualGUID( &IID_IDirectInput7W, riid ))
375     {
376         *ppobj = &This->IDirectInput7W_iface;
377         IUnknown_AddRef( (IUnknown*)*ppobj );
378
379         return DI_OK;
380     }
381
382     if (IsEqualGUID( &IID_IDirectInput8A, riid ))
383     {
384         *ppobj = &This->IDirectInput8A_iface;
385         IUnknown_AddRef( (IUnknown*)*ppobj );
386
387         return DI_OK;
388     }
389
390     if (IsEqualGUID( &IID_IDirectInput8W, riid ))
391     {
392         *ppobj = &This->IDirectInput8W_iface;
393         IUnknown_AddRef( (IUnknown*)*ppobj );
394
395         return DI_OK;
396     }
397
398     FIXME( "Unsupported interface: %s\n", debugstr_guid(riid));
399     return E_FAIL;
400 }
401
402 static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj)
403 {
404     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
405     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
406 }
407
408 static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD x) {
409         TRACE("(this=%p,%p,%x)\n",iface, hinst, x);
410         
411         /* Initialize can return: DIERR_BETADIRECTINPUTVERSION, DIERR_OLDDIRECTINPUTVERSION and DI_OK.
412          * Since we already initialized the device, return DI_OK. In the past we returned DIERR_ALREADYINITIALIZED
413          * which broke applications like Tomb Raider Legend because it isn't a legal return value.
414          */
415         return DI_OK;
416 }
417
418 static HRESULT WINAPI IDirectInputWImpl_Initialize(LPDIRECTINPUT7W iface, HINSTANCE hinst, DWORD x)
419 {
420     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
421     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
422 }
423
424 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, REFGUID rguid)
425 {
426     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
427     HRESULT hr;
428     LPDIRECTINPUTDEVICEA device;
429
430     TRACE( "(%p)->(%s)\n", This, debugstr_guid(rguid) );
431
432     hr = IDirectInput_CreateDevice( iface, rguid, &device, NULL );
433     if (hr != DI_OK) return DI_NOTATTACHED;
434
435     IUnknown_Release( device );
436
437     return DI_OK;
438 }
439
440 static HRESULT WINAPI IDirectInputWImpl_GetDeviceStatus(LPDIRECTINPUT7W iface, REFGUID rguid)
441 {
442     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
443     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
444 }
445
446 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,
447                                                         HWND hwndOwner,
448                                                         DWORD dwFlags)
449 {
450     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
451
452     FIXME( "(%p)->(%p,%08x): stub\n", This, hwndOwner, dwFlags );
453
454     return DI_OK;
455 }
456
457 static HRESULT WINAPI IDirectInputWImpl_RunControlPanel(LPDIRECTINPUT7W iface, HWND hwndOwner, DWORD dwFlags)
458 {
459     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
460     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
461 }
462
463 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
464                                                     LPCSTR pszName, LPGUID pguidInstance)
465 {
466     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
467
468     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance );
469
470     return DI_OK;
471 }
472
473 static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
474                                                     LPCWSTR pszName, LPGUID pguidInstance)
475 {
476     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
477
478     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance );
479
480     return DI_OK;
481 }
482
483 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid,
484                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
485 {
486   IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
487   HRESULT ret_value = DIERR_DEVICENOTREG;
488   unsigned int i;
489
490   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
491
492   if (!rguid || !pvOut) return E_POINTER;
493
494   /* Loop on all the devices to see if anyone matches the given GUID */
495   for (i = 0; i < NB_DINPUT_DEVICES; i++) {
496     HRESULT ret;
497
498     if (!dinput_devices[i]->create_deviceA) continue;
499     if ((ret = dinput_devices[i]->create_deviceA(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK)
500     {
501       EnterCriticalSection( &This->crit );
502       list_add_tail( &This->devices_list, &(*(IDirectInputDeviceImpl**)pvOut)->entry );
503       LeaveCriticalSection( &This->crit );
504       return DI_OK;
505     }
506
507     if (ret == DIERR_NOINTERFACE)
508       ret_value = DIERR_NOINTERFACE;
509   }
510
511   if (ret_value == DIERR_NOINTERFACE)
512   {
513     WARN("invalid device GUID %s\n", debugstr_guid(rguid));
514   }
515
516   return ret_value;
517 }
518
519 static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid,
520                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
521 {
522   IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
523   HRESULT ret_value = DIERR_DEVICENOTREG;
524   unsigned int i;
525
526   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
527
528   if (!rguid || !pvOut) return E_POINTER;
529
530   /* Loop on all the devices to see if anyone matches the given GUID */
531   for (i = 0; i < NB_DINPUT_DEVICES; i++) {
532     HRESULT ret;
533
534     if (!dinput_devices[i]->create_deviceW) continue;
535     if ((ret = dinput_devices[i]->create_deviceW(This, rguid, riid, (LPDIRECTINPUTDEVICEW*) pvOut)) == DI_OK)
536     {
537       EnterCriticalSection( &This->crit );
538       list_add_tail( &This->devices_list, &(*(IDirectInputDeviceImpl**)pvOut)->entry );
539       LeaveCriticalSection( &This->crit );
540       return DI_OK;
541     }
542
543     if (ret == DIERR_NOINTERFACE)
544       ret_value = DIERR_NOINTERFACE;
545   }
546
547   return ret_value;
548 }
549
550 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
551                                                      LPDIRECTINPUTDEVICEA* pdev, LPUNKNOWN punk)
552 {
553     return IDirectInput7AImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
554 }
555
556 static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
557                                                      LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk)
558 {
559     return IDirectInput7WImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
560 }
561
562 /*******************************************************************************
563  *      DirectInput8
564  */
565
566 static ULONG WINAPI IDirectInput8AImpl_AddRef(LPDIRECTINPUT8A iface)
567 {
568     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
569     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
570 }
571
572 static ULONG WINAPI IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface)
573 {
574     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
575     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
576 }
577
578 static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj)
579 {
580     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
581     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
582 }
583
584 static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj)
585 {
586     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
587     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
588 }
589
590 static ULONG WINAPI IDirectInput8AImpl_Release(LPDIRECTINPUT8A iface)
591 {
592     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
593     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
594 }
595
596 static ULONG WINAPI IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface)
597 {
598     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
599     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
600 }
601
602 static HRESULT WINAPI IDirectInput8AImpl_CreateDevice(LPDIRECTINPUT8A iface, REFGUID rguid,
603                                                       LPDIRECTINPUTDEVICE8A* pdev, LPUNKNOWN punk)
604 {
605     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
606     return IDirectInput7AImpl_CreateDeviceEx( &This->IDirectInput7A_iface, rguid, NULL, (LPVOID*)pdev, punk );
607 }
608
609 static HRESULT WINAPI IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface, REFGUID rguid,
610                                                       LPDIRECTINPUTDEVICE8W* pdev, LPUNKNOWN punk)
611 {
612     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
613     return IDirectInput7WImpl_CreateDeviceEx( &This->IDirectInput7W_iface, rguid, NULL, (LPVOID*)pdev, punk );
614 }
615
616 static HRESULT WINAPI IDirectInput8AImpl_EnumDevices(LPDIRECTINPUT8A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
617                                                      LPVOID pvRef, DWORD dwFlags)
618 {
619     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
620     return IDirectInputAImpl_EnumDevices( &This->IDirectInput7A_iface, dwDevType, lpCallback, pvRef, dwFlags );
621 }
622
623 static HRESULT WINAPI IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
624                                                      LPVOID pvRef, DWORD dwFlags)
625 {
626     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
627     return IDirectInputWImpl_EnumDevices( &This->IDirectInput7W_iface, dwDevType, lpCallback, pvRef, dwFlags );
628 }
629
630 static HRESULT WINAPI IDirectInput8AImpl_GetDeviceStatus(LPDIRECTINPUT8A iface, REFGUID rguid)
631 {
632     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
633     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
634 }
635
636 static HRESULT WINAPI IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface, REFGUID rguid)
637 {
638     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
639     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
640 }
641
642 static HRESULT WINAPI IDirectInput8AImpl_RunControlPanel(LPDIRECTINPUT8A iface, HWND hwndOwner, DWORD dwFlags)
643 {
644     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
645     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
646 }
647
648 static HRESULT WINAPI IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface, HWND hwndOwner, DWORD dwFlags)
649 {
650     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
651     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
652 }
653
654 static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface, HINSTANCE hinst, DWORD x)
655 {
656     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
657     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
658 }
659
660 static HRESULT WINAPI IDirectInput8WImpl_Initialize(LPDIRECTINPUT8W iface, HINSTANCE hinst, DWORD x)
661 {
662     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
663     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
664 }
665
666 static HRESULT WINAPI IDirectInput8AImpl_FindDevice(LPDIRECTINPUT8A iface, REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance)
667 {
668     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
669     return IDirectInput2AImpl_FindDevice( &This->IDirectInput7A_iface, rguid, pszName, pguidInstance );
670 }
671
672 static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance)
673 {
674     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
675     return IDirectInput2WImpl_FindDevice( &This->IDirectInput7W_iface, rguid, pszName, pguidInstance );
676 }
677
678 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
679       LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat,
680       LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,
681       LPVOID pvRef, DWORD dwFlags
682 )
683 {
684     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
685
686     FIXME("(this=%p,%s,%p,%p,%p,%04x): stub\n", This, ptszUserName, lpdiActionFormat,
687           lpCallback, pvRef, dwFlags);
688 #define X(x) if (dwFlags & x) FIXME("\tdwFlags |= "#x"\n");
689         X(DIEDBSFL_ATTACHEDONLY)
690         X(DIEDBSFL_THISUSER)
691         X(DIEDBSFL_FORCEFEEDBACK)
692         X(DIEDBSFL_AVAILABLEDEVICES)
693         X(DIEDBSFL_MULTIMICEKEYBOARDS)
694         X(DIEDBSFL_NONGAMINGDEVICES)
695 #undef X
696
697     _dump_diactionformatA(lpdiActionFormat);
698
699     return DI_OK;
700 }
701
702 static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
703       LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat,
704       LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
705       LPVOID pvRef, DWORD dwFlags
706 )
707 {
708       IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
709
710       FIXME("(this=%p,%s,%p,%p,%p,%04x): stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat,
711             lpCallback, pvRef, dwFlags);
712       return 0;
713 }
714
715 static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
716       LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
717       LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
718 )
719 {
720       IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
721
722       FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams,
723             dwFlags, pvRefData);
724       return 0;
725 }
726
727 static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices(
728       LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
729       LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
730 )
731 {
732       IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
733
734       FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams,
735             dwFlags, pvRefData);
736       return 0;
737 }
738
739 static const IDirectInput7AVtbl ddi7avt = {
740     IDirectInputAImpl_QueryInterface,
741     IDirectInputAImpl_AddRef,
742     IDirectInputAImpl_Release,
743     IDirectInputAImpl_CreateDevice,
744     IDirectInputAImpl_EnumDevices,
745     IDirectInputAImpl_GetDeviceStatus,
746     IDirectInputAImpl_RunControlPanel,
747     IDirectInputAImpl_Initialize,
748     IDirectInput2AImpl_FindDevice,
749     IDirectInput7AImpl_CreateDeviceEx
750 };
751
752 static const IDirectInput7WVtbl ddi7wvt = {
753     IDirectInputWImpl_QueryInterface,
754     IDirectInputWImpl_AddRef,
755     IDirectInputWImpl_Release,
756     IDirectInputWImpl_CreateDevice,
757     IDirectInputWImpl_EnumDevices,
758     IDirectInputWImpl_GetDeviceStatus,
759     IDirectInputWImpl_RunControlPanel,
760     IDirectInputWImpl_Initialize,
761     IDirectInput2WImpl_FindDevice,
762     IDirectInput7WImpl_CreateDeviceEx
763 };
764
765 static const IDirectInput8AVtbl ddi8avt = {
766     IDirectInput8AImpl_QueryInterface,
767     IDirectInput8AImpl_AddRef,
768     IDirectInput8AImpl_Release,
769     IDirectInput8AImpl_CreateDevice,
770     IDirectInput8AImpl_EnumDevices,
771     IDirectInput8AImpl_GetDeviceStatus,
772     IDirectInput8AImpl_RunControlPanel,
773     IDirectInput8AImpl_Initialize,
774     IDirectInput8AImpl_FindDevice,
775     IDirectInput8AImpl_EnumDevicesBySemantics,
776     IDirectInput8AImpl_ConfigureDevices
777 };
778
779 static const IDirectInput8WVtbl ddi8wvt = {
780     IDirectInput8WImpl_QueryInterface,
781     IDirectInput8WImpl_AddRef,
782     IDirectInput8WImpl_Release,
783     IDirectInput8WImpl_CreateDevice,
784     IDirectInput8WImpl_EnumDevices,
785     IDirectInput8WImpl_GetDeviceStatus,
786     IDirectInput8WImpl_RunControlPanel,
787     IDirectInput8WImpl_Initialize,
788     IDirectInput8WImpl_FindDevice,
789     IDirectInput8WImpl_EnumDevicesBySemantics,
790     IDirectInput8WImpl_ConfigureDevices
791 };
792
793 /*******************************************************************************
794  * DirectInput ClassFactory
795  */
796 typedef struct
797 {
798     /* IUnknown fields */
799     IClassFactory IClassFactory_iface;
800     LONG          ref;
801 } IClassFactoryImpl;
802
803 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
804 {
805         return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
806 }
807
808 static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
809         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
810
811         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
812         return E_NOINTERFACE;
813 }
814
815 static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) {
816         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
817         return InterlockedIncrement(&(This->ref));
818 }
819
820 static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) {
821         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
822         /* static class, won't be  freed */
823         return InterlockedDecrement(&(This->ref));
824 }
825
826 static HRESULT WINAPI DICF_CreateInstance(
827         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
828 ) {
829         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
830
831         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
832         if ( IsEqualGUID( &IID_IUnknown, riid ) ||
833              IsEqualGUID( &IID_IDirectInputA, riid ) ||
834              IsEqualGUID( &IID_IDirectInputW, riid ) ||
835              IsEqualGUID( &IID_IDirectInput2A, riid ) ||
836              IsEqualGUID( &IID_IDirectInput2W, riid ) ||
837              IsEqualGUID( &IID_IDirectInput7A, riid ) ||
838              IsEqualGUID( &IID_IDirectInput7W, riid ) ||
839              IsEqualGUID( &IID_IDirectInput8A, riid ) ||
840              IsEqualGUID( &IID_IDirectInput8W, riid ) ) {
841                 /* FIXME: reuse already created dinput if present? */
842                 return DirectInputCreateEx(0,0,riid,ppobj,pOuter);
843         }
844
845         FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);    
846         return E_NOINTERFACE;
847 }
848
849 static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
850         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
851         FIXME("(%p)->(%d),stub!\n",This,dolock);
852         return S_OK;
853 }
854
855 static const IClassFactoryVtbl DICF_Vtbl = {
856         DICF_QueryInterface,
857         DICF_AddRef,
858         DICF_Release,
859         DICF_CreateInstance,
860         DICF_LockServer
861 };
862 static IClassFactoryImpl DINPUT_CF = {{&DICF_Vtbl}, 1 };
863
864 /***********************************************************************
865  *              DllCanUnloadNow (DINPUT.@)
866  */
867 HRESULT WINAPI DllCanUnloadNow(void)
868 {
869     return S_FALSE;
870 }
871
872 /***********************************************************************
873  *              DllGetClassObject (DINPUT.@)
874  */
875 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
876 {
877     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
878     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
879         *ppv = &DINPUT_CF;
880         IClassFactory_AddRef((IClassFactory*)*ppv);
881     return S_OK;
882     }
883
884     FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
885     return CLASS_E_CLASSNOTAVAILABLE;
886 }
887
888 /***********************************************************************
889  *              DllRegisterServer (DINPUT.@)
890  */
891 HRESULT WINAPI DllRegisterServer(void)
892 {
893     return __wine_register_resources( DINPUT_instance, NULL );
894 }
895
896 /***********************************************************************
897  *              DllUnregisterServer (DINPUT.@)
898  */
899 HRESULT WINAPI DllUnregisterServer(void)
900 {
901     return __wine_unregister_resources( DINPUT_instance, NULL );
902 }
903
904 /******************************************************************************
905  *      DInput hook thread
906  */
907
908 static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
909 {
910     IDirectInputImpl *dinput;
911     int skip = 0;
912
913     if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
914
915     EnterCriticalSection( &dinput_hook_crit );
916     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
917     {
918         IDirectInputDeviceImpl *dev;
919
920         EnterCriticalSection( &dinput->crit );
921         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
922             if (dev->acquired && dev->event_proc)
923             {
924                 TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
925                 skip |= dev->event_proc( (LPDIRECTINPUTDEVICE8A)dev, wparam, lparam );
926             }
927         LeaveCriticalSection( &dinput->crit );
928     }
929     LeaveCriticalSection( &dinput_hook_crit );
930
931     return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam );
932 }
933
934 static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam )
935 {
936     CWPSTRUCT *msg = (CWPSTRUCT *)lparam;
937     IDirectInputImpl *dinput;
938     HWND foreground;
939
940     if (code != HC_ACTION || (msg->message != WM_KILLFOCUS &&
941         msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE))
942         return CallNextHookEx( 0, code, wparam, lparam );
943
944     foreground = GetForegroundWindow();
945
946     EnterCriticalSection( &dinput_hook_crit );
947
948     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
949     {
950         IDirectInputDeviceImpl *dev;
951
952         EnterCriticalSection( &dinput->crit );
953         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
954         {
955             if (!dev->acquired) continue;
956
957             if (msg->hwnd == dev->win && msg->hwnd != foreground)
958             {
959                 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
960                 IDirectInputDevice_Unacquire( (LPDIRECTINPUTDEVICE8A)dev );
961             }
962         }
963         LeaveCriticalSection( &dinput->crit );
964     }
965     LeaveCriticalSection( &dinput_hook_crit );
966
967     return CallNextHookEx( 0, code, wparam, lparam );
968 }
969
970 static DWORD WINAPI hook_thread_proc(void *param)
971 {
972     static HHOOK kbd_hook, mouse_hook;
973     MSG msg;
974
975     /* Force creation of the message queue */
976     PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
977     SetEvent(*(LPHANDLE)param);
978
979     while (GetMessageW( &msg, 0, 0, 0 ))
980     {
981         UINT kbd_cnt = 0, mice_cnt = 0;
982
983         if (msg.message == WM_USER+0x10)
984         {
985             IDirectInputImpl *dinput;
986
987             TRACE( "Processing hook change notification lp:%ld\n", msg.lParam );
988
989             if (!msg.wParam && !msg.lParam)
990             {
991                 if (kbd_hook) UnhookWindowsHookEx( kbd_hook );
992                 if (mouse_hook) UnhookWindowsHookEx( mouse_hook );
993                 kbd_hook = mouse_hook = NULL;
994                 break;
995             }
996
997             EnterCriticalSection( &dinput_hook_crit );
998
999             /* Count acquired keyboards and mice*/
1000             LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1001             {
1002                 IDirectInputDeviceImpl *dev;
1003
1004                 EnterCriticalSection( &dinput->crit );
1005                 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1006                 {
1007                     if (!dev->acquired || !dev->event_proc) continue;
1008
1009                     if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ) ||
1010                         IsEqualGUID( &dev->guid, &DInput_Wine_Keyboard_GUID ))
1011                         kbd_cnt++;
1012                     else
1013                         if (IsEqualGUID( &dev->guid, &GUID_SysMouse ) ||
1014                             IsEqualGUID( &dev->guid, &DInput_Wine_Mouse_GUID ))
1015                             mice_cnt++;
1016                 }
1017                 LeaveCriticalSection( &dinput->crit );
1018             }
1019             LeaveCriticalSection( &dinput_hook_crit );
1020
1021             if (kbd_cnt && !kbd_hook)
1022                 kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 );
1023             else if (!kbd_cnt && kbd_hook)
1024             {
1025                 UnhookWindowsHookEx( kbd_hook );
1026                 kbd_hook = NULL;
1027             }
1028
1029             if (mice_cnt && !mouse_hook)
1030                 mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 );
1031             else if (!mice_cnt && mouse_hook)
1032             {
1033                 UnhookWindowsHookEx( mouse_hook );
1034                 mouse_hook = NULL;
1035             }
1036         }
1037         TranslateMessage(&msg);
1038         DispatchMessageW(&msg);
1039     }
1040
1041     return 0;
1042 }
1043
1044 static DWORD hook_thread_id;
1045
1046 static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
1047 {
1048     0, 0, &dinput_hook_crit,
1049     { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
1050       0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
1051 };
1052 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
1053
1054 static BOOL check_hook_thread(void)
1055 {
1056     static HANDLE hook_thread;
1057
1058     EnterCriticalSection(&dinput_hook_crit);
1059
1060     TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list));
1061     if (!list_empty(&direct_input_list) && !hook_thread)
1062     {
1063         HANDLE event;
1064
1065         event = CreateEventW(NULL, FALSE, FALSE, NULL);
1066         hook_thread = CreateThread(NULL, 0, hook_thread_proc, &event, 0, &hook_thread_id);
1067         if (event && hook_thread)
1068         {
1069             HANDLE handles[2];
1070             handles[0] = event;
1071             handles[1] = hook_thread;
1072             WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1073         }
1074         LeaveCriticalSection(&dinput_hook_crit);
1075         CloseHandle(event);
1076     }
1077     else if (list_empty(&direct_input_list) && hook_thread)
1078     {
1079         DWORD tid = hook_thread_id;
1080
1081         hook_thread_id = 0;
1082         PostThreadMessageW(tid, WM_USER+0x10, 0, 0);
1083         LeaveCriticalSection(&dinput_hook_crit);
1084
1085         /* wait for hook thread to exit */
1086         WaitForSingleObject(hook_thread, INFINITE);
1087         CloseHandle(hook_thread);
1088         hook_thread = NULL;
1089     }
1090     else
1091         LeaveCriticalSection(&dinput_hook_crit);
1092
1093     return hook_thread_id != 0;
1094 }
1095
1096 void check_dinput_hooks(LPDIRECTINPUTDEVICE8A iface)
1097 {
1098     static HHOOK callwndproc_hook;
1099     static ULONG foreground_cnt;
1100     IDirectInputDeviceImpl *dev = (IDirectInputDeviceImpl *)iface;
1101
1102     EnterCriticalSection(&dinput_hook_crit);
1103
1104     if (dev->dwCoopLevel & DISCL_FOREGROUND)
1105     {
1106         if (dev->acquired)
1107             foreground_cnt++;
1108         else
1109             foreground_cnt--;
1110     }
1111
1112     if (foreground_cnt && !callwndproc_hook)
1113         callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc,
1114                                               DINPUT_instance, GetCurrentThreadId() );
1115     else if (!foreground_cnt && callwndproc_hook)
1116     {
1117         UnhookWindowsHookEx( callwndproc_hook );
1118         callwndproc_hook = NULL;
1119     }
1120
1121     PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 );
1122
1123     LeaveCriticalSection(&dinput_hook_crit);
1124 }