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