1 /*
2  * Copyright (c) 2004-2005 Robert Reif
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #define DIRECTINPUT_VERSION 0x0700
20 
21 #define COBJMACROS
22 #include <windows.h>
23 
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include "wine/test.h"
29 #include "windef.h"
30 #include "wingdi.h"
31 #include "dinput.h"
32 
33 typedef struct tagUserData {
34     IDirectInputA *pDI;
35     DWORD version;
36 } UserData;
37 
38 static const DIOBJECTDATAFORMAT dfDIJoystickTest[] = {
39   { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
40   { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
41   { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
42   { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
43   { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
44   { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
45   { &GUID_Button,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
46   { &GUID_Button,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
47   { &GUID_Button,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
48   { &GUID_Button,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
49   { &GUID_Button,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
50   { &GUID_Button,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
51   { &GUID_Button,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
52   { &GUID_Button,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
53   { &GUID_Button,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
54   { &GUID_Button,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
55   { &GUID_Button,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
56 };
57 
58 static const DIDATAFORMAT c_dfDIJoystickTest = {
59     sizeof(DIDATAFORMAT),
60     sizeof(DIOBJECTDATAFORMAT),
61     DIDF_ABSAXIS,
62     sizeof(DIJOYSTATE2),
63     ARRAY_SIZE(dfDIJoystickTest),
64     (LPDIOBJECTDATAFORMAT)dfDIJoystickTest
65 };
66 
67 static HWND get_hwnd(void)
68 {
69     HWND hwnd=GetForegroundWindow();
70     if (!hwnd)
71         hwnd=GetDesktopWindow();
72     return hwnd;
73 }
74 
75 typedef struct tagJoystickInfo
76 {
77     IDirectInputDeviceA *pJoystick;
78     DWORD axis;
79     DWORD pov;
80     DWORD button;
81     LONG  lMin, lMax;
82     DWORD dZone;
83 } JoystickInfo;
84 
85 static int get_refcount(IUnknown *object)
86 {
87     IUnknown_AddRef( object );
88     return IUnknown_Release( object );
89 }
90 
91 static BOOL CALLBACK EnumAxes(const DIDEVICEOBJECTINSTANCEA *pdidoi, void *pContext)
92 {
93     HRESULT hr;
94     JoystickInfo * info = pContext;
95 
96     if (IsEqualIID(&pdidoi->guidType, &GUID_XAxis) ||
97         IsEqualIID(&pdidoi->guidType, &GUID_YAxis) ||
98         IsEqualIID(&pdidoi->guidType, &GUID_ZAxis) ||
99         IsEqualIID(&pdidoi->guidType, &GUID_RxAxis) ||
100         IsEqualIID(&pdidoi->guidType, &GUID_RyAxis) ||
101         IsEqualIID(&pdidoi->guidType, &GUID_RzAxis) ||
102         IsEqualIID(&pdidoi->guidType, &GUID_Slider))
103     {
104         DIPROPRANGE diprg;
105         DIPROPDWORD dipdw;
106 
107         diprg.diph.dwSize       = sizeof(DIPROPRANGE);
108         diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
109         diprg.diph.dwHow        = DIPH_BYID;
110         diprg.diph.dwObj        = pdidoi->dwType;
111 
112         dipdw.diph.dwSize       = sizeof(dipdw);
113         dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
114         dipdw.diph.dwHow        = DIPH_BYID;
115         dipdw.diph.dwObj        = pdidoi->dwType;
116 
117         hr = IDirectInputDevice_GetProperty(info->pJoystick, DIPROP_RANGE, &diprg.diph);
118         ok(SUCCEEDED(hr), "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
119         ok(info->lMin == diprg.lMin && info->lMax == diprg.lMax, "Min/Max range invalid: "
120            "expected %d..%d got %d..%d\n", info->lMin, info->lMax, diprg.lMin, diprg.lMax);
121 
122         diprg.lMin = -2000;
123         diprg.lMax = +2000;
124 
125         hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_RANGE, NULL);
126         ok(hr==E_INVALIDARG,"IDirectInputDevice_SetProperty() should have returned "
127            "E_INVALIDARG, returned: %08x\n", hr);
128 
129         hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_RANGE, &diprg.diph);
130         ok(hr==DI_OK,"IDirectInputDevice_SetProperty() failed: %08x\n", hr);
131 
132         /* dead zone */
133         hr = IDirectInputDevice_GetProperty(info->pJoystick, DIPROP_DEADZONE, &dipdw.diph);
134         ok(SUCCEEDED(hr), "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
135         ok(info->dZone == dipdw.dwData, "deadzone invalid: expected %d got %d\n",
136            info->dZone, dipdw.dwData);
137 
138         dipdw.dwData = 123;
139 
140         hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_DEADZONE, &dipdw.diph);
141         ok(hr==DI_OK,"IDirectInputDevice_SetProperty() failed: %08x\n", hr);
142 
143         /* ensure DIDOI_ASPECTPOSITION is set for axes objects  */
144         ok(pdidoi->dwFlags & DIDOI_ASPECTPOSITION, "Missing DIDOI_ASPECTPOSITION, flags are 0x%x\n",
145            pdidoi->dwFlags);
146 
147         info->axis++;
148     } else if (IsEqualIID(&pdidoi->guidType, &GUID_POV))
149         info->pov++;
150     else if (IsEqualIID(&pdidoi->guidType, &GUID_Button))
151         info->button++;
152 
153     return DIENUM_CONTINUE;
154 }
155 
156 static const struct effect_id
157 {
158     const GUID *guid;
159     int dieft;
160     const char *name;
161 } effect_conversion[] = {
162     {&GUID_ConstantForce, DIEFT_CONSTANTFORCE, "Constant"},
163     {&GUID_RampForce,     DIEFT_RAMPFORCE,     "Ramp"},
164     {&GUID_Square,        DIEFT_PERIODIC,      "Square"},
165     {&GUID_Sine,          DIEFT_PERIODIC,      "Sine"},
166     {&GUID_Triangle,      DIEFT_PERIODIC,      "Triangle"},
167     {&GUID_SawtoothUp,    DIEFT_PERIODIC,      "Saw Tooth Up"},
168     {&GUID_SawtoothDown,  DIEFT_PERIODIC,      "Saw Tooth Down"},
169     {&GUID_Spring,        DIEFT_CONDITION,     "Spring"},
170     {&GUID_Damper,        DIEFT_CONDITION,     "Damper"},
171     {&GUID_Inertia,       DIEFT_CONDITION,     "Inertia"},
172     {&GUID_Friction,      DIEFT_CONDITION,     "Friction"},
173     {&GUID_CustomForce,   DIEFT_CUSTOMFORCE,   "Custom"}
174 };
175 
176 static const struct effect_id* effect_from_guid(const GUID *guid)
177 {
178     unsigned int i;
179     for (i = 0; i < ARRAY_SIZE(effect_conversion); i++)
180         if (IsEqualGUID(guid, effect_conversion[i].guid))
181             return &effect_conversion[i];
182     return NULL;
183 }
184 
185 struct effect_enum
186 {
187     DIEFFECT eff;
188     GUID guid;
189     int effect_count;
190     const char *effect_name;
191 };
192 
193 /* The last enumerated effect will be used for force feedback testing */
194 static BOOL CALLBACK EnumEffects(const DIEFFECTINFOA *lpef, void *ref)
195 {
196     const struct effect_id *id = effect_from_guid(&lpef->guid);
197     static union
198     {
199         DICONSTANTFORCE constant;
200         DIPERIODIC periodic;
201         DIRAMPFORCE ramp;
202         DICONDITION condition[2];
203     } specific;
204     struct effect_enum *data = ref;
205     int type = DIDFT_GETTYPE(lpef->dwEffType);
206 
207     /* Insanity check */
208     if (!id)
209     {
210         ok(0, "unsupported effect enumerated, GUID %s!\n", wine_dbgstr_guid(&lpef->guid));
211         return DIENUM_CONTINUE;
212     }
213     trace("controller supports '%s' effect\n", id->name);
214     ok(type == id->dieft, "Invalid effect type, expected 0x%x, got 0x%x\n",
215        id->dieft, lpef->dwEffType);
216 
217     /* Can't use custom for test as we don't know the data format */
218     if (type == DIEFT_CUSTOMFORCE)
219         return DIENUM_CONTINUE;
220 
221     data->effect_count++;
222     data->effect_name = id->name;
223     data->guid = *id->guid;
224 
225     ZeroMemory(&specific, sizeof(specific));
226     switch (type)
227     {
228         case DIEFT_PERIODIC:
229             data->eff.cbTypeSpecificParams  = sizeof(specific.periodic);
230             data->eff.lpvTypeSpecificParams = &specific.periodic;
231             specific.periodic.dwMagnitude = DI_FFNOMINALMAX / 2;
232             specific.periodic.dwPeriod = DI_SECONDS; /* 1 second */
233             break;
234         case DIEFT_CONSTANTFORCE:
235             data->eff.cbTypeSpecificParams  = sizeof(specific.constant);
236             data->eff.lpvTypeSpecificParams = &specific.constant;
237             specific.constant.lMagnitude = DI_FFNOMINALMAX / 2;
238             break;
239         case DIEFT_RAMPFORCE:
240             data->eff.cbTypeSpecificParams  = sizeof(specific.ramp);
241             data->eff.lpvTypeSpecificParams = &specific.ramp;
242             specific.ramp.lStart = -DI_FFNOMINALMAX / 2;
243             specific.ramp.lEnd = +DI_FFNOMINALMAX / 2;
244             break;
245         case DIEFT_CONDITION:
246         {
247             int i;
248             data->eff.cbTypeSpecificParams  = sizeof(specific.condition);
249             data->eff.lpvTypeSpecificParams = specific.condition;
250             for (i = 0; i < 2; i++)
251             {
252                 specific.condition[i].lNegativeCoefficient = -DI_FFNOMINALMAX / 2;
253                 specific.condition[i].lPositiveCoefficient = +DI_FFNOMINALMAX / 2;
254             }
255             break;
256         }
257     }
258     return DIENUM_CONTINUE;
259 }
260 
261 static const HRESULT SetCoop_null_window[16] =  {
262     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
263     E_INVALIDARG, E_HANDLE,     E_HANDLE,     E_INVALIDARG,
264     E_INVALIDARG, E_HANDLE,     S_OK,         E_INVALIDARG,
265     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG};
266 
267 static const HRESULT SetCoop_real_window[16] =  {
268     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
269     E_INVALIDARG, S_OK,         S_OK,         E_INVALIDARG,
270     E_INVALIDARG, S_OK,         S_OK,         E_INVALIDARG,
271     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG};
272 
273 static BOOL CALLBACK EnumAllFeedback(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
274 {
275     trace("---- Device Information ----\n"
276           "Product Name  : %s\n"
277           "Instance Name : %s\n"
278           "devType       : 0x%08x\n"
279           "GUID Product  : %s\n"
280           "GUID Instance : %s\n"
281           "HID Page      : 0x%04x\n"
282           "HID Usage     : 0x%04x\n",
283           lpddi->tszProductName,
284           lpddi->tszInstanceName,
285           lpddi->dwDevType,
286           wine_dbgstr_guid(&lpddi->guidProduct),
287           wine_dbgstr_guid(&lpddi->guidInstance),
288           lpddi->wUsagePage,
289           lpddi->wUsage);
290 
291     ok(!(IsEqualGUID(&GUID_SysMouse, &lpddi->guidProduct) || IsEqualGUID(&GUID_SysKeyboard, &lpddi->guidProduct)), "Invalid device returned.\n");
292 
293     return DIENUM_CONTINUE;
294 }
295 
296 static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
297 {
298     HRESULT hr;
299     UserData * data = pvRef;
300     IDirectInputDeviceA *pJoystick;
301     DIDATAFORMAT format;
302     DIDEVCAPS caps;
303     DIJOYSTATE2 js;
304     JoystickInfo info;
305     int i, count;
306     ULONG ref;
307     DIDEVICEINSTANCEA inst;
308     DIDEVICEINSTANCE_DX3A inst3;
309     DIPROPDWORD dipw;
310     DIPROPSTRING dps;
311     DIPROPGUIDANDPATH dpg;
312     WCHAR nameBuffer[MAX_PATH];
313     HWND hWnd = get_hwnd();
314     char oldstate[248], curstate[248];
315     DWORD axes[2] = {DIJOFS_X, DIJOFS_Y};
316     LONG  direction[2] = {0, 0};
317     LPDIRECTINPUTEFFECT effect = NULL;
318     LONG cnt1, cnt2;
319     HWND real_hWnd;
320     HINSTANCE hInstance = GetModuleHandleW(NULL);
321     DIPROPDWORD dip_gain_set, dip_gain_get;
322     struct effect_enum effect_data;
323 
324     ok(data->version >= 0x0300, "Joysticks not supported in version 0x%04x\n", data->version);
325 
326     hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance, NULL, NULL);
327     ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
328        "E_POINTER, returned: %08x\n", hr);
329 
330     hr = IDirectInput_CreateDevice(data->pDI, NULL, &pJoystick, NULL);
331     ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
332        "E_POINTER, returned: %08x\n", hr);
333 
334     hr = IDirectInput_CreateDevice(data->pDI, NULL, NULL, NULL);
335     ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
336        "E_POINTER, returned: %08x\n", hr);
337 
338     hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance,
339                                    &pJoystick, NULL);
340     ok(hr==DI_OK,"IDirectInput_CreateDevice() failed: %08x\n", hr);
341     if (hr!=DI_OK)
342         goto DONE;
343 
344     trace("---- Controller Information ----\n"
345           "Product Name  : %s\n"
346           "Instance Name : %s\n"
347           "devType       : 0x%08x\n"
348           "GUID Product  : %s\n"
349           "GUID Instance : %s\n"
350           "HID Page      : 0x%04x\n"
351           "HID Usage     : 0x%04x\n",
352           lpddi->tszProductName,
353           lpddi->tszInstanceName,
354           lpddi->dwDevType,
355           wine_dbgstr_guid(&lpddi->guidProduct),
356           wine_dbgstr_guid(&lpddi->guidInstance),
357           lpddi->wUsagePage,
358           lpddi->wUsage);
359 
360     /* Check if this is a HID device */
361     if (lpddi->dwDevType & DIDEVTYPE_HID)
362         ok(lpddi->wUsagePage == 0x01 && (lpddi->wUsage == 0x04 || lpddi->wUsage == 0x05),
363            "Expected a game controller HID UsagePage and Usage, got page 0x%x usage 0x%x\n",
364            lpddi->wUsagePage, lpddi->wUsage);
365 
366     /* Test for joystick ID property */
367     ZeroMemory(&dipw, sizeof(dipw));
368     dipw.diph.dwSize = sizeof(DIPROPDWORD);
369     dipw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
370     dipw.diph.dwObj = 0;
371     dipw.diph.dwHow = DIPH_DEVICE;
372 
373     hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_JOYSTICKID, &dipw.diph);
374     ok(SUCCEEDED(hr), "IDirectInputDevice_GetProperty() for DIPROP_JOYSTICKID failed\n");
375 
376     /* Test for INSTANCENAME property */
377     memset(&dps, 0, sizeof(dps));
378     dps.diph.dwSize = sizeof(DIPROPSTRING);
379     dps.diph.dwHeaderSize = sizeof(DIPROPHEADER);
380     dps.diph.dwHow = DIPH_DEVICE;
381 
382     hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_INSTANCENAME, &dps.diph);
383     ok(SUCCEEDED(hr), "IDirectInput_GetProperty() for DIPROP_INSTANCENAME failed: %08x\n", hr);
384 
385     /* Test if instance name is the same as present in DIDEVICEINSTANCE */
386     MultiByteToWideChar(CP_ACP, 0, lpddi->tszInstanceName, -1, nameBuffer, MAX_PATH);
387     ok(!lstrcmpW(nameBuffer, dps.wsz), "DIPROP_INSTANCENAME returned is wrong. Expected: %s Got: %s\n",
388                  wine_dbgstr_w(nameBuffer), wine_dbgstr_w(dps.wsz));
389 
390     hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_PRODUCTNAME, &dps.diph);
391     ok(SUCCEEDED(hr), "IDirectInput_GetProperty() for DIPROP_PRODUCTNAME failed: %08x\n", hr);
392 
393     /* Test if product name is the same as present in DIDEVICEINSTANCE */
394     MultiByteToWideChar(CP_ACP, 0, lpddi->tszProductName, -1, nameBuffer, MAX_PATH);
395     ok(!lstrcmpW(nameBuffer, dps.wsz), "DIPROP_PRODUCTNAME returned is wrong. Expected: %s Got: %s\n",
396                  wine_dbgstr_w(nameBuffer), wine_dbgstr_w(dps.wsz));
397 
398     /* Test for GUIDPATH properties */
399     memset(&dpg, 0, sizeof(dpg));
400     dpg.diph.dwSize = sizeof(DIPROPGUIDANDPATH);
401     dpg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
402     dpg.diph.dwHow = DIPH_DEVICE;
403 
404     hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_GUIDANDPATH, &dpg.diph);
405     ok(SUCCEEDED(hr), "IDirectInput_GetProperty() for DIPROP_GUIDANDPATH failed: %08x\n", hr);
406 
407     {
408         static const WCHAR formatW[] = {'\\','\\','?','\\','%','*','[','^','#',']','#','v','i','d','_',
409                                         '%','0','4','x','&','p','i','d','_','%','0','4','x',0};
410         static const WCHAR miW[] = {'m','i','_',0};
411         static const WCHAR igW[] = {'i','g','_',0};
412         int vid, pid;
413 
414         _wcslwr(dpg.wszPath);
415         count = swscanf(dpg.wszPath, formatW, &vid, &pid);
416         ok(count == 2, "DIPROP_GUIDANDPATH path has wrong format. Expected count: 2 Got: %i Path: %s\n",
417            count, wine_dbgstr_w(dpg.wszPath));
418         ok(wcsstr(dpg.wszPath, miW) != 0 || wcsstr(dpg.wszPath, igW) != 0,
419            "DIPROP_GUIDANDPATH path should contain either 'ig_' or 'mi_' substring. Path: %s\n",
420            wine_dbgstr_w(dpg.wszPath));
421     }
422 
423     hr = IDirectInputDevice_SetDataFormat(pJoystick, NULL);
424     ok(hr==E_POINTER,"IDirectInputDevice_SetDataFormat() should have returned "
425        "E_POINTER, returned: %08x\n", hr);
426 
427     ZeroMemory(&format, sizeof(format));
428     hr = IDirectInputDevice_SetDataFormat(pJoystick, &format);
429     ok(hr==DIERR_INVALIDPARAM,"IDirectInputDevice_SetDataFormat() should have "
430        "returned DIERR_INVALIDPARAM, returned: %08x\n", hr);
431 
432     /* try the default formats */
433     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick);
434     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
435 
436     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
437     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
438 
439     /* try an alternate format */
440     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystickTest);
441     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
442 
443     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
444     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
445     if (hr != DI_OK)
446         goto RELEASE;
447 
448     for (i=0; i<16; i++)
449     {
450         hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, NULL, i);
451         ok(hr == SetCoop_null_window[i], "SetCooperativeLevel(NULL, %d): %08x\n", i, hr);
452     }
453     for (i=0; i<16; i++)
454     {
455         hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, hWnd, i);
456         ok(hr == SetCoop_real_window[i], "SetCooperativeLevel(hwnd, %d): %08x\n", i, hr);
457     }
458 
459     hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, hWnd,
460                                                 DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
461     ok(hr==DI_OK,"IDirectInputDevice_SetCooperativeLevel() failed: %08x\n", hr);
462 
463     /* get capabilities */
464     hr = IDirectInputDevice_GetCapabilities(pJoystick, NULL);
465     ok(hr==E_POINTER,"IDirectInputDevice_GetCapabilities() "
466        "should have returned E_POINTER, returned: %08x\n", hr);
467 
468     ZeroMemory(&caps, sizeof(caps));
469     hr = IDirectInputDevice_GetCapabilities(pJoystick, &caps);
470     ok(hr==DIERR_INVALIDPARAM,"IDirectInputDevice_GetCapabilities() "
471        "should have returned DIERR_INVALIDPARAM, returned: %08x\n", hr);
472 
473     caps.dwSize = sizeof(caps);
474     hr = IDirectInputDevice_GetCapabilities(pJoystick, &caps);
475     ok(hr==DI_OK,"IDirectInputDevice_GetCapabilities() failed: %08x\n", hr);
476 
477     ZeroMemory(&info, sizeof(info));
478     info.pJoystick = pJoystick;
479 
480     /* default min/max limits */
481     info.lMin = 0;
482     info.lMax = 0xffff;
483     /* enumerate objects */
484     hr = IDirectInputDevice_EnumObjects(pJoystick, EnumAxes, &info, DIDFT_ALL);
485     ok(hr==DI_OK,"IDirectInputDevice_EnumObjects() failed: %08x\n", hr);
486 
487     ok(caps.dwAxes == info.axis, "Number of enumerated axes (%d) doesn't match capabilities (%d)\n", info.axis, caps.dwAxes);
488     ok(caps.dwButtons == info.button, "Number of enumerated buttons (%d) doesn't match capabilities (%d)\n", info.button, caps.dwButtons);
489     ok(caps.dwPOVs == info.pov, "Number of enumerated POVs (%d) doesn't match capabilities (%d)\n", info.pov, caps.dwPOVs);
490 
491     /* Set format and check limits again */
492     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
493     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
494     info.lMin = -2000;
495     info.lMax = +2000;
496     info.dZone= 123;
497     hr = IDirectInputDevice_EnumObjects(pJoystick, EnumAxes, &info, DIDFT_ALL);
498     ok(hr==DI_OK,"IDirectInputDevice_EnumObjects() failed: %08x\n", hr);
499 
500     hr = IDirectInputDevice_GetDeviceInfo(pJoystick, 0);
501     ok(hr==E_POINTER, "IDirectInputDevice_GetDeviceInfo() "
502        "should have returned E_POINTER, returned: %08x\n", hr);
503 
504     ZeroMemory(&inst, sizeof(inst));
505     ZeroMemory(&inst3, sizeof(inst3));
506 
507     hr = IDirectInputDevice_GetDeviceInfo(pJoystick, &inst);
508     ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_GetDeviceInfo() "
509        "should have returned DIERR_INVALIDPARAM, returned: %08x\n", hr);
510 
511     inst.dwSize = sizeof(inst);
512     hr = IDirectInputDevice_GetDeviceInfo(pJoystick, &inst);
513     ok(hr==DI_OK,"IDirectInputDevice_GetDeviceInfo() failed: %08x\n", hr);
514 
515     inst3.dwSize = sizeof(inst3);
516     hr = IDirectInputDevice_GetDeviceInfo(pJoystick, (DIDEVICEINSTANCEA*)&inst3);
517     ok(hr==DI_OK,"IDirectInputDevice_GetDeviceInfo() failed: %08x\n", hr);
518 
519     hr = IDirectInputDevice_Unacquire(pJoystick);
520     ok(hr == S_FALSE, "IDirectInputDevice_Unacquire() should have returned S_FALSE, got: %08x\n", hr);
521 
522     hr = IDirectInputDevice_Acquire(pJoystick);
523     ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
524     if (hr != DI_OK)
525         goto RELEASE;
526 
527     hr = IDirectInputDevice_Acquire(pJoystick);
528     ok(hr == S_FALSE, "IDirectInputDevice_Acquire() should have returned S_FALSE, got: %08x\n", hr);
529 
530     if (info.pov < 4)
531     {
532         hr = IDirectInputDevice_GetDeviceState(pJoystick, sizeof(DIJOYSTATE2), &js);
533         ok(hr == DI_OK, "IDirectInputDevice_GetDeviceState() failed: %08x\n", hr);
534         ok(js.rgdwPOV[3] == -1, "Default for unassigned POV should be -1 not: %d\n", js.rgdwPOV[3]);
535     }
536 
537     trace("Testing force feedback\n");
538     ZeroMemory(&effect_data, sizeof(effect_data));
539     effect_data.eff.dwSize          = sizeof(effect_data.eff);
540     effect_data.eff.dwFlags         = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
541     effect_data.eff.dwDuration      = INFINITE;
542     effect_data.eff.dwGain          = DI_FFNOMINALMAX;
543     effect_data.eff.dwTriggerButton = DIEB_NOTRIGGER;
544     effect_data.eff.cAxes           = ARRAY_SIZE(axes);
545     effect_data.eff.rgdwAxes        = axes;
546     effect_data.eff.rglDirection    = direction;
547 
548     /* Sending effects to joystick requires
549      * calling IDirectInputEffect_Initialize, which requires
550      * having exclusive access to the device, which requires
551      * - not having acquired the joystick when calling
552      *   IDirectInputDevice_SetCooperativeLevel
553      * - a visible window
554      */
555     real_hWnd = CreateWindowExA(0, "EDIT", "Test text", 0, 10, 10, 300, 300, NULL, NULL,
556                                 hInstance, NULL);
557     ok(real_hWnd!=0,"CreateWindowExA failed: %p\n", real_hWnd);
558     ShowWindow(real_hWnd, SW_SHOW);
559     hr = IDirectInputDevice_Unacquire(pJoystick);
560     ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
561     hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, real_hWnd,
562                                                 DISCL_EXCLUSIVE | DISCL_FOREGROUND);
563     ok(hr==DI_OK,"IDirectInputDevice_SetCooperativeLevel() failed: %08x\n", hr);
564     hr = IDirectInputDevice_Acquire(pJoystick);
565     ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
566 
567     cnt1 = get_refcount((IUnknown*)pJoystick);
568 
569     hr = IDirectInputDevice2_EnumEffects((IDirectInputDevice2A*)pJoystick, EnumEffects, &effect_data, DIEFT_ALL);
570     ok(hr==DI_OK,"IDirectInputDevice2_EnumEffects() failed: %08x\n", hr);
571 
572     /* If the controller does not support ANY effect use the constant effect to make
573      * CreateEffect fail but with the unsupported reason instead of invalid parameters. */
574     if (!effect_data.effect_count)
575     {
576         static DICONSTANTFORCE constant;
577         effect_data.guid = GUID_ConstantForce;
578         effect_data.eff.cbTypeSpecificParams  = sizeof(constant);
579         effect_data.eff.lpvTypeSpecificParams = &constant;
580         effect_data.effect_name = "Constant";
581         constant.lMagnitude = DI_FFNOMINALMAX / 2;
582 
583         ok(!(caps.dwFlags & DIDC_FORCEFEEDBACK), "effect count is zero but controller supports force feedback?\n");
584     }
585 
586     effect = (void *)0xdeadbeef;
587     hr = IDirectInputDevice2_CreateEffect((IDirectInputDevice2A*)pJoystick, &effect_data.guid,
588                                           &effect_data.eff, &effect, NULL);
589     if (caps.dwFlags & DIDC_FORCEFEEDBACK)
590     {
591         trace("force feedback supported with %d effects, using '%s' for test\n",
592               effect_data.effect_count, effect_data.effect_name);
593         ok(hr == DI_OK, "IDirectInputDevice_CreateEffect() failed: %08x\n", hr);
594         cnt2 = get_refcount((IUnknown*)pJoystick);
595         ok(cnt1 == cnt2, "Ref count is wrong %d != %d\n", cnt1, cnt2);
596 
597         if (effect)
598         {
599             DWORD effect_status;
600             struct DIPROPDWORD diprop_word;
601             GUID guid = {0};
602 
603             hr = IDirectInputEffect_Initialize(effect, hInstance, data->version,
604                                                &effect_data.guid);
605             ok(hr==DI_OK,"IDirectInputEffect_Initialize failed: %08x\n", hr);
606             hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_AXES | DIEP_DIRECTION |
607                                                   DIEP_TYPESPECIFICPARAMS);
608             ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
609             if (hr==DI_OK) {
610                 /* Test that upload, unacquire, acquire still permits updating
611                  * uploaded effect. */
612                 hr = IDirectInputDevice_Unacquire(pJoystick);
613                 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
614                 hr = IDirectInputDevice_Acquire(pJoystick);
615                 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
616                 hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_GAIN);
617                 ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
618             }
619 
620             /* Check effect status.
621              * State: initially stopped
622              * start
623              * State: started
624              * unacquire, acquire, download
625              * State: stopped
626              * start
627              * State: started
628              *
629              * Shows that:
630              * - effects are stopped after Unacquire + Acquire
631              * - effects are preserved (Download + Start doesn't complain
632              *   about incomplete effect)
633              */
634             hr = IDirectInputEffect_GetEffectStatus(effect, NULL);
635             ok(hr==E_POINTER,"IDirectInputEffect_GetEffectStatus() must fail with E_POINTER, got: %08x\n", hr);
636             effect_status = 0xdeadbeef;
637             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
638             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
639             ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
640             hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_START);
641             ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
642             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
643             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
644             todo_wine ok(effect_status!=0,"IDirectInputEffect_GetEffectStatus() reported effect as stopped\n");
645             hr = IDirectInputDevice_Unacquire(pJoystick);
646             ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
647             hr = IDirectInputDevice_Acquire(pJoystick);
648             ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
649             hr = IDirectInputEffect_Download(effect);
650             ok(hr==DI_OK,"IDirectInputEffect_Download() failed: %08x\n", hr);
651             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
652             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
653             ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
654             hr = IDirectInputEffect_Start(effect, 1, 0);
655             ok(hr==DI_OK,"IDirectInputEffect_Start() failed: %08x\n", hr);
656             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
657             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
658             Sleep(250); /* feel the magic */
659             todo_wine ok(effect_status!=0,"IDirectInputEffect_GetEffectStatus() reported effect as stopped\n");
660             hr = IDirectInputEffect_GetEffectGuid(effect, &guid);
661             ok(hr==DI_OK,"IDirectInputEffect_GetEffectGuid() failed: %08x\n", hr);
662             ok(IsEqualGUID(&effect_data.guid, &guid), "Wrong guid returned\n");
663 
664             /* Check autocenter status
665              * State: initially stopped
666              * enable
667              * State: enabled
668              * acquire
669              * State: enabled
670              * unacquire
671              * State: enabled
672              *
673              * IDirectInputDevice2_SetProperty(DIPROP_AUTOCENTER) can only be
674              * executed when the device is released.
675              *
676              * If Executed interactively, user can feel that autocenter is
677              * only disabled when the joystick is acquired.
678              */
679             diprop_word.diph.dwSize = sizeof(diprop_word);
680             diprop_word.diph.dwHeaderSize = sizeof(diprop_word.diph);
681             diprop_word.diph.dwObj = 0;
682             diprop_word.diph.dwHow = DIPH_DEVICE;
683             hr = IDirectInputDevice_Unacquire(pJoystick);
684             ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
685             hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
686             ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
687             ok(diprop_word.dwData==DIPROPAUTOCENTER_ON,"IDirectInputDevice2_GetProperty() reported autocenter as disabled\n");
688             diprop_word.dwData = DIPROPAUTOCENTER_OFF;
689             hr = IDirectInputDevice2_SetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
690             ok(hr==DI_OK,"IDirectInputDevice2_SetProperty() failed: %08x\n", hr);
691             hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
692             ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
693             ok(diprop_word.dwData==DIPROPAUTOCENTER_OFF,"IDirectInputDevice2_GetProperty() reported autocenter as enabled\n");
694             if (winetest_interactive) {
695                 trace("Acquiring in 2s, autocenter will be disabled.\n");
696                 Sleep(2000);
697             }
698             hr = IDirectInputDevice_Acquire(pJoystick);
699             ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
700             if (winetest_interactive)
701                 trace("Acquired.\n");
702             hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
703             ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
704             ok(diprop_word.dwData==DIPROPAUTOCENTER_OFF,"IDirectInputDevice2_GetProperty() reported autocenter as enabled\n");
705             if (winetest_interactive) {
706                 trace("Releasing in 2s, autocenter will be re-enabled.\n");
707                 Sleep(2000);
708             }
709             hr = IDirectInputDevice_Unacquire(pJoystick);
710             ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
711             if (winetest_interactive)
712                 trace("Released\n");
713             hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
714             ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
715             ok(diprop_word.dwData==DIPROPAUTOCENTER_OFF,"IDirectInputDevice2_GetProperty() reported autocenter as enabled\n");
716             hr = IDirectInputDevice_Acquire(pJoystick);
717             ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
718             hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
719             ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
720 
721             /* Device gain (DIPROP_FFGAIN).
722              * From MSDN:
723              *  0..10000 range, otherwise DIERR_INVALIDPARAM.
724              *  Can be changed even if device is acquired.
725              * Difference found by tests:
726              *  <0 is refused, >10000 is accepted
727              */
728             dip_gain_set.diph.dwSize       = sizeof(DIPROPDWORD);
729             dip_gain_set.diph.dwHeaderSize = sizeof(DIPROPHEADER);
730             dip_gain_set.diph.dwObj        = 0;
731             dip_gain_set.diph.dwHow        = DIPH_DEVICE;
732             dip_gain_get.diph.dwSize       = sizeof(DIPROPDWORD);
733             dip_gain_get.diph.dwHeaderSize = sizeof(DIPROPHEADER);
734             dip_gain_get.diph.dwObj        = 0;
735             dip_gain_get.diph.dwHow        = DIPH_DEVICE;
736             dip_gain_get.dwData            = 0;
737 
738             /* Test device is acquisition (non)impact. */
739             hr = IDirectInputDevice_Unacquire(pJoystick);
740             ok(hr == DI_OK, "IDirectInputDevice_Unacquire() should have returned S_FALSE, got: %08x\n", hr);
741             dip_gain_set.dwData = 1;
742             hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
743             ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
744             hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
745             ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
746             ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
747             hr = IDirectInputDevice_Acquire(pJoystick);
748             ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
749             dip_gain_set.dwData = 2;
750             hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
751             ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
752             hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
753             ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
754             ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
755             /* Test range and internal clamping. */
756             dip_gain_set.dwData = -1;
757             hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
758             todo_wine ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_SetProperty() should have returned %08x: %08x\n", DIERR_INVALIDPARAM, hr);
759             dip_gain_set.dwData = 0;
760             hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
761             ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
762             hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
763             ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
764             ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
765             dip_gain_set.dwData = 10000;
766             hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
767             ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
768             hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
769             ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
770             ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
771             /* WARNING: This call succeeds, on the contrary of what is stated on MSDN. */
772             dip_gain_set.dwData = 10001;
773             hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
774             ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
775             hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
776             ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
777             ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
778 
779             /* Test SendForceFeedbackCommand
780              * DISFFC_STOPALL - Should stop effects only
781              * DISFFC_RESET - Should stop effects and unload them (NOT release them)
782              * Tests for game Odallus (bug 41623) */
783             hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, 0);
784             ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
785             hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, 0xFF);
786             ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
787 
788             hr = IDirectInputEffect_Download(effect);
789             ok(hr==DI_OK,"IDirectInputEffect_Download() failed: %08x\n", hr);
790 
791             /* Send STOPALL and prove that the effect can still be started */
792             hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, DISFFC_STOPALL);
793             ok(hr==DI_OK, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
794             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
795             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
796             ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
797             hr = IDirectInputEffect_Start(effect, 1, 0);
798             ok(hr==DI_OK,"IDirectInputEffect_Start() failed: %08x\n", hr);
799             hr = IDirectInputEffect_GetEffectGuid(effect, &guid);
800             ok(hr==DI_OK,"IDirectInputEffect_GetEffectGuid() failed: %08x\n", hr);
801             ok(IsEqualGUID(&effect_data.guid, &guid), "Wrong guid returned\n");
802 
803             /* Send RESET and prove that we can still manipulate the effect, thus not released */
804             hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, DISFFC_RESET);
805             ok(hr==DI_OK, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
806             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
807             ok(hr==DIERR_NOTDOWNLOADED,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
808             hr = IDirectInputEffect_Download(effect);
809             ok(hr==DI_OK,"IDirectInputEffect_Download() failed: %08x\n", hr);
810             hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
811             ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
812             ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
813             hr = IDirectInputEffect_Start(effect, 1, 0);
814             ok(hr==DI_OK,"IDirectInputEffect_Start() failed: %08x\n", hr);
815             hr = IDirectInputEffect_GetEffectGuid(effect, &guid);
816             ok(hr==DI_OK,"IDirectInputEffect_GetEffectGuid() failed: %08x\n", hr);
817             ok(IsEqualGUID(&effect_data.guid, &guid), "Wrong guid returned\n");
818 
819             ref = IUnknown_Release(effect);
820             ok(ref == 0, "IDirectInputDevice_Release() reference count = %d\n", ref);
821         }
822         cnt1 = get_refcount((IUnknown*)pJoystick);
823         ok(cnt1 == cnt2, "Ref count is wrong %d != %d\n", cnt1, cnt2);
824     }
825     /* No force feedback support, CreateEffect is supposed to fail. Fairy Bloom Freesia
826      * calls CreateEffect without checking the DIDC_FORCEFEEDBACK. It expects the correct
827      * error return to determine if force feedback is unsupported. */
828     else
829     {
830         trace("No force feedback support\n");
831         ok(hr==DIERR_UNSUPPORTED, "IDirectInputDevice_CreateEffect() must fail with DIERR_UNSUPPORTED, got: %08x\n", hr);
832         ok(effect == NULL, "effect must be NULL, got %p\n", effect);
833     }
834 
835     /* Before destroying the window, release joystick to revert to
836      * non-exclusive, background cooperative level. */
837     hr = IDirectInputDevice_Unacquire(pJoystick);
838     ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
839     hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, hWnd,
840                                                 DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
841     ok(hr==DI_OK,"IDirectInputDevice_SetCooperativeLevel() failed: %08x\n", hr);
842     DestroyWindow (real_hWnd);
843     hr = IDirectInputDevice_Acquire(pJoystick);
844     ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
845 
846     if (winetest_interactive) {
847         trace("You have 30 seconds to test all axes, sliders, POVs and buttons\n");
848         count = 300;
849     } else
850         count = 1;
851 
852     trace("\n");
853     oldstate[0]='\0';
854     for (i = 0; i < count; i++) {
855         hr = IDirectInputDevice_GetDeviceState(pJoystick, sizeof(DIJOYSTATE2), &js);
856         ok(hr==DI_OK,"IDirectInputDevice_GetDeviceState() failed: %08x\n", hr);
857         if (hr != DI_OK)
858             break;
859         sprintf(curstate, "X%5d Y%5d Z%5d Rx%5d Ry%5d Rz%5d "
860               "S0%5d S1%5d POV0%5d POV1%5d POV2%5d POV3%5d "
861               "B %d %d %d %d %d %d %d %d %d %d %d %d\n",
862               js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz,
863               js.rglSlider[0], js.rglSlider[1],
864               js.rgdwPOV[0], js.rgdwPOV[1], js.rgdwPOV[2], js.rgdwPOV[3],
865               js.rgbButtons[0]>>7, js.rgbButtons[1]>>7, js.rgbButtons[2]>>7,
866               js.rgbButtons[3]>>7, js.rgbButtons[4]>>7, js.rgbButtons[5]>>7,
867               js.rgbButtons[6]>>7, js.rgbButtons[7]>>7, js.rgbButtons[8]>>7,
868               js.rgbButtons[9]>>7, js.rgbButtons[10]>>7, js.rgbButtons[11]>>7);
869         if (strcmp(oldstate, curstate) != 0)
870         {
871             trace("%s\n", curstate);
872             strcpy(oldstate, curstate);
873         }
874         Sleep(100);
875     }
876     trace("\n");
877 
878     hr = IDirectInputDevice_Unacquire(pJoystick);
879     ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
880 
881 RELEASE:
882     ref = IDirectInputDevice_Release(pJoystick);
883     ok(ref==0,"IDirectInputDevice_Release() reference count = %d\n", ref);
884 
885 DONE:
886     return DIENUM_CONTINUE;
887 }
888 
889 static void joystick_tests(DWORD version)
890 {
891     HRESULT hr;
892     IDirectInputA *pDI;
893     ULONG ref;
894     HINSTANCE hInstance = GetModuleHandleW(NULL);
895 
896     trace("-- Testing Direct Input Version 0x%04x --\n", version);
897     hr = DirectInputCreateA(hInstance, version, &pDI, NULL);
898     ok(hr==DI_OK||hr==DIERR_OLDDIRECTINPUTVERSION, "DirectInputCreateA() failed: %08x\n", hr);
899     if (hr==DI_OK && pDI!=0) {
900         UserData data;
901         data.pDI = pDI;
902         data.version = version;
903         hr = IDirectInput_EnumDevices(pDI, DIDEVTYPE_JOYSTICK, EnumJoysticks,
904                                       &data, DIEDFL_ALLDEVICES);
905         ok(hr==DI_OK,"IDirectInput_EnumDevices() failed: %08x\n", hr);
906         ref = IDirectInput_Release(pDI);
907         ok(ref==0,"IDirectInput_Release() reference count = %d\n", ref);
908     } else if (hr==DIERR_OLDDIRECTINPUTVERSION)
909         trace("  Version Not Supported\n");
910 }
911 
912 static void test_enum_feedback(void)
913 {
914     HRESULT hr;
915     IDirectInputA *pDI;
916     ULONG ref;
917     HINSTANCE hInstance = GetModuleHandleW(NULL);
918 
919     hr = DirectInputCreateA(hInstance, 0x0700, &pDI, NULL);
920     ok(hr==DI_OK||hr==DIERR_OLDDIRECTINPUTVERSION, "DirectInputCreateA() failed: %08x\n", hr);
921     if (hr==DI_OK && pDI!=0) {
922         hr = IDirectInput_EnumDevices(pDI, 0, EnumAllFeedback, NULL, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK);
923         ok(hr==DI_OK,"IDirectInput_EnumDevices() failed: %08x\n", hr);
924         ref = IDirectInput_Release(pDI);
925         ok(ref==0,"IDirectInput_Release() reference count = %d\n", ref);
926     } else if (hr==DIERR_OLDDIRECTINPUTVERSION)
927         trace("  Version Not Supported\n");
928 }
929 
930 START_TEST(joystick)
931 {
932     CoInitialize(NULL);
933 
934     joystick_tests(0x0700);
935     joystick_tests(0x0500);
936     joystick_tests(0x0300);
937 
938     test_enum_feedback();
939 
940     CoUninitialize();
941 }
942