xref: /reactos/dll/directx/wine/dinput/device.c (revision c7bba39a)
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 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
45 {
46     return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface);
47 }
48 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
49 {
50     return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface);
51 }
52 
53 static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(IDirectInputDeviceImpl *This)
54 {
55     return &This->IDirectInputDevice8A_iface;
56 }
57 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(IDirectInputDeviceImpl *This)
58 {
59     return &This->IDirectInputDevice8W_iface;
60 }
61 
62 /******************************************************************************
63  *	Various debugging tools
64  */
65 static void _dump_cooperativelevel_DI(DWORD dwFlags) {
66     if (TRACE_ON(dinput)) {
67 	unsigned int   i;
68 	static const struct {
69 	    DWORD       mask;
70 	    const char  *name;
71 	} flags[] = {
72 #define FE(x) { x, #x}
73 	    FE(DISCL_BACKGROUND),
74 	    FE(DISCL_EXCLUSIVE),
75 	    FE(DISCL_FOREGROUND),
76 	    FE(DISCL_NONEXCLUSIVE),
77 	    FE(DISCL_NOWINKEY)
78 #undef FE
79 	};
80 	TRACE(" cooperative level : ");
81 	for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
82 	    if (flags[i].mask & dwFlags)
83 		TRACE("%s ",flags[i].name);
84 	TRACE("\n");
85     }
86 }
87 
88 static void _dump_ObjectDataFormat_flags(DWORD dwFlags) {
89     unsigned int   i;
90     static const struct {
91         DWORD       mask;
92         const char  *name;
93     } flags[] = {
94 #define FE(x) { x, #x}
95         FE(DIDOI_FFACTUATOR),
96         FE(DIDOI_FFEFFECTTRIGGER),
97         FE(DIDOI_POLLED),
98         FE(DIDOI_GUIDISUSAGE)
99 #undef FE
100     };
101 
102     if (!dwFlags) return;
103 
104     TRACE("Flags:");
105 
106     /* First the flags */
107     for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
108         if (flags[i].mask & dwFlags)
109         TRACE(" %s",flags[i].name);
110     }
111 
112     /* Now specific values */
113 #define FE(x) case x: TRACE(" "#x); break
114     switch (dwFlags & DIDOI_ASPECTMASK) {
115         FE(DIDOI_ASPECTACCEL);
116         FE(DIDOI_ASPECTFORCE);
117         FE(DIDOI_ASPECTPOSITION);
118         FE(DIDOI_ASPECTVELOCITY);
119     }
120 #undef FE
121 
122 }
123 
124 static void _dump_EnumObjects_flags(DWORD dwFlags) {
125     if (TRACE_ON(dinput)) {
126 	unsigned int   i;
127 	DWORD type, instance;
128 	static const struct {
129 	    DWORD       mask;
130 	    const char  *name;
131 	} flags[] = {
132 #define FE(x) { x, #x}
133 	    FE(DIDFT_RELAXIS),
134 	    FE(DIDFT_ABSAXIS),
135 	    FE(DIDFT_PSHBUTTON),
136 	    FE(DIDFT_TGLBUTTON),
137 	    FE(DIDFT_POV),
138 	    FE(DIDFT_COLLECTION),
139 	    FE(DIDFT_NODATA),
140 	    FE(DIDFT_FFACTUATOR),
141 	    FE(DIDFT_FFEFFECTTRIGGER),
142 	    FE(DIDFT_OUTPUT),
143 	    FE(DIDFT_VENDORDEFINED),
144 	    FE(DIDFT_ALIAS),
145 	    FE(DIDFT_OPTIONAL)
146 #undef FE
147 	};
148 	type = (dwFlags & 0xFF0000FF);
149 	instance = ((dwFlags >> 8) & 0xFFFF);
150 	TRACE("Type:");
151 	if (type == DIDFT_ALL) {
152 	    TRACE(" DIDFT_ALL");
153 	} else {
154 	    for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
155 		if (flags[i].mask & type) {
156 		    type &= ~flags[i].mask;
157 		    TRACE(" %s",flags[i].name);
158 		}
159 	    }
160 	    if (type) {
161                 TRACE(" (unhandled: %08x)", type);
162 	    }
163 	}
164 	TRACE(" / Instance: ");
165 	if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) {
166 	    TRACE("DIDFT_ANYINSTANCE");
167 	} else {
168             TRACE("%3d", instance);
169 	}
170     }
171 }
172 
173 void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) {
174     if (TRACE_ON(dinput)) {
175         TRACE("  - dwObj = 0x%08x\n", diph->dwObj);
176         TRACE("  - dwHow = %s\n",
177             ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" :
178             ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" :
179             ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown")));
180     }
181 }
182 
183 void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) {
184     TRACE("    - enumerating : %s ('%s') - %2d - 0x%08x - %s - 0x%x\n",
185         debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName, ddoi->dwFlags);
186 }
187 
188 void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) {
189     TRACE("    - enumerating : %s ('%s'), - %2d - 0x%08x - %s - 0x%x\n",
190         debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName), ddoi->dwFlags);
191 }
192 
193 /* This function is a helper to convert a GUID into any possible DInput GUID out there */
194 const char *_dump_dinput_GUID(const GUID *guid) {
195     unsigned int i;
196     static const struct {
197 	const GUID *guid;
198 	const char *name;
199     } guids[] = {
200 #define FE(x) { &x, #x}
201 	FE(GUID_XAxis),
202 	FE(GUID_YAxis),
203 	FE(GUID_ZAxis),
204 	FE(GUID_RxAxis),
205 	FE(GUID_RyAxis),
206 	FE(GUID_RzAxis),
207 	FE(GUID_Slider),
208 	FE(GUID_Button),
209 	FE(GUID_Key),
210 	FE(GUID_POV),
211 	FE(GUID_Unknown),
212 	FE(GUID_SysMouse),
213 	FE(GUID_SysKeyboard),
214 	FE(GUID_Joystick),
215 	FE(GUID_ConstantForce),
216 	FE(GUID_RampForce),
217 	FE(GUID_Square),
218 	FE(GUID_Sine),
219 	FE(GUID_Triangle),
220 	FE(GUID_SawtoothUp),
221 	FE(GUID_SawtoothDown),
222 	FE(GUID_Spring),
223 	FE(GUID_Damper),
224 	FE(GUID_Inertia),
225 	FE(GUID_Friction),
226 	FE(GUID_CustomForce)
227 #undef FE
228     };
229     if (guid == NULL)
230 	return "null GUID";
231     for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) {
232 	if (IsEqualGUID(guids[i].guid, guid)) {
233 	    return guids[i].name;
234 	}
235     }
236     return debugstr_guid(guid);
237 }
238 
239 void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) {
240     unsigned int i;
241 
242     TRACE("Dumping DIDATAFORMAT structure:\n");
243     TRACE("  - dwSize: %d\n", df->dwSize);
244     if (df->dwSize != sizeof(DIDATAFORMAT)) {
245         WARN("Non-standard DIDATAFORMAT structure size %d\n", df->dwSize);
246     }
247     TRACE("  - dwObjsize: %d\n", df->dwObjSize);
248     if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) {
249         WARN("Non-standard DIOBJECTDATAFORMAT structure size %d\n", df->dwObjSize);
250     }
251     TRACE("  - dwFlags: 0x%08x (", df->dwFlags);
252     switch (df->dwFlags) {
253         case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break;
254 	case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break;
255 	default: TRACE("unknown"); break;
256     }
257     TRACE(")\n");
258     TRACE("  - dwDataSize: %d\n", df->dwDataSize);
259     TRACE("  - dwNumObjs: %d\n", df->dwNumObjs);
260 
261     for (i = 0; i < df->dwNumObjs; i++) {
262 	TRACE("  - Object %d:\n", i);
263 	TRACE("      * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid));
264         TRACE("      * dwOfs: %d\n", df->rgodf[i].dwOfs);
265         TRACE("      * dwType: 0x%08x\n", df->rgodf[i].dwType);
266 	TRACE("        "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n");
267         TRACE("      * dwFlags: 0x%08x\n", df->rgodf[i].dwFlags);
268 	TRACE("        "); _dump_ObjectDataFormat_flags(df->rgodf[i].dwFlags); TRACE("\n");
269     }
270 }
271 
272 /******************************************************************************
273  * Get the default and the app-specific config keys.
274  */
275 BOOL get_app_key(HKEY *defkey, HKEY *appkey)
276 {
277     char buffer[MAX_PATH+16];
278     DWORD len;
279 
280     *appkey = 0;
281 
282     /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
283     if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\DirectInput", defkey))
284         *defkey = 0;
285 
286     len = GetModuleFileNameA(0, buffer, MAX_PATH);
287     if (len && len < MAX_PATH)
288     {
289         HKEY tmpkey;
290 
291         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
292         if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey))
293         {
294             char *p, *appname = buffer;
295             if ((p = strrchr(appname, '/'))) appname = p + 1;
296             if ((p = strrchr(appname, '\\'))) appname = p + 1;
297             strcat(appname, "\\DirectInput");
298 
299             if (RegOpenKeyA(tmpkey, appname, appkey)) *appkey = 0;
300             RegCloseKey(tmpkey);
301         }
302     }
303 
304     return *defkey || *appkey;
305 }
306 
307 /******************************************************************************
308  * Get a config key from either the app-specific or the default config
309  */
310 DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
311                              char *buffer, DWORD size )
312 {
313     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size ))
314         return 0;
315 
316     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size ))
317         return 0;
318 
319     return ERROR_FILE_NOT_FOUND;
320 }
321 
322 /* Conversion between internal data buffer and external data buffer */
323 void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df)
324 {
325     int i;
326     const char *in_c = in;
327     char *out_c = out;
328 
329     memset(out, 0, size);
330     if (df->dt == NULL) {
331 	/* This means that the app uses Wine's internal data format */
332         memcpy(out, in, min(size, df->internal_format_size));
333     } else {
334 	for (i = 0; i < df->size; i++) {
335 	    if (df->dt[i].offset_in >= 0) {
336 		switch (df->dt[i].size) {
337 		    case 1:
338 		        TRACE("Copying (c) to %d from %d (value %d)\n",
339                               df->dt[i].offset_out, df->dt[i].offset_in, *(in_c + df->dt[i].offset_in));
340 			*(out_c + df->dt[i].offset_out) = *(in_c + df->dt[i].offset_in);
341 			break;
342 
343 		    case 2:
344 			TRACE("Copying (s) to %d from %d (value %d)\n",
345 			      df->dt[i].offset_out, df->dt[i].offset_in, *((const short *)(in_c + df->dt[i].offset_in)));
346 			*((short *)(out_c + df->dt[i].offset_out)) = *((const short *)(in_c + df->dt[i].offset_in));
347 			break;
348 
349 		    case 4:
350 			TRACE("Copying (i) to %d from %d (value %d)\n",
351                               df->dt[i].offset_out, df->dt[i].offset_in, *((const int *)(in_c + df->dt[i].offset_in)));
352                         *((int *)(out_c + df->dt[i].offset_out)) = *((const int *)(in_c + df->dt[i].offset_in));
353 			break;
354 
355 		    default:
356 			memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
357 			break;
358 		}
359 	    } else {
360 		switch (df->dt[i].size) {
361 		    case 1:
362 		        TRACE("Copying (c) to %d default value %d\n",
363 			      df->dt[i].offset_out, df->dt[i].value);
364 			*(out_c + df->dt[i].offset_out) = (char) df->dt[i].value;
365 			break;
366 
367 		    case 2:
368 			TRACE("Copying (s) to %d default value %d\n",
369 			      df->dt[i].offset_out, df->dt[i].value);
370 			*((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
371 			break;
372 
373 		    case 4:
374 			TRACE("Copying (i) to %d default value %d\n",
375 			      df->dt[i].offset_out, df->dt[i].value);
376 			*((int *) (out_c + df->dt[i].offset_out)) = df->dt[i].value;
377 			break;
378 
379 		    default:
380 			memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size);
381 			break;
382 		}
383 	    }
384 	}
385     }
386 }
387 
388 void release_DataFormat(DataFormat * format)
389 {
390     TRACE("Deleting DataFormat: %p\n", format);
391 
392     HeapFree(GetProcessHeap(), 0, format->dt);
393     format->dt = NULL;
394     HeapFree(GetProcessHeap(), 0, format->offsets);
395     format->offsets = NULL;
396     HeapFree(GetProcessHeap(), 0, format->user_df);
397     format->user_df = NULL;
398 }
399 
400 static inline LPDIOBJECTDATAFORMAT dataformat_to_odf(LPCDIDATAFORMAT df, int idx)
401 {
402     if (idx < 0 || idx >= df->dwNumObjs) return NULL;
403     return (LPDIOBJECTDATAFORMAT)((LPBYTE)df->rgodf + idx * df->dwObjSize);
404 }
405 
406 /* dataformat_to_odf_by_type
407  *  Find the Nth object of the selected type in the DataFormat
408  */
409 LPDIOBJECTDATAFORMAT dataformat_to_odf_by_type(LPCDIDATAFORMAT df, int n, DWORD type)
410 {
411     int i, nfound = 0;
412 
413     for (i=0; i < df->dwNumObjs; i++)
414     {
415         LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(df, i);
416 
417         if (odf->dwType & type)
418         {
419             if (n == nfound)
420                 return odf;
421 
422             nfound++;
423         }
424     }
425 
426     return NULL;
427 }
428 
429 static HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat *format)
430 {
431     DataTransform *dt;
432     unsigned int i, j;
433     int same = 1;
434     int *done;
435     int index = 0;
436     DWORD next = 0;
437 
438     if (!format->wine_df) return DIERR_INVALIDPARAM;
439     done = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, asked_format->dwNumObjs * sizeof(int));
440     dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
441     if (!dt || !done) goto failed;
442 
443     if (!(format->offsets = HeapAlloc(GetProcessHeap(), 0, format->wine_df->dwNumObjs * sizeof(int))))
444         goto failed;
445 
446     if (!(format->user_df = HeapAlloc(GetProcessHeap(), 0, asked_format->dwSize)))
447         goto failed;
448     memcpy(format->user_df, asked_format, asked_format->dwSize);
449 
450     TRACE("Creating DataTransform :\n");
451 
452     for (i = 0; i < format->wine_df->dwNumObjs; i++)
453     {
454         format->offsets[i] = -1;
455 
456 	for (j = 0; j < asked_format->dwNumObjs; j++) {
457 	    if (done[j] == 1)
458 		continue;
459 
460 	    if (/* Check if the application either requests any GUID and if not, it if matches
461 		 * the GUID of the Wine object.
462 		 */
463 		((asked_format->rgodf[j].pguid == NULL) ||
464 		 (format->wine_df->rgodf[i].pguid == NULL) ||
465 		 (IsEqualGUID(format->wine_df->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
466 		&&
467 		(/* Then check if it accepts any instance id, and if not, if it matches Wine's
468 		  * instance id.
469 		  */
470 		 ((asked_format->rgodf[j].dwType & DIDFT_INSTANCEMASK) == DIDFT_ANYINSTANCE) ||
471 		 (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0x00FF) || /* This is mentioned in no DX docs, but it works fine - tested on WinXP */
472 		 (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(format->wine_df->rgodf[i].dwType)))
473 		&&
474 		( /* Then if the asked type matches the one Wine provides */
475                  DIDFT_GETTYPE(asked_format->rgodf[j].dwType) & format->wine_df->rgodf[i].dwType))
476             {
477 		done[j] = 1;
478 
479 		TRACE("Matching :\n");
480 		TRACE("   - Asked (%d) :\n", j);
481 		TRACE("       * GUID: %s ('%s')\n",
482 		      debugstr_guid(asked_format->rgodf[j].pguid),
483 		      _dump_dinput_GUID(asked_format->rgodf[j].pguid));
484                 TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
485                 TRACE("       * dwType: 0x%08x\n", asked_format->rgodf[j].dwType);
486 		TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
487                 TRACE("       * dwFlags: 0x%08x\n", asked_format->rgodf[j].dwFlags);
488 		TRACE("         "); _dump_ObjectDataFormat_flags(asked_format->rgodf[j].dwFlags); TRACE("\n");
489 
490 		TRACE("   - Wine  (%d) :\n", i);
491 		TRACE("       * GUID: %s ('%s')\n",
492                       debugstr_guid(format->wine_df->rgodf[i].pguid),
493                       _dump_dinput_GUID(format->wine_df->rgodf[i].pguid));
494                 TRACE("       * Offset: %3d\n", format->wine_df->rgodf[i].dwOfs);
495                 TRACE("       * dwType: 0x%08x\n", format->wine_df->rgodf[i].dwType);
496                 TRACE("         "); _dump_EnumObjects_flags(format->wine_df->rgodf[i].dwType); TRACE("\n");
497                 TRACE("       * dwFlags: 0x%08x\n", format->wine_df->rgodf[i].dwFlags);
498                 TRACE("         "); _dump_ObjectDataFormat_flags(format->wine_df->rgodf[i].dwFlags); TRACE("\n");
499 
500                 if (format->wine_df->rgodf[i].dwType & DIDFT_BUTTON)
501 		    dt[index].size = sizeof(BYTE);
502 		else
503 		    dt[index].size = sizeof(DWORD);
504                 dt[index].offset_in = format->wine_df->rgodf[i].dwOfs;
505                 dt[index].offset_out = asked_format->rgodf[j].dwOfs;
506                 format->offsets[i]   = asked_format->rgodf[j].dwOfs;
507 		dt[index].value = 0;
508                 next = next + dt[index].size;
509 
510                 if (format->wine_df->rgodf[i].dwOfs != dt[index].offset_out)
511 		    same = 0;
512 
513 		index++;
514 		break;
515 	    }
516 	}
517     }
518 
519     TRACE("Setting to default value :\n");
520     for (j = 0; j < asked_format->dwNumObjs; j++) {
521 	if (done[j] == 0) {
522 	    TRACE("   - Asked (%d) :\n", j);
523 	    TRACE("       * GUID: %s ('%s')\n",
524 		  debugstr_guid(asked_format->rgodf[j].pguid),
525 		  _dump_dinput_GUID(asked_format->rgodf[j].pguid));
526             TRACE("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
527             TRACE("       * dwType: 0x%08x\n", asked_format->rgodf[j].dwType);
528 	    TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
529             TRACE("       * dwFlags: 0x%08x\n", asked_format->rgodf[j].dwFlags);
530 	    TRACE("         "); _dump_ObjectDataFormat_flags(asked_format->rgodf[j].dwFlags); TRACE("\n");
531 
532 	    if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
533 		dt[index].size = sizeof(BYTE);
534 	    else
535 		dt[index].size = sizeof(DWORD);
536 	    dt[index].offset_in  = -1;
537 	    dt[index].offset_out = asked_format->rgodf[j].dwOfs;
538             if (asked_format->rgodf[j].dwType & DIDFT_POV)
539                 dt[index].value = -1;
540             else
541                 dt[index].value = 0;
542 	    index++;
543 
544 	    same = 0;
545 	}
546     }
547 
548     format->internal_format_size = format->wine_df->dwDataSize;
549     format->size = index;
550     if (same) {
551 	HeapFree(GetProcessHeap(), 0, dt);
552         dt = NULL;
553     }
554     format->dt = dt;
555 
556     HeapFree(GetProcessHeap(), 0, done);
557 
558     return DI_OK;
559 
560 failed:
561     HeapFree(GetProcessHeap(), 0, done);
562     HeapFree(GetProcessHeap(), 0, dt);
563     format->dt = NULL;
564     HeapFree(GetProcessHeap(), 0, format->offsets);
565     format->offsets = NULL;
566     HeapFree(GetProcessHeap(), 0, format->user_df);
567     format->user_df = NULL;
568 
569     return DIERR_OUTOFMEMORY;
570 }
571 
572 /* find an object by its offset in a data format */
573 static int offset_to_object(const DataFormat *df, int offset)
574 {
575     int i;
576 
577     if (!df->offsets) return -1;
578 
579     for (i = 0; i < df->wine_df->dwNumObjs; i++)
580         if (df->offsets[i] == offset) return i;
581 
582     return -1;
583 }
584 
585 int id_to_object(LPCDIDATAFORMAT df, int id)
586 {
587     int i;
588 
589     id &= 0x00ffffff;
590     for (i = 0; i < df->dwNumObjs; i++)
591         if ((dataformat_to_odf(df, i)->dwType & 0x00ffffff) == id)
592             return i;
593 
594     return -1;
595 }
596 
597 static int id_to_offset(const DataFormat *df, int id)
598 {
599     int obj = id_to_object(df->wine_df, id);
600 
601     return obj >= 0 && df->offsets ? df->offsets[obj] : -1;
602 }
603 
604 int find_property(const DataFormat *df, LPCDIPROPHEADER ph)
605 {
606     switch (ph->dwHow)
607     {
608         case DIPH_BYID:     return id_to_object(df->wine_df, ph->dwObj);
609         case DIPH_BYOFFSET: return offset_to_object(df, ph->dwObj);
610     }
611     FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow);
612 
613     return -1;
614 }
615 
616 static DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD dwSemantic)
617 {
618     DWORD type = (0x0000ff00 & dwSemantic) >> 8;
619     DWORD offset = 0x000000ff & dwSemantic;
620     DWORD obj_instance = 0;
621     BOOL found = FALSE;
622     int i;
623 
624     for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
625     {
626         LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
627 
628         if (odf->dwOfs == offset)
629         {
630             obj_instance = DIDFT_GETINSTANCE(odf->dwType);
631             found = TRUE;
632             break;
633         }
634     }
635 
636     if (!found) return 0;
637 
638     if (type & DIDFT_AXIS)   type = DIDFT_RELAXIS;
639     if (type & DIDFT_BUTTON) type = DIDFT_PSHBUTTON;
640 
641     return type | (0x0000ff00 & (obj_instance << 8));
642 }
643 
644 /*
645  * get_mapping_key
646  * Retrieves an open registry key to save the mapping, parametrized for an username,
647  * specific device and specific action mapping guid.
648  */
649 static HKEY get_mapping_key(const WCHAR *device, const WCHAR *username, const WCHAR *guid)
650 {
651     static const WCHAR subkey[] = {
652         'S','o','f','t','w','a','r','e','\\',
653         'W','i','n','e','\\',
654         'D','i','r','e','c','t','I','n','p','u','t','\\',
655         'M','a','p','p','i','n','g','s','\\','%','s','\\','%','s','\\','%','s','\0'};
656     HKEY hkey;
657     WCHAR *keyname;
658 
659     keyname = HeapAlloc(GetProcessHeap(), 0,
660         sizeof(WCHAR) * (lstrlenW(subkey) + strlenW(username) + strlenW(device) + strlenW(guid)));
661     sprintfW(keyname, subkey, username, device, guid);
662 
663     /* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */
664     if (RegCreateKeyW(HKEY_CURRENT_USER, keyname, &hkey))
665         hkey = 0;
666 
667     HeapFree(GetProcessHeap(), 0, keyname);
668 
669     return hkey;
670 }
671 
672 static HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUsername)
673 {
674     WCHAR *guid_str = NULL;
675     DIDEVICEINSTANCEW didev;
676     HKEY hkey;
677     int i;
678 
679     didev.dwSize = sizeof(didev);
680     IDirectInputDevice8_GetDeviceInfo(iface, &didev);
681 
682     if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
683         return DI_SETTINGSNOTSAVED;
684 
685     hkey = get_mapping_key(didev.tszInstanceName, lpszUsername, guid_str);
686 
687     if (!hkey)
688     {
689         CoTaskMemFree(guid_str);
690         return DI_SETTINGSNOTSAVED;
691     }
692 
693     /* Write each of the actions mapped for this device.
694        Format is "dwSemantic"="dwObjID" and key is of type REG_DWORD
695     */
696     for (i = 0; i < lpdiaf->dwNumActions; i++)
697     {
698         static const WCHAR format[] = {'%','x','\0'};
699         WCHAR label[9];
700 
701         if (IsEqualGUID(&didev.guidInstance, &lpdiaf->rgoAction[i].guidInstance) &&
702             lpdiaf->rgoAction[i].dwHow != DIAH_UNMAPPED)
703         {
704              sprintfW(label, format, lpdiaf->rgoAction[i].dwSemantic);
705              RegSetValueExW(hkey, label, 0, REG_DWORD, (const BYTE*) &lpdiaf->rgoAction[i].dwObjID, sizeof(DWORD));
706         }
707     }
708 
709     RegCloseKey(hkey);
710     CoTaskMemFree(guid_str);
711 
712     return DI_OK;
713 }
714 
715 static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMATW lpdiaf, const WCHAR *username)
716 {
717     HKEY hkey;
718     WCHAR *guid_str;
719     DIDEVICEINSTANCEW didev;
720     int i, mapped = 0;
721 
722     didev.dwSize = sizeof(didev);
723     IDirectInputDevice8_GetDeviceInfo(&This->IDirectInputDevice8W_iface, &didev);
724 
725     if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
726         return FALSE;
727 
728     hkey = get_mapping_key(didev.tszInstanceName, username, guid_str);
729 
730     if (!hkey)
731     {
732         CoTaskMemFree(guid_str);
733         return FALSE;
734     }
735 
736     /* Try to read each action in the DIACTIONFORMAT from registry */
737     for (i = 0; i < lpdiaf->dwNumActions; i++)
738     {
739         static const WCHAR format[] = {'%','x','\0'};
740         DWORD id, size = sizeof(DWORD);
741         WCHAR label[9];
742 
743         sprintfW(label, format, lpdiaf->rgoAction[i].dwSemantic);
744 
745         if (!RegQueryValueExW(hkey, label, 0, NULL, (LPBYTE) &id, &size))
746         {
747             lpdiaf->rgoAction[i].dwObjID = id;
748             lpdiaf->rgoAction[i].guidInstance = didev.guidInstance;
749             lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT;
750             mapped += 1;
751         }
752     }
753 
754     RegCloseKey(hkey);
755     CoTaskMemFree(guid_str);
756 
757     return mapped > 0;
758 }
759 
760 HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df)
761 {
762     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
763     WCHAR username[MAX_PATH];
764     DWORD username_size = MAX_PATH;
765     int i;
766     BOOL load_success = FALSE, has_actions = FALSE;
767 
768     /* Unless asked the contrary by these flags, try to load a previous mapping */
769     if (!(dwFlags & DIDBAM_HWDEFAULTS))
770     {
771         /* Retrieve logged user name if necessary */
772         if (lpszUserName == NULL)
773             GetUserNameW(username, &username_size);
774         else
775             lstrcpynW(username, lpszUserName, MAX_PATH);
776 
777         load_success = load_mapping_settings(This, lpdiaf, username);
778     }
779 
780     if (load_success) return DI_OK;
781 
782     for (i=0; i < lpdiaf->dwNumActions; i++)
783     {
784         /* Don't touch a user configured action */
785         if (lpdiaf->rgoAction[i].dwHow == DIAH_USERCONFIG) continue;
786 
787         if ((lpdiaf->rgoAction[i].dwSemantic & devMask) == devMask)
788         {
789             DWORD obj_id = semantic_to_obj_id(This, lpdiaf->rgoAction[i].dwSemantic);
790             DWORD type = DIDFT_GETTYPE(obj_id);
791             DWORD inst = DIDFT_GETINSTANCE(obj_id);
792 
793             LPDIOBJECTDATAFORMAT odf;
794 
795             if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON;
796             if (type == DIDFT_RELAXIS) type = DIDFT_AXIS;
797 
798             /* Make sure the object exists */
799             odf = dataformat_to_odf_by_type(df, inst, type);
800 
801             if (odf != NULL)
802             {
803                 lpdiaf->rgoAction[i].dwObjID = obj_id;
804                 lpdiaf->rgoAction[i].guidInstance = This->guid;
805                 lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT;
806                 has_actions = TRUE;
807             }
808         }
809         else if (!(dwFlags & DIDBAM_PRESERVE))
810         {
811             /* We must clear action data belonging to other devices */
812             memset(&lpdiaf->rgoAction[i].guidInstance, 0, sizeof(GUID));
813             lpdiaf->rgoAction[i].dwHow = DIAH_UNMAPPED;
814         }
815     }
816 
817     if (!has_actions) return DI_NOEFFECT;
818 
819     return  IDirectInputDevice8WImpl_BuildActionMap(iface, lpdiaf, lpszUserName, dwFlags);
820 }
821 
822 HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, LPCDIDATAFORMAT df)
823 {
824     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
825     DIDATAFORMAT data_format;
826     DIOBJECTDATAFORMAT *obj_df = NULL;
827     DIPROPDWORD dp;
828     DIPROPRANGE dpr;
829     DIPROPSTRING dps;
830     WCHAR username[MAX_PATH];
831     DWORD username_size = MAX_PATH;
832     int i, action = 0, num_actions = 0;
833     unsigned int offset = 0;
834 
835     if (This->acquired) return DIERR_ACQUIRED;
836 
837     data_format.dwSize = sizeof(data_format);
838     data_format.dwObjSize = sizeof(DIOBJECTDATAFORMAT);
839     data_format.dwFlags = DIDF_RELAXIS;
840     data_format.dwDataSize = lpdiaf->dwDataSize;
841 
842     /* Count the actions */
843     for (i=0; i < lpdiaf->dwNumActions; i++)
844         if (IsEqualGUID(&This->guid, &lpdiaf->rgoAction[i].guidInstance))
845             num_actions++;
846 
847     if (num_actions == 0) return DI_NOEFFECT;
848 
849     This->num_actions = num_actions;
850 
851     /* Construct the dataformat and actionmap */
852     obj_df = HeapAlloc(GetProcessHeap(), 0, sizeof(DIOBJECTDATAFORMAT)*num_actions);
853     data_format.rgodf = (LPDIOBJECTDATAFORMAT)obj_df;
854     data_format.dwNumObjs = num_actions;
855 
856     HeapFree(GetProcessHeap(), 0, This->action_map);
857     This->action_map = HeapAlloc(GetProcessHeap(), 0, sizeof(ActionMap)*num_actions);
858 
859     for (i = 0; i < lpdiaf->dwNumActions; i++)
860     {
861         if (IsEqualGUID(&This->guid, &lpdiaf->rgoAction[i].guidInstance))
862         {
863             DWORD inst = DIDFT_GETINSTANCE(lpdiaf->rgoAction[i].dwObjID);
864             DWORD type = DIDFT_GETTYPE(lpdiaf->rgoAction[i].dwObjID);
865             LPDIOBJECTDATAFORMAT obj;
866 
867             if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON;
868             if (type == DIDFT_RELAXIS) type = DIDFT_AXIS;
869 
870             obj = dataformat_to_odf_by_type(df, inst, type);
871 
872             memcpy(&obj_df[action], obj, df->dwObjSize);
873 
874             This->action_map[action].uAppData = lpdiaf->rgoAction[i].uAppData;
875             This->action_map[action].offset = offset;
876             obj_df[action].dwOfs = offset;
877             offset += (type & DIDFT_BUTTON) ? 1 : 4;
878 
879             action++;
880         }
881     }
882 
883     IDirectInputDevice8_SetDataFormat(iface, &data_format);
884 
885     HeapFree(GetProcessHeap(), 0, obj_df);
886 
887     /* Set the device properties according to the action format */
888     dpr.diph.dwSize = sizeof(DIPROPRANGE);
889     dpr.lMin = lpdiaf->lAxisMin;
890     dpr.lMax = lpdiaf->lAxisMax;
891     dpr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
892     dpr.diph.dwHow = DIPH_DEVICE;
893     IDirectInputDevice8_SetProperty(iface, DIPROP_RANGE, &dpr.diph);
894 
895     if (lpdiaf->dwBufferSize > 0)
896     {
897         dp.diph.dwSize = sizeof(DIPROPDWORD);
898         dp.dwData = lpdiaf->dwBufferSize;
899         dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
900         dp.diph.dwHow = DIPH_DEVICE;
901         IDirectInputDevice8_SetProperty(iface, DIPROP_BUFFERSIZE, &dp.diph);
902     }
903 
904     /* Retrieve logged user name if necessary */
905     if (lpszUserName == NULL)
906         GetUserNameW(username, &username_size);
907     else
908         lstrcpynW(username, lpszUserName, MAX_PATH);
909 
910     dps.diph.dwSize = sizeof(dps);
911     dps.diph.dwHeaderSize = sizeof(DIPROPHEADER);
912     dps.diph.dwObj = 0;
913     dps.diph.dwHow = DIPH_DEVICE;
914     if (dwFlags & DIDSAM_NOUSER)
915         dps.wsz[0] = '\0';
916     else
917         lstrcpynW(dps.wsz, username, sizeof(dps.wsz)/sizeof(WCHAR));
918     IDirectInputDevice8_SetProperty(iface, DIPROP_USERNAME, &dps.diph);
919 
920     /* Save the settings to disk */
921     save_mapping_settings(iface, lpdiaf, username);
922 
923     return DI_OK;
924 }
925 
926 /******************************************************************************
927  *	queue_event - add new event to the ring queue
928  */
929 
930 void queue_event(LPDIRECTINPUTDEVICE8A iface, int inst_id, DWORD data, DWORD time, DWORD seq)
931 {
932     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
933     int next_pos, ofs = id_to_offset(&This->data_format, inst_id);
934 
935     /* Event is being set regardless of the queue state */
936     if (This->hEvent) SetEvent(This->hEvent);
937 
938     if (!This->queue_len || This->overflow || ofs < 0) return;
939 
940     next_pos = (This->queue_head + 1) % This->queue_len;
941     if (next_pos == This->queue_tail)
942     {
943         TRACE(" queue overflowed\n");
944         This->overflow = TRUE;
945         return;
946     }
947 
948     TRACE(" queueing %d at offset %d (queue head %d / size %d)\n",
949           data, ofs, This->queue_head, This->queue_len);
950 
951     This->data_queue[This->queue_head].dwOfs       = ofs;
952     This->data_queue[This->queue_head].dwData      = data;
953     This->data_queue[This->queue_head].dwTimeStamp = time;
954     This->data_queue[This->queue_head].dwSequence  = seq;
955 
956     /* Set uAppData by means of action mapping */
957     if (This->num_actions > 0)
958     {
959         int i;
960         for (i=0; i < This->num_actions; i++)
961         {
962             if (This->action_map[i].offset == ofs)
963             {
964                 TRACE("Offset %d mapped to uAppData %lu\n", ofs, This->action_map[i].uAppData);
965                 This->data_queue[This->queue_head].uAppData = This->action_map[i].uAppData;
966                 break;
967             }
968         }
969     }
970 
971     This->queue_head = next_pos;
972     /* Send event if asked */
973 }
974 
975 /******************************************************************************
976  *	Acquire
977  */
978 
979 HRESULT WINAPI IDirectInputDevice2WImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
980 {
981     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
982     HRESULT res;
983 
984     TRACE("(%p)\n", This);
985 
986     if (!This->data_format.user_df) return DIERR_INVALIDPARAM;
987     if (This->dwCoopLevel & DISCL_FOREGROUND && This->win != GetForegroundWindow())
988         return DIERR_OTHERAPPHASPRIO;
989 
990     EnterCriticalSection(&This->crit);
991     res = This->acquired ? S_FALSE : DI_OK;
992     This->acquired = 1;
993     LeaveCriticalSection(&This->crit);
994     if (res == DI_OK)
995         check_dinput_hooks(iface, TRUE);
996 
997     return res;
998 }
999 
1000 HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
1001 {
1002     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1003     return IDirectInputDevice2WImpl_Acquire(IDirectInputDevice8W_from_impl(This));
1004 }
1005 
1006 
1007 /******************************************************************************
1008  *	Unacquire
1009  */
1010 
1011 HRESULT WINAPI IDirectInputDevice2WImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
1012 {
1013     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1014     HRESULT res;
1015 
1016     TRACE("(%p)\n", This);
1017 
1018     EnterCriticalSection(&This->crit);
1019     res = !This->acquired ? DI_NOEFFECT : DI_OK;
1020     This->acquired = 0;
1021     LeaveCriticalSection(&This->crit);
1022     if (res == DI_OK)
1023         check_dinput_hooks(iface, FALSE);
1024 
1025     return res;
1026 }
1027 
1028 HRESULT WINAPI IDirectInputDevice2AImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
1029 {
1030     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1031     return IDirectInputDevice2WImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
1032 }
1033 
1034 /******************************************************************************
1035  *	IDirectInputDeviceA
1036  */
1037 
1038 HRESULT WINAPI IDirectInputDevice2WImpl_SetDataFormat(LPDIRECTINPUTDEVICE8W iface, LPCDIDATAFORMAT df)
1039 {
1040     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1041     HRESULT res = DI_OK;
1042 
1043     if (!df) return E_POINTER;
1044     TRACE("(%p) %p\n", This, df);
1045     _dump_DIDATAFORMAT(df);
1046 
1047     if (df->dwSize != sizeof(DIDATAFORMAT)) return DIERR_INVALIDPARAM;
1048     if (This->acquired) return DIERR_ACQUIRED;
1049 
1050     EnterCriticalSection(&This->crit);
1051 
1052     release_DataFormat(&This->data_format);
1053     res = create_DataFormat(df, &This->data_format);
1054 
1055     LeaveCriticalSection(&This->crit);
1056     return res;
1057 }
1058 
1059 HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(LPDIRECTINPUTDEVICE8A iface, LPCDIDATAFORMAT df)
1060 {
1061     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1062     return IDirectInputDevice2WImpl_SetDataFormat(IDirectInputDevice8W_from_impl(This), df);
1063 }
1064 
1065 /******************************************************************************
1066   *     SetCooperativeLevel
1067   *
1068   *  Set cooperative level and the source window for the events.
1069   */
1070 HRESULT WINAPI IDirectInputDevice2WImpl_SetCooperativeLevel(LPDIRECTINPUTDEVICE8W iface, HWND hwnd, DWORD dwflags)
1071 {
1072     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1073 
1074     TRACE("(%p) %p,0x%08x\n", This, hwnd, dwflags);
1075     _dump_cooperativelevel_DI(dwflags);
1076 
1077     if ((dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == 0 ||
1078         (dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE) ||
1079         (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == 0 ||
1080         (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == (DISCL_FOREGROUND | DISCL_BACKGROUND))
1081         return DIERR_INVALIDPARAM;
1082 
1083     if (hwnd && GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD) return E_HANDLE;
1084 
1085     if (!hwnd && dwflags == (DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))
1086         hwnd = GetDesktopWindow();
1087 
1088     if (!IsWindow(hwnd)) return E_HANDLE;
1089 
1090     /* For security reasons native does not allow exclusive background level
1091        for mouse and keyboard only */
1092     if (dwflags & DISCL_EXCLUSIVE && dwflags & DISCL_BACKGROUND &&
1093         (IsEqualGUID(&This->guid, &GUID_SysMouse) ||
1094          IsEqualGUID(&This->guid, &GUID_SysKeyboard)))
1095         return DIERR_UNSUPPORTED;
1096 
1097     /* Store the window which asks for the mouse */
1098     EnterCriticalSection(&This->crit);
1099     This->win = hwnd;
1100     This->dwCoopLevel = dwflags;
1101     LeaveCriticalSection(&This->crit);
1102 
1103     return DI_OK;
1104 }
1105 
1106 HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(LPDIRECTINPUTDEVICE8A iface, HWND hwnd, DWORD dwflags)
1107 {
1108     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1109     return IDirectInputDevice2WImpl_SetCooperativeLevel(IDirectInputDevice8W_from_impl(This), hwnd, dwflags);
1110 }
1111 
1112 /******************************************************************************
1113   *     SetEventNotification : specifies event to be sent on state change
1114   */
1115 HRESULT WINAPI IDirectInputDevice2WImpl_SetEventNotification(LPDIRECTINPUTDEVICE8W iface, HANDLE event)
1116 {
1117     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1118 
1119     TRACE("(%p) %p\n", This, event);
1120 
1121     EnterCriticalSection(&This->crit);
1122     This->hEvent = event;
1123     LeaveCriticalSection(&This->crit);
1124     return DI_OK;
1125 }
1126 
1127 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, HANDLE event)
1128 {
1129     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1130     return IDirectInputDevice2WImpl_SetEventNotification(IDirectInputDevice8W_from_impl(This), event);
1131 }
1132 
1133 
1134 ULONG WINAPI IDirectInputDevice2WImpl_Release(LPDIRECTINPUTDEVICE8W iface)
1135 {
1136     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1137     ULONG ref = InterlockedDecrement(&(This->ref));
1138 
1139     TRACE("(%p) releasing from %d\n", This, ref + 1);
1140 
1141     if (ref) return ref;
1142 
1143     IDirectInputDevice_Unacquire(iface);
1144     /* Reset the FF state, free all effects, etc */
1145     IDirectInputDevice8_SendForceFeedbackCommand(iface, DISFFC_RESET);
1146 
1147     HeapFree(GetProcessHeap(), 0, This->data_queue);
1148 
1149     /* Free data format */
1150     HeapFree(GetProcessHeap(), 0, This->data_format.wine_df->rgodf);
1151     HeapFree(GetProcessHeap(), 0, This->data_format.wine_df);
1152     release_DataFormat(&This->data_format);
1153 
1154     /* Free action mapping */
1155     HeapFree(GetProcessHeap(), 0, This->action_map);
1156 
1157     EnterCriticalSection( &This->dinput->crit );
1158     list_remove( &This->entry );
1159     LeaveCriticalSection( &This->dinput->crit );
1160 
1161     IDirectInput_Release(&This->dinput->IDirectInput7A_iface);
1162     This->crit.DebugInfo->Spare[0] = 0;
1163     DeleteCriticalSection(&This->crit);
1164 
1165     HeapFree(GetProcessHeap(), 0, This);
1166 
1167     return DI_OK;
1168 }
1169 
1170 ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
1171 {
1172     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1173     return IDirectInputDevice2WImpl_Release(IDirectInputDevice8W_from_impl(This));
1174 }
1175 
1176 HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W iface, REFIID riid, LPVOID *ppobj)
1177 {
1178     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1179 
1180     TRACE("(%p this=%p,%s,%p)\n", iface, This, debugstr_guid(riid), ppobj);
1181     if (IsEqualGUID(&IID_IUnknown, riid) ||
1182         IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
1183         IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
1184         IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
1185         IsEqualGUID(&IID_IDirectInputDevice8A, riid))
1186     {
1187         IDirectInputDevice2_AddRef(iface);
1188         *ppobj = IDirectInputDevice8A_from_impl(This);
1189         return DI_OK;
1190     }
1191     if (IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
1192         IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
1193         IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
1194         IsEqualGUID(&IID_IDirectInputDevice8W, riid))
1195     {
1196         IDirectInputDevice2_AddRef(iface);
1197         *ppobj = IDirectInputDevice8W_from_impl(This);
1198         return DI_OK;
1199     }
1200 
1201     WARN("Unsupported interface!\n");
1202     return E_FAIL;
1203 }
1204 
1205 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A iface, REFIID riid, LPVOID *ppobj)
1206 {
1207     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1208     return IDirectInputDevice2WImpl_QueryInterface(IDirectInputDevice8W_from_impl(This), riid, ppobj);
1209 }
1210 
1211 ULONG WINAPI IDirectInputDevice2WImpl_AddRef(LPDIRECTINPUTDEVICE8W iface)
1212 {
1213     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1214     return InterlockedIncrement(&This->ref);
1215 }
1216 
1217 ULONG WINAPI IDirectInputDevice2AImpl_AddRef(LPDIRECTINPUTDEVICE8A iface)
1218 {
1219     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1220     return IDirectInputDevice2WImpl_AddRef(IDirectInputDevice8W_from_impl(This));
1221 }
1222 
1223 HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(LPDIRECTINPUTDEVICE8A iface,
1224         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID lpvRef, DWORD dwFlags)
1225 {
1226     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1227     DIDEVICEOBJECTINSTANCEA ddoi;
1228     int i;
1229 
1230     TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
1231     TRACE("  - flags = ");
1232     _dump_EnumObjects_flags(dwFlags);
1233     TRACE("\n");
1234 
1235     /* Only the fields till dwFFMaxForce are relevant */
1236     memset(&ddoi, 0, sizeof(ddoi));
1237     ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1238 
1239     for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
1240     {
1241         LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
1242 
1243         if (dwFlags != DIDFT_ALL && !(dwFlags & DIDFT_GETTYPE(odf->dwType))) continue;
1244         if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
1245             continue;
1246 
1247 	if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
1248     }
1249 
1250     return DI_OK;
1251 }
1252 
1253 HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
1254         LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef, DWORD dwFlags)
1255 {
1256     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1257     DIDEVICEOBJECTINSTANCEW ddoi;
1258     int i;
1259 
1260     TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
1261     TRACE("  - flags = ");
1262     _dump_EnumObjects_flags(dwFlags);
1263     TRACE("\n");
1264 
1265     /* Only the fields till dwFFMaxForce are relevant */
1266     memset(&ddoi, 0, sizeof(ddoi));
1267     ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, dwFFMaxForce);
1268 
1269     for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
1270     {
1271         LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
1272 
1273         if (dwFlags != DIDFT_ALL && !(dwFlags & DIDFT_GETTYPE(odf->dwType))) continue;
1274         if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
1275             continue;
1276 
1277 	if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
1278     }
1279 
1280     return DI_OK;
1281 }
1282 
1283 /******************************************************************************
1284  *	GetProperty
1285  */
1286 
1287 HRESULT WINAPI IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
1288 {
1289     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1290 
1291     TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
1292     _dump_DIPROPHEADER(pdiph);
1293 
1294     if (!IS_DIPROP(rguid)) return DI_OK;
1295 
1296     switch (LOWORD(rguid))
1297     {
1298         case (DWORD_PTR) DIPROP_BUFFERSIZE:
1299         {
1300             LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
1301 
1302             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
1303 
1304             pd->dwData = This->queue_len;
1305             TRACE("buffersize = %d\n", pd->dwData);
1306             break;
1307         }
1308         case (DWORD_PTR) DIPROP_USERNAME:
1309         {
1310             LPDIPROPSTRING ps = (LPDIPROPSTRING)pdiph;
1311             struct DevicePlayer *device_player;
1312 
1313             if (pdiph->dwSize != sizeof(DIPROPSTRING)) return DIERR_INVALIDPARAM;
1314 
1315             LIST_FOR_EACH_ENTRY(device_player, &This->dinput->device_players,
1316                 struct DevicePlayer, entry)
1317             {
1318                 if (IsEqualGUID(&device_player->instance_guid, &This->guid))
1319                 {
1320                     if (*device_player->username)
1321                     {
1322                         lstrcpynW(ps->wsz, device_player->username, sizeof(ps->wsz)/sizeof(WCHAR));
1323                         return DI_OK;
1324                     }
1325                     else break;
1326                 }
1327             }
1328             return S_FALSE;
1329         }
1330         case (DWORD_PTR) DIPROP_VIDPID:
1331             FIXME("DIPROP_VIDPID not implemented\n");
1332             return DIERR_UNSUPPORTED;
1333         default:
1334             FIXME("Unknown property %s\n", debugstr_guid(rguid));
1335             return DIERR_INVALIDPARAM;
1336     }
1337 
1338     return DI_OK;
1339 }
1340 
1341 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
1342 {
1343     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1344     return IDirectInputDevice2WImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
1345 }
1346 
1347 /******************************************************************************
1348  *	SetProperty
1349  */
1350 
1351 HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty(
1352         LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER pdiph)
1353 {
1354     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1355 
1356     TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
1357     _dump_DIPROPHEADER(pdiph);
1358 
1359     if (!IS_DIPROP(rguid)) return DI_OK;
1360 
1361     switch (LOWORD(rguid))
1362     {
1363         case (DWORD_PTR) DIPROP_AXISMODE:
1364         {
1365             LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
1366 
1367             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
1368             if (pdiph->dwHow == DIPH_DEVICE && pdiph->dwObj) return DIERR_INVALIDPARAM;
1369             if (This->acquired) return DIERR_ACQUIRED;
1370             if (pdiph->dwHow != DIPH_DEVICE) return DIERR_UNSUPPORTED;
1371             if (!This->data_format.user_df) return DI_OK;
1372 
1373             TRACE("Axis mode: %s\n", pd->dwData == DIPROPAXISMODE_ABS ? "absolute" :
1374                                                                         "relative");
1375 
1376             EnterCriticalSection(&This->crit);
1377             This->data_format.user_df->dwFlags &= ~DIDFT_AXIS;
1378             This->data_format.user_df->dwFlags |= pd->dwData == DIPROPAXISMODE_ABS ?
1379                                                   DIDF_ABSAXIS : DIDF_RELAXIS;
1380             LeaveCriticalSection(&This->crit);
1381             break;
1382         }
1383         case (DWORD_PTR) DIPROP_BUFFERSIZE:
1384         {
1385             LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
1386 
1387             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
1388             if (This->acquired) return DIERR_ACQUIRED;
1389 
1390             TRACE("buffersize = %d\n", pd->dwData);
1391 
1392             EnterCriticalSection(&This->crit);
1393             HeapFree(GetProcessHeap(), 0, This->data_queue);
1394 
1395             This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0,
1396                                 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1397             This->queue_head = This->queue_tail = This->overflow = 0;
1398             This->queue_len  = pd->dwData;
1399 
1400             LeaveCriticalSection(&This->crit);
1401             break;
1402         }
1403         case (DWORD_PTR) DIPROP_USERNAME:
1404         {
1405             LPCDIPROPSTRING ps = (LPCDIPROPSTRING)pdiph;
1406             struct DevicePlayer *device_player;
1407             BOOL found = FALSE;
1408 
1409             if (pdiph->dwSize != sizeof(DIPROPSTRING)) return DIERR_INVALIDPARAM;
1410 
1411             LIST_FOR_EACH_ENTRY(device_player, &This->dinput->device_players,
1412                 struct DevicePlayer, entry)
1413             {
1414                 if (IsEqualGUID(&device_player->instance_guid, &This->guid))
1415                 {
1416                     found = TRUE;
1417                     break;
1418                 }
1419             }
1420             if (!found && (device_player =
1421                     HeapAlloc(GetProcessHeap(), 0, sizeof(struct DevicePlayer))))
1422             {
1423                 list_add_tail(&This->dinput->device_players, &device_player->entry);
1424                 device_player->instance_guid = This->guid;
1425             }
1426             if (device_player)
1427                 lstrcpynW(device_player->username, ps->wsz,
1428                     sizeof(device_player->username)/sizeof(WCHAR));
1429             break;
1430         }
1431         default:
1432             WARN("Unknown property %s\n", debugstr_guid(rguid));
1433             return DIERR_UNSUPPORTED;
1434     }
1435 
1436     return DI_OK;
1437 }
1438 
1439 HRESULT WINAPI IDirectInputDevice2AImpl_SetProperty(
1440         LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER pdiph)
1441 {
1442     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1443     return IDirectInputDevice2WImpl_SetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
1444 }
1445 
1446 HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
1447 	LPDIRECTINPUTDEVICE8A iface,
1448 	LPDIDEVICEOBJECTINSTANCEA pdidoi,
1449 	DWORD dwObj,
1450 	DWORD dwHow)
1451 {
1452     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1453     DIDEVICEOBJECTINSTANCEW didoiW;
1454     HRESULT res;
1455 
1456     if (!pdidoi ||
1457         (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA) &&
1458          pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A)))
1459         return DIERR_INVALIDPARAM;
1460 
1461     didoiW.dwSize = sizeof(didoiW);
1462     res = IDirectInputDevice2WImpl_GetObjectInfo(IDirectInputDevice8W_from_impl(This), &didoiW, dwObj, dwHow);
1463     if (res == DI_OK)
1464     {
1465         DWORD dwSize = pdidoi->dwSize;
1466 
1467         memset(pdidoi, 0, pdidoi->dwSize);
1468         pdidoi->dwSize   = dwSize;
1469         pdidoi->guidType = didoiW.guidType;
1470         pdidoi->dwOfs    = didoiW.dwOfs;
1471         pdidoi->dwType   = didoiW.dwType;
1472         pdidoi->dwFlags  = didoiW.dwFlags;
1473     }
1474 
1475     return res;
1476 }
1477 
1478 HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(
1479 	LPDIRECTINPUTDEVICE8W iface,
1480 	LPDIDEVICEOBJECTINSTANCEW pdidoi,
1481 	DWORD dwObj,
1482 	DWORD dwHow)
1483 {
1484     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1485     DWORD dwSize;
1486     LPDIOBJECTDATAFORMAT odf;
1487     int idx = -1;
1488 
1489     TRACE("(%p) %d(0x%08x) -> %p\n", This, dwHow, dwObj, pdidoi);
1490 
1491     if (!pdidoi ||
1492         (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW) &&
1493          pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W)))
1494         return DIERR_INVALIDPARAM;
1495 
1496     switch (dwHow)
1497     {
1498     case DIPH_BYOFFSET:
1499         if (!This->data_format.offsets) break;
1500         for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
1501             if (This->data_format.offsets[idx] == dwObj) break;
1502         break;
1503     case DIPH_BYID:
1504         dwObj &= 0x00ffffff;
1505         for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
1506             if ((dataformat_to_odf(This->data_format.wine_df, idx)->dwType & 0x00ffffff) == dwObj)
1507                 break;
1508         break;
1509 
1510     case DIPH_BYUSAGE:
1511         FIXME("dwHow = DIPH_BYUSAGE not implemented\n");
1512         break;
1513     default:
1514         WARN("invalid parameter: dwHow = %08x\n", dwHow);
1515         return DIERR_INVALIDPARAM;
1516     }
1517     if (idx < 0) return DIERR_OBJECTNOTFOUND;
1518 
1519     odf = dataformat_to_odf(This->data_format.wine_df, idx);
1520     dwSize = pdidoi->dwSize; /* save due to memset below */
1521     memset(pdidoi, 0, pdidoi->dwSize);
1522     pdidoi->dwSize   = dwSize;
1523     if (odf->pguid) pdidoi->guidType = *odf->pguid;
1524     pdidoi->dwOfs    = This->data_format.offsets ? This->data_format.offsets[idx] : odf->dwOfs;
1525     pdidoi->dwType   = odf->dwType;
1526     pdidoi->dwFlags  = odf->dwFlags;
1527 
1528     return DI_OK;
1529 }
1530 
1531 HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceData(LPDIRECTINPUTDEVICE8W iface, DWORD dodsize,
1532                                                       LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
1533 {
1534     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1535     HRESULT ret = DI_OK;
1536     int len;
1537 
1538     TRACE("(%p) %p -> %p(%d) x%d, 0x%08x\n",
1539           This, dod, entries, entries ? *entries : 0, dodsize, flags);
1540 
1541     if (This->dinput->dwVersion == 0x0800 || dodsize == sizeof(DIDEVICEOBJECTDATA_DX3))
1542     {
1543         if (!This->queue_len) return DIERR_NOTBUFFERED;
1544         if (!This->acquired) return DIERR_NOTACQUIRED;
1545     }
1546 
1547     if (!This->queue_len)
1548         return DI_OK;
1549     if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3))
1550         return DIERR_INVALIDPARAM;
1551 
1552     IDirectInputDevice2_Poll(iface);
1553     EnterCriticalSection(&This->crit);
1554 
1555     len = This->queue_head - This->queue_tail;
1556     if (len < 0) len += This->queue_len;
1557 
1558     if ((*entries != INFINITE) && (len > *entries)) len = *entries;
1559 
1560     if (dod)
1561     {
1562         int i;
1563         for (i = 0; i < len; i++)
1564         {
1565             int n = (This->queue_tail + i) % This->queue_len;
1566             memcpy((char *)dod + dodsize * i, This->data_queue + n, dodsize);
1567         }
1568     }
1569     *entries = len;
1570 
1571     if (This->overflow && This->dinput->dwVersion == 0x0800)
1572         ret = DI_BUFFEROVERFLOW;
1573 
1574     if (!(flags & DIGDD_PEEK))
1575     {
1576         /* Advance reading position */
1577         This->queue_tail = (This->queue_tail + len) % This->queue_len;
1578         This->overflow = FALSE;
1579     }
1580 
1581     LeaveCriticalSection(&This->crit);
1582 
1583     TRACE("Returning %d events queued\n", *entries);
1584     return ret;
1585 }
1586 
1587 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, DWORD dodsize,
1588                                                       LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
1589 {
1590     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1591     return IDirectInputDevice2WImpl_GetDeviceData(IDirectInputDevice8W_from_impl(This), dodsize, dod, entries, flags);
1592 }
1593 
1594 HRESULT WINAPI IDirectInputDevice2WImpl_RunControlPanel(LPDIRECTINPUTDEVICE8W iface, HWND hwndOwner, DWORD dwFlags)
1595 {
1596     FIXME("(this=%p,%p,0x%08x): stub!\n", iface, hwndOwner, dwFlags);
1597 
1598     return DI_OK;
1599 }
1600 
1601 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(LPDIRECTINPUTDEVICE8A iface, HWND hwndOwner, DWORD dwFlags)
1602 {
1603     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1604     return IDirectInputDevice2WImpl_RunControlPanel(IDirectInputDevice8W_from_impl(This), hwndOwner, dwFlags);
1605 }
1606 
1607 HRESULT WINAPI IDirectInputDevice2WImpl_Initialize(LPDIRECTINPUTDEVICE8W iface, HINSTANCE hinst, DWORD dwVersion,
1608                                                    REFGUID rguid)
1609 {
1610     FIXME("(this=%p,%p,%d,%s): stub!\n", iface, hinst, dwVersion, debugstr_guid(rguid));
1611     return DI_OK;
1612 }
1613 
1614 HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(LPDIRECTINPUTDEVICE8A iface, HINSTANCE hinst, DWORD dwVersion,
1615                                                    REFGUID rguid)
1616 {
1617     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1618     return IDirectInputDevice2WImpl_Initialize(IDirectInputDevice8W_from_impl(This), hinst, dwVersion, rguid);
1619 }
1620 
1621 /******************************************************************************
1622  *	IDirectInputDevice2A
1623  */
1624 
1625 HRESULT WINAPI IDirectInputDevice2WImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIEFFECT lpeff,
1626                                                      LPDIRECTINPUTEFFECT *ppdef, LPUNKNOWN pUnkOuter)
1627 {
1628     FIXME("(this=%p,%s,%p,%p,%p): stub!\n", iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
1629 
1630     FIXME("not available in the generic implementation\n");
1631     *ppdef = NULL;
1632     return DIERR_UNSUPPORTED;
1633 }
1634 
1635 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIEFFECT lpeff,
1636                                                      LPDIRECTINPUTEFFECT *ppdef, LPUNKNOWN pUnkOuter)
1637 {
1638     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1639     return IDirectInputDevice2WImpl_CreateEffect(IDirectInputDevice8W_from_impl(This), rguid, lpeff, ppdef, pUnkOuter);
1640 }
1641 
1642 HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
1643 	LPDIRECTINPUTDEVICE8A iface,
1644 	LPDIENUMEFFECTSCALLBACKA lpCallback,
1645 	LPVOID lpvRef,
1646 	DWORD dwFlags)
1647 {
1648     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1649 	  iface, lpCallback, lpvRef, dwFlags);
1650 
1651     return DI_OK;
1652 }
1653 
1654 HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
1655 	LPDIRECTINPUTDEVICE8W iface,
1656 	LPDIENUMEFFECTSCALLBACKW lpCallback,
1657 	LPVOID lpvRef,
1658 	DWORD dwFlags)
1659 {
1660     FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1661 	  iface, lpCallback, lpvRef, dwFlags);
1662 
1663     return DI_OK;
1664 }
1665 
1666 HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
1667 	LPDIRECTINPUTDEVICE8A iface,
1668 	LPDIEFFECTINFOA lpdei,
1669 	REFGUID rguid)
1670 {
1671     FIXME("(this=%p,%p,%s): stub!\n",
1672 	  iface, lpdei, debugstr_guid(rguid));
1673     return DI_OK;
1674 }
1675 
1676 HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo(
1677 	LPDIRECTINPUTDEVICE8W iface,
1678 	LPDIEFFECTINFOW lpdei,
1679 	REFGUID rguid)
1680 {
1681     FIXME("(this=%p,%p,%s): stub!\n",
1682 	  iface, lpdei, debugstr_guid(rguid));
1683     return DI_OK;
1684 }
1685 
1686 HRESULT WINAPI IDirectInputDevice2WImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W iface, LPDWORD pdwOut)
1687 {
1688     FIXME("(this=%p,%p): stub!\n", iface, pdwOut);
1689     return DI_OK;
1690 }
1691 
1692 HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8A iface, LPDWORD pdwOut)
1693 {
1694     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1695     return IDirectInputDevice2WImpl_GetForceFeedbackState(IDirectInputDevice8W_from_impl(This), pdwOut);
1696 }
1697 
1698 HRESULT WINAPI IDirectInputDevice2WImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags)
1699 {
1700     TRACE("(%p) 0x%08x:\n", iface, dwFlags);
1701     return DI_NOEFFECT;
1702 }
1703 
1704 HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags)
1705 {
1706     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1707     return IDirectInputDevice2WImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags);
1708 }
1709 
1710 HRESULT WINAPI IDirectInputDevice2WImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface,
1711         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID lpvRef, DWORD dwFlags)
1712 {
1713     FIXME("(this=%p,%p,%p,0x%08x): stub!\n", iface, lpCallback, lpvRef, dwFlags);
1714     return DI_OK;
1715 }
1716 
1717 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface,
1718         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID lpvRef, DWORD dwFlags)
1719 {
1720     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1721     return IDirectInputDevice2WImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, lpvRef, dwFlags);
1722 }
1723 
1724 HRESULT WINAPI IDirectInputDevice2WImpl_Escape(LPDIRECTINPUTDEVICE8W iface, LPDIEFFESCAPE lpDIEEsc)
1725 {
1726     FIXME("(this=%p,%p): stub!\n", iface, lpDIEEsc);
1727     return DI_OK;
1728 }
1729 
1730 HRESULT WINAPI IDirectInputDevice2AImpl_Escape(LPDIRECTINPUTDEVICE8A iface, LPDIEFFESCAPE lpDIEEsc)
1731 {
1732     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1733     return IDirectInputDevice2WImpl_Escape(IDirectInputDevice8W_from_impl(This), lpDIEEsc);
1734 }
1735 
1736 HRESULT WINAPI IDirectInputDevice2WImpl_Poll(LPDIRECTINPUTDEVICE8W iface)
1737 {
1738     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1739 
1740     if (!This->acquired) return DIERR_NOTACQUIRED;
1741 
1742     check_dinput_events();
1743     return DI_OK;
1744 }
1745 
1746 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(LPDIRECTINPUTDEVICE8A iface)
1747 {
1748     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1749     return IDirectInputDevice2WImpl_Poll(IDirectInputDevice8W_from_impl(This));
1750 }
1751 
1752 HRESULT WINAPI IDirectInputDevice2WImpl_SendDeviceData(LPDIRECTINPUTDEVICE8W iface, DWORD cbObjectData,
1753                                                        LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut,
1754                                                        DWORD dwFlags)
1755 {
1756     FIXME("(this=%p,0x%08x,%p,%p,0x%08x): stub!\n", iface, cbObjectData, rgdod, pdwInOut, dwFlags);
1757 
1758     return DI_OK;
1759 }
1760 
1761 HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(LPDIRECTINPUTDEVICE8A iface, DWORD cbObjectData,
1762                                                        LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut,
1763                                                        DWORD dwFlags)
1764 {
1765     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1766     return IDirectInputDevice2WImpl_SendDeviceData(IDirectInputDevice8W_from_impl(This), cbObjectData, rgdod,
1767                                                    pdwInOut, dwFlags);
1768 }
1769 
1770 HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface,
1771 							  LPCSTR lpszFileName,
1772 							  LPDIENUMEFFECTSINFILECALLBACK pec,
1773 							  LPVOID pvRef,
1774 							  DWORD dwFlags)
1775 {
1776     FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
1777 
1778     return DI_OK;
1779 }
1780 
1781 HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface,
1782 							  LPCWSTR lpszFileName,
1783 							  LPDIENUMEFFECTSINFILECALLBACK pec,
1784 							  LPVOID pvRef,
1785 							  DWORD dwFlags)
1786 {
1787     FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags);
1788 
1789     return DI_OK;
1790 }
1791 
1792 HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface,
1793 							  LPCSTR lpszFileName,
1794 							  DWORD dwEntries,
1795 							  LPDIFILEEFFECT rgDiFileEft,
1796 							  DWORD dwFlags)
1797 {
1798     FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
1799 
1800     return DI_OK;
1801 }
1802 
1803 HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface,
1804 							  LPCWSTR lpszFileName,
1805 							  DWORD dwEntries,
1806 							  LPDIFILEEFFECT rgDiFileEft,
1807 							  DWORD dwFlags)
1808 {
1809     FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
1810 
1811     return DI_OK;
1812 }
1813 
1814 HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
1815 						       LPDIACTIONFORMATW lpdiaf,
1816 						       LPCWSTR lpszUserName,
1817 						       DWORD dwFlags)
1818 {
1819     FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
1820 #define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
1821 	X(DIDBAM_DEFAULT)
1822 	X(DIDBAM_PRESERVE)
1823 	X(DIDBAM_INITIALIZE)
1824 	X(DIDBAM_HWDEFAULTS)
1825 #undef X
1826 
1827     return DI_OK;
1828 }
1829 
1830 HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
1831 						     LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
1832 {
1833     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1834 
1835     return DI_OK;
1836 }
1837 
1838 HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface,
1839 						     LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
1840 {
1841     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1842 
1843     return DI_OK;
1844 }
1845