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