setupapi/tests: Fix some typos.
[wine] / dlls / setupapi / tests / devinst.c
1 /*
2  * Devinst tests
3  *
4  * Copyright 2006 Christian Gmeiner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "guiddef.h"
30 #include "setupapi.h"
31
32 #include "wine/test.h"
33
34 /* function pointers */
35 static HMODULE hSetupAPI;
36 static HDEVINFO (WINAPI *pSetupDiCreateDeviceInfoList)(GUID*,HWND);
37 static HDEVINFO (WINAPI *pSetupDiCreateDeviceInfoListExW)(GUID*,HWND,PCWSTR,PVOID);
38 static BOOL     (WINAPI *pSetupDiCreateDeviceInterfaceA)(HDEVINFO, PSP_DEVINFO_DATA, const GUID *, PCSTR, DWORD, PSP_DEVICE_INTERFACE_DATA);
39 static BOOL     (WINAPI *pSetupDiCallClassInstaller)(DI_FUNCTION, HDEVINFO, PSP_DEVINFO_DATA);
40 static BOOL     (WINAPI *pSetupDiDestroyDeviceInfoList)(HDEVINFO);
41 static BOOL     (WINAPI *pSetupDiEnumDeviceInfo)(HDEVINFO, DWORD, PSP_DEVINFO_DATA);
42 static BOOL     (WINAPI *pSetupDiEnumDeviceInterfaces)(HDEVINFO, PSP_DEVINFO_DATA, const GUID *, DWORD, PSP_DEVICE_INTERFACE_DATA);
43 static BOOL     (WINAPI *pSetupDiInstallClassA)(HWND, PCSTR, DWORD, HSPFILEQ);
44 static HKEY     (WINAPI *pSetupDiOpenClassRegKeyExA)(GUID*,REGSAM,DWORD,PCSTR,PVOID);
45 static HKEY     (WINAPI *pSetupDiOpenDevRegKey)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM);
46 static HKEY     (WINAPI *pSetupDiCreateDevRegKeyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, HINF, PCWSTR);
47 static BOOL     (WINAPI *pSetupDiCreateDeviceInfoA)(HDEVINFO, PCSTR, GUID *, PCSTR, HWND, DWORD, PSP_DEVINFO_DATA);
48 static BOOL     (WINAPI *pSetupDiCreateDeviceInfoW)(HDEVINFO, PCWSTR, GUID *, PCWSTR, HWND, DWORD, PSP_DEVINFO_DATA);
49 static BOOL     (WINAPI *pSetupDiGetDeviceInstanceIdA)(HDEVINFO, PSP_DEVINFO_DATA, PSTR, DWORD, PDWORD);
50 static BOOL     (WINAPI *pSetupDiGetDeviceInterfaceDetailA)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA);
51 static BOOL     (WINAPI *pSetupDiGetDeviceInterfaceDetailW)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_W, DWORD, PDWORD, PSP_DEVINFO_DATA);
52 static BOOL     (WINAPI *pSetupDiRegisterDeviceInfo)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PSP_DETSIG_CMPPROC, PVOID, PSP_DEVINFO_DATA);
53 static HDEVINFO (WINAPI *pSetupDiGetClassDevsA)(CONST GUID *, LPCSTR, HWND, DWORD);
54 static HDEVINFO (WINAPI *pSetupDiGetClassDevsW)(CONST GUID *, LPCWSTR, HWND, DWORD);
55 static BOOL     (WINAPI *pSetupDiSetDeviceRegistryPropertyA)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const BYTE *, DWORD);
56 static BOOL     (WINAPI *pSetupDiSetDeviceRegistryPropertyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const BYTE *, DWORD);
57 static BOOL     (WINAPI *pSetupDiGetDeviceRegistryPropertyA)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD);
58 static BOOL     (WINAPI *pSetupDiGetDeviceRegistryPropertyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD);
59
60 /* This is a unique guid for testing purposes */
61 static GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c,0x2b,0xdb}};
62
63 static void init_function_pointers(void)
64 {
65     hSetupAPI = GetModuleHandleA("setupapi.dll");
66
67     pSetupDiCreateDeviceInfoA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoA");
68     pSetupDiCreateDeviceInfoW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoW");
69     pSetupDiCreateDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoList");
70     pSetupDiCreateDeviceInfoListExW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoListExW");
71     pSetupDiCreateDeviceInterfaceA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInterfaceA");
72     pSetupDiDestroyDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiDestroyDeviceInfoList");
73     pSetupDiCallClassInstaller = (void *)GetProcAddress(hSetupAPI, "SetupDiCallClassInstaller");
74     pSetupDiEnumDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInfo");
75     pSetupDiEnumDeviceInterfaces = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInterfaces");
76     pSetupDiGetDeviceInstanceIdA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInstanceIdA");
77     pSetupDiGetDeviceInterfaceDetailA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailA");
78     pSetupDiGetDeviceInterfaceDetailW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailW");
79     pSetupDiInstallClassA = (void *)GetProcAddress(hSetupAPI, "SetupDiInstallClassA");
80     pSetupDiOpenClassRegKeyExA = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenClassRegKeyExA");
81     pSetupDiOpenDevRegKey = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenDevRegKey");
82     pSetupDiCreateDevRegKeyW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDevRegKeyW");
83     pSetupDiRegisterDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiRegisterDeviceInfo");
84     pSetupDiGetClassDevsA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsA");
85     pSetupDiGetClassDevsW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsW");
86     pSetupDiSetDeviceRegistryPropertyA = (void *)GetProcAddress(hSetupAPI, "SetupDiSetDeviceRegistryPropertyA");
87     pSetupDiSetDeviceRegistryPropertyW = (void *)GetProcAddress(hSetupAPI, "SetupDiSetDeviceRegistryPropertyW");
88     pSetupDiGetDeviceRegistryPropertyA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceRegistryPropertyA");
89     pSetupDiGetDeviceRegistryPropertyW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceRegistryPropertyW");
90 }
91
92 static BOOL remove_device(void)
93 {
94     HDEVINFO set;
95     SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
96     BOOL ret;
97
98     SetLastError(0xdeadbeef);
99     set = pSetupDiGetClassDevsA(&guid, NULL, 0, 0);
100     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
101      GetLastError());
102
103     SetLastError(0xdeadbeef);
104     ok(pSetupDiEnumDeviceInfo(set, 0, &devInfo),
105      "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
106
107     SetLastError(0xdeadbeef);
108     ret = pSetupDiCallClassInstaller(DIF_REMOVE, set, &devInfo);
109     todo_wine
110     ok(ret, "SetupDiCallClassInstaller(DIF_REMOVE...) failed: %08x\n", GetLastError());
111
112     SetLastError(0xdeadbeef);
113     ok(pSetupDiDestroyDeviceInfoList(set),
114      "SetupDiDestroyDeviceInfoList failed: %08x\n", GetLastError());
115
116     return ret;
117 }
118
119 /* RegDeleteTreeW from dlls/advapi32/registry.c */
120 LSTATUS WINAPI devinst_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
121 {
122     LONG ret;
123     DWORD dwMaxSubkeyLen, dwMaxValueLen;
124     DWORD dwMaxLen, dwSize;
125     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
126     HKEY hSubKey = hKey;
127
128     if(lpszSubKey)
129     {
130         ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
131         if (ret) return ret;
132     }
133
134     /* Get highest length for keys, values */
135     ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
136             &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
137     if (ret) goto cleanup;
138
139     dwMaxSubkeyLen++;
140     dwMaxValueLen++;
141     dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
142     if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
143     {
144         /* Name too big: alloc a buffer for it */
145         if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
146         {
147             ret = ERROR_NOT_ENOUGH_MEMORY;
148             goto cleanup;
149         }
150     }
151
152
153     /* Recursively delete all the subkeys */
154     while (TRUE)
155     {
156         dwSize = dwMaxLen;
157         if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
158                           NULL, NULL, NULL)) break;
159
160         ret = devinst_RegDeleteTreeW(hSubKey, lpszName);
161         if (ret) goto cleanup;
162     }
163
164     if (lpszSubKey)
165         ret = RegDeleteKeyW(hKey, lpszSubKey);
166     else
167         while (TRUE)
168         {
169             dwSize = dwMaxLen;
170             if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
171                   NULL, NULL, NULL, NULL)) break;
172
173             ret = RegDeleteValueW(hKey, lpszName);
174             if (ret) goto cleanup;
175         }
176
177 cleanup:
178     /* Free buffer if allocated */
179     if (lpszName != szNameBuf)
180         HeapFree( GetProcessHeap(), 0, lpszName);
181     if(lpszSubKey)
182         RegCloseKey(hSubKey);
183     return ret;
184 }
185
186 static void clean_devclass_key(void)
187 {
188     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
189      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
190      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
191      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
192      '1','1','d','b','-','b','7','0','4','-',
193      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
194     HKEY key;
195     DWORD subkeys;
196
197     /* Check if we have subkeys as Windows 2000 doesn't delete
198      * the keys under the DeviceClasses key after a SetupDiDestroyDeviceInfoList.
199      */
200     RegOpenKeyW(HKEY_LOCAL_MACHINE, devclass, &key);
201     RegQueryInfoKey(key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
202     if (subkeys > 0)
203     {
204         trace("We are most likely on Windows 2000\n");
205         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
206     }
207     else
208     {
209         ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, devclass),
210          "Couldn't delete deviceclass key\n");
211     }
212 }
213
214 static void test_SetupDiCreateDeviceInfoListEx(void) 
215 {
216     HDEVINFO devlist;
217     BOOL ret;
218     DWORD error;
219     static CHAR notnull[] = "NotNull";
220     static const WCHAR machine[] = { 'd','u','m','m','y',0 };
221
222     SetLastError(0xdeadbeef);
223     /* create empty DeviceInfoList, but set Reserved to a value, which is not NULL */
224     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, notnull);
225
226     error = GetLastError();
227     if (error == ERROR_CALL_NOT_IMPLEMENTED)
228     {
229         skip("SetupDiCreateDeviceInfoListExW is not implemented\n");
230         return;
231     }
232     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
233     ok(error == ERROR_INVALID_PARAMETER, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_PARAMETER);
234
235     SetLastError(0xdeadbeef);
236     /* create empty DeviceInfoList, but set MachineName to something */
237     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, machine, NULL);
238
239     error = GetLastError();
240     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
241     ok(error == ERROR_INVALID_MACHINENAME, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_MACHINENAME);
242
243     /* create empty DeviceInfoList */
244     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
245     ok(devlist && devlist != INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected != %p)\n", devlist, error, INVALID_HANDLE_VALUE);
246
247     /* destroy DeviceInfoList */
248     ret = pSetupDiDestroyDeviceInfoList(devlist);
249     ok(ret, "SetupDiDestroyDeviceInfoList failed : %d\n", error);
250 }
251
252 static void test_SetupDiOpenClassRegKeyExA(void)
253 {
254     static const CHAR guidString[] = "{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
255     HKEY hkey;
256
257     /* Check return value for nonexistent key */
258     hkey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
259         DIOCR_INSTALLER, NULL, NULL);
260     ok(hkey == INVALID_HANDLE_VALUE,
261         "returned %p (expected INVALID_HANDLE_VALUE)\n", hkey);
262
263     /* Test it for a key that exists */
264     hkey = SetupDiOpenClassRegKey(NULL, KEY_ALL_ACCESS);
265     if (hkey != INVALID_HANDLE_VALUE)
266     {
267         HKEY classKey;
268         if (RegCreateKeyA(hkey, guidString, &classKey) == ERROR_SUCCESS)
269         {
270             RegCloseKey(classKey);
271             SetLastError(0xdeadbeef);
272             classKey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
273                 DIOCR_INSTALLER, NULL, NULL);
274             ok(classKey != INVALID_HANDLE_VALUE,
275                 "opening class registry key failed with error %d\n",
276                 GetLastError());
277             if (classKey != INVALID_HANDLE_VALUE)
278                 RegCloseKey(classKey);
279             RegDeleteKeyA(hkey, guidString);
280         }
281         else
282             trace("failed to create registry key for test\n");
283
284         RegCloseKey(hkey);
285     }
286     else
287         trace("failed to open classes key\n");
288 }
289
290 static void append_str(char **str, const char *data)
291 {
292     sprintf(*str, data);
293     *str += strlen(*str);
294 }
295
296 static void create_inf_file(LPCSTR filename)
297 {
298     char data[1024];
299     char *ptr = data;
300     DWORD dwNumberOfBytesWritten;
301     HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
302                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
303
304     append_str(&ptr, "[Version]\n");
305     append_str(&ptr, "Signature=\"$Chicago$\"\n");
306     append_str(&ptr, "Class=Bogus\n");
307     append_str(&ptr, "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n");
308     append_str(&ptr, "[ClassInstall32]\n");
309     append_str(&ptr, "AddReg=BogusClass.NT.AddReg\n");
310     append_str(&ptr, "[BogusClass.NT.AddReg]\n");
311     append_str(&ptr, "HKR,,,,\"Wine test devices\"\n");
312
313     WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL);
314     CloseHandle(hf);
315 }
316
317 static void get_temp_filename(LPSTR path)
318 {
319     static char curr[MAX_PATH] = { 0 };
320     char temp[MAX_PATH];
321     LPSTR ptr;
322
323     if (!*curr)
324         GetCurrentDirectoryA(MAX_PATH, curr);
325     GetTempFileNameA(curr, "set", 0, temp);
326     ptr = strrchr(temp, '\\');
327
328     lstrcpyA(path, ptr + 1);
329 }
330
331 static void testInstallClass(void)
332 {
333     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
334      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
335      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
336      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
337      '1','1','d','b','-','b','7','0','4','-',
338      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
339     static const CHAR classKey_win9x[] =
340      "System\\CurrentControlSet\\Services\\Class\\"
341      "{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
342     static const CHAR bogus_win9x[] =
343      "System\\CurrentControlSet\\Services\\Class\\Bogus";
344     char tmpfile[MAX_PATH];
345     BOOL ret;
346     HKEY hkey;
347
348     if (!pSetupDiInstallClassA)
349     {
350         skip("No SetupDiInstallClassA\n");
351         return;
352     }
353     tmpfile[0] = '.';
354     tmpfile[1] = '\\';
355     get_temp_filename(tmpfile + 2);
356     create_inf_file(tmpfile + 2);
357
358     ret = pSetupDiInstallClassA(NULL, NULL, 0, NULL);
359     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
360      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
361     ret = pSetupDiInstallClassA(NULL, NULL, DI_NOVCP, NULL);
362     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
363      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
364     ret = pSetupDiInstallClassA(NULL, tmpfile + 2, DI_NOVCP, NULL);
365     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
366      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
367     ret = pSetupDiInstallClassA(NULL, tmpfile + 2, 0, NULL);
368     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
369      "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
370     /* The next call will succeed. Information is put into the registry but the
371      * location(s) is/are depending on the Windows version.
372      */
373     ret = pSetupDiInstallClassA(NULL, tmpfile, 0, NULL);
374     ok(ret, "SetupDiInstallClassA failed: %08x\n", GetLastError());
375     if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, classKey_win9x, &hkey))
376     {
377         /* We are on win9x */
378         RegCloseKey(hkey);
379         ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, classKey_win9x),
380          "Couldn't delete win9x classkey\n");
381         ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus_win9x),
382          "Couldn't delete win9x bogus services class\n");
383     }
384     else
385     {
386         /* NT4 and above */
387         ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey),
388          "Couldn't delete NT classkey\n");
389     }
390     DeleteFile(tmpfile);
391 }
392
393 static void testCreateDeviceInfo(void)
394 {
395     BOOL ret;
396     HDEVINFO set;
397     HKEY key;
398     LONG res;
399     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
400      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
401      'E','n','u','m','\\','R','o','o','t','\\',
402      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
403
404     if (!pSetupDiCreateDeviceInfoList || !pSetupDiEnumDeviceInfo ||
405      !pSetupDiDestroyDeviceInfoList || !pSetupDiCreateDeviceInfoA)
406     {
407         skip("No SetupDiCreateDeviceInfoA\n");
408         return;
409     }
410     SetLastError(0xdeadbeef);
411     ret = pSetupDiCreateDeviceInfoA(NULL, NULL, NULL, NULL, NULL, 0, NULL);
412     ok(!ret, "Expected failure\n");
413     ok(GetLastError() == ERROR_INVALID_DEVINST_NAME ||
414       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */ ||
415       GetLastError() == ERROR_INVALID_HANDLE /* Win9x */,
416      "Unexpected last error, got %08x\n", GetLastError());
417
418     /* If we are running on win9x we should skip these tests. Win95
419      * fails most tests anyway and win98 pops up the "Add New Hardware
420      * Wizard".
421      */
422     if (GetLastError() == ERROR_INVALID_HANDLE)
423     {
424         skip("We are on win9x where the tests introduce issues\n");
425         return;
426     }
427
428     SetLastError(0xdeadbeef);
429     ret = pSetupDiCreateDeviceInfoA(NULL, "Root\\LEGACY_BOGUS\\0000", NULL,
430      NULL, NULL, 0, NULL);
431     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
432      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
433     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
434     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
435      GetLastError());
436     if (set)
437     {
438         SP_DEVINFO_DATA devInfo = { 0 };
439         DWORD i;
440         static GUID deadbeef =
441          {0xdeadbeef, 0xdead, 0xbeef, {0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
442
443         /* No GUID given */
444         SetLastError(0xdeadbeef);
445         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", NULL,
446          NULL, NULL, 0, NULL);
447         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
448             "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
449         /* We can't add device information to the set with a different GUID */
450         SetLastError(0xdeadbeef);
451         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000",
452          &deadbeef, NULL, NULL, 0, NULL);
453         ok(!ret && GetLastError() == ERROR_CLASS_MISMATCH,
454          "Expected ERROR_CLASS_MISMATCH, got %08x\n", GetLastError());
455         /* Finally, with all three required parameters, this succeeds: */
456         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
457          NULL, NULL, 0, NULL);
458         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
459         /* This fails because the device ID already exists.. */
460         SetLastError(0xdeadbeef);
461         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
462          NULL, NULL, 0, &devInfo);
463         ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
464          "Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError());
465         /* whereas this "fails" because cbSize is wrong.. */
466         SetLastError(0xdeadbeef);
467         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
468          DICD_GENERATE_ID, &devInfo);
469         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
470          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
471         /* and this finally succeeds. */
472         devInfo.cbSize = sizeof(devInfo);
473         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
474          DICD_GENERATE_ID, &devInfo);
475         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
476         /* There were three devices added, however - the second failure just
477          * resulted in the SP_DEVINFO_DATA not getting copied.
478          */
479         SetLastError(0xdeadbeef);
480         i = 0;
481         while (pSetupDiEnumDeviceInfo(set, i, &devInfo))
482             i++;
483         ok(i == 3, "Expected 3 devices, got %d\n", i);
484         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
485          "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
486         pSetupDiDestroyDeviceInfoList(set);
487     }
488
489     /* The bogus registry key shouldn't be there after this test. The only
490      * reasons this key would still be present:
491      *
492      * - We are running on Wine which has to be fixed
493      * - We have leftovers from old tests
494      */
495     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
496     todo_wine
497     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
498     if (res == ERROR_SUCCESS)
499     {
500         DWORD subkeys;
501
502         /* Check if we have subkeys */
503         RegQueryInfoKey(key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
504         if (subkeys > 0)
505         {
506             int i;
507
508             /* Leftovers from old tests */
509             trace("Going to remove %d devices\n", subkeys);
510             for (i = 0; i < subkeys; i++)
511             {
512                 BOOL ret;
513
514                 ret = remove_device();
515                 ok(ret, "Expected a device to be removed\n");
516             }
517         }
518         else
519         {
520             /* Wine doesn't delete the bogus key itself currently */
521             trace("We are most likely on Wine\n");
522             RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus);
523         }
524     }
525 }
526
527 static void testGetDeviceInstanceId(void)
528 {
529     BOOL ret;
530     HDEVINFO set;
531     SP_DEVINFO_DATA devInfo = { 0 };
532
533     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
534      !pSetupDiCreateDeviceInfoA || !pSetupDiGetDeviceInstanceIdA)
535     {
536         skip("No SetupDiGetDeviceInstanceIdA\n");
537         return;
538     }
539     SetLastError(0xdeadbeef);
540     ret = pSetupDiGetDeviceInstanceIdA(NULL, NULL, NULL, 0, NULL);
541     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
542      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
543     SetLastError(0xdeadbeef);
544     ret = pSetupDiGetDeviceInstanceIdA(NULL, &devInfo, NULL, 0, NULL);
545     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
546      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
547     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
548     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
549      GetLastError());
550     if (set)
551     {
552         char instanceID[MAX_PATH];
553         DWORD size;
554
555         SetLastError(0xdeadbeef);
556         ret = pSetupDiGetDeviceInstanceIdA(set, NULL, NULL, 0, NULL);
557         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
558          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
559         SetLastError(0xdeadbeef);
560         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, NULL);
561         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
562          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
563         SetLastError(0xdeadbeef);
564         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
565         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
566          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
567         devInfo.cbSize = sizeof(devInfo);
568         SetLastError(0xdeadbeef);
569         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
570         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
571          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
572         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
573          NULL, NULL, 0, &devInfo);
574         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
575         SetLastError(0xdeadbeef);
576         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
577         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
578          "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
579         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
580          sizeof(instanceID), NULL);
581         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
582         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0000"),
583          "Unexpected instance ID %s\n", instanceID);
584         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid,
585          NULL, NULL, DICD_GENERATE_ID, &devInfo);
586         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
587         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
588          sizeof(instanceID), NULL);
589         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
590         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"),
591          "Unexpected instance ID %s\n", instanceID);
592         pSetupDiDestroyDeviceInfoList(set);
593     }
594 }
595
596 static void testRegisterDeviceInfo(void)
597 {
598     BOOL ret;
599     HDEVINFO set;
600
601     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
602      !pSetupDiRegisterDeviceInfo)
603     {
604         skip("No SetupDiRegisterDeviceInfo\n");
605         return;
606     }
607     SetLastError(0xdeadbeef);
608     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
609     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
610      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
611     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
612     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
613     if (set)
614     {
615         SP_DEVINFO_DATA devInfo = { 0 };
616
617         SetLastError(0xdeadbeef);
618         ret = pSetupDiRegisterDeviceInfo(set, NULL, 0, NULL, NULL, NULL);
619         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
620          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
621         SetLastError(0xdeadbeef);
622         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
623         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
624          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
625         devInfo.cbSize = sizeof(devInfo);
626         SetLastError(0xdeadbeef);
627         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
628         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
629          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
630         ret = pSetupDiCreateDeviceInfoA(set, "USB\\BOGUS\\0000", &guid,
631          NULL, NULL, 0, &devInfo);
632         ok(ret || GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
633                 "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
634         if (ret)
635         {
636             /* If it already existed, registering it again will fail */
637             ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL,
638              NULL);
639             ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
640         }
641         /* FIXME: On Win2K+ systems, this is now persisted to registry in
642          * HKLM\System\CCS\Enum\USB\Bogus\0000.  I don't check because the
643          * Win9x location is different.
644          * FIXME: the key also becomes undeletable.  How to get rid of it?
645          */
646         pSetupDiDestroyDeviceInfoList(set);
647     }
648 }
649
650 static void testCreateDeviceInterface(void)
651 {
652     BOOL ret;
653     HDEVINFO set;
654     HKEY key;
655     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
656      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
657      'E','n','u','m','\\','R','o','o','t','\\',
658      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
659     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
660      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
661      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
662      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
663      '1','1','d','b','-','b','7','0','4','-',
664      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
665
666     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
667      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
668      !pSetupDiEnumDeviceInterfaces)
669     {
670         skip("No SetupDiCreateDeviceInterfaceA\n");
671         return;
672     }
673     SetLastError(0xdeadbeef);
674     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, NULL, NULL, 0, NULL);
675     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
676      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
677     SetLastError(0xdeadbeef);
678     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, &guid, NULL, 0, NULL);
679     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
680      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
681     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
682     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
683     if (set)
684     {
685         SP_DEVINFO_DATA devInfo = { 0 };
686         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
687             { 0 } };
688         DWORD i;
689
690         SetLastError(0xdeadbeef);
691         ret = pSetupDiCreateDeviceInterfaceA(set, NULL, NULL, NULL, 0, NULL);
692         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
693          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
694         SetLastError(0xdeadbeef);
695         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
696                 NULL);
697         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
698          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
699         devInfo.cbSize = sizeof(devInfo);
700         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
701                 NULL, NULL, 0, &devInfo);
702         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
703         SetLastError(0xdeadbeef);
704         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
705                 NULL);
706         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
707          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
708         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
709                 NULL);
710         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
711         /* Creating the same interface a second time succeeds */
712         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
713                 NULL);
714         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
715         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0,
716                 NULL);
717         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
718         ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0,
719                 &interfaceData);
720         ok(ret, "SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError());
721         i = 0;
722         while (pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, i,
723                     &interfaceData))
724             i++;
725         ok(i == 2, "expected 2 interfaces, got %d\n", i);
726         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
727          "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
728         ret = pSetupDiDestroyDeviceInfoList(set);
729         ok(ret, "SetupDiDestroyDeviceInfoList failed: %08x\n", GetLastError());
730
731         /* Cleanup */
732         /* FIXME: On Wine we still have the bogus entry in Enum\Root and
733          * subkeys, as well as the deviceclass key with subkeys.
734          * Only clean the deviceclass key once Wine if fixed.
735          */
736         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key))
737         {
738             /* Wine doesn't delete the information currently */
739             trace("We are most likely on Wine\n");
740             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
741             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
742         }
743         else
744         {
745             clean_devclass_key();
746         }
747     }
748 }
749
750 static void testGetDeviceInterfaceDetail(void)
751 {
752     BOOL ret;
753     HDEVINFO set;
754     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
755      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
756      'E','n','u','m','\\','R','o','o','t','\\',
757      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
758     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
759      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
760      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
761      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
762      '1','1','d','b','-','b','7','0','4','-',
763      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
764
765     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
766      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
767      !pSetupDiGetDeviceInterfaceDetailA)
768     {
769         skip("No SetupDiGetDeviceInterfaceDetailA\n");
770         return;
771     }
772     SetLastError(0xdeadbeef);
773     ret = pSetupDiGetDeviceInterfaceDetailA(NULL, NULL, NULL, 0, NULL, NULL);
774     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
775      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
776     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
777     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
778     if (set)
779     {
780         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
781         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
782             { 0 } };
783         DWORD size = 0;
784         HKEY key;
785
786         SetLastError(0xdeadbeef);
787         ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL,
788                 NULL);
789         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
790          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
791         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
792                 NULL, NULL, 0, &devInfo);
793         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
794         SetLastError(0xdeadbeef);
795         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
796                 &interfaceData);
797         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
798         SetLastError(0xdeadbeef);
799         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
800                 0, NULL, NULL);
801         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
802          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
803         SetLastError(0xdeadbeef);
804         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
805                 100, NULL, NULL);
806         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
807          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
808         SetLastError(0xdeadbeef);
809         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
810                 0, &size, NULL);
811         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
812          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
813         if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
814         {
815             static const char path[] =
816              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
817             static const char path_w2k[] =
818              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\";
819             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
820             SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail =
821                 (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf;
822             DWORD expectedsize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path));
823
824             detail->cbSize = 0;
825             SetLastError(0xdeadbeef);
826             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
827                     size, &size, NULL);
828             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
829              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
830             detail->cbSize = size;
831             SetLastError(0xdeadbeef);
832             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
833                     size, &size, NULL);
834             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
835              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
836             detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
837             SetLastError(0xdeadbeef);
838             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
839                     size, &size, NULL);
840             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
841              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
842             /* Windows 2000 and up check for the exact size. Win9x returns ERROR_INVALID_PARAMETER
843              * on every call (so doesn't get here) and NT4 doesn't have this function.
844              */
845             detail->cbSize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
846             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
847                     size, &size, NULL);
848             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n",
849                     GetLastError());
850             ok(!lstrcmpiA(path, detail->DevicePath) ||
851              !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n",
852              detail->DevicePath);
853             /* Check SetupDiGetDeviceInterfaceDetailW */
854             if (pSetupDiGetDeviceInterfaceDetailW)
855             {
856                 ret = pSetupDiGetDeviceInterfaceDetailW(set, &interfaceData, NULL, 0, &size, NULL);
857                 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
858                  "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError());
859                 ok(expectedsize == size ||
860                  (expectedsize + sizeof(WCHAR)) == size /* W2K adds a backslash */,
861                  "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize, got %d\n",
862                  size);
863             }
864             else
865                 skip("SetupDiGetDeviceInterfaceDetailW is not available\n");
866
867             HeapFree(GetProcessHeap(), 0, buf);
868         }
869         pSetupDiDestroyDeviceInfoList(set);
870
871         /* Cleanup */
872         /* FIXME: On Wine we still have the bogus entry in Enum\Root and
873          * subkeys, as well as the deviceclass key with subkeys.
874          * Only do the RegDeleteKey, once Wine is fixed.
875          */
876         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key))
877         {
878             /* Wine doesn't delete the information currently */
879             trace("We are most likely on Wine\n");
880             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
881             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
882         }
883         else
884         {
885             clean_devclass_key();
886         }
887     }
888 }
889
890 static void testDevRegKey(void)
891 {
892     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
893      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
894      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
895      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
896      '1','1','d','b','-','b','7','0','4','-',
897      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
898     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
899      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
900      'E','n','u','m','\\','R','o','o','t','\\',
901      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
902     BOOL ret;
903     HDEVINFO set;
904     HKEY key = NULL;
905
906     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
907      !pSetupDiCreateDeviceInfoA || !pSetupDiOpenDevRegKey ||
908      !pSetupDiRegisterDeviceInfo || !pSetupDiCreateDevRegKeyW ||
909      !pSetupDiCallClassInstaller)
910     {
911         skip("No SetupDiOpenDevRegKey\n");
912         return;
913     }
914
915     /* Check if we are on win9x */
916     SetLastError(0xdeadbeef);
917     key = pSetupDiCreateDevRegKeyW(NULL, NULL, 0, 0, 0, NULL, NULL);
918     if (key == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
919     {
920         skip("We are on win9x where the tests introduce issues\n");
921         return;
922     }
923     ok(key == INVALID_HANDLE_VALUE,
924      "Expected INVALID_HANDLE_VALUE, got %p\n", key);
925     ok(GetLastError() == ERROR_INVALID_HANDLE,
926      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
927
928     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
929     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
930     if (set)
931     {
932         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
933         LONG res;
934
935         /* The device info key shouldn't be there */
936         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
937         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
938         RegCloseKey(key);
939         /* Create the device information */
940         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
941                 NULL, NULL, 0, &devInfo);
942         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
943         /* The device info key should have been created */
944         ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key),
945          "Expected registry key to exist\n");
946         RegCloseKey(key);
947         SetLastError(0xdeadbeef);
948         key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
949         ok(!key || key == INVALID_HANDLE_VALUE,
950          "Expected INVALID_HANDLE_VALUE or a NULL key (NT4)\n");
951         ok(GetLastError() == ERROR_INVALID_HANDLE,
952          "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
953         SetLastError(0xdeadbeef);
954         key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
955         ok(key == INVALID_HANDLE_VALUE &&
956          GetLastError() == ERROR_INVALID_PARAMETER,
957          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
958         SetLastError(0xdeadbeef);
959         key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0);
960         ok(key == INVALID_HANDLE_VALUE &&
961          GetLastError() == ERROR_INVALID_FLAGS,
962          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
963         SetLastError(0xdeadbeef);
964         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0);
965         ok(key == INVALID_HANDLE_VALUE &&
966          GetLastError() == ERROR_INVALID_FLAGS,
967          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
968         SetLastError(0xdeadbeef);
969         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
970          DIREG_BOTH, 0);
971         ok(key == INVALID_HANDLE_VALUE &&
972          GetLastError() == ERROR_INVALID_FLAGS,
973          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
974         SetLastError(0xdeadbeef);
975         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
976          DIREG_DRV, 0);
977         ok(key == INVALID_HANDLE_VALUE &&
978          GetLastError() == ERROR_DEVINFO_NOT_REGISTERED,
979          "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError());
980         SetLastError(0xdeadbeef);
981         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
982         ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
983         SetLastError(0xdeadbeef);
984         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
985          DIREG_DRV, 0);
986         /* The software key isn't created by default */
987         todo_wine
988         ok(key == INVALID_HANDLE_VALUE &&
989          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
990          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
991         SetLastError(0xdeadbeef);
992         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
993          DIREG_DEV, 0);
994         todo_wine
995         ok(key == INVALID_HANDLE_VALUE &&
996          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
997          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
998         SetLastError(0xdeadbeef);
999         /* The class key shouldn't be there */
1000         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key);
1001         todo_wine
1002         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
1003         RegCloseKey(key);
1004         /* Create the device reg key */
1005         key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0,
1006          DIREG_DRV, NULL, NULL);
1007         ok(key != INVALID_HANDLE_VALUE, "SetupDiCreateDevRegKey failed: %08x\n",
1008          GetLastError());
1009         RegCloseKey(key);
1010         /* The class key should have been created */
1011         ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key),
1012          "Expected registry key to exist\n");
1013         RegCloseKey(key);
1014         SetLastError(0xdeadbeef);
1015         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
1016          DIREG_DRV, 0);
1017         todo_wine
1018         ok(key == INVALID_HANDLE_VALUE &&
1019          (GetLastError() == ERROR_INVALID_DATA ||
1020          GetLastError() == ERROR_ACCESS_DENIED), /* win2k3 */
1021          "Expected ERROR_INVALID_DATA or ERROR_ACCESS_DENIED, got %08x\n", GetLastError());
1022         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
1023          DIREG_DRV, KEY_READ);
1024         ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n",
1025          GetLastError());
1026         pSetupDiDestroyDeviceInfoList(set);
1027
1028         /* Cleanup */
1029         ret = remove_device();
1030         todo_wine
1031         ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1032
1033         /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1034         if (!ret)
1035         {
1036             /* Wine doesn't delete the information currently */
1037             trace("We are most likely on Wine\n");
1038             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1039             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
1040         }
1041         else
1042         {
1043             /* There should only be a class key entry, so a simple
1044              * RegDeleteKey should work
1045              *
1046              * This could fail if it's the first time for this new test
1047              * after running the old tests.
1048              */
1049             ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey),
1050              "Couldn't delete classkey\n");
1051         }
1052     }
1053 }
1054
1055 static void testRegisterAndGetDetail(void)
1056 {
1057     HDEVINFO set;
1058     BOOL ret;
1059     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1060     SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } };
1061     DWORD dwSize = 0;
1062     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1063      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1064      'E','n','u','m','\\','R','o','o','t','\\',
1065      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1066     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
1067      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1068      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
1069      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
1070      '1','1','d','b','-','b','7','0','4','-',
1071      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
1072
1073     SetLastError(0xdeadbeef);
1074     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES);
1075     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1076      GetLastError());
1077
1078     SetLastError(0xdeadbeef);
1079     ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, 0,
1080      DICD_GENERATE_ID, &devInfo);
1081     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1082     SetLastError(0xdeadbeef);
1083     ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, &interfaceData);
1084     ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
1085     SetLastError(0xdeadbeef);
1086     ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
1087     ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
1088
1089     pSetupDiDestroyDeviceInfoList(set);
1090
1091     SetLastError(0xdeadbeef);
1092     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1093     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1094      GetLastError());
1095
1096     SetLastError(0xdeadbeef);
1097     ret = pSetupDiEnumDeviceInterfaces(set, NULL, &guid, 0, &interfaceData);
1098     ok(ret, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
1099     SetLastError(0xdeadbeef);
1100     ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, 0, &dwSize, NULL);
1101     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1102      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1103     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1104     {
1105         static const char path[] =
1106             "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
1107         static const char path_w2k[] =
1108          "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\";
1109         PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL;
1110
1111         detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)HeapAlloc(GetProcessHeap(), 0, dwSize);
1112         if (detail)
1113         {
1114             detail->cbSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char);
1115             SetLastError(0xdeadbeef);
1116             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData,
1117              detail, dwSize, &dwSize, NULL);
1118             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError());
1119             /* FIXME: This one only worked because old data wasn't removed properly. As soon
1120              * as all the tests are cleaned up correctly this has to be (or should be) fixed
1121              */
1122             todo_wine
1123             ok(!lstrcmpiA(path, detail->DevicePath) ||
1124              !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n",
1125              detail->DevicePath);
1126             HeapFree(GetProcessHeap(), 0, detail);
1127         }
1128     }
1129
1130     pSetupDiDestroyDeviceInfoList(set);
1131
1132     /* Cleanup */
1133     ret = remove_device();
1134     todo_wine
1135     ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1136
1137     /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1138     if (!ret)
1139     {
1140         /* Wine doesn't delete the information currently */
1141         trace("We are most likely on Wine\n");
1142         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1143         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
1144     }
1145     else
1146     {
1147         clean_devclass_key();
1148     }
1149 }
1150
1151 static void testDeviceRegistryPropertyA()
1152 {
1153     HDEVINFO set;
1154     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1155     CHAR devName[] = "LEGACY_BOGUS";
1156     CHAR friendlyName[] = "Bogus";
1157     CHAR buf[6] = "";
1158     DWORD buflen = 6;
1159     DWORD size;
1160     DWORD regType;
1161     BOOL ret;
1162     LONG res;
1163     HKEY key;
1164     static const CHAR bogus[] =
1165      "System\\CurrentControlSet\\Enum\\Root\\LEGACY_BOGUS";
1166
1167     SetLastError(0xdeadbeef);
1168     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1169     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1170      GetLastError());
1171     SetLastError(0xdeadbeef);
1172     ret = pSetupDiCreateDeviceInfoA(set, devName, &guid, NULL, NULL,
1173      DICD_GENERATE_ID, &devInfo);
1174     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1175     SetLastError(0xdeadbeef);
1176     ret = pSetupDiSetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, 0);
1177     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1178      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1179     SetLastError(0xdeadbeef);
1180     ret = pSetupDiSetDeviceRegistryPropertyA(set, NULL, -1, NULL, 0);
1181     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1182      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1183     SetLastError(0xdeadbeef);
1184     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, 0);
1185     todo_wine
1186     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1187      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1188     /* GetLastError() returns nonsense in win2k3 */
1189     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1190      NULL, 0);
1191     todo_wine
1192     ok(!ret, "Expected failure, got %d\n", ret);
1193     SetLastError(0xdeadbeef);
1194     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1195      (PBYTE)friendlyName, buflen);
1196     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1197     SetLastError(0xdeadbeef);
1198     ret = pSetupDiGetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, NULL, 0, NULL);
1199     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1200      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1201     SetLastError(0xdeadbeef);
1202     ret = pSetupDiGetDeviceRegistryPropertyA(set, NULL, -1, NULL, NULL, 0, NULL);
1203     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1204      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1205     SetLastError(0xdeadbeef);
1206     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, NULL, 0, NULL);
1207     todo_wine
1208     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1209      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1210     /* GetLastError() returns nonsense in win2k3 */
1211     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1212      NULL, NULL, buflen, NULL);
1213     ok(!ret, "Expected failure, got %d\n", ret);
1214     SetLastError(0xdeadbeef);
1215     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1216      NULL, NULL, 0, &size);
1217     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1218      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1219     ok(buflen == size, "Unexpected size: %d\n", size);
1220     SetLastError(0xdeadbeef);
1221     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1222      NULL, (PBYTE)buf, buflen, NULL);
1223     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1224     ok(!lstrcmpiA(friendlyName, buf), "Unexpected property\n");
1225     SetLastError(0xdeadbeef);
1226     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1227      &regType, (PBYTE)buf, buflen, NULL);
1228     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1229     ok(!lstrcmpiA(friendlyName, buf), "Unexpected value of property\n");
1230     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1231     SetLastError(0xdeadbeef);
1232     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1233      NULL, 0);
1234     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1235     SetLastError(0xdeadbeef);
1236     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1237      NULL, (PBYTE)buf, buflen, &size);
1238     todo_wine
1239     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1240      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1241     pSetupDiDestroyDeviceInfoList(set);
1242
1243     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, bogus, &key);
1244     todo_wine
1245     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1246     /* FIXME: Remove when Wine is fixed */
1247     if (res == ERROR_SUCCESS)
1248     {
1249         /* Wine doesn't delete the information currently */
1250         trace("We are most likely on Wine\n");
1251         RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus);
1252     }
1253 }
1254
1255 static void testDeviceRegistryPropertyW()
1256 {
1257     HDEVINFO set;
1258     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1259     WCHAR devName[] = {'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1260     WCHAR friendlyName[] = {'B','o','g','u','s',0};
1261     WCHAR buf[6] = {0};
1262     DWORD buflen = 6 * sizeof(WCHAR);
1263     DWORD size;
1264     DWORD regType;
1265     BOOL ret;
1266     LONG res;
1267     HKEY key;
1268     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1269      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1270      'E','n','u','m','\\','R','o','o','t','\\',
1271      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1272
1273     SetLastError(0xdeadbeef);
1274     set = pSetupDiGetClassDevsW(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1275     if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1276     {
1277         skip("W-functions are not implemented\n");
1278         return;
1279     }
1280     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %08x\n",
1281      GetLastError());
1282     SetLastError(0xdeadbeef);
1283     ret = pSetupDiCreateDeviceInfoW(set, devName, &guid, NULL, NULL,
1284      DICD_GENERATE_ID, &devInfo);
1285     ok(ret, "SetupDiCreateDeviceInfoW failed: %08x\n", GetLastError());
1286     SetLastError(0xdeadbeef);
1287     ret = pSetupDiSetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, 0);
1288     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1289      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1290     SetLastError(0xdeadbeef);
1291     ret = pSetupDiSetDeviceRegistryPropertyW(set, NULL, -1, NULL, 0);
1292     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1293      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1294     SetLastError(0xdeadbeef);
1295     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, 0);
1296     todo_wine
1297     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1298      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1299     /* GetLastError() returns nonsense in win2k3 */
1300     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1301      NULL, 0);
1302     todo_wine
1303     ok(!ret, "Expected failure, got %d\n", ret);
1304     SetLastError(0xdeadbeef);
1305     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1306      (PBYTE)friendlyName, buflen);
1307     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1308     SetLastError(0xdeadbeef);
1309     ret = pSetupDiGetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, NULL, 0, NULL);
1310     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1311      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1312     SetLastError(0xdeadbeef);
1313     ret = pSetupDiGetDeviceRegistryPropertyW(set, NULL, -1, NULL, NULL, 0, NULL);
1314     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1315      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1316     SetLastError(0xdeadbeef);
1317     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, NULL, 0, NULL);
1318     todo_wine
1319     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1320      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1321     /* GetLastError() returns nonsense in win2k3 */
1322     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1323      NULL, NULL, buflen, NULL);
1324     ok(!ret, "Expected failure, got %d\n", ret);
1325     SetLastError(0xdeadbeef);
1326     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1327      NULL, NULL, 0, &size);
1328     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1329      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1330     ok(buflen == size, "Unexpected size: %d\n", size);
1331     SetLastError(0xdeadbeef);
1332     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1333      NULL, (PBYTE)buf, buflen, NULL);
1334     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1335     ok(!lstrcmpiW(friendlyName, buf), "Unexpected property\n");
1336     SetLastError(0xdeadbeef);
1337     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1338      &regType, (PBYTE)buf, buflen, NULL);
1339     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1340     ok(!lstrcmpiW(friendlyName, buf), "Unexpected value of property\n");
1341     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1342     SetLastError(0xdeadbeef);
1343     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1344      NULL, 0);
1345     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1346     SetLastError(0xdeadbeef);
1347     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1348      NULL, (PBYTE)buf, buflen, &size);
1349     todo_wine
1350     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1351      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1352     pSetupDiDestroyDeviceInfoList(set);
1353
1354     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
1355     todo_wine
1356     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1357     /* FIXME: Remove when Wine is fixed */
1358     if (res == ERROR_SUCCESS)
1359     {
1360         /* Wine doesn't delete the information currently */
1361         trace("We are most likely on Wine\n");
1362         RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus);
1363     }
1364 }
1365
1366 START_TEST(devinst)
1367 {
1368     init_function_pointers();
1369
1370     if (pSetupDiCreateDeviceInfoListExW && pSetupDiDestroyDeviceInfoList)
1371         test_SetupDiCreateDeviceInfoListEx();
1372     else
1373         skip("SetupDiCreateDeviceInfoListExW and/or SetupDiDestroyDeviceInfoList not available\n");
1374
1375     if (pSetupDiOpenClassRegKeyExA)
1376         test_SetupDiOpenClassRegKeyExA();
1377     else
1378         skip("SetupDiOpenClassRegKeyExA is not available\n");
1379     testInstallClass();
1380     testCreateDeviceInfo();
1381     testGetDeviceInstanceId();
1382     testRegisterDeviceInfo();
1383     testCreateDeviceInterface();
1384     testGetDeviceInterfaceDetail();
1385     testDevRegKey();
1386     testRegisterAndGetDetail();
1387     testDeviceRegistryPropertyA();
1388     testDeviceRegistryPropertyW();
1389 }