quartz: Fix discontinuities in wave parser.
[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 *pSetupDiGetDeviceInstanceIdA)(HDEVINFO, PSP_DEVINFO_DATA, PSTR, DWORD, PDWORD);
49 static BOOL     (WINAPI *pSetupDiGetDeviceInterfaceDetailA)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA);
50 static BOOL     (WINAPI *pSetupDiGetDeviceInterfaceDetailW)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_W, DWORD, PDWORD, PSP_DEVINFO_DATA);
51 static BOOL     (WINAPI *pSetupDiRegisterDeviceInfo)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PSP_DETSIG_CMPPROC, PVOID, PSP_DEVINFO_DATA);
52 static HDEVINFO (WINAPI *pSetupDiGetClassDevsA)(CONST GUID *, LPCSTR, HWND, DWORD);
53
54 static void init_function_pointers(void)
55 {
56     hSetupAPI = GetModuleHandleA("setupapi.dll");
57
58     pSetupDiCreateDeviceInfoA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoA");
59     pSetupDiCreateDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoList");
60     pSetupDiCreateDeviceInfoListExW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoListExW");
61     pSetupDiCreateDeviceInterfaceA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInterfaceA");
62     pSetupDiDestroyDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiDestroyDeviceInfoList");
63     pSetupDiCallClassInstaller = (void *)GetProcAddress(hSetupAPI, "SetupDiCallClassInstaller");
64     pSetupDiEnumDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInfo");
65     pSetupDiEnumDeviceInterfaces = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInterfaces");
66     pSetupDiGetDeviceInstanceIdA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInstanceIdA");
67     pSetupDiGetDeviceInterfaceDetailA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailA");
68     pSetupDiGetDeviceInterfaceDetailW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailW");
69     pSetupDiInstallClassA = (void *)GetProcAddress(hSetupAPI, "SetupDiInstallClassA");
70     pSetupDiOpenClassRegKeyExA = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenClassRegKeyExA");
71     pSetupDiOpenDevRegKey = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenDevRegKey");
72     pSetupDiCreateDevRegKeyW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDevRegKeyW");
73     pSetupDiRegisterDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiRegisterDeviceInfo");
74     pSetupDiGetClassDevsA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsA");
75 }
76
77 /* RegDeleteTreeW from dlls/advapi32/registry.c */
78 LSTATUS WINAPI devinst_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
79 {
80     LONG ret;
81     DWORD dwMaxSubkeyLen, dwMaxValueLen;
82     DWORD dwMaxLen, dwSize;
83     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
84     HKEY hSubKey = hKey;
85
86     if(lpszSubKey)
87     {
88         ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
89         if (ret) return ret;
90     }
91
92     /* Get highest length for keys, values */
93     ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
94             &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
95     if (ret) goto cleanup;
96
97     dwMaxSubkeyLen++;
98     dwMaxValueLen++;
99     dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
100     if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
101     {
102         /* Name too big: alloc a buffer for it */
103         if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
104         {
105             ret = ERROR_NOT_ENOUGH_MEMORY;
106             goto cleanup;
107         }
108     }
109
110
111     /* Recursively delete all the subkeys */
112     while (TRUE)
113     {
114         dwSize = dwMaxLen;
115         if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
116                           NULL, NULL, NULL)) break;
117
118         ret = devinst_RegDeleteTreeW(hSubKey, lpszName);
119         if (ret) goto cleanup;
120     }
121
122     if (lpszSubKey)
123         ret = RegDeleteKeyW(hKey, lpszSubKey);
124     else
125         while (TRUE)
126         {
127             dwSize = dwMaxLen;
128             if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
129                   NULL, NULL, NULL, NULL)) break;
130
131             ret = RegDeleteValueW(hKey, lpszName);
132             if (ret) goto cleanup;
133         }
134
135 cleanup:
136     /* Free buffer if allocated */
137     if (lpszName != szNameBuf)
138         HeapFree( GetProcessHeap(), 0, lpszName);
139     if(lpszSubKey)
140         RegCloseKey(hSubKey);
141     return ret;
142 }
143
144
145 static void test_SetupDiCreateDeviceInfoListEx(void) 
146 {
147     HDEVINFO devlist;
148     BOOL ret;
149     DWORD error;
150     static CHAR notnull[] = "NotNull";
151     static const WCHAR machine[] = { 'd','u','m','m','y',0 };
152
153     SetLastError(0xdeadbeef);
154     /* create empty DeviceInfoList, but set Reserved to a value, which is not NULL */
155     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, notnull);
156
157     error = GetLastError();
158     if (error == ERROR_CALL_NOT_IMPLEMENTED)
159     {
160         skip("SetupDiCreateDeviceInfoListExW is not implemented\n");
161         return;
162     }
163     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
164     ok(error == ERROR_INVALID_PARAMETER, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_PARAMETER);
165
166     SetLastError(0xdeadbeef);
167     /* create empty DeviceInfoList, but set MachineName to something */
168     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, machine, NULL);
169
170     error = GetLastError();
171     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
172     ok(error == ERROR_INVALID_MACHINENAME, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_MACHINENAME);
173
174     /* create empty DeviceInfoList */
175     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
176     ok(devlist && devlist != INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected != %p)\n", devlist, error, INVALID_HANDLE_VALUE);
177
178     /* destroy DeviceInfoList */
179     ret = pSetupDiDestroyDeviceInfoList(devlist);
180     ok(ret, "SetupDiDestroyDeviceInfoList failed : %d\n", error);
181 }
182
183 static void test_SetupDiOpenClassRegKeyExA(void)
184 {
185     /* This is a unique guid for testing purposes */
186     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
187         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
188     static const CHAR guidString[] = "{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
189     HKEY hkey;
190
191     /* Check return value for nonexistent key */
192     hkey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
193         DIOCR_INSTALLER, NULL, NULL);
194     ok(hkey == INVALID_HANDLE_VALUE,
195         "returned %p (expected INVALID_HANDLE_VALUE)\n", hkey);
196
197     /* Test it for a key that exists */
198     hkey = SetupDiOpenClassRegKey(NULL, KEY_ALL_ACCESS);
199     if (hkey != INVALID_HANDLE_VALUE)
200     {
201         HKEY classKey;
202         if (RegCreateKeyA(hkey, guidString, &classKey) == ERROR_SUCCESS)
203         {
204             RegCloseKey(classKey);
205             SetLastError(0xdeadbeef);
206             classKey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
207                 DIOCR_INSTALLER, NULL, NULL);
208             ok(classKey != INVALID_HANDLE_VALUE,
209                 "opening class registry key failed with error %d\n",
210                 GetLastError());
211             if (classKey != INVALID_HANDLE_VALUE)
212                 RegCloseKey(classKey);
213             RegDeleteKeyA(hkey, guidString);
214         }
215         else
216             trace("failed to create registry key for test\n");
217     }
218     else
219         trace("failed to open classes key\n");
220 }
221
222 static void append_str(char **str, const char *data)
223 {
224     sprintf(*str, data);
225     *str += strlen(*str);
226 }
227
228 static void create_inf_file(LPCSTR filename)
229 {
230     char data[1024];
231     char *ptr = data;
232     DWORD dwNumberOfBytesWritten;
233     HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
234                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
235
236     append_str(&ptr, "[Version]\n");
237     append_str(&ptr, "Signature=\"$Chicago$\"\n");
238     append_str(&ptr, "Class=Bogus\n");
239     append_str(&ptr, "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n");
240     append_str(&ptr, "[ClassInstall32]\n");
241     append_str(&ptr, "AddReg=BogusClass.NT.AddReg\n");
242     append_str(&ptr, "[BogusClass.NT.AddReg]\n");
243     append_str(&ptr, "HKR,,,,\"Wine test devices\"\n");
244
245     WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL);
246     CloseHandle(hf);
247 }
248
249 static void get_temp_filename(LPSTR path)
250 {
251     static char curr[MAX_PATH] = { 0 };
252     char temp[MAX_PATH];
253     LPSTR ptr;
254
255     if (!*curr)
256         GetCurrentDirectoryA(MAX_PATH, curr);
257     GetTempFileNameA(curr, "set", 0, temp);
258     ptr = strrchr(temp, '\\');
259
260     lstrcpyA(path, ptr + 1);
261 }
262
263 static void testInstallClass(void)
264 {
265     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
266      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
267      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
268      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
269      '1','1','d','b','-','b','7','0','4','-',
270      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
271     char tmpfile[MAX_PATH];
272     BOOL ret;
273
274     if (!pSetupDiInstallClassA)
275     {
276         skip("No SetupDiInstallClassA\n");
277         return;
278     }
279     tmpfile[0] = '.';
280     tmpfile[1] = '\\';
281     get_temp_filename(tmpfile + 2);
282     create_inf_file(tmpfile + 2);
283
284     ret = pSetupDiInstallClassA(NULL, NULL, 0, NULL);
285     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
286      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
287     ret = pSetupDiInstallClassA(NULL, NULL, DI_NOVCP, NULL);
288     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
289      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
290     ret = pSetupDiInstallClassA(NULL, tmpfile + 2, DI_NOVCP, NULL);
291     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
292      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
293     ret = pSetupDiInstallClassA(NULL, tmpfile + 2, 0, NULL);
294     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
295      "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
296     ret = pSetupDiInstallClassA(NULL, tmpfile, 0, NULL);
297     ok(ret, "SetupDiInstallClassA failed: %08x\n", GetLastError());
298     RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey);
299     DeleteFile(tmpfile);
300 }
301
302 static void testCreateDeviceInfo(void)
303 {
304     BOOL ret;
305     HDEVINFO set;
306     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
307         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
308
309     if (!pSetupDiCreateDeviceInfoList || !pSetupDiEnumDeviceInfo ||
310      !pSetupDiDestroyDeviceInfoList || !pSetupDiCreateDeviceInfoA)
311     {
312         skip("No SetupDiCreateDeviceInfoA\n");
313         return;
314     }
315     SetLastError(0xdeadbeef);
316     ret = pSetupDiCreateDeviceInfoA(NULL, NULL, NULL, NULL, NULL, 0, NULL);
317     ok(!ret && GetLastError() == ERROR_INVALID_DEVINST_NAME,
318      "Expected ERROR_INVALID_DEVINST_NAME, got %08x\n", GetLastError());
319     SetLastError(0xdeadbeef);
320     ret = pSetupDiCreateDeviceInfoA(NULL, "Root\\LEGACY_BOGUS\\0000", NULL,
321      NULL, NULL, 0, NULL);
322     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
323      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
324     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
325     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
326      GetLastError());
327     if (set)
328     {
329         SP_DEVINFO_DATA devInfo = { 0 };
330         DWORD i;
331
332         SetLastError(0xdeadbeef);
333         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", NULL,
334          NULL, NULL, 0, NULL);
335         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
336             "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
337         /* Finally, with all three required parameters, this succeeds: */
338         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
339          NULL, NULL, 0, NULL);
340         ok(ret, "pSetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
341         /* This fails because the device ID already exists.. */
342         SetLastError(0xdeadbeef);
343         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
344          NULL, NULL, 0, &devInfo);
345         ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
346          "Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError());
347         /* whereas this "fails" because cbSize is wrong.. */
348         SetLastError(0xdeadbeef);
349         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
350          DICD_GENERATE_ID, &devInfo);
351         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
352          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
353         devInfo.cbSize = sizeof(devInfo);
354         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
355          DICD_GENERATE_ID, &devInfo);
356         /* and this finally succeeds. */
357         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
358         /* There were three devices added, however - the second failure just
359          * resulted in the SP_DEVINFO_DATA not getting copied.
360          */
361         SetLastError(0xdeadbeef);
362         i = 0;
363         while (pSetupDiEnumDeviceInfo(set, i, &devInfo))
364             i++;
365         ok(i == 3, "Expected 3 devices, got %d\n", i);
366         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
367          "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
368         pSetupDiDestroyDeviceInfoList(set);
369     }
370 }
371
372 static void testGetDeviceInstanceId(void)
373 {
374     BOOL ret;
375     HDEVINFO set;
376     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
377         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
378     SP_DEVINFO_DATA devInfo = { 0 };
379
380     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
381      !pSetupDiCreateDeviceInfoA || !pSetupDiGetDeviceInstanceIdA)
382     {
383         skip("No SetupDiGetDeviceInstanceIdA\n");
384         return;
385     }
386     SetLastError(0xdeadbeef);
387     ret = pSetupDiGetDeviceInstanceIdA(NULL, NULL, NULL, 0, NULL);
388     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
389      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
390     SetLastError(0xdeadbeef);
391     ret = pSetupDiGetDeviceInstanceIdA(NULL, &devInfo, NULL, 0, NULL);
392     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
393      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
394     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
395     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
396      GetLastError());
397     if (set)
398     {
399         char instanceID[MAX_PATH];
400         DWORD size;
401
402         SetLastError(0xdeadbeef);
403         ret = pSetupDiGetDeviceInstanceIdA(set, NULL, NULL, 0, NULL);
404         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
405          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
406         SetLastError(0xdeadbeef);
407         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, NULL);
408         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
409          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
410         SetLastError(0xdeadbeef);
411         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
412         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
413          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
414         devInfo.cbSize = sizeof(devInfo);
415         SetLastError(0xdeadbeef);
416         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
417         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
418          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
419         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
420          NULL, NULL, 0, &devInfo);
421         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
422         SetLastError(0xdeadbeef);
423         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
424         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
425          "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
426         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
427          sizeof(instanceID), NULL);
428         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
429         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0000"),
430          "Unexpected instance ID %s\n", instanceID);
431         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid,
432          NULL, NULL, DICD_GENERATE_ID, &devInfo);
433         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
434         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
435          sizeof(instanceID), NULL);
436         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
437         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"),
438          "Unexpected instance ID %s\n", instanceID);
439         pSetupDiDestroyDeviceInfoList(set);
440     }
441 }
442
443 static void testRegisterDeviceInfo(void)
444 {
445     BOOL ret;
446     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
447         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
448     HDEVINFO set;
449
450     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
451      !pSetupDiRegisterDeviceInfo)
452     {
453         skip("No SetupDiRegisterDeviceInfo\n");
454         return;
455     }
456     SetLastError(0xdeadbeef);
457     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
458     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
459      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
460     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
461     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
462     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
463     if (set)
464     {
465         SP_DEVINFO_DATA devInfo = { 0 };
466
467         SetLastError(0xdeadbeef);
468         ret = pSetupDiRegisterDeviceInfo(set, NULL, 0, NULL, NULL, NULL);
469         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
470          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
471         SetLastError(0xdeadbeef);
472         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
473         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
474          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
475         devInfo.cbSize = sizeof(devInfo);
476         SetLastError(0xdeadbeef);
477         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
478         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
479          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
480         ret = pSetupDiCreateDeviceInfoA(set, "USB\\BOGUS\\0000", &guid,
481          NULL, NULL, 0, &devInfo);
482         ok(ret || GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
483                 "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
484         if (ret)
485         {
486             /* If it already existed, registering it again will fail */
487             ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL,
488              NULL);
489             ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
490         }
491         /* FIXME: On Win2K+ systems, this is now persisted to registry in
492          * HKLM\System\CCS\Enum\USB\Bogus\0000.  I don't check because the
493          * Win9x location is different.
494          * FIXME: the key also becomes undeletable.  How to get rid of it?
495          */
496         pSetupDiDestroyDeviceInfoList(set);
497     }
498 }
499
500 static void testCreateDeviceInterface(void)
501 {
502     BOOL ret;
503     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
504         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
505     HDEVINFO set;
506
507     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
508      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
509      !pSetupDiEnumDeviceInterfaces)
510     {
511         skip("No SetupDiCreateDeviceInterfaceA\n");
512         return;
513     }
514     SetLastError(0xdeadbeef);
515     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, NULL, NULL, 0, NULL);
516     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
517      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
518     SetLastError(0xdeadbeef);
519     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, &guid, NULL, 0, NULL);
520     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
521      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
522     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
523     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
524     if (set)
525     {
526         SP_DEVINFO_DATA devInfo = { 0 };
527         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
528             { 0 } };
529         DWORD i;
530
531         SetLastError(0xdeadbeef);
532         ret = pSetupDiCreateDeviceInterfaceA(set, NULL, NULL, NULL, 0, NULL);
533         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
534          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
535         SetLastError(0xdeadbeef);
536         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
537                 NULL);
538         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
539          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
540         devInfo.cbSize = sizeof(devInfo);
541         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
542                 NULL, NULL, 0, &devInfo);
543         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
544         SetLastError(0xdeadbeef);
545         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
546                 NULL);
547         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
548          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
549         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
550                 NULL);
551         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
552         /* Creating the same interface a second time succeeds */
553         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
554                 NULL);
555         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
556         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0,
557                 NULL);
558         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
559         ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0,
560                 &interfaceData);
561         ok(ret, "SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError());
562         i = 0;
563         while (pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, i,
564                     &interfaceData))
565             i++;
566         ok(i == 2, "expected 2 interfaces, got %d\n", i);
567         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
568          "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
569         pSetupDiDestroyDeviceInfoList(set);
570     }
571 }
572
573 static void testGetDeviceInterfaceDetail(void)
574 {
575     BOOL ret;
576     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
577         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
578     HDEVINFO set;
579
580     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
581      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
582      !pSetupDiGetDeviceInterfaceDetailA)
583     {
584         skip("No SetupDiGetDeviceInterfaceDetailA\n");
585         return;
586     }
587     SetLastError(0xdeadbeef);
588     ret = pSetupDiGetDeviceInterfaceDetailA(NULL, NULL, NULL, 0, NULL, NULL);
589     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
590      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
591     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
592     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
593     if (set)
594     {
595         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
596         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
597             { 0 } };
598         DWORD size = 0;
599
600         SetLastError(0xdeadbeef);
601         ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL,
602                 NULL);
603         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
604          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
605         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
606                 NULL, NULL, 0, &devInfo);
607         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
608         SetLastError(0xdeadbeef);
609         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
610                 &interfaceData);
611         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
612         SetLastError(0xdeadbeef);
613         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
614                 0, NULL, NULL);
615         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
616          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
617         SetLastError(0xdeadbeef);
618         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
619                 100, NULL, NULL);
620         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
621          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
622         SetLastError(0xdeadbeef);
623         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
624                 0, &size, NULL);
625         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
626          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
627         if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
628         {
629             static const char path[] =
630              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
631             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
632             SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail =
633                 (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf;
634             DWORD expectedsize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path));
635
636             detail->cbSize = 0;
637             SetLastError(0xdeadbeef);
638             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
639                     size, &size, NULL);
640             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
641              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
642             detail->cbSize = size;
643             SetLastError(0xdeadbeef);
644             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
645                     size, &size, NULL);
646             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
647              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
648             detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
649             SetLastError(0xdeadbeef);
650             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
651                     size, &size, NULL);
652             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
653              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
654             /* Windows 2000 and up check for the exact size. Win9x returns ERROR_INVALID_PARAMETER
655              * on every call (so doesn't get here) and NT4 doesn't have this function.
656              */
657             detail->cbSize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
658             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
659                     size, &size, NULL);
660             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n",
661                     GetLastError());
662             ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n",
663                     detail->DevicePath);
664             /* Check SetupDiGetDeviceInterfaceDetailW */
665             if (pSetupDiGetDeviceInterfaceDetailW)
666             {
667                 ret = pSetupDiGetDeviceInterfaceDetailW(set, &interfaceData, NULL, 0, &size, NULL);
668                 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError());
669                 ok(expectedsize == size, "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize: expected %d, got %d\n", expectedsize, size);
670             }
671             else
672                 skip("SetupDiGetDeviceInterfaceDetailW is not available\n");
673
674             HeapFree(GetProcessHeap(), 0, buf);
675         }
676         pSetupDiDestroyDeviceInfoList(set);
677     }
678 }
679
680 static void testDevRegKey(void)
681 {
682     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
683      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
684      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
685      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
686      '1','1','d','b','-','b','7','0','4','-',
687      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
688     BOOL ret;
689     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
690         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
691     HDEVINFO set;
692
693     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
694      !pSetupDiCreateDeviceInfoA || !pSetupDiOpenDevRegKey ||
695      !pSetupDiRegisterDeviceInfo || !pSetupDiCreateDevRegKeyW ||
696      !pSetupDiCallClassInstaller)
697     {
698         skip("No SetupDiOpenDevRegKey\n");
699         return;
700     }
701     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
702     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
703     if (set)
704     {
705         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
706         HKEY key = INVALID_HANDLE_VALUE;
707
708         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
709                 NULL, NULL, 0, &devInfo);
710         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
711         SetLastError(0xdeadbeef);
712         key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
713         ok(key == INVALID_HANDLE_VALUE &&
714          GetLastError() == ERROR_INVALID_HANDLE,
715          "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
716         SetLastError(0xdeadbeef);
717         key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
718         ok(key == INVALID_HANDLE_VALUE &&
719          GetLastError() == ERROR_INVALID_PARAMETER,
720          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
721         SetLastError(0xdeadbeef);
722         key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0);
723         ok(key == INVALID_HANDLE_VALUE &&
724          GetLastError() == ERROR_INVALID_FLAGS,
725          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
726         SetLastError(0xdeadbeef);
727         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0);
728         ok(key == INVALID_HANDLE_VALUE &&
729          GetLastError() == ERROR_INVALID_FLAGS,
730          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
731         SetLastError(0xdeadbeef);
732         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
733          DIREG_BOTH, 0);
734         ok(key == INVALID_HANDLE_VALUE &&
735          GetLastError() == ERROR_INVALID_FLAGS,
736          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
737         SetLastError(0xdeadbeef);
738         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
739          DIREG_DRV, 0);
740         ok(key == INVALID_HANDLE_VALUE &&
741          GetLastError() == ERROR_DEVINFO_NOT_REGISTERED,
742          "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError());
743         SetLastError(0xdeadbeef);
744         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
745         ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
746         SetLastError(0xdeadbeef);
747         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
748          DIREG_DRV, 0);
749         /* The software key isn't created by default */
750         todo_wine
751         ok(key == INVALID_HANDLE_VALUE &&
752          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
753          "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError());
754         SetLastError(0xdeadbeef);
755         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
756          DIREG_DEV, 0);
757         todo_wine
758         ok(key == INVALID_HANDLE_VALUE &&
759          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
760          "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError());
761         SetLastError(0xdeadbeef);
762         key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0,
763          DIREG_DRV, NULL, NULL);
764         ok(key != INVALID_HANDLE_VALUE, "SetupDiCreateDevRegKey failed: %08x\n",
765          GetLastError());
766         RegCloseKey(key);
767         SetLastError(0xdeadbeef);
768         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
769          DIREG_DRV, 0);
770         todo_wine
771         ok(key == INVALID_HANDLE_VALUE &&
772          GetLastError() == ERROR_INVALID_DATA,
773          "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
774         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
775          DIREG_DRV, KEY_READ);
776         ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n",
777          GetLastError());
778         ret = pSetupDiCallClassInstaller(DIF_REMOVE, set, &devInfo);
779         pSetupDiDestroyDeviceInfoList(set);
780     }
781     devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
782 }
783
784 static void testRegisterAndGetDetail(void)
785 {
786     HDEVINFO set;
787     BOOL ret;
788     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
789         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
790     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
791     SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } };
792     DWORD dwSize = 0;
793
794     SetLastError(0xdeadbeef);
795     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES);
796     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
797      GetLastError());
798
799     SetLastError(0xdeadbeef);
800     ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, 0,
801      DICD_GENERATE_ID, &devInfo);
802     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
803     SetLastError(0xdeadbeef);
804     ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, &interfaceData);
805     ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
806     SetLastError(0xdeadbeef);
807     ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
808     ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
809
810     pSetupDiDestroyDeviceInfoList(set);
811
812     SetLastError(0xdeadbeef);
813     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
814     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
815      GetLastError());
816
817     SetLastError(0xdeadbeef);
818     ret = pSetupDiEnumDeviceInterfaces(set, NULL, &guid, 0, &interfaceData);
819     ok(ret, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
820     SetLastError(0xdeadbeef);
821     ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, 0, &dwSize, NULL);
822     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
823      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
824     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
825     {
826         static const char path[] =
827             "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
828         PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL;
829
830         detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)HeapAlloc(GetProcessHeap(), 0, dwSize);
831         if (detail)
832         {
833             detail->cbSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char);
834             SetLastError(0xdeadbeef);
835             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData,
836              detail, dwSize, &dwSize, NULL);
837             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError());
838             ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n",
839                     detail->DevicePath);
840             HeapFree(GetProcessHeap(), 0, detail);
841         }
842     }
843
844     pSetupDiDestroyDeviceInfoList(set);
845 }
846
847 START_TEST(devinst)
848 {
849     init_function_pointers();
850
851     if (pSetupDiCreateDeviceInfoListExW && pSetupDiDestroyDeviceInfoList)
852         test_SetupDiCreateDeviceInfoListEx();
853     else
854         skip("SetupDiCreateDeviceInfoListExW and/or SetupDiDestroyDeviceInfoList not available\n");
855
856     if (pSetupDiOpenClassRegKeyExA)
857         test_SetupDiOpenClassRegKeyExA();
858     else
859         skip("SetupDiOpenClassRegKeyExA is not available\n");
860     testInstallClass();
861     testCreateDeviceInfo();
862     testGetDeviceInstanceId();
863     testRegisterDeviceInfo();
864     testCreateDeviceInterface();
865     testGetDeviceInterfaceDetail();
866     testDevRegKey();
867     testRegisterAndGetDetail();
868 }