ole32: Include ole2.h in ole32_main.c to type-check the function signature of OleMeta...
[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     SetLastError(0xdeadbeef);
602     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
603     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
604      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
605     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
606     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
607     if (set)
608     {
609         SP_DEVINFO_DATA devInfo = { 0 };
610
611         SetLastError(0xdeadbeef);
612         ret = pSetupDiRegisterDeviceInfo(set, NULL, 0, NULL, NULL, NULL);
613         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
614          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
615         SetLastError(0xdeadbeef);
616         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
617         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
618          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
619         devInfo.cbSize = sizeof(devInfo);
620         SetLastError(0xdeadbeef);
621         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
622         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
623          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
624         ret = pSetupDiCreateDeviceInfoA(set, "USB\\BOGUS\\0000", &guid,
625          NULL, NULL, 0, &devInfo);
626         ok(ret || GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
627                 "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
628         if (ret)
629         {
630             /* If it already existed, registering it again will fail */
631             ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL,
632              NULL);
633             ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
634         }
635         /* FIXME: On Win2K+ systems, this is now persisted to registry in
636          * HKLM\System\CCS\Enum\USB\Bogus\0000.  I don't check because the
637          * Win9x location is different.
638          * FIXME: the key also becomes undeletable.  How to get rid of it?
639          */
640         pSetupDiDestroyDeviceInfoList(set);
641     }
642 }
643
644 static void testCreateDeviceInterface(void)
645 {
646     BOOL ret;
647     HDEVINFO set;
648     HKEY key;
649     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
650      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
651      'E','n','u','m','\\','R','o','o','t','\\',
652      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
653     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
654      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
655      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
656      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
657      '1','1','d','b','-','b','7','0','4','-',
658      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
659
660     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
661      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
662      !pSetupDiEnumDeviceInterfaces)
663     {
664         skip("No SetupDiCreateDeviceInterfaceA\n");
665         return;
666     }
667     SetLastError(0xdeadbeef);
668     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, NULL, NULL, 0, NULL);
669     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
670      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
671     SetLastError(0xdeadbeef);
672     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, &guid, NULL, 0, NULL);
673     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
674      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
675     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
676     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
677     if (set)
678     {
679         SP_DEVINFO_DATA devInfo = { 0 };
680         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
681             { 0 } };
682         DWORD i;
683
684         SetLastError(0xdeadbeef);
685         ret = pSetupDiCreateDeviceInterfaceA(set, NULL, NULL, NULL, 0, NULL);
686         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
687          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
688         SetLastError(0xdeadbeef);
689         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
690                 NULL);
691         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
692          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
693         devInfo.cbSize = sizeof(devInfo);
694         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
695                 NULL, NULL, 0, &devInfo);
696         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
697         SetLastError(0xdeadbeef);
698         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
699                 NULL);
700         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
701          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
702         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
703                 NULL);
704         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
705         /* Creating the same interface a second time succeeds */
706         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
707                 NULL);
708         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
709         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0,
710                 NULL);
711         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
712         ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0,
713                 &interfaceData);
714         ok(ret, "SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError());
715         i = 0;
716         while (pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, i,
717                     &interfaceData))
718             i++;
719         ok(i == 2, "expected 2 interfaces, got %d\n", i);
720         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
721          "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
722         ret = pSetupDiDestroyDeviceInfoList(set);
723         ok(ret, "SetupDiDestroyDeviceInfoList failed: %08x\n", GetLastError());
724
725         /* Cleanup */
726         /* FIXME: On Wine we still have the bogus entry in Enum\Root and
727          * subkeys, as well as the deviceclass key with subkeys.
728          * Only clean the deviceclass key once Wine if fixed.
729          */
730         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key))
731         {
732             /* Wine doesn't delete the information currently */
733             trace("We are most likely on Wine\n");
734             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
735             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
736         }
737         else
738         {
739             clean_devclass_key();
740         }
741     }
742 }
743
744 static void testGetDeviceInterfaceDetail(void)
745 {
746     BOOL ret;
747     HDEVINFO set;
748     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
749      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
750      'E','n','u','m','\\','R','o','o','t','\\',
751      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
752     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
753      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
754      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
755      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
756      '1','1','d','b','-','b','7','0','4','-',
757      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
758
759     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
760      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
761      !pSetupDiGetDeviceInterfaceDetailA)
762     {
763         skip("No SetupDiGetDeviceInterfaceDetailA\n");
764         return;
765     }
766     SetLastError(0xdeadbeef);
767     ret = pSetupDiGetDeviceInterfaceDetailA(NULL, NULL, NULL, 0, NULL, NULL);
768     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
769      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
770     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
771     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
772     if (set)
773     {
774         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
775         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
776             { 0 } };
777         DWORD size = 0;
778         HKEY key;
779
780         SetLastError(0xdeadbeef);
781         ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL,
782                 NULL);
783         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
784          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
785         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
786                 NULL, NULL, 0, &devInfo);
787         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
788         SetLastError(0xdeadbeef);
789         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
790                 &interfaceData);
791         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
792         SetLastError(0xdeadbeef);
793         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
794                 0, NULL, NULL);
795         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
796          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
797         SetLastError(0xdeadbeef);
798         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
799                 100, NULL, NULL);
800         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
801          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
802         SetLastError(0xdeadbeef);
803         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
804                 0, &size, NULL);
805         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
806          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
807         if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
808         {
809             static const char path[] =
810              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
811             static const char path_w2k[] =
812              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\";
813             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
814             SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail =
815                 (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf;
816             DWORD expectedsize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path));
817
818             detail->cbSize = 0;
819             SetLastError(0xdeadbeef);
820             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
821                     size, &size, NULL);
822             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
823              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
824             detail->cbSize = size;
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 = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
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             /* Windows 2000 and up check for the exact size. Win9x returns ERROR_INVALID_PARAMETER
837              * on every call (so doesn't get here) and NT4 doesn't have this function.
838              */
839             detail->cbSize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
840             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
841                     size, &size, NULL);
842             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n",
843                     GetLastError());
844             ok(!lstrcmpiA(path, detail->DevicePath) ||
845              !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n",
846              detail->DevicePath);
847             /* Check SetupDiGetDeviceInterfaceDetailW */
848             if (pSetupDiGetDeviceInterfaceDetailW)
849             {
850                 ret = pSetupDiGetDeviceInterfaceDetailW(set, &interfaceData, NULL, 0, &size, NULL);
851                 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
852                  "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError());
853                 ok(expectedsize == size ||
854                  (expectedsize + sizeof(WCHAR)) == size /* W2K adds a backslash */,
855                  "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize, got %d\n",
856                  size);
857             }
858             else
859                 skip("SetupDiGetDeviceInterfaceDetailW is not available\n");
860
861             HeapFree(GetProcessHeap(), 0, buf);
862         }
863         pSetupDiDestroyDeviceInfoList(set);
864
865         /* Cleanup */
866         /* FIXME: On Wine we still have the bogus entry in Enum\Root and
867          * subkeys, as well as the deviceclass key with subkeys.
868          * Only do the RegDeleteKey, once Wine is fixed.
869          */
870         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key))
871         {
872             /* Wine doesn't delete the information currently */
873             trace("We are most likely on Wine\n");
874             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
875             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
876         }
877         else
878         {
879             clean_devclass_key();
880         }
881     }
882 }
883
884 static void testDevRegKey(void)
885 {
886     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
887      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
888      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
889      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
890      '1','1','d','b','-','b','7','0','4','-',
891      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
892     static const WCHAR bogus[] = {'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      'E','n','u','m','\\','R','o','o','t','\\',
895      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
896     BOOL ret;
897     HDEVINFO set;
898     HKEY key = NULL;
899
900     SetLastError(0xdeadbeef);
901     key = pSetupDiCreateDevRegKeyW(NULL, NULL, 0, 0, 0, NULL, NULL);
902     ok(key == INVALID_HANDLE_VALUE,
903      "Expected INVALID_HANDLE_VALUE, got %p\n", key);
904     ok(GetLastError() == ERROR_INVALID_HANDLE,
905      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
906
907     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
908     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
909     if (set)
910     {
911         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
912         LONG res;
913
914         /* The device info key shouldn't be there */
915         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
916         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
917         RegCloseKey(key);
918         /* Create the device information */
919         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
920                 NULL, NULL, 0, &devInfo);
921         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
922         /* The device info key should have been created */
923         ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key),
924          "Expected registry key to exist\n");
925         RegCloseKey(key);
926         SetLastError(0xdeadbeef);
927         key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
928         ok(!key || key == INVALID_HANDLE_VALUE,
929          "Expected INVALID_HANDLE_VALUE or a NULL key (NT4)\n");
930         ok(GetLastError() == ERROR_INVALID_HANDLE,
931          "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
932         SetLastError(0xdeadbeef);
933         key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
934         ok(key == INVALID_HANDLE_VALUE &&
935          GetLastError() == ERROR_INVALID_PARAMETER,
936          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
937         SetLastError(0xdeadbeef);
938         key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0);
939         ok(key == INVALID_HANDLE_VALUE &&
940          GetLastError() == ERROR_INVALID_FLAGS,
941          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
942         SetLastError(0xdeadbeef);
943         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0);
944         ok(key == INVALID_HANDLE_VALUE &&
945          GetLastError() == ERROR_INVALID_FLAGS,
946          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
947         SetLastError(0xdeadbeef);
948         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
949          DIREG_BOTH, 0);
950         ok(key == INVALID_HANDLE_VALUE &&
951          GetLastError() == ERROR_INVALID_FLAGS,
952          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
953         SetLastError(0xdeadbeef);
954         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
955          DIREG_DRV, 0);
956         ok(key == INVALID_HANDLE_VALUE &&
957          GetLastError() == ERROR_DEVINFO_NOT_REGISTERED,
958          "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError());
959         SetLastError(0xdeadbeef);
960         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
961         ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
962         SetLastError(0xdeadbeef);
963         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
964          DIREG_DRV, 0);
965         /* The software key isn't created by default */
966         todo_wine
967         ok(key == INVALID_HANDLE_VALUE &&
968          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
969          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
970         SetLastError(0xdeadbeef);
971         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
972          DIREG_DEV, 0);
973         todo_wine
974         ok(key == INVALID_HANDLE_VALUE &&
975          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
976          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
977         SetLastError(0xdeadbeef);
978         /* The class key shouldn't be there */
979         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key);
980         todo_wine
981         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
982         RegCloseKey(key);
983         /* Create the device reg key */
984         key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0,
985          DIREG_DRV, NULL, NULL);
986         ok(key != INVALID_HANDLE_VALUE, "SetupDiCreateDevRegKey failed: %08x\n",
987          GetLastError());
988         RegCloseKey(key);
989         /* The class key should have been created */
990         ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key),
991          "Expected registry key to exist\n");
992         RegCloseKey(key);
993         SetLastError(0xdeadbeef);
994         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
995          DIREG_DRV, 0);
996         todo_wine
997         ok(key == INVALID_HANDLE_VALUE &&
998          (GetLastError() == ERROR_INVALID_DATA ||
999          GetLastError() == ERROR_ACCESS_DENIED), /* win2k3 */
1000          "Expected ERROR_INVALID_DATA or ERROR_ACCESS_DENIED, got %08x\n", GetLastError());
1001         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
1002          DIREG_DRV, KEY_READ);
1003         ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n",
1004          GetLastError());
1005         pSetupDiDestroyDeviceInfoList(set);
1006
1007         /* Cleanup */
1008         ret = remove_device();
1009         todo_wine
1010         ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1011
1012         /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1013         if (!ret)
1014         {
1015             /* Wine doesn't delete the information currently */
1016             trace("We are most likely on Wine\n");
1017             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1018             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
1019         }
1020         else
1021         {
1022             /* There should only be a class key entry, so a simple
1023              * RegDeleteKey should work
1024              *
1025              * This could fail if it's the first time for this new test
1026              * after running the old tests.
1027              */
1028             ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey),
1029              "Couldn't delete classkey\n");
1030         }
1031     }
1032 }
1033
1034 static void testRegisterAndGetDetail(void)
1035 {
1036     HDEVINFO set;
1037     BOOL ret;
1038     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1039     SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } };
1040     DWORD dwSize = 0;
1041     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1042      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1043      'E','n','u','m','\\','R','o','o','t','\\',
1044      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1045     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
1046      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1047      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
1048      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
1049      '1','1','d','b','-','b','7','0','4','-',
1050      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
1051
1052     SetLastError(0xdeadbeef);
1053     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES);
1054     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1055      GetLastError());
1056
1057     SetLastError(0xdeadbeef);
1058     ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, 0,
1059      DICD_GENERATE_ID, &devInfo);
1060     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1061     SetLastError(0xdeadbeef);
1062     ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, &interfaceData);
1063     ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
1064     SetLastError(0xdeadbeef);
1065     ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
1066     ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
1067
1068     pSetupDiDestroyDeviceInfoList(set);
1069
1070     SetLastError(0xdeadbeef);
1071     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1072     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1073      GetLastError());
1074
1075     SetLastError(0xdeadbeef);
1076     ret = pSetupDiEnumDeviceInterfaces(set, NULL, &guid, 0, &interfaceData);
1077     ok(ret, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
1078     SetLastError(0xdeadbeef);
1079     ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, 0, &dwSize, NULL);
1080     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1081      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1082     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1083     {
1084         static const char path[] =
1085             "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
1086         static const char path_w2k[] =
1087          "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\";
1088         PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL;
1089
1090         detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)HeapAlloc(GetProcessHeap(), 0, dwSize);
1091         if (detail)
1092         {
1093             detail->cbSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char);
1094             SetLastError(0xdeadbeef);
1095             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData,
1096              detail, dwSize, &dwSize, NULL);
1097             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError());
1098             /* FIXME: This one only worked because old data wasn't removed properly. As soon
1099              * as all the tests are cleaned up correctly this has to be (or should be) fixed
1100              */
1101             todo_wine
1102             ok(!lstrcmpiA(path, detail->DevicePath) ||
1103              !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n",
1104              detail->DevicePath);
1105             HeapFree(GetProcessHeap(), 0, detail);
1106         }
1107     }
1108
1109     pSetupDiDestroyDeviceInfoList(set);
1110
1111     /* Cleanup */
1112     ret = remove_device();
1113     todo_wine
1114     ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1115
1116     /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1117     if (!ret)
1118     {
1119         /* Wine doesn't delete the information currently */
1120         trace("We are most likely on Wine\n");
1121         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1122         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
1123     }
1124     else
1125     {
1126         clean_devclass_key();
1127     }
1128 }
1129
1130 static void testDeviceRegistryPropertyA()
1131 {
1132     HDEVINFO set;
1133     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1134     CHAR devName[] = "LEGACY_BOGUS";
1135     CHAR friendlyName[] = "Bogus";
1136     CHAR buf[6] = "";
1137     DWORD buflen = 6;
1138     DWORD size;
1139     DWORD regType;
1140     BOOL ret;
1141     LONG res;
1142     HKEY key;
1143     static const CHAR bogus[] =
1144      "System\\CurrentControlSet\\Enum\\Root\\LEGACY_BOGUS";
1145
1146     SetLastError(0xdeadbeef);
1147     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1148     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1149      GetLastError());
1150     SetLastError(0xdeadbeef);
1151     ret = pSetupDiCreateDeviceInfoA(set, devName, &guid, NULL, NULL,
1152      DICD_GENERATE_ID, &devInfo);
1153     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1154     SetLastError(0xdeadbeef);
1155     ret = pSetupDiSetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, 0);
1156     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1157      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1158     SetLastError(0xdeadbeef);
1159     ret = pSetupDiSetDeviceRegistryPropertyA(set, NULL, -1, NULL, 0);
1160     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1161      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1162     SetLastError(0xdeadbeef);
1163     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, 0);
1164     todo_wine
1165     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1166      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1167     /* GetLastError() returns nonsense in win2k3 */
1168     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1169      NULL, 0);
1170     todo_wine
1171     ok(!ret, "Expected failure, got %d\n", ret);
1172     SetLastError(0xdeadbeef);
1173     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1174      (PBYTE)friendlyName, buflen);
1175     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1176     SetLastError(0xdeadbeef);
1177     ret = pSetupDiGetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, NULL, 0, NULL);
1178     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1179      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1180     SetLastError(0xdeadbeef);
1181     ret = pSetupDiGetDeviceRegistryPropertyA(set, NULL, -1, NULL, NULL, 0, NULL);
1182     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1183      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1184     SetLastError(0xdeadbeef);
1185     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, NULL, 0, NULL);
1186     todo_wine
1187     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1188      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1189     /* GetLastError() returns nonsense in win2k3 */
1190     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1191      NULL, NULL, buflen, NULL);
1192     ok(!ret, "Expected failure, got %d\n", ret);
1193     SetLastError(0xdeadbeef);
1194     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1195      NULL, NULL, 0, &size);
1196     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1197      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1198     ok(buflen == size, "Unexpected size: %d\n", size);
1199     SetLastError(0xdeadbeef);
1200     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1201      NULL, (PBYTE)buf, buflen, NULL);
1202     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1203     ok(!lstrcmpiA(friendlyName, buf), "Unexpected property\n");
1204     SetLastError(0xdeadbeef);
1205     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1206      &regType, (PBYTE)buf, buflen, NULL);
1207     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1208     ok(!lstrcmpiA(friendlyName, buf), "Unexpected value of property\n");
1209     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1210     SetLastError(0xdeadbeef);
1211     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1212      NULL, 0);
1213     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1214     SetLastError(0xdeadbeef);
1215     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1216      NULL, (PBYTE)buf, buflen, &size);
1217     todo_wine
1218     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1219      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1220     pSetupDiDestroyDeviceInfoList(set);
1221
1222     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, bogus, &key);
1223     todo_wine
1224     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1225     /* FIXME: Remove when Wine is fixed */
1226     if (res == ERROR_SUCCESS)
1227     {
1228         /* Wine doesn't delete the information currently */
1229         trace("We are most likely on Wine\n");
1230         RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus);
1231     }
1232 }
1233
1234 static void testDeviceRegistryPropertyW()
1235 {
1236     HDEVINFO set;
1237     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1238     WCHAR devName[] = {'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1239     WCHAR friendlyName[] = {'B','o','g','u','s',0};
1240     WCHAR buf[6] = {0};
1241     DWORD buflen = 6 * sizeof(WCHAR);
1242     DWORD size;
1243     DWORD regType;
1244     BOOL ret;
1245     LONG res;
1246     HKEY key;
1247     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1248      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1249      'E','n','u','m','\\','R','o','o','t','\\',
1250      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1251
1252     SetLastError(0xdeadbeef);
1253     set = pSetupDiGetClassDevsW(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1254     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %08x\n",
1255      GetLastError());
1256     SetLastError(0xdeadbeef);
1257     ret = pSetupDiCreateDeviceInfoW(set, devName, &guid, NULL, NULL,
1258      DICD_GENERATE_ID, &devInfo);
1259     ok(ret, "SetupDiCreateDeviceInfoW failed: %08x\n", GetLastError());
1260     SetLastError(0xdeadbeef);
1261     ret = pSetupDiSetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, 0);
1262     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1263      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1264     SetLastError(0xdeadbeef);
1265     ret = pSetupDiSetDeviceRegistryPropertyW(set, NULL, -1, NULL, 0);
1266     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1267      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1268     SetLastError(0xdeadbeef);
1269     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, 0);
1270     todo_wine
1271     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1272      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1273     /* GetLastError() returns nonsense in win2k3 */
1274     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1275      NULL, 0);
1276     todo_wine
1277     ok(!ret, "Expected failure, got %d\n", ret);
1278     SetLastError(0xdeadbeef);
1279     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1280      (PBYTE)friendlyName, buflen);
1281     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1282     SetLastError(0xdeadbeef);
1283     ret = pSetupDiGetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, NULL, 0, NULL);
1284     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1285      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1286     SetLastError(0xdeadbeef);
1287     ret = pSetupDiGetDeviceRegistryPropertyW(set, NULL, -1, NULL, NULL, 0, NULL);
1288     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1289      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1290     SetLastError(0xdeadbeef);
1291     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, NULL, 0, NULL);
1292     todo_wine
1293     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1294      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1295     /* GetLastError() returns nonsense in win2k3 */
1296     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1297      NULL, NULL, buflen, NULL);
1298     ok(!ret, "Expected failure, got %d\n", ret);
1299     SetLastError(0xdeadbeef);
1300     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1301      NULL, NULL, 0, &size);
1302     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1303      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1304     ok(buflen == size, "Unexpected size: %d\n", size);
1305     SetLastError(0xdeadbeef);
1306     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1307      NULL, (PBYTE)buf, buflen, NULL);
1308     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1309     ok(!lstrcmpiW(friendlyName, buf), "Unexpected property\n");
1310     SetLastError(0xdeadbeef);
1311     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1312      &regType, (PBYTE)buf, buflen, NULL);
1313     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1314     ok(!lstrcmpiW(friendlyName, buf), "Unexpected value of property\n");
1315     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1316     SetLastError(0xdeadbeef);
1317     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1318      NULL, 0);
1319     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1320     SetLastError(0xdeadbeef);
1321     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1322      NULL, (PBYTE)buf, buflen, &size);
1323     todo_wine
1324     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1325      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1326     pSetupDiDestroyDeviceInfoList(set);
1327
1328     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
1329     todo_wine
1330     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1331     /* FIXME: Remove when Wine is fixed */
1332     if (res == ERROR_SUCCESS)
1333     {
1334         /* Wine doesn't delete the information currently */
1335         trace("We are most likely on Wine\n");
1336         RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus);
1337     }
1338 }
1339
1340 START_TEST(devinst)
1341 {
1342     HDEVINFO set;
1343
1344      init_function_pointers();
1345
1346     /* Win9x/WinMe does things totally different so we skip all the tests
1347      *
1348      * We don't want to exclude NT4 so hence this check.
1349      */
1350     SetLastError(0xdeadbeef);
1351     set = pSetupDiGetClassDevsW(NULL, NULL, 0, 0);
1352     if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1353     {
1354         skip("Win9x/WinMe has totally different behavior\n");
1355         return;
1356     }
1357
1358     if (pSetupDiCreateDeviceInfoListExW && pSetupDiDestroyDeviceInfoList)
1359         test_SetupDiCreateDeviceInfoListEx();
1360     else
1361         skip("SetupDiCreateDeviceInfoListExW and/or SetupDiDestroyDeviceInfoList not available\n");
1362
1363     if (pSetupDiOpenClassRegKeyExA)
1364         test_SetupDiOpenClassRegKeyExA();
1365     else
1366         skip("SetupDiOpenClassRegKeyExA is not available\n");
1367
1368     testInstallClass();
1369     testCreateDeviceInfo();
1370     testGetDeviceInstanceId();
1371     testRegisterDeviceInfo();
1372     testCreateDeviceInterface();
1373     testGetDeviceInterfaceDetail();
1374     testDevRegKey();
1375     testRegisterAndGetDetail();
1376     testDeviceRegistryPropertyA();
1377     testDeviceRegistryPropertyW();
1378 }