dinput: Move few helper functions and standardize them.
[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 "winuser.h"
36 #include "winerror.h"
37 #include "dinput.h"
38 #include "device_private.h"
39 #include "dinput_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
42
43 /******************************************************************************
44  *      Various debugging tools
45  */
46 void _dump_cooperativelevel_DI(DWORD dwFlags) {
47     if (TRACE_ON(dinput)) {
48         unsigned int   i;
49         static const struct {
50             DWORD       mask;
51             const char  *name;
52         } flags[] = {
53 #define FE(x) { x, #x}
54             FE(DISCL_BACKGROUND),
55             FE(DISCL_EXCLUSIVE),
56             FE(DISCL_FOREGROUND),
57             FE(DISCL_NONEXCLUSIVE),
58             FE(DISCL_NOWINKEY)
59 #undef FE
60         };
61         for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
62             if (flags[i].mask & dwFlags)
63                 DPRINTF("%s ",flags[i].name);
64         DPRINTF("\n");
65     }
66 }
67
68 void _dump_EnumObjects_flags(DWORD dwFlags) {
69     if (TRACE_ON(dinput)) {
70         unsigned int   i;
71         DWORD type, instance;
72         static const struct {
73             DWORD       mask;
74             const char  *name;
75         } flags[] = {
76 #define FE(x) { x, #x}
77             FE(DIDFT_RELAXIS),
78             FE(DIDFT_ABSAXIS),
79             FE(DIDFT_PSHBUTTON),
80             FE(DIDFT_TGLBUTTON),
81             FE(DIDFT_POV),
82             FE(DIDFT_COLLECTION),
83             FE(DIDFT_NODATA),       
84             FE(DIDFT_FFACTUATOR),
85             FE(DIDFT_FFEFFECTTRIGGER),
86             FE(DIDFT_OUTPUT),
87             FE(DIDFT_VENDORDEFINED),
88             FE(DIDFT_ALIAS),
89             FE(DIDFT_OPTIONAL)
90 #undef FE
91         };
92         type = (dwFlags & 0xFF0000FF);
93         instance = ((dwFlags >> 8) & 0xFFFF);
94         DPRINTF("Type:");
95         if (type == DIDFT_ALL) {
96             DPRINTF(" DIDFT_ALL");
97         } else {
98             for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
99                 if (flags[i].mask & type) {
100                     type &= ~flags[i].mask;
101                     DPRINTF(" %s",flags[i].name);
102                 }
103             }
104             if (type) {
105                 DPRINTF(" (unhandled: %08x)", type);
106             }
107         }
108         DPRINTF(" / Instance: ");
109         if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) {
110             DPRINTF("DIDFT_ANYINSTANCE");
111         } else {
112             DPRINTF("%3d", instance);
113         }
114     }
115 }
116
117 void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) {
118     if (TRACE_ON(dinput)) {
119         DPRINTF("  - dwObj = 0x%08x\n", diph->dwObj);
120         DPRINTF("  - dwHow = %s\n",
121                 ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" :
122                  ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" :
123                   ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown")));
124     }
125 }
126
127 void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) {
128     if (TRACE_ON(dinput)) {
129         DPRINTF("    - enumerating : %s ('%s') - %2d - 0x%08x - %s\n",
130                 debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName);
131     }
132 }
133
134 void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) {
135     if (TRACE_ON(dinput)) {
136         DPRINTF("    - enumerating : %s ('%s'), - %2d - 0x%08x - %s\n",
137                 debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName));
138     }
139 }
140
141 /* This function is a helper to convert a GUID into any possible DInput GUID out there */
142 const char *_dump_dinput_GUID(const GUID *guid) {
143     unsigned int i;
144     static const struct {
145         const GUID *guid;
146         const char *name;
147     } guids[] = {
148 #define FE(x) { &x, #x}
149         FE(GUID_XAxis),
150         FE(GUID_YAxis),
151         FE(GUID_ZAxis),
152         FE(GUID_RxAxis),
153         FE(GUID_RyAxis),
154         FE(GUID_RzAxis),
155         FE(GUID_Slider),
156         FE(GUID_Button),
157         FE(GUID_Key),
158         FE(GUID_POV),
159         FE(GUID_Unknown),
160         FE(GUID_SysMouse),
161         FE(GUID_SysKeyboard),
162         FE(GUID_Joystick),
163         FE(GUID_ConstantForce),
164         FE(GUID_RampForce),
165         FE(GUID_Square),
166         FE(GUID_Sine),
167         FE(GUID_Triangle),
168         FE(GUID_SawtoothUp),
169         FE(GUID_SawtoothDown),
170         FE(GUID_Spring),
171         FE(GUID_Damper),
172         FE(GUID_Inertia),
173         FE(GUID_Friction),
174         FE(GUID_CustomForce)
175 #undef FE
176     };
177     if (guid == NULL)
178         return "null GUID";
179     for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) {
180         if (IsEqualGUID(guids[i].guid, guid)) {
181             return guids[i].name;
182         }
183     }
184     return "Unknown GUID";
185 }
186
187 void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) {
188     unsigned int i;
189
190     TRACE("Dumping DIDATAFORMAT structure:\n");
191     TRACE("  - dwSize: %d\n", df->dwSize);
192     if (df->dwSize != sizeof(DIDATAFORMAT)) {
193         WARN("Non-standard DIDATAFORMAT structure size %d\n", df->dwSize);
194     }
195     TRACE("  - dwObjsize: %d\n", df->dwObjSize);
196     if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) {
197         WARN("Non-standard DIOBJECTDATAFORMAT structure size %d\n", df->dwObjSize);
198     }
199     TRACE("  - dwFlags: 0x%08x (", df->dwFlags);
200     switch (df->dwFlags) {
201         case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break;
202         case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break;
203         default: TRACE("unknown"); break;
204     }
205     TRACE(")\n");
206     TRACE("  - dwDataSize: %d\n", df->dwDataSize);
207     TRACE("  - dwNumObjs: %d\n", df->dwNumObjs);
208     
209     for (i = 0; i < df->dwNumObjs; i++) {
210         TRACE("  - Object %d:\n", i);
211         TRACE("      * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid));
212         TRACE("      * dwOfs: %d\n", df->rgodf[i].dwOfs);
213         TRACE("      * dwType: 0x%08x\n", df->rgodf[i].dwType);
214         TRACE("        "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n");
215         TRACE("      * dwFlags: 0x%08x\n", df->rgodf[i].dwFlags);
216     }
217 }
218
219 /* Conversion between internal data buffer and external data buffer */
220 void fill_DataFormat(void *out, const void *in, DataFormat *df) {
221     int i;
222     const char *in_c = in;
223     char *out_c = (char *) out;
224
225     if (df->dt == NULL) {
226         /* This means that the app uses Wine's internal data format */
227         memcpy(out, in, df->internal_format_size);
228     } else {
229         for (i = 0; i < df->size; i++) {
230             if (df->dt[i].offset_in >= 0) {
231                 switch (df->dt[i].size) {
232                     case 1:
233                         TRACE("Copying (c) to %d from %d (value %d)\n",
234                               df->dt[i].offset_out, df->dt[i].offset_in, *(in_c + df->dt[i].offset_in));
235                         *(out_c + df->dt[i].offset_out) = *(in_c + df->dt[i].offset_in);
236                         break;
237
238                     case 2:
239                         TRACE("Copying (s) to %d from %d (value %d)\n",
240                               df->dt[i].offset_out, df->dt[i].offset_in, *((const short *)(in_c + df->dt[i].offset_in)));
241                         *((short *)(out_c + df->dt[i].offset_out)) = *((const short *)(in_c + df->dt[i].offset_in));
242                         break;
243
244                     case 4:
245                         TRACE("Copying (i) to %d from %d (value %d)\n",
246                               df->dt[i].offset_out, df->dt[i].offset_in, *((const int *)(in_c + df->dt[i].offset_in)));
247                         *((int *)(out_c + df->dt[i].offset_out)) = *((const int *)(in_c + df->dt[i].offset_in));
248                         break;
249
250                     default:
251                         memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
252                         break;
253                 }
254             } else {
255                 switch (df->dt[i].size) {
256                     case 1:
257                         TRACE("Copying (c) to %d default value %d\n",
258                               df->dt[i].offset_out, df->dt[i].value);
259                         *(out_c + df->dt[i].offset_out) = (char) df->dt[i].value;
260                         break;
261                         
262                     case 2:
263                         TRACE("Copying (s) to %d default value %d\n",
264                               df->dt[i].offset_out, df->dt[i].value);
265                         *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
266                         break;
267                         
268                     case 4:
269                         TRACE("Copying (i) to %d default value %d\n",
270                               df->dt[i].offset_out, df->dt[i].value);
271                         *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value;
272                         break;
273                         
274                     default:
275                         memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size);
276                         break;
277                 }
278             }
279         }
280     }
281 }
282
283 void release_DataFormat(DataFormat * format)
284 {
285     TRACE("Deleting DataTransform :\n");
286
287     HeapFree(GetProcessHeap(), 0, format->dt);
288 }
289
290 /* Make all instances sequential */
291 static void calculate_ids(LPDIDATAFORMAT df)
292 {
293     int i, axis = 0, pov = 0, button = 0;
294     int axis_base, pov_base, button_base;
295     DWORD type;
296
297     /* Make two passes over the format. The first counts the number
298      * for each type and the second sets the id */
299     for (i = 0; i < df->dwNumObjs; i++)
300     {
301         type = DIDFT_GETTYPE(df->rgodf[i].dwType);
302         if      (type & DIDFT_AXIS)   axis++;
303         else if (type & DIDFT_POV)    pov++;
304         else if (type & DIDFT_BUTTON) button++;
305     }
306
307     axis_base   = 0;
308     pov_base    = axis_base + axis;
309     button_base = pov_base + pov;
310     axis = pov = button = 0;
311
312     for (i = 0; i < df->dwNumObjs; i++)
313     {
314         type = DIDFT_GETTYPE(df->rgodf[i].dwType);
315         if (type & DIDFT_AXIS)
316         {
317             type |= DIDFT_MAKEINSTANCE(axis_base + axis++);
318             TRACE("axis type = 0x%08x\n", type);
319         } else if (type & DIDFT_POV)
320         {
321             type |= DIDFT_MAKEINSTANCE(pov_base + pov++);
322             TRACE("POV type = 0x%08x\n", type);
323         } else if (type & DIDFT_BUTTON)
324         {
325             type |= DIDFT_MAKEINSTANCE(button_base + button++);
326             TRACE("button type = 0x%08x\n", type);
327         }
328         df->rgodf[i].dwType = type;
329     }
330 }
331
332 DataFormat *create_DataFormat(LPCDIDATAFORMAT wine_format, LPDIDATAFORMAT asked_format, int *offset)
333 {
334     DataFormat *ret;
335     DataTransform *dt;
336     unsigned int i, j;
337     int same = 1;
338     int *done;
339     int index = 0;
340     DWORD next = 0;
341     
342     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
343     
344     done = HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs);
345     memset(done, 0, sizeof(int) * asked_format->dwNumObjs);
346     
347     dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
348     
349     TRACE("Creating DataTransform :\n");
350     
351     for (i = 0; i < wine_format->dwNumObjs; i++) {
352         offset[i] = -1;
353         
354         for (j = 0; j < asked_format->dwNumObjs; j++) {
355             if (done[j] == 1)
356                 continue;
357             
358             if (/* Check if the application either requests any GUID and if not, it if matches
359                  * the GUID of the Wine object.
360                  */
361                 ((asked_format->rgodf[j].pguid == NULL) ||
362                  (wine_format->rgodf[i].pguid == NULL) ||
363                  (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
364                 &&
365                 (/* Then check if it accepts any instance id, and if not, if it matches Wine's
366                   * instance id.
367                   */
368                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0xFFFF) ||
369                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0x00FF) || /* This is mentionned in no DX docs, but it works fine - tested on WinXP */
370                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(wine_format->rgodf[i].dwType)))
371                 &&
372                 ( /* Then if the asked type matches the one Wine provides */
373                  DIDFT_GETTYPE(asked_format->rgodf[j].dwType) & wine_format->rgodf[i].dwType))
374             {
375                 done[j] = 1;
376                 
377                 TRACE("Matching :\n");
378                 TRACE("   - Asked (%d) :\n", j);
379                 TRACE("       * GUID: %s ('%s')\n",
380                       debugstr_guid(asked_format->rgodf[j].pguid),
381                       _dump_dinput_GUID(asked_format->rgodf[j].pguid));
382                 TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
383                 TRACE("       * dwType: %08x\n", asked_format->rgodf[j].dwType);
384                 TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
385                 
386                 TRACE("   - Wine  (%d) :\n", i);
387                 TRACE("       * GUID: %s ('%s')\n",
388                       debugstr_guid(wine_format->rgodf[i].pguid),
389                       _dump_dinput_GUID(wine_format->rgodf[i].pguid));
390                 TRACE("       * Offset: %3d\n", wine_format->rgodf[i].dwOfs);
391                 TRACE("       * dwType: %08x\n", wine_format->rgodf[i].dwType);
392                 TRACE("         "); _dump_EnumObjects_flags(wine_format->rgodf[i].dwType); TRACE("\n");
393                 
394                 if (wine_format->rgodf[i].dwType & DIDFT_BUTTON)
395                     dt[index].size = sizeof(BYTE);
396                 else
397                     dt[index].size = sizeof(DWORD);
398                 dt[index].offset_in = wine_format->rgodf[i].dwOfs;
399                 dt[index].offset_out = asked_format->rgodf[j].dwOfs;
400                 offset[i] = asked_format->rgodf[j].dwOfs;
401                 dt[index].value = 0;
402                 next = next + dt[index].size;
403                 
404                 if (wine_format->rgodf[i].dwOfs != dt[index].offset_out)
405                     same = 0;
406                 
407                 index++;
408                 break;
409             }
410         }
411         
412         if (j == asked_format->dwNumObjs)
413             same = 0;
414     }
415     
416     TRACE("Setting to default value :\n");
417     for (j = 0; j < asked_format->dwNumObjs; j++) {
418         if (done[j] == 0) {
419             TRACE("   - Asked (%d) :\n", j);
420             TRACE("       * GUID: %s ('%s')\n",
421                   debugstr_guid(asked_format->rgodf[j].pguid),
422                   _dump_dinput_GUID(asked_format->rgodf[j].pguid));
423             TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
424             TRACE("       * dwType: %08x\n", asked_format->rgodf[j].dwType);
425             TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
426             
427             if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
428                 dt[index].size = sizeof(BYTE);
429             else
430                 dt[index].size = sizeof(DWORD);
431             dt[index].offset_in  = -1;
432             dt[index].offset_out = asked_format->rgodf[j].dwOfs;
433             dt[index].value = 0;
434             index++;
435             
436             same = 0;
437         }
438     }
439     
440     ret->internal_format_size = wine_format->dwDataSize;
441     ret->size = index;
442     if (same) {
443         ret->dt = NULL;
444         HeapFree(GetProcessHeap(), 0, dt);
445     } else {
446         ret->dt = dt;
447     }
448     
449     HeapFree(GetProcessHeap(), 0, done);
450
451     /* Last step - reset all instances of the new format */
452     calculate_ids(asked_format);
453     return ret;
454 }
455
456 /* find an object by it's offset in a data format */
457 int offset_to_object(LPCDIDATAFORMAT df, int offset)
458 {
459     int i;
460
461     for (i = 0; i < df->dwNumObjs; i++)
462         if (df->rgodf[i].dwOfs == offset)
463             return i;
464
465     return -1;
466 }
467
468 static int id_to_object(LPCDIDATAFORMAT df, int id)
469 {
470     int i;
471
472     for (i = 0; i < df->dwNumObjs; i++)
473         if ((df->rgodf[i].dwType & 0x00ffffff) == (id & 0x00ffffff))
474             return i;
475
476     return -1;
477 }
478
479 int find_property(LPCDIDATAFORMAT df, LPCDIPROPHEADER ph)
480 {
481     switch (ph->dwHow)
482     {
483         case DIPH_BYID:     return id_to_object(df, ph->dwObj);
484         case DIPH_BYOFFSET: return offset_to_object(df, ph->dwObj);
485     }
486     FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow);
487
488     return -1;
489 }
490
491
492 BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) {
493     DIDEVICEOBJECTINSTANCEW ddtmp;
494     device_enumobjects_AtoWcb_data* data;
495
496     data = (device_enumobjects_AtoWcb_data*) lpvRef;
497     
498     memset(&ddtmp, 0, sizeof(ddtmp));
499     
500     ddtmp.dwSize = sizeof(DIDEVICEINSTANCEW);
501     ddtmp.guidType     = lpddi->guidType;
502     ddtmp.dwOfs        = lpddi->dwOfs;
503     ddtmp.dwType       = lpddi->dwType;
504     ddtmp.dwFlags      = lpddi->dwFlags;
505     MultiByteToWideChar(CP_ACP, 0, lpddi->tszName, -1, ddtmp.tszName, MAX_PATH);
506     
507     if (lpddi->dwSize == sizeof(DIDEVICEINSTANCEA)) {
508         /**
509          * if dwSize < sizeof(DIDEVICEINSTANCEA of DInput version >= 5)
510          *  force feedback and other newer datas aren't available
511          */
512         ddtmp.dwFFMaxForce        = lpddi->dwFFMaxForce;
513         ddtmp.dwFFForceResolution = lpddi->dwFFForceResolution;
514         ddtmp.wCollectionNumber   = lpddi->wCollectionNumber;
515         ddtmp.wDesignatorIndex    = lpddi->wDesignatorIndex;
516         ddtmp.wUsagePage          = lpddi->wUsagePage;
517         ddtmp.wUsage              = lpddi->wUsage;
518         ddtmp.dwDimension         = lpddi->dwDimension;
519         ddtmp.wExponent           = lpddi->wExponent;
520         ddtmp.wReserved           = lpddi->wReserved;
521     }
522     return data->lpCallBack(&ddtmp, data->lpvRef);
523 }
524
525 /******************************************************************************
526  *      queue_event - add new event to the ring queue
527  */
528
529 void queue_event(LPDIRECTINPUTDEVICE8A iface, int ofs, DWORD data, DWORD time, DWORD seq)
530 {
531     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
532     int next_pos;
533
534     if (!This->queue_len || This->overflow || ofs < 0) return;
535
536     next_pos = (This->queue_head + 1) % This->queue_len;
537     if (next_pos == This->queue_tail)
538     {
539         TRACE(" queue overflowed\n");
540         This->overflow = TRUE;
541         return;
542     }
543
544     TRACE(" queueing %d at offset %d (queue head %d / size %d)\n",
545           data, ofs, This->queue_head, This->queue_len);
546
547     This->data_queue[This->queue_head].dwOfs       = ofs;
548     This->data_queue[This->queue_head].dwData      = data;
549     This->data_queue[This->queue_head].dwTimeStamp = time;
550     This->data_queue[This->queue_head].dwSequence  = seq;
551     This->queue_head = next_pos;
552 }
553
554 /******************************************************************************
555  *      Acquire
556  */
557
558 HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
559 {
560     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
561     HRESULT res;
562
563     EnterCriticalSection(&This->crit);
564     res = This->acquired ? S_FALSE : DI_OK;
565     This->acquired = 1;
566     if (res == DI_OK)
567         This->queue_head = This->queue_tail = This->overflow = 0;
568     LeaveCriticalSection(&This->crit);
569
570     return res;
571 }
572
573 /******************************************************************************
574  *      Unacquire
575  */
576
577 HRESULT WINAPI IDirectInputDevice2AImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
578 {
579     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
580     HRESULT res;
581
582     EnterCriticalSection(&This->crit);
583     res = !This->acquired ? DI_NOEFFECT : DI_OK;
584     This->acquired = 0;
585     LeaveCriticalSection(&This->crit);
586
587     return res;
588 }
589
590 /******************************************************************************
591  *      IDirectInputDeviceA
592  */
593
594 HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
595         LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
596 ) {
597     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
598     
599     TRACE("(this=%p,%p)\n",This,df);
600     
601     _dump_DIDATAFORMAT(df);
602     
603     return DI_OK;
604 }
605
606 /******************************************************************************
607   *     SetCooperativeLevel
608   *
609   *  Set cooperative level and the source window for the events.
610   */
611 HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
612         LPDIRECTINPUTDEVICE8A iface, HWND hwnd, DWORD dwflags)
613 {
614     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
615
616     TRACE("(%p) %p,0x%08x\n", This, hwnd, dwflags);
617     TRACE(" cooperative level : ");
618     _dump_cooperativelevel_DI(dwflags);
619
620     if ((dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == 0 ||
621         (dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE) ||
622         (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == 0 ||
623         (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == (DISCL_FOREGROUND | DISCL_BACKGROUND))
624         return DIERR_INVALIDPARAM;
625
626     if (dwflags == (DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))
627         hwnd = GetDesktopWindow();
628
629     if (!hwnd) return E_HANDLE;
630
631     /* For security reasons native does not allow exclusive background level
632        for mouse and keyboard only */
633     if (dwflags & DISCL_EXCLUSIVE && dwflags & DISCL_BACKGROUND &&
634         (IsEqualGUID(&This->guid, &GUID_SysMouse) ||
635          IsEqualGUID(&This->guid, &GUID_SysKeyboard)))
636         return DIERR_UNSUPPORTED;
637
638     /* Store the window which asks for the mouse */
639     EnterCriticalSection(&This->crit);
640     This->win = hwnd;
641     This->dwCoopLevel = dwflags;
642     LeaveCriticalSection(&This->crit);
643
644     return DI_OK;
645 }
646
647 /******************************************************************************
648   *     SetEventNotification : specifies event to be sent on state change
649   */
650 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
651         LPDIRECTINPUTDEVICE8A iface, HANDLE event)
652 {
653     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
654
655     TRACE("(%p) %p\n", This, event);
656
657     EnterCriticalSection(&This->crit);
658     This->hEvent = event;
659     LeaveCriticalSection(&This->crit);
660     return DI_OK;
661 }
662
663 ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
664 {
665     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
666     ULONG ref;
667
668     ref = InterlockedDecrement(&(This->ref));
669     if (ref) return ref;
670
671     DeleteCriticalSection(&This->crit);
672     HeapFree(GetProcessHeap(), 0, This->data_queue);
673     HeapFree(GetProcessHeap(), 0, This);
674
675     return DI_OK;
676 }
677
678 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
679         LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj
680 )
681 {
682     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
683     
684     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
685     if (IsEqualGUID(&IID_IUnknown,riid)) {
686         IDirectInputDevice2_AddRef(iface);
687         *ppobj = This;
688         return DI_OK;
689     }
690     if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) {
691         IDirectInputDevice2_AddRef(iface);
692         *ppobj = This;
693         return DI_OK;
694     }
695     if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) {
696         IDirectInputDevice2_AddRef(iface);
697         *ppobj = This;
698         return DI_OK;
699     }
700     if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
701         IDirectInputDevice7_AddRef(iface);
702         *ppobj = This;
703         return DI_OK;
704     }
705     if (IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
706         IDirectInputDevice8_AddRef(iface);
707         *ppobj = This;
708         return DI_OK;
709     }
710     TRACE("Unsupported interface !\n");
711     return E_FAIL;
712 }
713
714 HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(
715         LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj
716 )
717 {
718     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
719     
720     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
721     if (IsEqualGUID(&IID_IUnknown,riid)) {
722         IDirectInputDevice2_AddRef(iface);
723         *ppobj = This;
724         return DI_OK;
725     }
726     if (IsEqualGUID(&IID_IDirectInputDeviceW,riid)) {
727         IDirectInputDevice2_AddRef(iface);
728         *ppobj = This;
729         return DI_OK;
730     }
731     if (IsEqualGUID(&IID_IDirectInputDevice2W,riid)) {
732         IDirectInputDevice2_AddRef(iface);
733         *ppobj = This;
734         return DI_OK;
735     }
736     if (IsEqualGUID(&IID_IDirectInputDevice7W,riid)) {
737         IDirectInputDevice7_AddRef(iface);
738         *ppobj = This;
739         return DI_OK;
740     }
741     if (IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
742         IDirectInputDevice8_AddRef(iface);
743         *ppobj = This;
744         return DI_OK;
745     }
746     TRACE("Unsupported interface !\n");
747     return E_FAIL;
748 }
749
750 ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
751         LPDIRECTINPUTDEVICE8A iface)
752 {
753     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
754     return InterlockedIncrement(&(This->ref));
755 }
756
757 HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
758         LPDIRECTINPUTDEVICE8A iface,
759         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
760         LPVOID lpvRef,
761         DWORD dwFlags)
762 {
763     FIXME("(this=%p,%p,%p,%08x): stub!\n", iface, lpCallback, lpvRef, dwFlags);
764     if (TRACE_ON(dinput)) {
765         DPRINTF("  - flags = ");
766         _dump_EnumObjects_flags(dwFlags);
767         DPRINTF("\n");
768     }
769     
770     return DI_OK;
771 }
772
773 HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(
774         LPDIRECTINPUTDEVICE8W iface,
775         LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
776         LPVOID lpvRef,
777         DWORD dwFlags)
778 {
779     FIXME("(this=%p,%p,%p,%08x): stub!\n", iface, lpCallback, lpvRef, dwFlags);
780     if (TRACE_ON(dinput)) {
781         DPRINTF("  - flags = ");
782         _dump_EnumObjects_flags(dwFlags);
783         DPRINTF("\n");
784     }
785     
786     return DI_OK;
787 }
788
789 /******************************************************************************
790  *      GetProperty
791  */
792
793 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
794         LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
795 {
796     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
797
798     TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
799     _dump_DIPROPHEADER(pdiph);
800
801     if (HIWORD(rguid)) return DI_OK;
802
803     switch (LOWORD(rguid))
804     {
805         case (DWORD) DIPROP_BUFFERSIZE:
806         {
807             LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
808
809             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
810
811             pd->dwData = This->queue_len;
812             TRACE("buffersize = %d\n", pd->dwData);
813             break;
814         }
815         default:
816             WARN("Unknown property %s\n", debugstr_guid(rguid));
817             break;
818     }
819
820     return DI_OK;
821 }
822
823 /******************************************************************************
824  *      SetProperty
825  */
826
827 HRESULT WINAPI IDirectInputDevice2AImpl_SetProperty(
828         LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER pdiph)
829 {
830     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
831
832     TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
833     _dump_DIPROPHEADER(pdiph);
834
835     if (HIWORD(rguid)) return DI_OK;
836
837     switch (LOWORD(rguid))
838     {
839         case (DWORD) DIPROP_BUFFERSIZE:
840         {
841             LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
842
843             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
844             if (This->acquired) return DIERR_ACQUIRED;
845
846             TRACE("buffersize = %d\n", pd->dwData);
847
848             EnterCriticalSection(&This->crit);
849             HeapFree(GetProcessHeap(), 0, This->data_queue);
850
851             This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0,
852                                 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
853             This->queue_head = This->queue_tail = This->overflow = 0;
854             This->queue_len  = pd->dwData;
855
856             LeaveCriticalSection(&This->crit);
857             break;
858         }
859         default:
860             WARN("Unknown property %s\n", debugstr_guid(rguid));
861             return DIERR_UNSUPPORTED;
862     }
863
864     return DI_OK;
865 }
866
867 HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
868         LPDIRECTINPUTDEVICE8A iface,
869         LPDIDEVICEOBJECTINSTANCEA pdidoi,
870         DWORD dwObj,
871         DWORD dwHow)
872 {
873     FIXME("(this=%p,%p,%d,0x%08x): stub!\n",
874           iface, pdidoi, dwObj, dwHow);
875     
876     return DI_OK;
877 }
878
879 HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(
880         LPDIRECTINPUTDEVICE8W iface,
881         LPDIDEVICEOBJECTINSTANCEW pdidoi,
882         DWORD dwObj,
883         DWORD dwHow)
884 {
885     FIXME("(this=%p,%p,%d,0x%08x): stub!\n",
886           iface, pdidoi, dwObj, dwHow);
887     
888     return DI_OK;
889 }
890
891 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceData(
892         LPDIRECTINPUTDEVICE8A iface, DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
893         LPDWORD entries, DWORD flags)
894 {
895     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
896     HRESULT ret = DI_OK;
897     int len;
898
899     TRACE("(%p) %p -> %p(%d) x%d, 0x%08x\n",
900           This, dod, entries, entries ? *entries : 0, dodsize, flags);
901
902     if (!This->acquired)
903         return DIERR_NOTACQUIRED;
904     if (!This->queue_len)
905         return DIERR_NOTBUFFERED;
906     if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3))
907         return DIERR_INVALIDPARAM;
908
909     IDirectInputDevice2_Poll(iface);
910     EnterCriticalSection(&This->crit);
911
912     len = This->queue_head - This->queue_tail;
913     if (len < 0) len += This->queue_len;
914
915     if ((*entries != INFINITE) && (len > *entries)) len = *entries;
916
917     if (dod)
918     {
919         int i;
920         for (i = 0; i < len; i++)
921         {
922             int n = (This->queue_tail + i) % This->queue_len;
923             memcpy((char *)dod + dodsize * i, This->data_queue + n, dodsize);
924         }
925     }
926     *entries = len;
927
928     if (This->overflow)
929         ret = DI_BUFFEROVERFLOW;
930
931     if (!(flags & DIGDD_PEEK))
932     {
933         /* Advance reading position */
934         This->queue_tail = (This->queue_tail + len) % This->queue_len;
935         This->overflow = FALSE;
936     }
937
938     LeaveCriticalSection(&This->crit);
939
940     TRACE("Returning %d events queued\n", *entries);
941     return ret;
942 }
943
944 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
945         LPDIRECTINPUTDEVICE8A iface,
946         LPDIDEVICEINSTANCEA pdidi)
947 {
948     FIXME("(this=%p,%p): stub!\n",
949           iface, pdidi);
950     
951     return DI_OK;
952 }
953
954 HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo(
955         LPDIRECTINPUTDEVICE8W iface,
956         LPDIDEVICEINSTANCEW pdidi)
957 {
958     FIXME("(this=%p,%p): stub!\n",
959           iface, pdidi);
960     
961     return DI_OK;
962 }
963
964 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
965         LPDIRECTINPUTDEVICE8A iface,
966         HWND hwndOwner,
967         DWORD dwFlags)
968 {
969     FIXME("(this=%p,%p,0x%08x): stub!\n",
970           iface, hwndOwner, dwFlags);
971
972     return DI_OK;
973 }
974
975 HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
976         LPDIRECTINPUTDEVICE8A iface,
977         HINSTANCE hinst,
978         DWORD dwVersion,
979         REFGUID rguid)
980 {
981     FIXME("(this=%p,%p,%d,%s): stub!\n",
982           iface, hinst, dwVersion, debugstr_guid(rguid));
983     return DI_OK;
984 }
985
986 /******************************************************************************
987  *      IDirectInputDevice2A
988  */
989
990 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
991         LPDIRECTINPUTDEVICE8A iface,
992         REFGUID rguid,
993         LPCDIEFFECT lpeff,
994         LPDIRECTINPUTEFFECT *ppdef,
995         LPUNKNOWN pUnkOuter)
996 {
997     FIXME("(this=%p,%s,%p,%p,%p): stub!\n",
998           iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
999     return DI_OK;
1000 }
1001
1002 HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
1003         LPDIRECTINPUTDEVICE8A iface,
1004         LPDIENUMEFFECTSCALLBACKA lpCallback,
1005         LPVOID lpvRef,
1006         DWORD dwFlags)
1007 {
1008     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1009           iface, lpCallback, lpvRef, dwFlags);
1010     
1011     return DI_OK;
1012 }
1013
1014 HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
1015         LPDIRECTINPUTDEVICE8W iface,
1016         LPDIENUMEFFECTSCALLBACKW lpCallback,
1017         LPVOID lpvRef,
1018         DWORD dwFlags)
1019 {
1020     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1021           iface, lpCallback, lpvRef, dwFlags);
1022     
1023     return DI_OK;
1024 }
1025
1026 HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
1027         LPDIRECTINPUTDEVICE8A iface,
1028         LPDIEFFECTINFOA lpdei,
1029         REFGUID rguid)
1030 {
1031     FIXME("(this=%p,%p,%s): stub!\n",
1032           iface, lpdei, debugstr_guid(rguid));
1033     return DI_OK;
1034 }
1035
1036 HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo(
1037         LPDIRECTINPUTDEVICE8W iface,
1038         LPDIEFFECTINFOW lpdei,
1039         REFGUID rguid)
1040 {
1041     FIXME("(this=%p,%p,%s): stub!\n",
1042           iface, lpdei, debugstr_guid(rguid));
1043     return DI_OK;
1044 }
1045
1046 HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
1047         LPDIRECTINPUTDEVICE8A iface,
1048         LPDWORD pdwOut)
1049 {
1050     FIXME("(this=%p,%p): stub!\n",
1051           iface, pdwOut);
1052     return DI_OK;
1053 }
1054
1055 HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
1056         LPDIRECTINPUTDEVICE8A iface,
1057         DWORD dwFlags)
1058 {
1059     FIXME("(this=%p,0x%08x): stub!\n",
1060           iface, dwFlags);
1061     return DI_OK;
1062 }
1063
1064 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
1065         LPDIRECTINPUTDEVICE8A iface,
1066         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1067         LPVOID lpvRef,
1068         DWORD dwFlags)
1069 {
1070     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1071           iface, lpCallback, lpvRef, dwFlags);
1072     return DI_OK;
1073 }
1074
1075 HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
1076         LPDIRECTINPUTDEVICE8A iface,
1077         LPDIEFFESCAPE lpDIEEsc)
1078 {
1079     FIXME("(this=%p,%p): stub!\n",
1080           iface, lpDIEEsc);
1081     return DI_OK;
1082 }
1083
1084 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
1085         LPDIRECTINPUTDEVICE8A iface)
1086 {
1087     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
1088
1089     if (!This->acquired) return DIERR_NOTACQUIRED;
1090     /* Because wine devices do not need to be polled, just return DI_NOEFFECT */
1091     return DI_NOEFFECT;
1092 }
1093
1094 HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
1095         LPDIRECTINPUTDEVICE8A iface,
1096         DWORD cbObjectData,
1097         LPCDIDEVICEOBJECTDATA rgdod,
1098         LPDWORD pdwInOut,
1099         DWORD dwFlags)
1100 {
1101     FIXME("(this=%p,0x%08x,%p,%p,0x%08x): stub!\n",
1102           iface, cbObjectData, rgdod, pdwInOut, dwFlags);
1103     
1104     return DI_OK;
1105 }
1106
1107 HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface,
1108                                                           LPCSTR lpszFileName,
1109                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
1110                                                           LPVOID pvRef,
1111                                                           DWORD dwFlags)
1112 {
1113     FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
1114     
1115     return DI_OK;
1116 }
1117
1118 HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface,
1119                                                           LPCWSTR lpszFileName,
1120                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
1121                                                           LPVOID pvRef,
1122                                                           DWORD dwFlags)
1123 {
1124     FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags);
1125     
1126     return DI_OK;
1127 }
1128
1129 HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface,
1130                                                           LPCSTR lpszFileName,
1131                                                           DWORD dwEntries,
1132                                                           LPDIFILEEFFECT rgDiFileEft,
1133                                                           DWORD dwFlags)
1134 {
1135     FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
1136     
1137     return DI_OK;
1138 }
1139
1140 HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface,
1141                                                           LPCWSTR lpszFileName,
1142                                                           DWORD dwEntries,
1143                                                           LPDIFILEEFFECT rgDiFileEft,
1144                                                           DWORD dwFlags)
1145 {
1146     FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
1147     
1148     return DI_OK;
1149 }
1150
1151 HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
1152                                                        LPDIACTIONFORMATA lpdiaf,
1153                                                        LPCSTR lpszUserName,
1154                                                        DWORD dwFlags)
1155 {
1156     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
1157     
1158     return DI_OK;
1159 }
1160
1161 HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
1162                                                        LPDIACTIONFORMATW lpdiaf,
1163                                                        LPCWSTR lpszUserName,
1164                                                        DWORD dwFlags)
1165 {
1166     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
1167   
1168     return DI_OK;
1169 }
1170
1171 HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
1172                                                      LPDIACTIONFORMATA lpdiaf,
1173                                                      LPCSTR lpszUserName,
1174                                                      DWORD dwFlags)
1175 {
1176     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
1177     
1178     return DI_OK;
1179 }
1180
1181 HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
1182                                                      LPDIACTIONFORMATW lpdiaf,
1183                                                      LPCWSTR lpszUserName,
1184                                                      DWORD dwFlags)
1185 {
1186     FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
1187     
1188     return DI_OK;
1189 }
1190
1191 HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
1192                                                      LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
1193 {
1194     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1195     
1196     return DI_OK;
1197 }
1198
1199 HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface,
1200                                                      LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
1201 {
1202     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1203     
1204     return DI_OK;
1205 }