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