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