shell32: Indentation fix.
[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 "initguid.h"
50 #include "dinput_private.h"
51 #include "device_private.h"
52 #include "dinputd.h"
53
54 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
55
56 static const IDirectInput7AVtbl ddi7avt;
57 static const IDirectInput7WVtbl ddi7wvt;
58 static const IDirectInput8AVtbl ddi8avt;
59 static const IDirectInput8WVtbl ddi8wvt;
60 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt;
61
62 static inline IDirectInputImpl *impl_from_IDirectInput7A( IDirectInput7A *iface )
63 {
64     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7A_iface );
65 }
66
67 static inline IDirectInputImpl *impl_from_IDirectInput7W( IDirectInput7W *iface )
68 {
69     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7W_iface );
70 }
71
72 static inline IDirectInputImpl *impl_from_IDirectInput8A( IDirectInput8A *iface )
73 {
74     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8A_iface );
75 }
76
77 static inline IDirectInputImpl *impl_from_IDirectInput8W( IDirectInput8W *iface )
78 {
79     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8W_iface );
80 }
81
82 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
83 {
84     return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface);
85 }
86 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
87 {
88     return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface);
89 }
90
91 static const struct dinput_device *dinput_devices[] =
92 {
93     &mouse_device,
94     &keyboard_device,
95     &joystick_linuxinput_device,
96     &joystick_linux_device,
97     &joystick_osx_device
98 };
99 #define NB_DINPUT_DEVICES (sizeof(dinput_devices)/sizeof(dinput_devices[0]))
100
101 static HINSTANCE DINPUT_instance = NULL;
102
103 static BOOL check_hook_thread(void);
104 static CRITICAL_SECTION dinput_hook_crit;
105 static struct list direct_input_list = LIST_INIT( direct_input_list );
106
107 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion);
108 static void uninitialize_directinput_instance(IDirectInputImpl *This);
109
110 static HRESULT create_directinput_instance(REFIID riid, LPVOID *ppDI, IDirectInputImpl **out)
111 {
112     IDirectInputImpl *This = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectInputImpl) );
113     HRESULT hr;
114
115     if (!This)
116         return E_OUTOFMEMORY;
117
118     This->IDirectInput7A_iface.lpVtbl = &ddi7avt;
119     This->IDirectInput7W_iface.lpVtbl = &ddi7wvt;
120     This->IDirectInput8A_iface.lpVtbl = &ddi8avt;
121     This->IDirectInput8W_iface.lpVtbl = &ddi8wvt;
122     This->IDirectInputJoyConfig8_iface.lpVtbl = &JoyConfig8vt;
123
124     hr = IDirectInput_QueryInterface( &This->IDirectInput7A_iface, riid, ppDI );
125     if (FAILED(hr))
126     {
127         HeapFree( GetProcessHeap(), 0, This );
128         return hr;
129     }
130
131     if (out) *out = This;
132     return DI_OK;
133 }
134
135 /******************************************************************************
136  *      DirectInputCreateEx (DINPUT.@)
137  */
138 HRESULT WINAPI DirectInputCreateEx(
139         HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
140         LPUNKNOWN punkOuter)
141 {
142     IDirectInputImpl *This;
143     HRESULT hr;
144
145     TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter);
146
147     if (IsEqualGUID( &IID_IDirectInputA,  riid ) ||
148         IsEqualGUID( &IID_IDirectInput2A, riid ) ||
149         IsEqualGUID( &IID_IDirectInput7A, riid ) ||
150         IsEqualGUID( &IID_IDirectInputW,  riid ) ||
151         IsEqualGUID( &IID_IDirectInput2W, riid ) ||
152         IsEqualGUID( &IID_IDirectInput7W, riid ))
153     {
154         hr = create_directinput_instance(riid, ppDI, &This);
155         if (FAILED(hr))
156             return hr;
157     }
158     else
159         return DIERR_NOINTERFACE;
160
161     hr = IDirectInput_Initialize( &This->IDirectInput7A_iface, hinst, dwVersion );
162     if (FAILED(hr))
163     {
164         IDirectInput_Release( &This->IDirectInput7A_iface );
165         *ppDI = NULL;
166         return hr;
167     }
168
169     return DI_OK;
170 }
171
172 /******************************************************************************
173  *      DirectInputCreateA (DINPUT.@)
174  */
175 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
176 {
177     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter);
178 }
179
180 /******************************************************************************
181  *      DirectInputCreateW (DINPUT.@)
182  */
183 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter)
184 {
185     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter);
186 }
187
188 static const char *_dump_DIDEVTYPE_value(DWORD dwDevType)
189 {
190     switch (dwDevType) {
191         case 0: return "All devices";
192         case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
193         case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
194         case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
195         case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
196         default: return "Unknown";
197     }
198 }
199
200 static void _dump_EnumDevices_dwFlags(DWORD dwFlags)
201 {
202     if (TRACE_ON(dinput)) {
203         unsigned int   i;
204         static const struct {
205             DWORD       mask;
206             const char  *name;
207         } flags[] = {
208 #define FE(x) { x, #x}
209             FE(DIEDFL_ALLDEVICES),
210             FE(DIEDFL_ATTACHEDONLY),
211             FE(DIEDFL_FORCEFEEDBACK),
212             FE(DIEDFL_INCLUDEALIASES),
213             FE(DIEDFL_INCLUDEPHANTOMS),
214             FE(DIEDFL_INCLUDEHIDDEN)
215 #undef FE
216         };
217         TRACE(" flags: ");
218         if (dwFlags == 0) {
219             TRACE("DIEDFL_ALLDEVICES\n");
220             return;
221         }
222         for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
223             if (flags[i].mask & dwFlags)
224                 TRACE("%s ",flags[i].name);
225     }
226     TRACE("\n");
227 }
228
229 static void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat)
230 {
231     unsigned int i;
232
233     TRACE("diaf.dwSize = %d\n", lpdiActionFormat->dwSize);
234     TRACE("diaf.dwActionSize = %d\n", lpdiActionFormat->dwActionSize);
235     TRACE("diaf.dwDataSize = %d\n", lpdiActionFormat->dwDataSize);
236     TRACE("diaf.dwNumActions = %d\n", lpdiActionFormat->dwNumActions);
237     TRACE("diaf.rgoAction = %p\n", lpdiActionFormat->rgoAction);
238     TRACE("diaf.guidActionMap = %s\n", debugstr_guid(&lpdiActionFormat->guidActionMap));
239     TRACE("diaf.dwGenre = 0x%08x\n", lpdiActionFormat->dwGenre);
240     TRACE("diaf.dwBufferSize = %d\n", lpdiActionFormat->dwBufferSize);
241     TRACE("diaf.lAxisMin = %d\n", lpdiActionFormat->lAxisMin);
242     TRACE("diaf.lAxisMax = %d\n", lpdiActionFormat->lAxisMax);
243     TRACE("diaf.hInstString = %p\n", lpdiActionFormat->hInstString);
244     TRACE("diaf.ftTimeStamp ...\n");
245     TRACE("diaf.dwCRC = 0x%x\n", lpdiActionFormat->dwCRC);
246     TRACE("diaf.tszActionMap = %s\n", debugstr_a(lpdiActionFormat->tszActionMap));
247     for (i = 0; i < lpdiActionFormat->dwNumActions; i++)
248     {
249         TRACE("diaf.rgoAction[%u]:\n", i);
250         TRACE("\tuAppData=0x%lx\n", lpdiActionFormat->rgoAction[i].uAppData);
251         TRACE("\tdwSemantic=0x%08x\n", lpdiActionFormat->rgoAction[i].dwSemantic);
252         TRACE("\tdwFlags=0x%x\n", lpdiActionFormat->rgoAction[i].dwFlags);
253         TRACE("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName));
254         TRACE("\tguidInstance=%s\n", debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance));
255         TRACE("\tdwObjID=0x%x\n", lpdiActionFormat->rgoAction[i].dwObjID);
256         TRACE("\tdwHow=0x%x\n", lpdiActionFormat->rgoAction[i].dwHow);
257     }
258 }
259
260 void _copy_diactionformatAtoW(LPDIACTIONFORMATW to, LPDIACTIONFORMATA from)
261 {
262     int i;
263
264     to->dwSize = sizeof(DIACTIONFORMATW);
265     to->dwActionSize = sizeof(DIACTIONW);
266     to->dwDataSize = from->dwDataSize;
267     to->dwNumActions = from->dwNumActions;
268     to->guidActionMap = from->guidActionMap;
269     to->dwGenre = from->dwGenre;
270     to->dwBufferSize = from->dwBufferSize;
271     to->lAxisMin = from->lAxisMin;
272     to->lAxisMax = from->lAxisMax;
273     to->dwCRC = from->dwCRC;
274     to->ftTimeStamp = from->ftTimeStamp;
275
276     for (i=0; i < to->dwNumActions; i++)
277     {
278         to->rgoAction[i].uAppData = from->rgoAction[i].uAppData;
279         to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic;
280         to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags;
281         to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
282         to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
283         to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
284     }
285 }
286
287 void _copy_diactionformatWtoA(LPDIACTIONFORMATA to, LPDIACTIONFORMATW from)
288 {
289     int i;
290
291     to->dwSize = sizeof(DIACTIONFORMATA);
292     to->dwActionSize = sizeof(DIACTIONA);
293     to->dwDataSize = from->dwDataSize;
294     to->dwNumActions = from->dwNumActions;
295     to->guidActionMap = from->guidActionMap;
296     to->dwGenre = from->dwGenre;
297     to->dwBufferSize = from->dwBufferSize;
298     to->lAxisMin = from->lAxisMin;
299     to->lAxisMax = from->lAxisMax;
300     to->dwCRC = from->dwCRC;
301     to->ftTimeStamp = from->ftTimeStamp;
302
303     for (i=0; i < to->dwNumActions; i++)
304     {
305         to->rgoAction[i].uAppData = from->rgoAction[i].uAppData;
306         to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic;
307         to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags;
308         to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
309         to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
310         to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
311     }
312 }
313
314 /* diactionformat_priority
315  *
316  *  Given a DIACTIONFORMAT structure and a DI genre, returns the enumeration
317  *  priority. Joysticks should pass the game genre, and mouse or keyboard their
318  *  respective DI*_MASK
319  */
320 static DWORD diactionformat_priorityA(LPDIACTIONFORMATA lpdiaf, DWORD genre)
321 {
322     int i;
323     DWORD priorityFlags = 0;
324
325     /* If there's at least one action for the device it's priority 1 */
326     for(i=0; i < lpdiaf->dwNumActions; i++)
327         if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre)
328             priorityFlags |= DIEDBS_MAPPEDPRI1;
329
330     return priorityFlags;
331 }
332
333 static DWORD diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf, DWORD genre)
334 {
335     int i;
336     DWORD priorityFlags = 0;
337
338     /* If there's at least one action for the device it's priority 1 */
339     for(i=0; i < lpdiaf->dwNumActions; i++)
340         if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre)
341             priorityFlags |= DIEDBS_MAPPEDPRI1;
342
343     return priorityFlags;
344 }
345
346 /******************************************************************************
347  *      IDirectInputA_EnumDevices
348  */
349 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
350         LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
351         LPVOID pvRef, DWORD dwFlags)
352 {
353     IDirectInputImpl *This = impl_from_IDirectInput7A(iface);
354     DIDEVICEINSTANCEA devInstance;
355     unsigned int i;
356     int j, r;
357
358     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
359           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
360           lpCallback, pvRef, dwFlags);
361     _dump_EnumDevices_dwFlags(dwFlags);
362
363     if (!lpCallback ||
364         dwFlags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN) ||
365         (dwDevType > DI8DEVCLASS_GAMECTRL && dwDevType < DI8DEVTYPE_DEVICE) || dwDevType > DI8DEVTYPE_SUPPLEMENTAL)
366         return DIERR_INVALIDPARAM;
367
368     if (!This->initialized)
369         return DIERR_NOTINITIALIZED;
370
371     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
372         if (!dinput_devices[i]->enum_deviceA) continue;
373         for (j = 0, r = -1; r != 0; j++) {
374             devInstance.dwSize = sizeof(devInstance);
375             TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
376             if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
377                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
378                     return 0;
379             }
380         }
381     }
382     
383     return 0;
384 }
385 /******************************************************************************
386  *      IDirectInputW_EnumDevices
387  */
388 static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
389         LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
390         LPVOID pvRef, DWORD dwFlags) 
391 {
392     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
393     DIDEVICEINSTANCEW devInstance;
394     unsigned int i;
395     int j, r;
396
397     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
398           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
399           lpCallback, pvRef, dwFlags);
400     _dump_EnumDevices_dwFlags(dwFlags);
401
402     if (!lpCallback ||
403         dwFlags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN) ||
404         (dwDevType > DI8DEVCLASS_GAMECTRL && dwDevType < DI8DEVTYPE_DEVICE) || dwDevType > DI8DEVTYPE_SUPPLEMENTAL)
405         return DIERR_INVALIDPARAM;
406
407     if (!This->initialized)
408         return DIERR_NOTINITIALIZED;
409
410     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
411         if (!dinput_devices[i]->enum_deviceW) continue;
412         for (j = 0, r = -1; r != 0; j++) {
413             devInstance.dwSize = sizeof(devInstance);
414             TRACE("  - checking device %u ('%s')\n", i, dinput_devices[i]->name);
415             if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
416                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
417                     return 0;
418             }
419         }
420     }
421     
422     return 0;
423 }
424
425 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
426 {
427     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
428     ULONG ref = InterlockedIncrement(&This->ref);
429
430     TRACE( "(%p) incrementing from %d\n", This, ref - 1);
431     return ref;
432 }
433
434 static ULONG WINAPI IDirectInputWImpl_AddRef(LPDIRECTINPUT7W iface)
435 {
436     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
437     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
438 }
439
440 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
441 {
442     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
443     ULONG ref = InterlockedDecrement( &This->ref );
444
445     TRACE( "(%p) releasing from %d\n", This, ref + 1 );
446
447     if (ref == 0)
448     {
449         uninitialize_directinput_instance( This );
450         HeapFree( GetProcessHeap(), 0, This );
451     }
452
453     return ref;
454 }
455
456 static ULONG WINAPI IDirectInputWImpl_Release(LPDIRECTINPUT7W iface)
457 {
458     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
459     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
460 }
461
462 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj)
463 {
464     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
465
466     TRACE( "(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj );
467
468     if (!riid || !ppobj)
469         return E_POINTER;
470
471     if (IsEqualGUID( &IID_IUnknown, riid ) ||
472         IsEqualGUID( &IID_IDirectInputA,  riid ) ||
473         IsEqualGUID( &IID_IDirectInput2A, riid ) ||
474         IsEqualGUID( &IID_IDirectInput7A, riid ))
475     {
476         *ppobj = &This->IDirectInput7A_iface;
477         IUnknown_AddRef( (IUnknown*)*ppobj );
478
479         return DI_OK;
480     }
481
482     if (IsEqualGUID( &IID_IDirectInputW,  riid ) ||
483         IsEqualGUID( &IID_IDirectInput2W, riid ) ||
484         IsEqualGUID( &IID_IDirectInput7W, riid ))
485     {
486         *ppobj = &This->IDirectInput7W_iface;
487         IUnknown_AddRef( (IUnknown*)*ppobj );
488
489         return DI_OK;
490     }
491
492     if (IsEqualGUID( &IID_IDirectInput8A, riid ))
493     {
494         *ppobj = &This->IDirectInput8A_iface;
495         IUnknown_AddRef( (IUnknown*)*ppobj );
496
497         return DI_OK;
498     }
499
500     if (IsEqualGUID( &IID_IDirectInput8W, riid ))
501     {
502         *ppobj = &This->IDirectInput8W_iface;
503         IUnknown_AddRef( (IUnknown*)*ppobj );
504
505         return DI_OK;
506     }
507
508     if (IsEqualGUID( &IID_IDirectInputJoyConfig8, riid ))
509     {
510         *ppobj = &This->IDirectInputJoyConfig8_iface;
511         IUnknown_AddRef( (IUnknown*)*ppobj );
512
513         return DI_OK;
514     }
515
516     FIXME( "Unsupported interface: %s\n", debugstr_guid(riid));
517     *ppobj = NULL;
518     return E_NOINTERFACE;
519 }
520
521 static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj)
522 {
523     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
524     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
525 }
526
527 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion)
528 {
529     if (!This->initialized)
530     {
531         This->dwVersion = dwVersion;
532         This->evsequence = 1;
533
534         InitializeCriticalSection( &This->crit );
535         This->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectInputImpl*->crit");
536
537         list_init( &This->devices_list );
538
539         /* Add self to the list of the IDirectInputs */
540         EnterCriticalSection( &dinput_hook_crit );
541         list_add_head( &direct_input_list, &This->entry );
542         LeaveCriticalSection( &dinput_hook_crit );
543
544         This->initialized = TRUE;
545
546         if (!check_hook_thread())
547         {
548             uninitialize_directinput_instance( This );
549             return DIERR_GENERIC;
550         }
551     }
552
553     return DI_OK;
554 }
555
556 static void uninitialize_directinput_instance(IDirectInputImpl *This)
557 {
558     if (This->initialized)
559     {
560         /* Remove self from the list of the IDirectInputs */
561         EnterCriticalSection( &dinput_hook_crit );
562         list_remove( &This->entry );
563         LeaveCriticalSection( &dinput_hook_crit );
564
565         check_hook_thread();
566
567         This->crit.DebugInfo->Spare[0] = 0;
568         DeleteCriticalSection( &This->crit );
569
570         This->initialized = FALSE;
571     }
572 }
573
574 enum directinput_versions
575 {
576     DIRECTINPUT_VERSION_300 = 0x0300,
577     DIRECTINPUT_VERSION_500 = 0x0500,
578     DIRECTINPUT_VERSION_50A = 0x050A,
579     DIRECTINPUT_VERSION_5B2 = 0x05B2,
580     DIRECTINPUT_VERSION_602 = 0x0602,
581     DIRECTINPUT_VERSION_61A = 0x061A,
582     DIRECTINPUT_VERSION_700 = 0x0700,
583 };
584
585 static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD version)
586 {
587     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
588
589     TRACE("(%p)->(%p, 0x%04x)\n", iface, hinst, version);
590
591     if (!hinst)
592         return DIERR_INVALIDPARAM;
593     else if (version == 0)
594         return DIERR_NOTINITIALIZED;
595     else if (version > DIRECTINPUT_VERSION_700)
596         return DIERR_OLDDIRECTINPUTVERSION;
597     else if (version != DIRECTINPUT_VERSION_300 && version != DIRECTINPUT_VERSION_500 &&
598              version != DIRECTINPUT_VERSION_50A && version != DIRECTINPUT_VERSION_5B2 &&
599              version != DIRECTINPUT_VERSION_602 && version != DIRECTINPUT_VERSION_61A &&
600              version != DIRECTINPUT_VERSION_700 && version != DIRECTINPUT_VERSION)
601         return DIERR_BETADIRECTINPUTVERSION;
602
603     return initialize_directinput_instance(This, version);
604 }
605
606 static HRESULT WINAPI IDirectInputWImpl_Initialize(LPDIRECTINPUT7W iface, HINSTANCE hinst, DWORD x)
607 {
608     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
609     return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x );
610 }
611
612 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, REFGUID rguid)
613 {
614     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
615     HRESULT hr;
616     LPDIRECTINPUTDEVICEA device;
617
618     TRACE( "(%p)->(%s)\n", This, debugstr_guid(rguid) );
619
620     if (!rguid) return E_POINTER;
621     if (!This->initialized)
622         return DIERR_NOTINITIALIZED;
623
624     hr = IDirectInput_CreateDevice( iface, rguid, &device, NULL );
625     if (hr != DI_OK) return DI_NOTATTACHED;
626
627     IUnknown_Release( device );
628
629     return DI_OK;
630 }
631
632 static HRESULT WINAPI IDirectInputWImpl_GetDeviceStatus(LPDIRECTINPUT7W iface, REFGUID rguid)
633 {
634     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
635     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
636 }
637
638 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,
639                                                         HWND hwndOwner,
640                                                         DWORD dwFlags)
641 {
642     WCHAR control_exeW[] = {'c','o','n','t','r','o','l','.','e','x','e',0};
643     STARTUPINFOW si = {0};
644     PROCESS_INFORMATION pi;
645
646     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
647
648     TRACE( "(%p)->(%p, %08x)\n", This, hwndOwner, dwFlags );
649
650     if (hwndOwner && !IsWindow(hwndOwner))
651         return E_HANDLE;
652
653     if (dwFlags)
654         return DIERR_INVALIDPARAM;
655
656     if (!This->initialized)
657         return DIERR_NOTINITIALIZED;
658
659     if (!CreateProcessW(NULL, control_exeW, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
660         return HRESULT_FROM_WIN32(GetLastError());
661
662     return DI_OK;
663 }
664
665 static HRESULT WINAPI IDirectInputWImpl_RunControlPanel(LPDIRECTINPUT7W iface, HWND hwndOwner, DWORD dwFlags)
666 {
667     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
668     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
669 }
670
671 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
672                                                     LPCSTR pszName, LPGUID pguidInstance)
673 {
674     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
675
676     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance );
677
678     return DI_OK;
679 }
680
681 static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
682                                                     LPCWSTR pszName, LPGUID pguidInstance)
683 {
684     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
685
686     FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance );
687
688     return DI_OK;
689 }
690
691 static HRESULT create_device(IDirectInputImpl *This, REFGUID rguid, REFIID riid, LPVOID *pvOut, BOOL unicode)
692 {
693     unsigned int i;
694
695     if (pvOut)
696         *pvOut = NULL;
697
698     if (!rguid || !pvOut)
699         return E_POINTER;
700
701     if (!This->initialized)
702         return DIERR_NOTINITIALIZED;
703
704     /* Loop on all the devices to see if anyone matches the given GUID */
705     for (i = 0; i < NB_DINPUT_DEVICES; i++)
706     {
707         HRESULT ret;
708
709         if (!dinput_devices[i]->create_device) continue;
710         if ((ret = dinput_devices[i]->create_device(This, rguid, riid, pvOut, unicode)) == DI_OK)
711             return DI_OK;
712     }
713
714     WARN("invalid device GUID %s\n", debugstr_guid(rguid));
715     return DIERR_DEVICENOTREG;
716 }
717
718 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid,
719                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
720 {
721     IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
722
723     TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
724
725     return create_device(This, rguid, riid, pvOut, FALSE);
726 }
727
728 static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid,
729                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
730 {
731     IDirectInputImpl *This = impl_from_IDirectInput7W( iface );
732
733     TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
734
735     return create_device(This, rguid, riid, pvOut, TRUE);
736 }
737
738 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
739                                                      LPDIRECTINPUTDEVICEA* pdev, LPUNKNOWN punk)
740 {
741     return IDirectInput7AImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
742 }
743
744 static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
745                                                      LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk)
746 {
747     return IDirectInput7WImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
748 }
749
750 /*******************************************************************************
751  *      DirectInput8
752  */
753
754 static ULONG WINAPI IDirectInput8AImpl_AddRef(LPDIRECTINPUT8A iface)
755 {
756     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
757     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
758 }
759
760 static ULONG WINAPI IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface)
761 {
762     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
763     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
764 }
765
766 static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj)
767 {
768     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
769     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
770 }
771
772 static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj)
773 {
774     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
775     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
776 }
777
778 static ULONG WINAPI IDirectInput8AImpl_Release(LPDIRECTINPUT8A iface)
779 {
780     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
781     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
782 }
783
784 static ULONG WINAPI IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface)
785 {
786     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
787     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
788 }
789
790 static HRESULT WINAPI IDirectInput8AImpl_CreateDevice(LPDIRECTINPUT8A iface, REFGUID rguid,
791                                                       LPDIRECTINPUTDEVICE8A* pdev, LPUNKNOWN punk)
792 {
793     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
794     return IDirectInput7AImpl_CreateDeviceEx( &This->IDirectInput7A_iface, rguid, NULL, (LPVOID*)pdev, punk );
795 }
796
797 static HRESULT WINAPI IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface, REFGUID rguid,
798                                                       LPDIRECTINPUTDEVICE8W* pdev, LPUNKNOWN punk)
799 {
800     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
801     return IDirectInput7WImpl_CreateDeviceEx( &This->IDirectInput7W_iface, rguid, NULL, (LPVOID*)pdev, punk );
802 }
803
804 static HRESULT WINAPI IDirectInput8AImpl_EnumDevices(LPDIRECTINPUT8A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
805                                                      LPVOID pvRef, DWORD dwFlags)
806 {
807     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
808     return IDirectInputAImpl_EnumDevices( &This->IDirectInput7A_iface, dwDevType, lpCallback, pvRef, dwFlags );
809 }
810
811 static HRESULT WINAPI IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
812                                                      LPVOID pvRef, DWORD dwFlags)
813 {
814     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
815     return IDirectInputWImpl_EnumDevices( &This->IDirectInput7W_iface, dwDevType, lpCallback, pvRef, dwFlags );
816 }
817
818 static HRESULT WINAPI IDirectInput8AImpl_GetDeviceStatus(LPDIRECTINPUT8A iface, REFGUID rguid)
819 {
820     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
821     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
822 }
823
824 static HRESULT WINAPI IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface, REFGUID rguid)
825 {
826     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
827     return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid );
828 }
829
830 static HRESULT WINAPI IDirectInput8AImpl_RunControlPanel(LPDIRECTINPUT8A iface, HWND hwndOwner, DWORD dwFlags)
831 {
832     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
833     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
834 }
835
836 static HRESULT WINAPI IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface, HWND hwndOwner, DWORD dwFlags)
837 {
838     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
839     return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags );
840 }
841
842 static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface, HINSTANCE hinst, DWORD version)
843 {
844     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
845
846     TRACE("(%p)->(%p, 0x%04x)\n", iface, hinst, version);
847
848     if (!hinst)
849         return DIERR_INVALIDPARAM;
850     else if (version == 0)
851         return DIERR_NOTINITIALIZED;
852     else if (version < DIRECTINPUT_VERSION)
853         return DIERR_BETADIRECTINPUTVERSION;
854     else if (version > DIRECTINPUT_VERSION)
855         return DIERR_OLDDIRECTINPUTVERSION;
856
857     return initialize_directinput_instance(This, version);
858 }
859
860 static HRESULT WINAPI IDirectInput8WImpl_Initialize(LPDIRECTINPUT8W iface, HINSTANCE hinst, DWORD version)
861 {
862     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
863     return IDirectInput8AImpl_Initialize( &This->IDirectInput8A_iface, hinst, version );
864 }
865
866 static HRESULT WINAPI IDirectInput8AImpl_FindDevice(LPDIRECTINPUT8A iface, REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance)
867 {
868     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
869     return IDirectInput2AImpl_FindDevice( &This->IDirectInput7A_iface, rguid, pszName, pguidInstance );
870 }
871
872 static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance)
873 {
874     IDirectInputImpl *This = impl_from_IDirectInput8W( iface );
875     return IDirectInput2WImpl_FindDevice( &This->IDirectInput7W_iface, rguid, pszName, pguidInstance );
876 }
877
878 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
879       LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat,
880       LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,
881       LPVOID pvRef, DWORD dwFlags
882 )
883 {
884     static REFGUID guids[2] = { &GUID_SysKeyboard, &GUID_SysMouse };
885     static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK };
886     IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
887     DIDEVICEINSTANCEA didevi;
888     LPDIRECTINPUTDEVICE8A lpdid;
889     DWORD callbackFlags;
890     int i, j;
891
892
893     FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_a(ptszUserName), lpdiActionFormat,
894           lpCallback, pvRef, dwFlags);
895 #define X(x) if (dwFlags & x) FIXME("\tdwFlags |= "#x"\n");
896         X(DIEDBSFL_ATTACHEDONLY)
897         X(DIEDBSFL_THISUSER)
898         X(DIEDBSFL_FORCEFEEDBACK)
899         X(DIEDBSFL_AVAILABLEDEVICES)
900         X(DIEDBSFL_MULTIMICEKEYBOARDS)
901         X(DIEDBSFL_NONGAMINGDEVICES)
902 #undef X
903
904     _dump_diactionformatA(lpdiActionFormat);
905
906     didevi.dwSize = sizeof(didevi);
907
908     /* Enumerate all the joysticks */
909     for (i = 0; i < NB_DINPUT_DEVICES; i++)
910     {
911         BOOL enumSuccess;
912
913         if (!dinput_devices[i]->enum_deviceA) continue;
914
915         for (j = 0, enumSuccess = -1; enumSuccess != 0; j++)
916         {
917             TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
918
919             callbackFlags = diactionformat_priorityA(lpdiActionFormat, lpdiActionFormat->dwGenre);
920             /* Default behavior is to enumerate attached game controllers */
921             enumSuccess = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
922             if (enumSuccess)
923             {
924                 IDirectInput_CreateDevice(iface, &didevi.guidInstance, &lpdid, NULL);
925
926                 if (lpCallback(&didevi, lpdid, callbackFlags, 0, pvRef) == DIENUM_STOP)
927                     return DI_OK;
928             }
929         }
930     }
931
932     if (dwFlags & DIEDBSFL_FORCEFEEDBACK) return DI_OK;
933
934     /* Enumerate keyboard and mouse */
935     for(i=0; i < sizeof(guids)/sizeof(guids[0]); i++)
936     {
937         callbackFlags = diactionformat_priorityA(lpdiActionFormat, actionMasks[i]);
938
939         IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
940         IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
941
942         if (lpCallback(&didevi, lpdid, callbackFlags, sizeof(guids)/sizeof(guids[0]) - (i+1), pvRef) == DIENUM_STOP)
943             return DI_OK;
944     }
945
946     return DI_OK;
947 }
948
949 static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
950       LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat,
951       LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
952       LPVOID pvRef, DWORD dwFlags
953 )
954 {
955     static REFGUID guids[2] = { &GUID_SysKeyboard, &GUID_SysMouse };
956     static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK };
957     IDirectInputImpl *This = impl_from_IDirectInput8W(iface);
958     DIDEVICEINSTANCEW didevi;
959     LPDIRECTINPUTDEVICE8W lpdid;
960     DWORD callbackFlags;
961     int i, j;
962
963     FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat,
964           lpCallback, pvRef, dwFlags);
965
966     didevi.dwSize = sizeof(didevi);
967
968     /* Enumerate all the joysticks */
969     for (i = 0; i < NB_DINPUT_DEVICES; i++)
970     {
971         BOOL enumSuccess;
972
973         if (!dinput_devices[i]->enum_deviceW) continue;
974
975         for (j = 0, enumSuccess = -1; enumSuccess != 0; j++)
976         {
977             TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name);
978
979             callbackFlags = diactionformat_priorityW(lpdiActionFormat, lpdiActionFormat->dwGenre);
980             /* Default behavior is to enumerate attached game controllers */
981             enumSuccess = dinput_devices[i]->enum_deviceW(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
982             if (enumSuccess)
983             {
984                 IDirectInput_CreateDevice(iface, &didevi.guidInstance, &lpdid, NULL);
985
986                 if (lpCallback(&didevi, lpdid, callbackFlags, 0, pvRef) == DIENUM_STOP)
987                     return DI_OK;
988             }
989         }
990     }
991
992     if (dwFlags & DIEDBSFL_FORCEFEEDBACK) return DI_OK;
993
994     /* Enumerate keyboard and mouse */
995     for(i=0; i < sizeof(guids)/sizeof(guids[0]); i++)
996     {
997         callbackFlags = diactionformat_priorityW(lpdiActionFormat, actionMasks[i]);
998
999         IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
1000         IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
1001
1002         if (lpCallback(&didevi, lpdid, callbackFlags, sizeof(guids)/sizeof(guids[0]) - (i+1), pvRef) == DIENUM_STOP)
1003             return DI_OK;
1004     }
1005
1006     return DI_OK;
1007 }
1008
1009 static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices(
1010       LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
1011       LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
1012 )
1013 {
1014     IDirectInputImpl *This = impl_from_IDirectInput8W(iface);
1015
1016     FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
1017
1018     /* Call helper function in config.c to do the real work */
1019     return _configure_devices(iface, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
1020 }
1021
1022 static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
1023       LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
1024       LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
1025 )
1026 {
1027     IDirectInputImpl *This = impl_from_IDirectInput8A(iface);
1028     DIACTIONFORMATW diafW;
1029     DICONFIGUREDEVICESPARAMSW diCDParamsW;
1030     HRESULT hr;
1031     int i;
1032
1033      FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData);
1034
1035     /* Copy parameters */
1036     diCDParamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW);
1037     diCDParamsW.dwcFormats = lpdiCDParams->dwcFormats;
1038     diCDParamsW.lprgFormats = &diafW;
1039     diCDParamsW.hwnd = lpdiCDParams->hwnd;
1040
1041     diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiCDParams->lprgFormats->dwNumActions);
1042     _copy_diactionformatAtoW(&diafW, lpdiCDParams->lprgFormats);
1043
1044     /* Copy action names */
1045     for (i=0; i < diafW.dwNumActions; i++)
1046     {
1047         const char* from = lpdiCDParams->lprgFormats->rgoAction[i].u.lptszActionName;
1048         int len = MultiByteToWideChar(CP_ACP, 0, from , -1, NULL , 0);
1049         WCHAR *to = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
1050
1051         MultiByteToWideChar(CP_ACP, 0, from , -1, to , len);
1052         diafW.rgoAction[i].u.lptszActionName = to;
1053     }
1054
1055     hr = IDirectInput8WImpl_ConfigureDevices(&This->IDirectInput8W_iface, lpdiCallback, &diCDParamsW, dwFlags, pvRefData);
1056
1057     /* Copy back configuration */
1058     if (SUCCEEDED(hr))
1059         _copy_diactionformatWtoA(lpdiCDParams->lprgFormats, &diafW);
1060
1061     /* Free memory */
1062     for (i=0; i < diafW.dwNumActions; i++)
1063         HeapFree(GetProcessHeap(), 0, (void*) diafW.rgoAction[i].u.lptszActionName);
1064
1065     HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
1066
1067     return hr;
1068 }
1069
1070 /*****************************************************************************
1071  * IDirectInputJoyConfig8 interface
1072  */
1073
1074 static inline IDirectInputImpl *impl_from_IDirectInputJoyConfig8(IDirectInputJoyConfig8 *iface)
1075 {
1076     return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInputJoyConfig8_iface );
1077 }
1078
1079 static HRESULT WINAPI JoyConfig8Impl_QueryInterface(IDirectInputJoyConfig8 *iface, REFIID riid, void** ppobj)
1080 {
1081     IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
1082     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
1083 }
1084
1085 static ULONG WINAPI JoyConfig8Impl_AddRef(IDirectInputJoyConfig8 *iface)
1086 {
1087     IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
1088     return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface );
1089 }
1090
1091 static ULONG WINAPI JoyConfig8Impl_Release(IDirectInputJoyConfig8 *iface)
1092 {
1093     IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface );
1094     return IDirectInputAImpl_Release( &This->IDirectInput7A_iface );
1095 }
1096
1097 static HRESULT WINAPI JoyConfig8Impl_Acquire(IDirectInputJoyConfig8 *iface)
1098 {
1099     FIXME( "(%p): stub!\n", iface );
1100     return E_NOTIMPL;
1101 }
1102
1103 static HRESULT WINAPI JoyConfig8Impl_Unacquire(IDirectInputJoyConfig8 *iface)
1104 {
1105     FIXME( "(%p): stub!\n", iface );
1106     return E_NOTIMPL;
1107 }
1108
1109 static HRESULT WINAPI JoyConfig8Impl_SetCooperativeLevel(IDirectInputJoyConfig8 *iface, HWND hwnd, DWORD flags)
1110 {
1111     FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, hwnd, flags );
1112     return E_NOTIMPL;
1113 }
1114
1115 static HRESULT WINAPI JoyConfig8Impl_SendNotify(IDirectInputJoyConfig8 *iface)
1116 {
1117     FIXME( "(%p): stub!\n", iface );
1118     return E_NOTIMPL;
1119 }
1120
1121 static HRESULT WINAPI JoyConfig8Impl_EnumTypes(IDirectInputJoyConfig8 *iface, LPDIJOYTYPECALLBACK cb, void *ref)
1122 {
1123     FIXME( "(%p)->(%p, %p): stub!\n", iface, cb, ref );
1124     return E_NOTIMPL;
1125 }
1126
1127 static HRESULT WINAPI JoyConfig8Impl_GetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPDIJOYTYPEINFO info, DWORD flags)
1128 {
1129     FIXME( "(%p)->(%s, %p, 0x%08x): stub!\n", iface, debugstr_w(name), info, flags );
1130     return E_NOTIMPL;
1131 }
1132
1133 static HRESULT WINAPI JoyConfig8Impl_SetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPCDIJOYTYPEINFO info, DWORD flags,
1134                                                  LPWSTR new_name)
1135 {
1136     FIXME( "(%p)->(%s, %p, 0x%08x, %s): stub!\n", iface, debugstr_w(name), info, flags, debugstr_w(new_name) );
1137     return E_NOTIMPL;
1138 }
1139
1140 static HRESULT WINAPI JoyConfig8Impl_DeleteType(IDirectInputJoyConfig8 *iface, LPCWSTR name)
1141 {
1142     FIXME( "(%p)->(%s): stub!\n", iface, debugstr_w(name) );
1143     return E_NOTIMPL;
1144 }
1145
1146 static HRESULT WINAPI JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPDIJOYCONFIG info, DWORD flags)
1147 {
1148     IDirectInputImpl *di = impl_from_IDirectInputJoyConfig8(iface);
1149     UINT found = 0;
1150     int i, j, r;
1151
1152     FIXME("(%p)->(%d, %p, 0x%08x): semi-stub!\n", iface, id, info, flags);
1153
1154 #define X(x) if (flags & x) FIXME("\tflags |= "#x"\n");
1155     X(DIJC_GUIDINSTANCE)
1156     X(DIJC_REGHWCONFIGTYPE)
1157     X(DIJC_GAIN)
1158     X(DIJC_CALLOUT)
1159 #undef X
1160
1161     /* Enumerate all joysticks in order */
1162     for (i = 0; i < NB_DINPUT_DEVICES; i++)
1163     {
1164         if (!dinput_devices[i]->enum_deviceA) continue;
1165
1166         for (j = 0, r = -1; r != 0; j++)
1167         {
1168             DIDEVICEINSTANCEA dev;
1169             dev.dwSize = sizeof(dev);
1170             if ((r = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, 0, &dev, di->dwVersion, j)))
1171             {
1172                 /* Only take into account the chosen id */
1173                 if (found == id)
1174                 {
1175                     if (flags & DIJC_GUIDINSTANCE)
1176                         info->guidInstance = dev.guidInstance;
1177
1178                     return DI_OK;
1179                 }
1180                 found += 1;
1181             }
1182         }
1183     }
1184
1185     return DIERR_NOMOREITEMS;
1186 }
1187
1188 static HRESULT WINAPI JoyConfig8Impl_SetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPCDIJOYCONFIG info, DWORD flags)
1189 {
1190     FIXME( "(%p)->(%d, %p, 0x%08x): stub!\n", iface, id, info, flags );
1191     return E_NOTIMPL;
1192 }
1193
1194 static HRESULT WINAPI JoyConfig8Impl_DeleteConfig(IDirectInputJoyConfig8 *iface, UINT id)
1195 {
1196     FIXME( "(%p)->(%d): stub!\n", iface, id );
1197     return E_NOTIMPL;
1198 }
1199
1200 static HRESULT WINAPI JoyConfig8Impl_GetUserValues(IDirectInputJoyConfig8 *iface, LPDIJOYUSERVALUES info, DWORD flags)
1201 {
1202     FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags );
1203     return E_NOTIMPL;
1204 }
1205
1206 static HRESULT WINAPI JoyConfig8Impl_SetUserValues(IDirectInputJoyConfig8 *iface, LPCDIJOYUSERVALUES info, DWORD flags)
1207 {
1208     FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags );
1209     return E_NOTIMPL;
1210 }
1211
1212 static HRESULT WINAPI JoyConfig8Impl_AddNewHardware(IDirectInputJoyConfig8 *iface, HWND hwnd, REFGUID guid)
1213 {
1214     FIXME( "(%p)->(%p, %s): stub!\n", iface, hwnd, debugstr_guid(guid) );
1215     return E_NOTIMPL;
1216 }
1217
1218 static HRESULT WINAPI JoyConfig8Impl_OpenTypeKey(IDirectInputJoyConfig8 *iface, LPCWSTR name, DWORD security, PHKEY key)
1219 {
1220     FIXME( "(%p)->(%s, 0x%08x, %p): stub!\n", iface, debugstr_w(name), security, key );
1221     return E_NOTIMPL;
1222 }
1223
1224 static HRESULT WINAPI JoyConfig8Impl_OpenAppStatusKey(IDirectInputJoyConfig8 *iface, PHKEY key)
1225 {
1226     FIXME( "(%p)->(%p): stub!\n", iface, key );
1227     return E_NOTIMPL;
1228 }
1229
1230 static const IDirectInput7AVtbl ddi7avt = {
1231     IDirectInputAImpl_QueryInterface,
1232     IDirectInputAImpl_AddRef,
1233     IDirectInputAImpl_Release,
1234     IDirectInputAImpl_CreateDevice,
1235     IDirectInputAImpl_EnumDevices,
1236     IDirectInputAImpl_GetDeviceStatus,
1237     IDirectInputAImpl_RunControlPanel,
1238     IDirectInputAImpl_Initialize,
1239     IDirectInput2AImpl_FindDevice,
1240     IDirectInput7AImpl_CreateDeviceEx
1241 };
1242
1243 static const IDirectInput7WVtbl ddi7wvt = {
1244     IDirectInputWImpl_QueryInterface,
1245     IDirectInputWImpl_AddRef,
1246     IDirectInputWImpl_Release,
1247     IDirectInputWImpl_CreateDevice,
1248     IDirectInputWImpl_EnumDevices,
1249     IDirectInputWImpl_GetDeviceStatus,
1250     IDirectInputWImpl_RunControlPanel,
1251     IDirectInputWImpl_Initialize,
1252     IDirectInput2WImpl_FindDevice,
1253     IDirectInput7WImpl_CreateDeviceEx
1254 };
1255
1256 static const IDirectInput8AVtbl ddi8avt = {
1257     IDirectInput8AImpl_QueryInterface,
1258     IDirectInput8AImpl_AddRef,
1259     IDirectInput8AImpl_Release,
1260     IDirectInput8AImpl_CreateDevice,
1261     IDirectInput8AImpl_EnumDevices,
1262     IDirectInput8AImpl_GetDeviceStatus,
1263     IDirectInput8AImpl_RunControlPanel,
1264     IDirectInput8AImpl_Initialize,
1265     IDirectInput8AImpl_FindDevice,
1266     IDirectInput8AImpl_EnumDevicesBySemantics,
1267     IDirectInput8AImpl_ConfigureDevices
1268 };
1269
1270 static const IDirectInput8WVtbl ddi8wvt = {
1271     IDirectInput8WImpl_QueryInterface,
1272     IDirectInput8WImpl_AddRef,
1273     IDirectInput8WImpl_Release,
1274     IDirectInput8WImpl_CreateDevice,
1275     IDirectInput8WImpl_EnumDevices,
1276     IDirectInput8WImpl_GetDeviceStatus,
1277     IDirectInput8WImpl_RunControlPanel,
1278     IDirectInput8WImpl_Initialize,
1279     IDirectInput8WImpl_FindDevice,
1280     IDirectInput8WImpl_EnumDevicesBySemantics,
1281     IDirectInput8WImpl_ConfigureDevices
1282 };
1283
1284 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt =
1285 {
1286     JoyConfig8Impl_QueryInterface,
1287     JoyConfig8Impl_AddRef,
1288     JoyConfig8Impl_Release,
1289     JoyConfig8Impl_Acquire,
1290     JoyConfig8Impl_Unacquire,
1291     JoyConfig8Impl_SetCooperativeLevel,
1292     JoyConfig8Impl_SendNotify,
1293     JoyConfig8Impl_EnumTypes,
1294     JoyConfig8Impl_GetTypeInfo,
1295     JoyConfig8Impl_SetTypeInfo,
1296     JoyConfig8Impl_DeleteType,
1297     JoyConfig8Impl_GetConfig,
1298     JoyConfig8Impl_SetConfig,
1299     JoyConfig8Impl_DeleteConfig,
1300     JoyConfig8Impl_GetUserValues,
1301     JoyConfig8Impl_SetUserValues,
1302     JoyConfig8Impl_AddNewHardware,
1303     JoyConfig8Impl_OpenTypeKey,
1304     JoyConfig8Impl_OpenAppStatusKey
1305 };
1306
1307 /*******************************************************************************
1308  * DirectInput ClassFactory
1309  */
1310 typedef struct
1311 {
1312     /* IUnknown fields */
1313     IClassFactory IClassFactory_iface;
1314     LONG          ref;
1315 } IClassFactoryImpl;
1316
1317 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1318 {
1319         return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
1320 }
1321
1322 static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1323         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1324
1325         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1326         return E_NOINTERFACE;
1327 }
1328
1329 static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) {
1330         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1331         return InterlockedIncrement(&(This->ref));
1332 }
1333
1334 static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) {
1335         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1336         /* static class, won't be  freed */
1337         return InterlockedDecrement(&(This->ref));
1338 }
1339
1340 static HRESULT WINAPI DICF_CreateInstance(
1341         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1342 ) {
1343         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1344
1345         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1346         if ( IsEqualGUID( &IID_IUnknown, riid ) ||
1347              IsEqualGUID( &IID_IDirectInputA, riid ) ||
1348              IsEqualGUID( &IID_IDirectInputW, riid ) ||
1349              IsEqualGUID( &IID_IDirectInput2A, riid ) ||
1350              IsEqualGUID( &IID_IDirectInput2W, riid ) ||
1351              IsEqualGUID( &IID_IDirectInput7A, riid ) ||
1352              IsEqualGUID( &IID_IDirectInput7W, riid ) ) {
1353                 return create_directinput_instance(riid, ppobj, NULL);
1354         }
1355
1356         FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);    
1357         return E_NOINTERFACE;
1358 }
1359
1360 static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1361         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1362         FIXME("(%p)->(%d),stub!\n",This,dolock);
1363         return S_OK;
1364 }
1365
1366 static const IClassFactoryVtbl DICF_Vtbl = {
1367         DICF_QueryInterface,
1368         DICF_AddRef,
1369         DICF_Release,
1370         DICF_CreateInstance,
1371         DICF_LockServer
1372 };
1373 static IClassFactoryImpl DINPUT_CF = {{&DICF_Vtbl}, 1 };
1374
1375 /***********************************************************************
1376  *              DllCanUnloadNow (DINPUT.@)
1377  */
1378 HRESULT WINAPI DllCanUnloadNow(void)
1379 {
1380     return S_FALSE;
1381 }
1382
1383 /***********************************************************************
1384  *              DllGetClassObject (DINPUT.@)
1385  */
1386 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1387 {
1388     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1389     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1390         *ppv = &DINPUT_CF;
1391         IClassFactory_AddRef((IClassFactory*)*ppv);
1392     return S_OK;
1393     }
1394
1395     FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1396     return CLASS_E_CLASSNOTAVAILABLE;
1397 }
1398
1399 /***********************************************************************
1400  *              DllRegisterServer (DINPUT.@)
1401  */
1402 HRESULT WINAPI DllRegisterServer(void)
1403 {
1404     return __wine_register_resources( DINPUT_instance );
1405 }
1406
1407 /***********************************************************************
1408  *              DllUnregisterServer (DINPUT.@)
1409  */
1410 HRESULT WINAPI DllUnregisterServer(void)
1411 {
1412     return __wine_unregister_resources( DINPUT_instance );
1413 }
1414
1415 /******************************************************************************
1416  *      DInput hook thread
1417  */
1418
1419 static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
1420 {
1421     IDirectInputImpl *dinput;
1422     int skip = 0;
1423
1424     if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
1425
1426     EnterCriticalSection( &dinput_hook_crit );
1427     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1428     {
1429         IDirectInputDeviceImpl *dev;
1430
1431         EnterCriticalSection( &dinput->crit );
1432         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1433             if (dev->acquired && dev->event_proc)
1434             {
1435                 TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
1436                 skip |= dev->event_proc( &dev->IDirectInputDevice8A_iface, wparam, lparam );
1437             }
1438         LeaveCriticalSection( &dinput->crit );
1439     }
1440     LeaveCriticalSection( &dinput_hook_crit );
1441
1442     return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam );
1443 }
1444
1445 static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam )
1446 {
1447     CWPSTRUCT *msg = (CWPSTRUCT *)lparam;
1448     IDirectInputImpl *dinput;
1449     HWND foreground;
1450
1451     if (code != HC_ACTION || (msg->message != WM_KILLFOCUS &&
1452         msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE))
1453         return CallNextHookEx( 0, code, wparam, lparam );
1454
1455     foreground = GetForegroundWindow();
1456
1457     EnterCriticalSection( &dinput_hook_crit );
1458
1459     LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1460     {
1461         IDirectInputDeviceImpl *dev;
1462
1463         EnterCriticalSection( &dinput->crit );
1464         LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1465         {
1466             if (!dev->acquired) continue;
1467
1468             if (msg->hwnd == dev->win && msg->hwnd != foreground)
1469             {
1470                 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev );
1471                 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8A_iface );
1472             }
1473         }
1474         LeaveCriticalSection( &dinput->crit );
1475     }
1476     LeaveCriticalSection( &dinput_hook_crit );
1477
1478     return CallNextHookEx( 0, code, wparam, lparam );
1479 }
1480
1481 static DWORD WINAPI hook_thread_proc(void *param)
1482 {
1483     static HHOOK kbd_hook, mouse_hook;
1484     MSG msg;
1485
1486     /* Force creation of the message queue */
1487     PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
1488     SetEvent(*(LPHANDLE)param);
1489
1490     while (GetMessageW( &msg, 0, 0, 0 ))
1491     {
1492         UINT kbd_cnt = 0, mice_cnt = 0;
1493
1494         if (msg.message == WM_USER+0x10)
1495         {
1496             IDirectInputImpl *dinput;
1497
1498             TRACE( "Processing hook change notification lp:%ld\n", msg.lParam );
1499
1500             if (!msg.wParam && !msg.lParam)
1501             {
1502                 if (kbd_hook) UnhookWindowsHookEx( kbd_hook );
1503                 if (mouse_hook) UnhookWindowsHookEx( mouse_hook );
1504                 kbd_hook = mouse_hook = NULL;
1505                 break;
1506             }
1507
1508             EnterCriticalSection( &dinput_hook_crit );
1509
1510             /* Count acquired keyboards and mice*/
1511             LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
1512             {
1513                 IDirectInputDeviceImpl *dev;
1514
1515                 EnterCriticalSection( &dinput->crit );
1516                 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
1517                 {
1518                     if (!dev->acquired || !dev->event_proc) continue;
1519
1520                     if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ) ||
1521                         IsEqualGUID( &dev->guid, &DInput_Wine_Keyboard_GUID ))
1522                         kbd_cnt++;
1523                     else
1524                         if (IsEqualGUID( &dev->guid, &GUID_SysMouse ) ||
1525                             IsEqualGUID( &dev->guid, &DInput_Wine_Mouse_GUID ))
1526                             mice_cnt++;
1527                 }
1528                 LeaveCriticalSection( &dinput->crit );
1529             }
1530             LeaveCriticalSection( &dinput_hook_crit );
1531
1532             if (kbd_cnt && !kbd_hook)
1533                 kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 );
1534             else if (!kbd_cnt && kbd_hook)
1535             {
1536                 UnhookWindowsHookEx( kbd_hook );
1537                 kbd_hook = NULL;
1538             }
1539
1540             if (mice_cnt && !mouse_hook)
1541                 mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 );
1542             else if (!mice_cnt && mouse_hook)
1543             {
1544                 UnhookWindowsHookEx( mouse_hook );
1545                 mouse_hook = NULL;
1546             }
1547         }
1548         TranslateMessage(&msg);
1549         DispatchMessageW(&msg);
1550     }
1551
1552     return 0;
1553 }
1554
1555 static DWORD hook_thread_id;
1556
1557 static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
1558 {
1559     0, 0, &dinput_hook_crit,
1560     { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
1561       0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
1562 };
1563 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
1564
1565 static BOOL check_hook_thread(void)
1566 {
1567     static HANDLE hook_thread;
1568
1569     EnterCriticalSection(&dinput_hook_crit);
1570
1571     TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list));
1572     if (!list_empty(&direct_input_list) && !hook_thread)
1573     {
1574         HANDLE event;
1575
1576         event = CreateEventW(NULL, FALSE, FALSE, NULL);
1577         hook_thread = CreateThread(NULL, 0, hook_thread_proc, &event, 0, &hook_thread_id);
1578         if (event && hook_thread)
1579         {
1580             HANDLE handles[2];
1581             handles[0] = event;
1582             handles[1] = hook_thread;
1583             WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1584         }
1585         LeaveCriticalSection(&dinput_hook_crit);
1586         CloseHandle(event);
1587     }
1588     else if (list_empty(&direct_input_list) && hook_thread)
1589     {
1590         DWORD tid = hook_thread_id;
1591
1592         hook_thread_id = 0;
1593         PostThreadMessageW(tid, WM_USER+0x10, 0, 0);
1594         LeaveCriticalSection(&dinput_hook_crit);
1595
1596         /* wait for hook thread to exit */
1597         WaitForSingleObject(hook_thread, INFINITE);
1598         CloseHandle(hook_thread);
1599         hook_thread = NULL;
1600     }
1601     else
1602         LeaveCriticalSection(&dinput_hook_crit);
1603
1604     return hook_thread_id != 0;
1605 }
1606
1607 void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface)
1608 {
1609     static HHOOK callwndproc_hook;
1610     static ULONG foreground_cnt;
1611     IDirectInputDeviceImpl *dev = impl_from_IDirectInputDevice8W(iface);
1612
1613     EnterCriticalSection(&dinput_hook_crit);
1614
1615     if (dev->dwCoopLevel & DISCL_FOREGROUND)
1616     {
1617         if (dev->acquired)
1618             foreground_cnt++;
1619         else
1620             foreground_cnt--;
1621     }
1622
1623     if (foreground_cnt && !callwndproc_hook)
1624         callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc,
1625                                               DINPUT_instance, GetCurrentThreadId() );
1626     else if (!foreground_cnt && callwndproc_hook)
1627     {
1628         UnhookWindowsHookEx( callwndproc_hook );
1629         callwndproc_hook = NULL;
1630     }
1631
1632     PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 );
1633
1634     LeaveCriticalSection(&dinput_hook_crit);
1635 }
1636
1637 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv)
1638 {
1639     switch(reason)
1640     {
1641       case DLL_PROCESS_ATTACH:
1642         DisableThreadLibraryCalls(inst);
1643         DINPUT_instance = inst;
1644         break;
1645       case DLL_PROCESS_DETACH:
1646         DeleteCriticalSection(&dinput_hook_crit);
1647         break;
1648     }
1649     return TRUE;
1650 }