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