ole32/tests: Fix a test on win98 and W2K.
[wine] / dlls / dinput / device.c
1 /*              DirectInput Device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 /* This file contains all the Device specific functions that can be used as stubs
23    by real device implementations.
24
25    It also contains all the helper functions.
26 */
27 #include "config.h"
28
29 #include <stdarg.h>
30 #include <string.h>
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winreg.h"
36 #include "winuser.h"
37 #include "winerror.h"
38 #include "dinput.h"
39 #include "device_private.h"
40 #include "dinput_private.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
43
44 /******************************************************************************
45  *      Various debugging tools
46  */
47 void _dump_cooperativelevel_DI(DWORD dwFlags) {
48     if (TRACE_ON(dinput)) {
49         unsigned int   i;
50         static const struct {
51             DWORD       mask;
52             const char  *name;
53         } flags[] = {
54 #define FE(x) { x, #x}
55             FE(DISCL_BACKGROUND),
56             FE(DISCL_EXCLUSIVE),
57             FE(DISCL_FOREGROUND),
58             FE(DISCL_NONEXCLUSIVE),
59             FE(DISCL_NOWINKEY)
60 #undef FE
61         };
62         TRACE(" cooperative level : ");
63         for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
64             if (flags[i].mask & dwFlags)
65                 TRACE("%s ",flags[i].name);
66         TRACE("\n");
67     }
68 }
69
70 void _dump_EnumObjects_flags(DWORD dwFlags) {
71     if (TRACE_ON(dinput)) {
72         unsigned int   i;
73         DWORD type, instance;
74         static const struct {
75             DWORD       mask;
76             const char  *name;
77         } flags[] = {
78 #define FE(x) { x, #x}
79             FE(DIDFT_RELAXIS),
80             FE(DIDFT_ABSAXIS),
81             FE(DIDFT_PSHBUTTON),
82             FE(DIDFT_TGLBUTTON),
83             FE(DIDFT_POV),
84             FE(DIDFT_COLLECTION),
85             FE(DIDFT_NODATA),       
86             FE(DIDFT_FFACTUATOR),
87             FE(DIDFT_FFEFFECTTRIGGER),
88             FE(DIDFT_OUTPUT),
89             FE(DIDFT_VENDORDEFINED),
90             FE(DIDFT_ALIAS),
91             FE(DIDFT_OPTIONAL)
92 #undef FE
93         };
94         type = (dwFlags & 0xFF0000FF);
95         instance = ((dwFlags >> 8) & 0xFFFF);
96         TRACE("Type:");
97         if (type == DIDFT_ALL) {
98             TRACE(" DIDFT_ALL");
99         } else {
100             for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
101                 if (flags[i].mask & type) {
102                     type &= ~flags[i].mask;
103                     TRACE(" %s",flags[i].name);
104                 }
105             }
106             if (type) {
107                 TRACE(" (unhandled: %08x)", type);
108             }
109         }
110         TRACE(" / Instance: ");
111         if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) {
112             TRACE("DIDFT_ANYINSTANCE");
113         } else {
114             TRACE("%3d", instance);
115         }
116     }
117 }
118
119 void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) {
120     if (TRACE_ON(dinput)) {
121         TRACE("  - dwObj = 0x%08x\n", diph->dwObj);
122         TRACE("  - dwHow = %s\n",
123             ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" :
124             ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" :
125             ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown")));
126     }
127 }
128
129 void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) {
130     TRACE("    - enumerating : %s ('%s') - %2d - 0x%08x - %s\n",
131         debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName);
132 }
133
134 void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) {
135     TRACE("    - enumerating : %s ('%s'), - %2d - 0x%08x - %s\n",
136         debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName));
137 }
138
139 /* This function is a helper to convert a GUID into any possible DInput GUID out there */
140 const char *_dump_dinput_GUID(const GUID *guid) {
141     unsigned int i;
142     static const struct {
143         const GUID *guid;
144         const char *name;
145     } guids[] = {
146 #define FE(x) { &x, #x}
147         FE(GUID_XAxis),
148         FE(GUID_YAxis),
149         FE(GUID_ZAxis),
150         FE(GUID_RxAxis),
151         FE(GUID_RyAxis),
152         FE(GUID_RzAxis),
153         FE(GUID_Slider),
154         FE(GUID_Button),
155         FE(GUID_Key),
156         FE(GUID_POV),
157         FE(GUID_Unknown),
158         FE(GUID_SysMouse),
159         FE(GUID_SysKeyboard),
160         FE(GUID_Joystick),
161         FE(GUID_ConstantForce),
162         FE(GUID_RampForce),
163         FE(GUID_Square),
164         FE(GUID_Sine),
165         FE(GUID_Triangle),
166         FE(GUID_SawtoothUp),
167         FE(GUID_SawtoothDown),
168         FE(GUID_Spring),
169         FE(GUID_Damper),
170         FE(GUID_Inertia),
171         FE(GUID_Friction),
172         FE(GUID_CustomForce)
173 #undef FE
174     };
175     if (guid == NULL)
176         return "null GUID";
177     for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) {
178         if (IsEqualGUID(guids[i].guid, guid)) {
179             return guids[i].name;
180         }
181     }
182     return debugstr_guid(guid);
183 }
184
185 void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) {
186     unsigned int i;
187
188     TRACE("Dumping DIDATAFORMAT structure:\n");
189     TRACE("  - dwSize: %d\n", df->dwSize);
190     if (df->dwSize != sizeof(DIDATAFORMAT)) {
191         WARN("Non-standard DIDATAFORMAT structure size %d\n", df->dwSize);
192     }
193     TRACE("  - dwObjsize: %d\n", df->dwObjSize);
194     if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) {
195         WARN("Non-standard DIOBJECTDATAFORMAT structure size %d\n", df->dwObjSize);
196     }
197     TRACE("  - dwFlags: 0x%08x (", df->dwFlags);
198     switch (df->dwFlags) {
199         case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break;
200         case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break;
201         default: TRACE("unknown"); break;
202     }
203     TRACE(")\n");
204     TRACE("  - dwDataSize: %d\n", df->dwDataSize);
205     TRACE("  - dwNumObjs: %d\n", df->dwNumObjs);
206     
207     for (i = 0; i < df->dwNumObjs; i++) {
208         TRACE("  - Object %d:\n", i);
209         TRACE("      * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid));
210         TRACE("      * dwOfs: %d\n", df->rgodf[i].dwOfs);
211         TRACE("      * dwType: 0x%08x\n", df->rgodf[i].dwType);
212         TRACE("        "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n");
213         TRACE("      * dwFlags: 0x%08x\n", df->rgodf[i].dwFlags);
214     }
215 }
216
217 /******************************************************************************
218  * Get the default and the app-specific config keys.
219  */
220 BOOL get_app_key(HKEY *defkey, HKEY *appkey)
221 {
222     char buffer[MAX_PATH+16];
223     DWORD len;
224
225     *appkey = 0;
226
227     /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
228     if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\DirectInput", defkey))
229         *defkey = 0;
230
231     len = GetModuleFileNameA(0, buffer, MAX_PATH);
232     if (len && len < MAX_PATH)
233     {
234         HKEY tmpkey;
235
236         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
237         if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey))
238         {
239             char *p, *appname = buffer;
240             if ((p = strrchr(appname, '/'))) appname = p + 1;
241             if ((p = strrchr(appname, '\\'))) appname = p + 1;
242             strcat(appname, "\\DirectInput");
243
244             if (RegOpenKeyA(tmpkey, appname, appkey)) *appkey = 0;
245             RegCloseKey(tmpkey);
246         }
247     }
248
249     return *defkey || *appkey;
250 }
251
252 /******************************************************************************
253  * Get a config key from either the app-specific or the default config
254  */
255 DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
256                              char *buffer, DWORD size )
257 {
258     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size ))
259         return 0;
260
261     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size ))
262         return 0;
263
264     return ERROR_FILE_NOT_FOUND;
265 }
266
267 /* Conversion between internal data buffer and external data buffer */
268 void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df)
269 {
270     int i;
271     const char *in_c = in;
272     char *out_c = (char *) out;
273
274     memset(out, 0, size);
275     if (df->dt == NULL) {
276         /* This means that the app uses Wine's internal data format */
277         memcpy(out, in, df->internal_format_size);
278     } else {
279         for (i = 0; i < df->size; i++) {
280             if (df->dt[i].offset_in >= 0) {
281                 switch (df->dt[i].size) {
282                     case 1:
283                         TRACE("Copying (c) to %d from %d (value %d)\n",
284                               df->dt[i].offset_out, df->dt[i].offset_in, *(in_c + df->dt[i].offset_in));
285                         *(out_c + df->dt[i].offset_out) = *(in_c + df->dt[i].offset_in);
286                         break;
287
288                     case 2:
289                         TRACE("Copying (s) to %d from %d (value %d)\n",
290                               df->dt[i].offset_out, df->dt[i].offset_in, *((const short *)(in_c + df->dt[i].offset_in)));
291                         *((short *)(out_c + df->dt[i].offset_out)) = *((const short *)(in_c + df->dt[i].offset_in));
292                         break;
293
294                     case 4:
295                         TRACE("Copying (i) to %d from %d (value %d)\n",
296                               df->dt[i].offset_out, df->dt[i].offset_in, *((const int *)(in_c + df->dt[i].offset_in)));
297                         *((int *)(out_c + df->dt[i].offset_out)) = *((const int *)(in_c + df->dt[i].offset_in));
298                         break;
299
300                     default:
301                         memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
302                         break;
303                 }
304             } else {
305                 switch (df->dt[i].size) {
306                     case 1:
307                         TRACE("Copying (c) to %d default value %d\n",
308                               df->dt[i].offset_out, df->dt[i].value);
309                         *(out_c + df->dt[i].offset_out) = (char) df->dt[i].value;
310                         break;
311                         
312                     case 2:
313                         TRACE("Copying (s) to %d default value %d\n",
314                               df->dt[i].offset_out, df->dt[i].value);
315                         *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
316                         break;
317                         
318                     case 4:
319                         TRACE("Copying (i) to %d default value %d\n",
320                               df->dt[i].offset_out, df->dt[i].value);
321                         *((int *) (out_c + df->dt[i].offset_out)) = df->dt[i].value;
322                         break;
323                         
324                     default:
325                         memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size);
326                         break;
327                 }
328             }
329         }
330     }
331 }
332
333 void release_DataFormat(DataFormat * format)
334 {
335     TRACE("Deleting DataFormat: %p\n", format);
336
337     HeapFree(GetProcessHeap(), 0, format->dt);
338     format->dt = NULL;
339     HeapFree(GetProcessHeap(), 0, format->offsets);
340     format->offsets = NULL;
341     HeapFree(GetProcessHeap(), 0, format->user_df);
342     format->user_df = NULL;
343 }
344
345 inline LPDIOBJECTDATAFORMAT dataformat_to_odf(LPCDIDATAFORMAT df, int idx)
346 {
347     if (idx < 0 || idx >= df->dwNumObjs) return NULL;
348     return (LPDIOBJECTDATAFORMAT)((LPBYTE)df->rgodf + idx * df->dwObjSize);
349 }
350
351 HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat *format)
352 {
353     DataTransform *dt;
354     unsigned int i, j;
355     int same = 1;
356     int *done;
357     int index = 0;
358     DWORD next = 0;
359
360     if (!format->wine_df) return DIERR_INVALIDPARAM;
361     done = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, asked_format->dwNumObjs * sizeof(int));
362     dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
363     if (!dt || !done) goto failed;
364
365     if (!(format->offsets = HeapAlloc(GetProcessHeap(), 0, format->wine_df->dwNumObjs * sizeof(int))))
366         goto failed;
367
368     if (!(format->user_df = HeapAlloc(GetProcessHeap(), 0, asked_format->dwSize)))
369         goto failed;
370     memcpy(format->user_df, asked_format, asked_format->dwSize);
371
372     TRACE("Creating DataTransform :\n");
373     
374     for (i = 0; i < format->wine_df->dwNumObjs; i++)
375     {
376         format->offsets[i] = -1;
377
378         for (j = 0; j < asked_format->dwNumObjs; j++) {
379             if (done[j] == 1)
380                 continue;
381             
382             if (/* Check if the application either requests any GUID and if not, it if matches
383                  * the GUID of the Wine object.
384                  */
385                 ((asked_format->rgodf[j].pguid == NULL) ||
386                  (format->wine_df->rgodf[i].pguid == NULL) ||
387                  (IsEqualGUID(format->wine_df->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
388                 &&
389                 (/* Then check if it accepts any instance id, and if not, if it matches Wine's
390                   * instance id.
391                   */
392                  ((asked_format->rgodf[j].dwType & DIDFT_INSTANCEMASK) == DIDFT_ANYINSTANCE) ||
393                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0x00FF) || /* This is mentionned in no DX docs, but it works fine - tested on WinXP */
394                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(format->wine_df->rgodf[i].dwType)))
395                 &&
396                 ( /* Then if the asked type matches the one Wine provides */
397                  DIDFT_GETTYPE(asked_format->rgodf[j].dwType) & format->wine_df->rgodf[i].dwType))
398             {
399                 done[j] = 1;
400                 
401                 TRACE("Matching :\n");
402                 TRACE("   - Asked (%d) :\n", j);
403                 TRACE("       * GUID: %s ('%s')\n",
404                       debugstr_guid(asked_format->rgodf[j].pguid),
405                       _dump_dinput_GUID(asked_format->rgodf[j].pguid));
406                 TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
407                 TRACE("       * dwType: %08x\n", asked_format->rgodf[j].dwType);
408                 TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
409                 
410                 TRACE("   - Wine  (%d) :\n", i);
411                 TRACE("       * GUID: %s ('%s')\n",
412                       debugstr_guid(format->wine_df->rgodf[i].pguid),
413                       _dump_dinput_GUID(format->wine_df->rgodf[i].pguid));
414                 TRACE("       * Offset: %3d\n", format->wine_df->rgodf[i].dwOfs);
415                 TRACE("       * dwType: %08x\n", format->wine_df->rgodf[i].dwType);
416                 TRACE("         "); _dump_EnumObjects_flags(format->wine_df->rgodf[i].dwType); TRACE("\n");
417                 
418                 if (format->wine_df->rgodf[i].dwType & DIDFT_BUTTON)
419                     dt[index].size = sizeof(BYTE);
420                 else
421                     dt[index].size = sizeof(DWORD);
422                 dt[index].offset_in = format->wine_df->rgodf[i].dwOfs;
423                 dt[index].offset_out = asked_format->rgodf[j].dwOfs;
424                 format->offsets[i]   = asked_format->rgodf[j].dwOfs;
425                 dt[index].value = 0;
426                 next = next + dt[index].size;
427                 
428                 if (format->wine_df->rgodf[i].dwOfs != dt[index].offset_out)
429                     same = 0;
430                 
431                 index++;
432                 break;
433             }
434         }
435         
436         if (j == asked_format->dwNumObjs)
437             same = 0;
438     }
439     
440     TRACE("Setting to default value :\n");
441     for (j = 0; j < asked_format->dwNumObjs; j++) {
442         if (done[j] == 0) {
443             TRACE("   - Asked (%d) :\n", j);
444             TRACE("       * GUID: %s ('%s')\n",
445                   debugstr_guid(asked_format->rgodf[j].pguid),
446                   _dump_dinput_GUID(asked_format->rgodf[j].pguid));
447             TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
448             TRACE("       * dwType: %08x\n", asked_format->rgodf[j].dwType);
449             TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
450             
451             if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
452                 dt[index].size = sizeof(BYTE);
453             else
454                 dt[index].size = sizeof(DWORD);
455             dt[index].offset_in  = -1;
456             dt[index].offset_out = asked_format->rgodf[j].dwOfs;
457             if (asked_format->rgodf[j].dwType & DIDFT_POV)
458                 dt[index].value = -1;
459             else
460                 dt[index].value = 0;
461             index++;
462
463             same = 0;
464         }
465     }
466     
467     format->internal_format_size = format->wine_df->dwDataSize;
468     format->size = index;
469     if (same) {
470         HeapFree(GetProcessHeap(), 0, dt);
471         dt = NULL;
472     }
473     format->dt = dt;
474
475     HeapFree(GetProcessHeap(), 0, done);
476
477     return DI_OK;
478
479 failed:
480     HeapFree(GetProcessHeap(), 0, done);
481     HeapFree(GetProcessHeap(), 0, dt);
482     format->dt = NULL;
483     HeapFree(GetProcessHeap(), 0, format->offsets);
484     format->offsets = NULL;
485     HeapFree(GetProcessHeap(), 0, format->user_df);
486     format->user_df = NULL;
487
488     return DIERR_OUTOFMEMORY;
489 }
490
491 /* find an object by it's offset in a data format */
492 static int offset_to_object(const DataFormat *df, int offset)
493 {
494     int i;
495
496     if (!df->offsets) return -1;
497
498     for (i = 0; i < df->wine_df->dwNumObjs; i++)
499         if (df->offsets[i] == offset) return i;
500
501     return -1;
502 }
503
504 int id_to_object(LPCDIDATAFORMAT df, int id)
505 {
506     int i;
507
508     id &= 0x00ffffff;
509     for (i = 0; i < df->dwNumObjs; i++)
510         if ((dataformat_to_odf(df, i)->dwType & 0x00ffffff) == id)
511             return i;
512
513     return -1;
514 }
515
516 int id_to_offset(const DataFormat *df, int id)
517 {
518     int obj = id_to_object(df->wine_df, id);
519
520     return obj >= 0 && df->offsets ? df->offsets[obj] : -1;
521 }
522
523 int find_property(const DataFormat *df, LPCDIPROPHEADER ph)
524 {
525     switch (ph->dwHow)
526     {
527         case DIPH_BYID:     return id_to_object(df->wine_df, ph->dwObj);
528         case DIPH_BYOFFSET: return offset_to_object(df, ph->dwObj);
529     }
530     FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow);
531
532     return -1;
533 }
534
535
536 BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) {
537     DIDEVICEOBJECTINSTANCEW ddtmp;
538     device_enumobjects_AtoWcb_data* data;
539
540     data = (device_enumobjects_AtoWcb_data*) lpvRef;
541     
542     memset(&ddtmp, 0, sizeof(ddtmp));
543     
544     ddtmp.dwSize = sizeof(DIDEVICEINSTANCEW);
545     ddtmp.guidType     = lpddi->guidType;
546     ddtmp.dwOfs        = lpddi->dwOfs;
547     ddtmp.dwType       = lpddi->dwType;
548     ddtmp.dwFlags      = lpddi->dwFlags;
549     MultiByteToWideChar(CP_ACP, 0, lpddi->tszName, -1, ddtmp.tszName, MAX_PATH);
550     
551     if (lpddi->dwSize == sizeof(DIDEVICEINSTANCEA)) {
552         /**
553          * if dwSize < sizeof(DIDEVICEINSTANCEA of DInput version >= 5)
554          *  force feedback and other newer data aren't available
555          */
556         ddtmp.dwFFMaxForce        = lpddi->dwFFMaxForce;
557         ddtmp.dwFFForceResolution = lpddi->dwFFForceResolution;
558         ddtmp.wCollectionNumber   = lpddi->wCollectionNumber;
559         ddtmp.wDesignatorIndex    = lpddi->wDesignatorIndex;
560         ddtmp.wUsagePage          = lpddi->wUsagePage;
561         ddtmp.wUsage              = lpddi->wUsage;
562         ddtmp.dwDimension         = lpddi->dwDimension;
563         ddtmp.wExponent           = lpddi->wExponent;
564         ddtmp.wReserved           = lpddi->wReserved;
565     }
566     return data->lpCallBack(&ddtmp, data->lpvRef);
567 }
568
569 /******************************************************************************
570  *      queue_event - add new event to the ring queue
571  */
572
573 void queue_event(LPDIRECTINPUTDEVICE8A iface, int ofs, DWORD data, DWORD time, DWORD seq)
574 {
575     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
576     int next_pos;
577
578     /* Event is being set regardless of the queue state */
579     if (This->hEvent) SetEvent(This->hEvent);
580
581     if (!This->queue_len || This->overflow || ofs < 0) return;
582
583     next_pos = (This->queue_head + 1) % This->queue_len;
584     if (next_pos == This->queue_tail)
585     {
586         TRACE(" queue overflowed\n");
587         This->overflow = TRUE;
588         return;
589     }
590
591     TRACE(" queueing %d at offset %d (queue head %d / size %d)\n",
592           data, ofs, This->queue_head, This->queue_len);
593
594     This->data_queue[This->queue_head].dwOfs       = ofs;
595     This->data_queue[This->queue_head].dwData      = data;
596     This->data_queue[This->queue_head].dwTimeStamp = time;
597     This->data_queue[This->queue_head].dwSequence  = seq;
598     This->queue_head = next_pos;
599     /* Send event if asked */
600 }
601
602 /******************************************************************************
603  *      Acquire
604  */
605
606 HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
607 {
608     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
609     HRESULT res;
610
611     if (!This->data_format.user_df) return DIERR_INVALIDPARAM;
612     if (This->dwCoopLevel & DISCL_FOREGROUND && This->win != GetForegroundWindow())
613         return DIERR_OTHERAPPHASPRIO;
614
615     EnterCriticalSection(&This->crit);
616     res = This->acquired ? S_FALSE : DI_OK;
617     This->acquired = 1;
618     if (res == DI_OK)
619     {
620         This->queue_head = This->queue_tail = This->overflow = 0;
621         check_dinput_hooks(iface);
622     }
623     LeaveCriticalSection(&This->crit);
624
625     return res;
626 }
627
628 /******************************************************************************
629  *      Unacquire
630  */
631
632 HRESULT WINAPI IDirectInputDevice2AImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
633 {
634     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
635     HRESULT res;
636
637     EnterCriticalSection(&This->crit);
638     res = !This->acquired ? DI_NOEFFECT : DI_OK;
639     This->acquired = 0;
640     if (res == DI_OK)
641         check_dinput_hooks(iface);
642     LeaveCriticalSection(&This->crit);
643
644     return res;
645 }
646
647 /******************************************************************************
648  *      IDirectInputDeviceA
649  */
650
651 HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
652         LPDIRECTINPUTDEVICE8A iface, LPCDIDATAFORMAT df)
653 {
654     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
655     HRESULT res = DI_OK;
656
657     if (!df) return E_POINTER;
658     TRACE("(%p) %p\n", This, df);
659     _dump_DIDATAFORMAT(df);
660
661     if (df->dwSize != sizeof(DIDATAFORMAT)) return DIERR_INVALIDPARAM;
662     if (This->acquired) return DIERR_ACQUIRED;
663
664     EnterCriticalSection(&This->crit);
665
666     release_DataFormat(&This->data_format);
667     res = create_DataFormat(df, &This->data_format);
668
669     LeaveCriticalSection(&This->crit);
670     return res;
671 }
672
673 /******************************************************************************
674   *     SetCooperativeLevel
675   *
676   *  Set cooperative level and the source window for the events.
677   */
678 HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
679         LPDIRECTINPUTDEVICE8A iface, HWND hwnd, DWORD dwflags)
680 {
681     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
682
683     TRACE("(%p) %p,0x%08x\n", This, hwnd, dwflags);
684     _dump_cooperativelevel_DI(dwflags);
685
686     if ((dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == 0 ||
687         (dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE) ||
688         (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == 0 ||
689         (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == (DISCL_FOREGROUND | DISCL_BACKGROUND))
690         return DIERR_INVALIDPARAM;
691
692     if (dwflags == (DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))
693         hwnd = GetDesktopWindow();
694
695     if (!hwnd) return E_HANDLE;
696
697     /* For security reasons native does not allow exclusive background level
698        for mouse and keyboard only */
699     if (dwflags & DISCL_EXCLUSIVE && dwflags & DISCL_BACKGROUND &&
700         (IsEqualGUID(&This->guid, &GUID_SysMouse) ||
701          IsEqualGUID(&This->guid, &GUID_SysKeyboard)))
702         return DIERR_UNSUPPORTED;
703
704     /* Store the window which asks for the mouse */
705     EnterCriticalSection(&This->crit);
706     This->win = hwnd;
707     This->dwCoopLevel = dwflags;
708     LeaveCriticalSection(&This->crit);
709
710     return DI_OK;
711 }
712
713 /******************************************************************************
714   *     SetEventNotification : specifies event to be sent on state change
715   */
716 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
717         LPDIRECTINPUTDEVICE8A iface, HANDLE event)
718 {
719     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
720
721     TRACE("(%p) %p\n", This, event);
722
723     EnterCriticalSection(&This->crit);
724     This->hEvent = event;
725     LeaveCriticalSection(&This->crit);
726     return DI_OK;
727 }
728
729 ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
730 {
731     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
732     ULONG ref;
733
734     ref = InterlockedDecrement(&(This->ref));
735     if (ref) return ref;
736
737     IDirectInputDevice_Unacquire(iface);
738     /* Reset the FF state, free all effects, etc */
739     IDirectInputDevice8_SendForceFeedbackCommand(iface, DISFFC_RESET);
740
741     HeapFree(GetProcessHeap(), 0, This->data_queue);
742
743     /* Free data format */
744     HeapFree(GetProcessHeap(), 0, This->data_format.wine_df->rgodf);
745     HeapFree(GetProcessHeap(), 0, This->data_format.wine_df);
746     release_DataFormat(&This->data_format);
747
748     EnterCriticalSection( &This->dinput->crit );
749     list_remove( &This->entry );
750     LeaveCriticalSection( &This->dinput->crit );
751
752     IDirectInput_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
753     This->crit.DebugInfo->Spare[0] = 0;
754     DeleteCriticalSection(&This->crit);
755
756     HeapFree(GetProcessHeap(), 0, This);
757
758     return DI_OK;
759 }
760
761 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
762         LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj
763 )
764 {
765     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
766     
767     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
768     if (IsEqualGUID(&IID_IUnknown,riid)) {
769         IDirectInputDevice2_AddRef(iface);
770         *ppobj = This;
771         return DI_OK;
772     }
773     if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) {
774         IDirectInputDevice2_AddRef(iface);
775         *ppobj = This;
776         return DI_OK;
777     }
778     if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) {
779         IDirectInputDevice2_AddRef(iface);
780         *ppobj = This;
781         return DI_OK;
782     }
783     if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
784         IDirectInputDevice7_AddRef(iface);
785         *ppobj = This;
786         return DI_OK;
787     }
788     if (IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
789         IDirectInputDevice8_AddRef(iface);
790         *ppobj = This;
791         return DI_OK;
792     }
793     TRACE("Unsupported interface !\n");
794     return E_FAIL;
795 }
796
797 HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(
798         LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj
799 )
800 {
801     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
802     
803     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
804     if (IsEqualGUID(&IID_IUnknown,riid)) {
805         IDirectInputDevice2_AddRef(iface);
806         *ppobj = This;
807         return DI_OK;
808     }
809     if (IsEqualGUID(&IID_IDirectInputDeviceW,riid)) {
810         IDirectInputDevice2_AddRef(iface);
811         *ppobj = This;
812         return DI_OK;
813     }
814     if (IsEqualGUID(&IID_IDirectInputDevice2W,riid)) {
815         IDirectInputDevice2_AddRef(iface);
816         *ppobj = This;
817         return DI_OK;
818     }
819     if (IsEqualGUID(&IID_IDirectInputDevice7W,riid)) {
820         IDirectInputDevice7_AddRef(iface);
821         *ppobj = This;
822         return DI_OK;
823     }
824     if (IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
825         IDirectInputDevice8_AddRef(iface);
826         *ppobj = This;
827         return DI_OK;
828     }
829     TRACE("Unsupported interface !\n");
830     return E_FAIL;
831 }
832
833 ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
834         LPDIRECTINPUTDEVICE8A iface)
835 {
836     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
837     return InterlockedIncrement(&(This->ref));
838 }
839
840 HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(LPDIRECTINPUTDEVICE8A iface,
841         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID lpvRef, DWORD dwFlags)
842 {
843     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
844     DIDEVICEOBJECTINSTANCEA ddoi;
845     int i;
846
847     TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
848     TRACE("  - flags = ");
849     _dump_EnumObjects_flags(dwFlags);
850     TRACE("\n");
851
852     /* Only the fields till dwFFMaxForce are relevant */
853     memset(&ddoi, 0, sizeof(ddoi));
854     ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
855
856     for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
857     {
858         LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
859
860         if (dwFlags != DIDFT_ALL && !(dwFlags & DIEFT_GETTYPE(odf->dwType))) continue;
861         if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
862             continue;
863
864         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
865     }
866
867     return DI_OK;
868 }
869
870 HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
871         LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef, DWORD dwFlags)
872 {
873     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
874     DIDEVICEOBJECTINSTANCEW ddoi;
875     int i;
876
877     TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
878     TRACE("  - flags = ");
879     _dump_EnumObjects_flags(dwFlags);
880     TRACE("\n");
881
882     /* Only the fields till dwFFMaxForce are relevant */
883     memset(&ddoi, 0, sizeof(ddoi));
884     ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, dwFFMaxForce);
885
886     for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
887     {
888         LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
889
890         if (dwFlags != DIDFT_ALL && !(dwFlags & DIEFT_GETTYPE(odf->dwType))) continue;
891         if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
892             continue;
893
894         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
895     }
896
897     return DI_OK;
898 }
899
900 /******************************************************************************
901  *      GetProperty
902  */
903
904 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
905         LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
906 {
907     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
908
909     TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
910     _dump_DIPROPHEADER(pdiph);
911
912     if (HIWORD(rguid)) return DI_OK;
913
914     switch (LOWORD(rguid))
915     {
916         case (DWORD) DIPROP_BUFFERSIZE:
917         {
918             LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
919
920             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
921
922             pd->dwData = This->queue_len;
923             TRACE("buffersize = %d\n", pd->dwData);
924             break;
925         }
926         default:
927             WARN("Unknown property %s\n", debugstr_guid(rguid));
928             break;
929     }
930
931     return DI_OK;
932 }
933
934 /******************************************************************************
935  *      SetProperty
936  */
937
938 HRESULT WINAPI IDirectInputDevice2AImpl_SetProperty(
939         LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER pdiph)
940 {
941     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
942
943     TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
944     _dump_DIPROPHEADER(pdiph);
945
946     if (HIWORD(rguid)) return DI_OK;
947
948     switch (LOWORD(rguid))
949     {
950         case (DWORD) DIPROP_AXISMODE:
951         {
952             LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
953
954             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
955             if (pdiph->dwHow == DIPH_DEVICE && pdiph->dwObj) return DIERR_INVALIDPARAM;
956             if (This->acquired) return DIERR_ACQUIRED;
957             if (pdiph->dwHow != DIPH_DEVICE) return DIERR_UNSUPPORTED;
958             if (!This->data_format.user_df) return DI_OK;
959
960             TRACE("Axis mode: %s\n", pd->dwData == DIPROPAXISMODE_ABS ? "absolute" :
961                                                                         "relative");
962
963             EnterCriticalSection(&This->crit);
964             This->data_format.user_df->dwFlags &= ~DIDFT_AXIS;
965             This->data_format.user_df->dwFlags |= pd->dwData == DIPROPAXISMODE_ABS ?
966                                                   DIDF_ABSAXIS : DIDF_RELAXIS;
967             LeaveCriticalSection(&This->crit);
968             break;
969         }
970         case (DWORD) DIPROP_BUFFERSIZE:
971         {
972             LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
973
974             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
975             if (This->acquired) return DIERR_ACQUIRED;
976
977             TRACE("buffersize = %d\n", pd->dwData);
978
979             EnterCriticalSection(&This->crit);
980             HeapFree(GetProcessHeap(), 0, This->data_queue);
981
982             This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0,
983                                 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
984             This->queue_head = This->queue_tail = This->overflow = 0;
985             This->queue_len  = pd->dwData;
986
987             LeaveCriticalSection(&This->crit);
988             break;
989         }
990         default:
991             WARN("Unknown property %s\n", debugstr_guid(rguid));
992             return DIERR_UNSUPPORTED;
993     }
994
995     return DI_OK;
996 }
997
998 HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
999         LPDIRECTINPUTDEVICE8A iface,
1000         LPDIDEVICEOBJECTINSTANCEA pdidoi,
1001         DWORD dwObj,
1002         DWORD dwHow)
1003 {
1004     DIDEVICEOBJECTINSTANCEW didoiW;
1005     HRESULT res;
1006
1007     if (!pdidoi ||
1008         (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA) &&
1009          pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A)))
1010         return DIERR_INVALIDPARAM;
1011
1012     didoiW.dwSize = sizeof(didoiW);
1013     res = IDirectInputDevice2WImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow);
1014     if (res == DI_OK)
1015     {
1016         DWORD dwSize = pdidoi->dwSize;
1017
1018         memset(pdidoi, 0, pdidoi->dwSize);
1019         pdidoi->dwSize   = dwSize;
1020         pdidoi->guidType = didoiW.guidType;
1021         pdidoi->dwOfs    = didoiW.dwOfs;
1022         pdidoi->dwType   = didoiW.dwType;
1023         pdidoi->dwFlags  = didoiW.dwFlags;
1024     }
1025
1026     return res;
1027 }
1028
1029 HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(
1030         LPDIRECTINPUTDEVICE8W iface,
1031         LPDIDEVICEOBJECTINSTANCEW pdidoi,
1032         DWORD dwObj,
1033         DWORD dwHow)
1034 {
1035     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
1036     DWORD dwSize;
1037     LPDIOBJECTDATAFORMAT odf;
1038     int idx = -1;
1039
1040     TRACE("(%p) %d(0x%08x) -> %p\n", This, dwHow, dwObj, pdidoi);
1041
1042     if (!pdidoi ||
1043         (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW) &&
1044          pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W)))
1045         return DIERR_INVALIDPARAM;
1046
1047     switch (dwHow)
1048     {
1049     case DIPH_BYOFFSET:
1050         if (!This->data_format.offsets) break;
1051         for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
1052             if (This->data_format.offsets[idx] == dwObj) break;
1053         break;
1054     case DIPH_BYID:
1055         dwObj &= 0x00ffffff;
1056         for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
1057             if ((dataformat_to_odf(This->data_format.wine_df, idx)->dwType & 0x00ffffff) == dwObj)
1058                 break;
1059         break;
1060
1061     case DIPH_BYUSAGE:
1062         FIXME("dwHow = DIPH_BYUSAGE not implemented\n");
1063         break;
1064     default:
1065         WARN("invalid parameter: dwHow = %08x\n", dwHow);
1066         return DIERR_INVALIDPARAM;
1067     }
1068     if (idx < 0) return DIERR_OBJECTNOTFOUND;
1069
1070     odf = dataformat_to_odf(This->data_format.wine_df, idx);
1071     dwSize = pdidoi->dwSize; /* save due to memset below */
1072     memset(pdidoi, 0, pdidoi->dwSize);
1073     pdidoi->dwSize   = dwSize;
1074     if (odf->pguid) pdidoi->guidType = *odf->pguid;
1075     pdidoi->dwOfs    = This->data_format.offsets ? This->data_format.offsets[idx] : odf->dwOfs;
1076     pdidoi->dwType   = odf->dwType;
1077     pdidoi->dwFlags  = odf->dwFlags;
1078
1079     return DI_OK;
1080 }
1081
1082 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceData(
1083         LPDIRECTINPUTDEVICE8A iface, DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1084         LPDWORD entries, DWORD flags)
1085 {
1086     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
1087     HRESULT ret = DI_OK;
1088     int len;
1089
1090     TRACE("(%p) %p -> %p(%d) x%d, 0x%08x\n",
1091           This, dod, entries, entries ? *entries : 0, dodsize, flags);
1092
1093     if (!This->acquired)
1094         return DIERR_NOTACQUIRED;
1095     if (!This->queue_len)
1096         return DIERR_NOTBUFFERED;
1097     if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3))
1098         return DIERR_INVALIDPARAM;
1099
1100     IDirectInputDevice2_Poll(iface);
1101     EnterCriticalSection(&This->crit);
1102
1103     len = This->queue_head - This->queue_tail;
1104     if (len < 0) len += This->queue_len;
1105
1106     if ((*entries != INFINITE) && (len > *entries)) len = *entries;
1107
1108     if (dod)
1109     {
1110         int i;
1111         for (i = 0; i < len; i++)
1112         {
1113             int n = (This->queue_tail + i) % This->queue_len;
1114             memcpy((char *)dod + dodsize * i, This->data_queue + n, dodsize);
1115         }
1116     }
1117     *entries = len;
1118
1119     if (This->overflow)
1120         ret = DI_BUFFEROVERFLOW;
1121
1122     if (!(flags & DIGDD_PEEK))
1123     {
1124         /* Advance reading position */
1125         This->queue_tail = (This->queue_tail + len) % This->queue_len;
1126         This->overflow = FALSE;
1127     }
1128
1129     LeaveCriticalSection(&This->crit);
1130
1131     TRACE("Returning %d events queued\n", *entries);
1132     return ret;
1133 }
1134
1135 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
1136         LPDIRECTINPUTDEVICE8A iface,
1137         LPDIDEVICEINSTANCEA pdidi)
1138 {
1139     FIXME("(this=%p,%p): stub!\n",
1140           iface, pdidi);
1141     
1142     return DI_OK;
1143 }
1144
1145 HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo(
1146         LPDIRECTINPUTDEVICE8W iface,
1147         LPDIDEVICEINSTANCEW pdidi)
1148 {
1149     FIXME("(this=%p,%p): stub!\n",
1150           iface, pdidi);
1151     
1152     return DI_OK;
1153 }
1154
1155 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
1156         LPDIRECTINPUTDEVICE8A iface,
1157         HWND hwndOwner,
1158         DWORD dwFlags)
1159 {
1160     FIXME("(this=%p,%p,0x%08x): stub!\n",
1161           iface, hwndOwner, dwFlags);
1162
1163     return DI_OK;
1164 }
1165
1166 HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
1167         LPDIRECTINPUTDEVICE8A iface,
1168         HINSTANCE hinst,
1169         DWORD dwVersion,
1170         REFGUID rguid)
1171 {
1172     FIXME("(this=%p,%p,%d,%s): stub!\n",
1173           iface, hinst, dwVersion, debugstr_guid(rguid));
1174     return DI_OK;
1175 }
1176
1177 /******************************************************************************
1178  *      IDirectInputDevice2A
1179  */
1180
1181 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
1182         LPDIRECTINPUTDEVICE8A iface,
1183         REFGUID rguid,
1184         LPCDIEFFECT lpeff,
1185         LPDIRECTINPUTEFFECT *ppdef,
1186         LPUNKNOWN pUnkOuter)
1187 {
1188     FIXME("(this=%p,%s,%p,%p,%p): stub!\n",
1189           iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
1190     return DI_OK;
1191 }
1192
1193 HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
1194         LPDIRECTINPUTDEVICE8A iface,
1195         LPDIENUMEFFECTSCALLBACKA lpCallback,
1196         LPVOID lpvRef,
1197         DWORD dwFlags)
1198 {
1199     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1200           iface, lpCallback, lpvRef, dwFlags);
1201     
1202     return DI_OK;
1203 }
1204
1205 HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
1206         LPDIRECTINPUTDEVICE8W iface,
1207         LPDIENUMEFFECTSCALLBACKW lpCallback,
1208         LPVOID lpvRef,
1209         DWORD dwFlags)
1210 {
1211     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1212           iface, lpCallback, lpvRef, dwFlags);
1213     
1214     return DI_OK;
1215 }
1216
1217 HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
1218         LPDIRECTINPUTDEVICE8A iface,
1219         LPDIEFFECTINFOA lpdei,
1220         REFGUID rguid)
1221 {
1222     FIXME("(this=%p,%p,%s): stub!\n",
1223           iface, lpdei, debugstr_guid(rguid));
1224     return DI_OK;
1225 }
1226
1227 HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo(
1228         LPDIRECTINPUTDEVICE8W iface,
1229         LPDIEFFECTINFOW lpdei,
1230         REFGUID rguid)
1231 {
1232     FIXME("(this=%p,%p,%s): stub!\n",
1233           iface, lpdei, debugstr_guid(rguid));
1234     return DI_OK;
1235 }
1236
1237 HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
1238         LPDIRECTINPUTDEVICE8A iface,
1239         LPDWORD pdwOut)
1240 {
1241     FIXME("(this=%p,%p): stub!\n",
1242           iface, pdwOut);
1243     return DI_OK;
1244 }
1245
1246 HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
1247         LPDIRECTINPUTDEVICE8A iface,
1248         DWORD dwFlags)
1249 {
1250     TRACE("(%p) 0x%08x:\n", iface, dwFlags);
1251     return DI_NOEFFECT;
1252 }
1253
1254 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
1255         LPDIRECTINPUTDEVICE8A iface,
1256         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1257         LPVOID lpvRef,
1258         DWORD dwFlags)
1259 {
1260     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1261           iface, lpCallback, lpvRef, dwFlags);
1262     return DI_OK;
1263 }
1264
1265 HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
1266         LPDIRECTINPUTDEVICE8A iface,
1267         LPDIEFFESCAPE lpDIEEsc)
1268 {
1269     FIXME("(this=%p,%p): stub!\n",
1270           iface, lpDIEEsc);
1271     return DI_OK;
1272 }
1273
1274 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
1275         LPDIRECTINPUTDEVICE8A iface)
1276 {
1277     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
1278
1279     if (!This->acquired) return DIERR_NOTACQUIRED;
1280     /* Because wine devices do not need to be polled, just return DI_NOEFFECT */
1281     return DI_NOEFFECT;
1282 }
1283
1284 HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
1285         LPDIRECTINPUTDEVICE8A iface,
1286         DWORD cbObjectData,
1287         LPCDIDEVICEOBJECTDATA rgdod,
1288         LPDWORD pdwInOut,
1289         DWORD dwFlags)
1290 {
1291     FIXME("(this=%p,0x%08x,%p,%p,0x%08x): stub!\n",
1292           iface, cbObjectData, rgdod, pdwInOut, dwFlags);
1293     
1294     return DI_OK;
1295 }
1296
1297 HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface,
1298                                                           LPCSTR lpszFileName,
1299                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
1300                                                           LPVOID pvRef,
1301                                                           DWORD dwFlags)
1302 {
1303     FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
1304     
1305     return DI_OK;
1306 }
1307
1308 HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface,
1309                                                           LPCWSTR lpszFileName,
1310                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
1311                                                           LPVOID pvRef,
1312                                                           DWORD dwFlags)
1313 {
1314     FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags);
1315     
1316     return DI_OK;
1317 }
1318
1319 HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface,
1320                                                           LPCSTR lpszFileName,
1321                                                           DWORD dwEntries,
1322                                                           LPDIFILEEFFECT rgDiFileEft,
1323                                                           DWORD dwFlags)
1324 {
1325     FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
1326     
1327     return DI_OK;
1328 }
1329
1330 HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface,
1331                                                           LPCWSTR lpszFileName,
1332                                                           DWORD dwEntries,
1333                                                           LPDIFILEEFFECT rgDiFileEft,
1334                                                           DWORD dwFlags)
1335 {
1336     FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
1337     
1338     return DI_OK;
1339 }
1340
1341 HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
1342                                                        LPDIACTIONFORMATA lpdiaf,
1343                                                        LPCSTR lpszUserName,
1344                                                        DWORD dwFlags)
1345 {
1346     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
1347 #define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
1348         X(DIDBAM_DEFAULT)
1349         X(DIDBAM_PRESERVE)
1350         X(DIDBAM_INITIALIZE)
1351         X(DIDBAM_HWDEFAULTS)
1352 #undef X
1353     _dump_diactionformatA(lpdiaf);
1354     return DI_OK;
1355 }
1356
1357 HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
1358                                                        LPDIACTIONFORMATW lpdiaf,
1359                                                        LPCWSTR lpszUserName,
1360                                                        DWORD dwFlags)
1361 {
1362     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
1363 #define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
1364         X(DIDBAM_DEFAULT)
1365         X(DIDBAM_PRESERVE)
1366         X(DIDBAM_INITIALIZE)
1367         X(DIDBAM_HWDEFAULTS)
1368 #undef X
1369   
1370     return DI_OK;
1371 }
1372
1373 HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
1374                                                      LPDIACTIONFORMATA lpdiaf,
1375                                                      LPCSTR lpszUserName,
1376                                                      DWORD dwFlags)
1377 {
1378     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
1379     
1380     return DI_OK;
1381 }
1382
1383 HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
1384                                                      LPDIACTIONFORMATW lpdiaf,
1385                                                      LPCWSTR lpszUserName,
1386                                                      DWORD dwFlags)
1387 {
1388     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
1389     
1390     return DI_OK;
1391 }
1392
1393 HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
1394                                                      LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
1395 {
1396     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1397     
1398     return DI_OK;
1399 }
1400
1401 HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface,
1402                                                      LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
1403 {
1404     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1405     
1406     return DI_OK;
1407 }