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