crypt32: Implement CryptMsgUpdate for data messages opened to encode.
[wine] / dlls / dinput / dinput_main.c
1 /*              DirectInput
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2002 TransGaming Technologies Inc.
6  *
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 /* Status:
23  *
24  * - Tomb Raider 2 Demo:
25  *   Playable using keyboard only.
26  * - WingCommander Prophecy Demo:
27  *   Doesn't get Input Focus.
28  *
29  * - Fallout : works great in X and DGA mode
30  */
31
32 #include "config.h"
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <string.h>
36
37 #define COBJMACROS
38
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winuser.h"
44 #include "winerror.h"
45 #include "dinput_private.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
48
49 static const IDirectInput7AVtbl ddi7avt;
50 static const IDirectInput7WVtbl ddi7wvt;
51 static const IDirectInput8AVtbl ddi8avt;
52 static const IDirectInput8WVtbl ddi8wvt;
53
54 static const struct dinput_device *dinput_devices[] =
55 {
56     &mouse_device,
57     &keyboard_device,
58     &joystick_linuxinput_device,
59     &joystick_linux_device
60 };
61 #define NB_DINPUT_DEVICES (sizeof(dinput_devices)/sizeof(dinput_devices[0]))
62
63 HINSTANCE DINPUT_instance = NULL;
64
65 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv)
66 {
67     switch(reason)
68     {
69       case DLL_PROCESS_ATTACH:
70         DisableThreadLibraryCalls(inst);
71         DINPUT_instance = inst;
72         break;
73       case DLL_PROCESS_DETACH:
74         break;
75     }
76     return TRUE;
77 }
78
79 static BOOL create_hook_thread(void);
80 static void release_hook_thread(void);
81
82 /******************************************************************************
83  *      DirectInputCreateEx (DINPUT.@)
84  */
85 HRESULT WINAPI DirectInputCreateEx(
86         HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
87         LPUNKNOWN punkOuter) 
88 {
89     IDirectInputImpl* This;
90     HRESULT res = DIERR_OLDDIRECTINPUTVERSION;
91     LPCVOID vtable = NULL;
92
93     TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter);
94
95     if (IsEqualGUID(&IID_IDirectInputA,riid) ||
96         IsEqualGUID(&IID_IDirectInput2A,riid) ||
97         IsEqualGUID(&IID_IDirectInput7A,riid))
98     {
99         vtable = &ddi7avt;
100         res = DI_OK;
101     }
102
103     if (IsEqualGUID(&IID_IDirectInputW,riid) ||
104         IsEqualGUID(&IID_IDirectInput2W,riid) ||
105         IsEqualGUID(&IID_IDirectInput7W,riid))
106     {
107         vtable = &ddi7wvt;
108         res = DI_OK;
109     }
110
111     if (IsEqualGUID(&IID_IDirectInput8A,riid))
112     {
113         vtable = &ddi8avt;
114         res = DI_OK;
115     }
116
117     if (IsEqualGUID(&IID_IDirectInput8W,riid))
118     {
119         vtable = &ddi8wvt;
120         res = DI_OK;
121     }
122
123     if (res == DI_OK && !create_hook_thread()) res = DIERR_GENERIC;
124     if (res == DI_OK)
125     {
126         This = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectInputImpl));
127         This->lpVtbl = vtable;
128         This->ref = 1;
129         This->dwVersion = dwVersion;
130         This->evsequence = 1;
131         *ppDI = This;
132     }
133     return res;
134 }
135
136 /******************************************************************************
137  *      DirectInputCreateA (DINPUT.@)
138  */
139 HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
140 {
141     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter);
142 }
143
144 /******************************************************************************
145  *      DirectInputCreateW (DINPUT.@)
146  */
147 HRESULT WINAPI DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter)
148 {
149     return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter);
150 }
151
152 static const char *_dump_DIDEVTYPE_value(DWORD dwDevType) {
153     switch (dwDevType) {
154         case 0: return "All devices";
155         case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE";
156         case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD";
157         case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK";
158         case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE";
159         default: return "Unknown";
160     }
161 }
162
163 static void _dump_EnumDevices_dwFlags(DWORD dwFlags) {
164     if (TRACE_ON(dinput)) {
165         unsigned int   i;
166         static const struct {
167             DWORD       mask;
168             const char  *name;
169         } flags[] = {
170 #define FE(x) { x, #x}
171             FE(DIEDFL_ALLDEVICES),
172             FE(DIEDFL_ATTACHEDONLY),
173             FE(DIEDFL_FORCEFEEDBACK),
174             FE(DIEDFL_INCLUDEALIASES),
175             FE(DIEDFL_INCLUDEPHANTOMS)
176 #undef FE
177         };
178         if (dwFlags == 0) {
179             DPRINTF("DIEDFL_ALLDEVICES");
180             return;
181         }
182         for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
183             if (flags[i].mask & dwFlags)
184                 DPRINTF("%s ",flags[i].name);
185     }
186 }
187
188 /******************************************************************************
189  *      IDirectInputA_EnumDevices
190  */
191 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
192         LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
193         LPVOID pvRef, DWORD dwFlags)
194 {
195     IDirectInputImpl *This = (IDirectInputImpl *)iface;
196     DIDEVICEINSTANCEA devInstance;
197     int i, j, r;
198     
199     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
200           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
201           lpCallback, pvRef, dwFlags);
202     TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n");
203
204     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
205         if (!dinput_devices[i]->enum_deviceA) continue;
206         for (j = 0, r = -1; r != 0; j++) {
207             devInstance.dwSize = sizeof(devInstance);
208             TRACE("  - checking device %d ('%s')\n", i, dinput_devices[i]->name);
209             if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
210                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
211                     return 0;
212             }
213         }
214     }
215     
216     return 0;
217 }
218 /******************************************************************************
219  *      IDirectInputW_EnumDevices
220  */
221 static HRESULT WINAPI IDirectInputWImpl_EnumDevices(
222         LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback,
223         LPVOID pvRef, DWORD dwFlags) 
224 {
225     IDirectInputImpl *This = (IDirectInputImpl *)iface;
226     DIDEVICEINSTANCEW devInstance;
227     int i, j, r;
228     
229     TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n",
230           This, dwDevType, _dump_DIDEVTYPE_value(dwDevType),
231           lpCallback, pvRef, dwFlags);
232     TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n");
233
234     for (i = 0; i < NB_DINPUT_DEVICES; i++) {
235         if (!dinput_devices[i]->enum_deviceW) continue;
236         for (j = 0, r = -1; r != 0; j++) {
237             devInstance.dwSize = sizeof(devInstance);
238             TRACE("  - checking device %d ('%s')\n", i, dinput_devices[i]->name);
239             if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) {
240                 if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
241                     return 0;
242             }
243         }
244     }
245     
246     return 0;
247 }
248
249 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
250 {
251         IDirectInputImpl *This = (IDirectInputImpl *)iface;
252         return InterlockedIncrement((&This->ref));
253 }
254
255 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
256 {
257         IDirectInputImpl *This = (IDirectInputImpl *)iface;
258         ULONG ref;
259         ref = InterlockedDecrement(&(This->ref));
260         if (ref == 0)
261         {
262             HeapFree(GetProcessHeap(), 0, This);
263             release_hook_thread();
264         }
265         return ref;
266 }
267
268 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj) {
269         IDirectInputImpl *This = (IDirectInputImpl *)iface;
270
271         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
272         if (IsEqualGUID(&IID_IUnknown,riid) ||
273             IsEqualGUID(&IID_IDirectInputA,riid) ||
274             IsEqualGUID(&IID_IDirectInput2A,riid) ||
275             IsEqualGUID(&IID_IDirectInput7A,riid)) {
276                 IDirectInputAImpl_AddRef(iface);
277                 *ppobj = This;
278                 return 0;
279         }
280         TRACE("Unsupported interface !\n");
281         return E_FAIL;
282 }
283
284 static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj) {
285         IDirectInputImpl *This = (IDirectInputImpl *)iface;
286
287         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
288         if (IsEqualGUID(&IID_IUnknown,riid) ||
289             IsEqualGUID(&IID_IDirectInputW,riid) ||
290             IsEqualGUID(&IID_IDirectInput2W,riid) ||
291             IsEqualGUID(&IID_IDirectInput7W,riid)) {
292                 IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface);
293                 *ppobj = This;
294                 return 0;
295         }
296         TRACE("Unsupported interface !\n");
297         return E_FAIL;
298 }
299
300 static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD x) {
301         TRACE("(this=%p,%p,%x)\n",iface, hinst, x);
302         
303         /* Initialize can return: DIERR_BETADIRECTINPUTVERSION, DIERR_OLDDIRECTINPUTVERSION and DI_OK.
304          * Since we already initialized the device, return DI_OK. In the past we returned DIERR_ALREADYINITIALIZED
305          * which broke applications like Tomb Raider Legend because it isn't a legal return value.
306          */
307         return DI_OK;
308 }
309
310 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface,
311                                                         REFGUID rguid) {
312   IDirectInputImpl *This = (IDirectInputImpl *)iface;
313
314   FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid));
315
316   return DI_OK;
317 }
318
319 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,
320                                                         HWND hwndOwner,
321                                                         DWORD dwFlags) {
322   IDirectInputImpl *This = (IDirectInputImpl *)iface;
323   FIXME("(%p)->(%p,%08x): stub\n",This, hwndOwner, dwFlags);
324
325   return DI_OK;
326 }
327
328 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
329                                                     LPCSTR pszName, LPGUID pguidInstance) {
330   IDirectInputImpl *This = (IDirectInputImpl *)iface;
331   FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance);
332
333   return DI_OK;
334 }
335
336 static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
337                                                     LPCWSTR pszName, LPGUID pguidInstance) {
338   IDirectInputImpl *This = (IDirectInputImpl *)iface;
339   FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance);
340
341   return DI_OK;
342 }
343
344 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid,
345                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
346 {
347   IDirectInputImpl *This = (IDirectInputImpl *)iface;
348   HRESULT ret_value = DIERR_DEVICENOTREG;
349   int i;
350
351   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
352
353   if (!rguid || !pvOut) return E_POINTER;
354
355   /* Loop on all the devices to see if anyone matches the given GUID */
356   for (i = 0; i < NB_DINPUT_DEVICES; i++) {
357     HRESULT ret;
358     if (!dinput_devices[i]->create_deviceA) continue;
359     if ((ret = dinput_devices[i]->create_deviceA(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK)
360       return DI_OK;
361
362     if (ret == DIERR_NOINTERFACE)
363       ret_value = DIERR_NOINTERFACE;
364   }
365
366   return ret_value;
367 }
368
369 static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid,
370                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
371 {
372   IDirectInputImpl *This = (IDirectInputImpl *)iface;
373   HRESULT ret_value = DIERR_DEVICENOTREG;
374   int i;
375
376   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
377
378   if (!rguid || !pvOut) return E_POINTER;
379
380   /* Loop on all the devices to see if anyone matches the given GUID */
381   for (i = 0; i < NB_DINPUT_DEVICES; i++) {
382     HRESULT ret;
383     if (!dinput_devices[i]->create_deviceW) continue;
384     if ((ret = dinput_devices[i]->create_deviceW(This, rguid, riid, (LPDIRECTINPUTDEVICEW*) pvOut)) == DI_OK)
385       return DI_OK;
386
387     if (ret == DIERR_NOINTERFACE)
388       ret_value = DIERR_NOINTERFACE;
389   }
390
391   return ret_value;
392 }
393
394 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface, REFGUID rguid,
395                                                      LPDIRECTINPUTDEVICEA* pdev, LPUNKNOWN punk)
396 {
397     return IDirectInput7AImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
398 }
399
400 static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid,
401                                                      LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk)
402 {
403     return IDirectInput7WImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk);
404 }
405
406 static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj) {
407       IDirectInputImpl *This = (IDirectInputImpl *)iface;
408
409       TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
410       if (IsEqualGUID(&IID_IUnknown,riid) ||
411           IsEqualGUID(&IID_IDirectInput8A,riid)) {
412               IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface);
413               *ppobj = This;
414               return 0;
415       }
416       TRACE("Unsupported interface !\n");
417       return E_NOINTERFACE;
418 }
419
420 static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj) {
421       IDirectInputImpl *This = (IDirectInputImpl *)iface;
422
423       TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
424       if (IsEqualGUID(&IID_IUnknown,riid) ||
425           IsEqualGUID(&IID_IDirectInput8W,riid)) {
426               IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface);
427               *ppobj = This;
428               return 0;
429       }
430       TRACE("Unsupported interface !\n");
431       return E_NOINTERFACE;
432 }
433
434 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
435       LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat,
436       LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,
437       LPVOID pvRef, DWORD dwFlags
438 )
439 {
440       IDirectInputImpl *This = (IDirectInputImpl *)iface;
441
442       FIXME("(this=%p,%s,%p,%p,%p,%04x): stub\n", This, ptszUserName, lpdiActionFormat,
443             lpCallback, pvRef, dwFlags);
444       return 0;
445 }
446
447 static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
448       LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat,
449       LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
450       LPVOID pvRef, DWORD dwFlags
451 )
452 {
453       IDirectInputImpl *This = (IDirectInputImpl *)iface;
454
455       FIXME("(this=%p,%s,%p,%p,%p,%04x): stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat,
456             lpCallback, pvRef, dwFlags);
457       return 0;
458 }
459
460 static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
461       LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
462       LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
463 )
464 {
465       IDirectInputImpl *This = (IDirectInputImpl *)iface;
466
467       FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams,
468             dwFlags, pvRefData);
469       return 0;
470 }
471
472 static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices(
473       LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
474       LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData
475 )
476 {
477       IDirectInputImpl *This = (IDirectInputImpl *)iface;
478
479       FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams,
480             dwFlags, pvRefData);
481       return 0;
482 }
483
484 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
485 # define XCAST(fun)   (typeof(ddi7avt.fun))
486 #else
487 # define XCAST(fun)     (void*)
488 #endif
489
490 static const IDirectInput7AVtbl ddi7avt = {
491         XCAST(QueryInterface)IDirectInputAImpl_QueryInterface,
492         XCAST(AddRef)IDirectInputAImpl_AddRef,
493         XCAST(Release)IDirectInputAImpl_Release,
494         XCAST(CreateDevice)IDirectInputAImpl_CreateDevice,
495         XCAST(EnumDevices)IDirectInputAImpl_EnumDevices,
496         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
497         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
498         XCAST(Initialize)IDirectInputAImpl_Initialize,
499         XCAST(FindDevice)IDirectInput2AImpl_FindDevice,
500         XCAST(CreateDeviceEx)IDirectInput7AImpl_CreateDeviceEx
501 };
502
503 #undef XCAST
504 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
505 # define XCAST(fun)   (typeof(ddi7wvt.fun))
506 #else
507 # define XCAST(fun)     (void*)
508 #endif
509
510 static const IDirectInput7WVtbl ddi7wvt = {
511         XCAST(QueryInterface)IDirectInputWImpl_QueryInterface,
512         XCAST(AddRef)IDirectInputAImpl_AddRef,
513         XCAST(Release)IDirectInputAImpl_Release,
514         XCAST(CreateDevice)IDirectInputWImpl_CreateDevice,
515         XCAST(EnumDevices)IDirectInputWImpl_EnumDevices,
516         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
517         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
518         XCAST(Initialize)IDirectInputAImpl_Initialize,
519         XCAST(FindDevice)IDirectInput2WImpl_FindDevice,
520         XCAST(CreateDeviceEx)IDirectInput7WImpl_CreateDeviceEx
521 };
522 #undef XCAST
523
524 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
525 # define XCAST(fun)     (typeof(ddi8avt.fun))
526 #else
527 # define XCAST(fun)     (void*)
528 #endif
529
530 static const IDirectInput8AVtbl ddi8avt = {
531         XCAST(QueryInterface)IDirectInput8AImpl_QueryInterface,
532         XCAST(AddRef)IDirectInputAImpl_AddRef,
533         XCAST(Release)IDirectInputAImpl_Release,
534         XCAST(CreateDevice)IDirectInputAImpl_CreateDevice,
535         XCAST(EnumDevices)IDirectInputAImpl_EnumDevices,
536         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
537         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
538         XCAST(Initialize)IDirectInputAImpl_Initialize,
539         XCAST(FindDevice)IDirectInput2AImpl_FindDevice,
540         XCAST(EnumDevicesBySemantics)IDirectInput8AImpl_EnumDevicesBySemantics,
541         XCAST(ConfigureDevices)IDirectInput8AImpl_ConfigureDevices
542 };
543 #undef XCAST
544
545 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
546 # define XCAST(fun)     (typeof(ddi8wvt.fun))
547 #else
548 # define XCAST(fun)     (void*)
549 #endif
550 static const IDirectInput8WVtbl ddi8wvt = {
551         XCAST(QueryInterface)IDirectInput8WImpl_QueryInterface,
552         XCAST(AddRef)IDirectInputAImpl_AddRef,
553         XCAST(Release)IDirectInputAImpl_Release,
554         XCAST(CreateDevice)IDirectInputWImpl_CreateDevice,
555         XCAST(EnumDevices)IDirectInputWImpl_EnumDevices,
556         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
557         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
558         XCAST(Initialize)IDirectInputAImpl_Initialize,
559         XCAST(FindDevice)IDirectInput2WImpl_FindDevice,
560         XCAST(EnumDevicesBySemantics)IDirectInput8WImpl_EnumDevicesBySemantics,
561         XCAST(ConfigureDevices)IDirectInput8WImpl_ConfigureDevices
562 };
563 #undef XCAST
564
565 /*******************************************************************************
566  * DirectInput ClassFactory
567  */
568 typedef struct
569 {
570     /* IUnknown fields */
571     const IClassFactoryVtbl    *lpVtbl;
572     LONG                        ref;
573 } IClassFactoryImpl;
574
575 static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
576         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
577
578         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
579         return E_NOINTERFACE;
580 }
581
582 static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) {
583         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
584         return InterlockedIncrement(&(This->ref));
585 }
586
587 static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) {
588         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
589         /* static class, won't be  freed */
590         return InterlockedDecrement(&(This->ref));
591 }
592
593 static HRESULT WINAPI DICF_CreateInstance(
594         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
595 ) {
596         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
597
598         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
599         if ( IsEqualGUID( &IID_IDirectInputA, riid ) ||
600              IsEqualGUID( &IID_IDirectInputW, riid ) ||
601              IsEqualGUID( &IID_IDirectInput2A, riid ) ||
602              IsEqualGUID( &IID_IDirectInput2W, riid ) ||
603              IsEqualGUID( &IID_IDirectInput7A, riid ) ||
604              IsEqualGUID( &IID_IDirectInput7W, riid ) ||
605              IsEqualGUID( &IID_IDirectInput8A, riid ) ||
606              IsEqualGUID( &IID_IDirectInput8W, riid ) ) {
607                 /* FIXME: reuse already created dinput if present? */
608                 return DirectInputCreateEx(0,0,riid,ppobj,pOuter);
609         }
610
611         FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);    
612         return E_NOINTERFACE;
613 }
614
615 static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
616         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
617         FIXME("(%p)->(%d),stub!\n",This,dolock);
618         return S_OK;
619 }
620
621 static const IClassFactoryVtbl DICF_Vtbl = {
622         DICF_QueryInterface,
623         DICF_AddRef,
624         DICF_Release,
625         DICF_CreateInstance,
626         DICF_LockServer
627 };
628 static IClassFactoryImpl DINPUT_CF = {&DICF_Vtbl, 1 };
629
630 /***********************************************************************
631  *              DllCanUnloadNow (DINPUT.@)
632  */
633 HRESULT WINAPI DllCanUnloadNow(void)
634 {
635     FIXME("(void): stub\n");
636
637     return S_FALSE;
638 }
639
640 /***********************************************************************
641  *              DllGetClassObject (DINPUT.@)
642  */
643 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
644 {
645     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
646     if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
647         *ppv = (LPVOID)&DINPUT_CF;
648         IClassFactory_AddRef((IClassFactory*)*ppv);
649     return S_OK;
650     }
651
652     FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
653     return CLASS_E_CLASSNOTAVAILABLE;
654 }
655
656 /******************************************************************************
657  *      DInput hook thread
658  */
659
660 static LRESULT CALLBACK dinput_hook_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
661 {
662     static HHOOK kbd_hook, mouse_hook;
663     BOOL res;
664
665     TRACE("got message %x %p %p\n", message, (LPVOID)wParam, (LPVOID)lParam);
666     switch (message)
667     {
668     case WM_USER+0x10:
669         if (wParam == WH_KEYBOARD_LL)
670         {
671             if (lParam)
672             {
673                 if (kbd_hook) return 0;
674                 kbd_hook = SetWindowsHookExW(WH_KEYBOARD_LL, (LPVOID)lParam, DINPUT_instance, 0);
675                 return (LRESULT)kbd_hook;
676             }
677             else
678             {
679                 if (!kbd_hook) return 0;
680                 res = UnhookWindowsHookEx(kbd_hook);
681                 kbd_hook = NULL;
682                 return res;
683             }
684         }
685         else if (wParam == WH_MOUSE_LL)
686         {
687             if (lParam)
688             {
689                 if (mouse_hook) return 0;
690                 mouse_hook = SetWindowsHookExW(WH_MOUSE_LL, (LPVOID)lParam, DINPUT_instance, 0);
691                 return (LRESULT)mouse_hook;
692             }
693             else
694             {
695                 if (!mouse_hook) return 0;
696                 res = UnhookWindowsHookEx(mouse_hook);
697                 mouse_hook = NULL;
698                 return res;
699             }
700         }
701         else if (!wParam && !lParam)
702             DestroyWindow(hWnd);
703
704         return 0;
705
706     case WM_DESTROY:
707         if (kbd_hook) UnhookWindowsHookEx(kbd_hook);
708         if (mouse_hook) UnhookWindowsHookEx(mouse_hook);
709         PostQuitMessage(0);
710     }
711     return DefWindowProcW(hWnd, message, wParam, lParam);
712 }
713
714 static HWND hook_thread_hwnd;
715 static LONG hook_thread_refcount;
716 static HANDLE hook_thread;
717
718 static const WCHAR classW[]={'H','o','o','k','_','L','L','_','C','L',0};
719
720 static DWORD WINAPI hook_thread_proc(void *param)
721 {
722     MSG msg;
723     HWND hwnd;
724
725     hwnd = CreateWindowExW(0, classW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, 0);
726     hook_thread_hwnd = hwnd;
727
728     SetEvent(*(LPHANDLE)param);
729     if (hwnd)
730     {
731         while (GetMessageW(&msg, 0, 0, 0))
732         {
733             TranslateMessage(&msg);
734             DispatchMessageW(&msg);
735         }
736         DestroyWindow(hwnd);
737     }
738     else ERR("Error creating message window\n");
739
740     UnregisterClassW(classW, DINPUT_instance);
741     return 0;
742 }
743
744 static CRITICAL_SECTION dinput_hook_crit;
745 static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
746 {
747     0, 0, &dinput_hook_crit,
748     { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
749       0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
750 };
751 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
752
753 static BOOL create_hook_thread(void)
754 {
755     LONG ref;
756
757     EnterCriticalSection(&dinput_hook_crit);
758
759     ref = ++hook_thread_refcount;
760     TRACE("Refcount %d\n", ref);
761     if (ref == 1)
762     {
763         DWORD tid;
764         HANDLE event;
765
766         /* Create window class */
767         WNDCLASSEXW wcex;
768         memset(&wcex, 0, sizeof(wcex));
769         wcex.cbSize = sizeof(wcex);
770         wcex.lpfnWndProc = dinput_hook_WndProc;
771         wcex.lpszClassName = classW;
772         wcex.hInstance = DINPUT_instance;
773         if (!RegisterClassExW(&wcex))
774             ERR("Error registering window class\n");
775
776         event = CreateEventW(NULL, FALSE, FALSE, NULL);
777         hook_thread = CreateThread(NULL, 0, hook_thread_proc, &event, 0, &tid);
778         if (event && hook_thread)
779         {
780             HANDLE handles[2];
781             handles[0] = event;
782             handles[1] = hook_thread;
783             WaitForMultipleObjects(2, handles, FALSE, INFINITE);
784         }
785         CloseHandle(event);
786     }
787     LeaveCriticalSection(&dinput_hook_crit);
788
789     return hook_thread_hwnd != 0;
790 }
791
792 static void release_hook_thread(void)
793 {
794     LONG ref;
795
796     EnterCriticalSection(&dinput_hook_crit);
797     ref = --hook_thread_refcount;
798     TRACE("Releasing to %d\n", ref);
799     if (ref == 0) 
800     {
801         HWND hwnd = hook_thread_hwnd;
802         hook_thread_hwnd = 0;
803         SendMessageW(hwnd, WM_USER+0x10, 0, 0);
804         /* wait for hook thread to exit */
805         WaitForSingleObject(hook_thread, INFINITE);
806         CloseHandle(hook_thread);
807     }
808     LeaveCriticalSection(&dinput_hook_crit);
809 }
810
811 HHOOK set_dinput_hook(int hook_id, LPVOID proc)
812 {
813     HWND hwnd;
814
815     EnterCriticalSection(&dinput_hook_crit);
816     hwnd = hook_thread_hwnd;
817     LeaveCriticalSection(&dinput_hook_crit);
818     return (HHOOK)SendMessageW(hwnd, WM_USER+0x10, (WPARAM)hook_id, (LPARAM)proc);
819 }