setupapi: Create symbolic link value when interface is created.
[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
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 *pSetupDiDestroyDeviceInfoList)(HDEVINFO);
40 static BOOL     (WINAPI *pSetupDiEnumDeviceInfo)(HDEVINFO, DWORD, PSP_DEVINFO_DATA);
41 static BOOL     (WINAPI *pSetupDiEnumDeviceInterfaces)(HDEVINFO, PSP_DEVINFO_DATA, const GUID *, DWORD, PSP_DEVICE_INTERFACE_DATA);
42 static HKEY     (WINAPI *pSetupDiOpenClassRegKeyExA)(GUID*,REGSAM,DWORD,PCSTR,PVOID);
43 static BOOL     (WINAPI *pSetupDiCreateDeviceInfoA)(HDEVINFO, PCSTR, GUID *, PCSTR, HWND, DWORD, PSP_DEVINFO_DATA);
44 static BOOL     (WINAPI *pSetupDiGetDeviceInstanceIdA)(HDEVINFO, PSP_DEVINFO_DATA, PSTR, DWORD, PDWORD);
45 static BOOL     (WINAPI *pSetupDiGetDeviceInterfaceDetailA)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA);
46 static BOOL     (WINAPI *pSetupDiRegisterDeviceInfo)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PSP_DETSIG_CMPPROC, PVOID, PSP_DEVINFO_DATA);
47
48 static void init_function_pointers(void)
49 {
50     hSetupAPI = GetModuleHandleA("setupapi.dll");
51
52     pSetupDiCreateDeviceInfoA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoA");
53     pSetupDiCreateDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoList");
54     pSetupDiCreateDeviceInfoListExW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoListExW");
55     pSetupDiCreateDeviceInterfaceA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInterfaceA");
56     pSetupDiDestroyDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiDestroyDeviceInfoList");
57     pSetupDiEnumDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInfo");
58     pSetupDiEnumDeviceInterfaces = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInterfaces");
59     pSetupDiGetDeviceInstanceIdA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInstanceIdA");
60     pSetupDiGetDeviceInterfaceDetailA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailA");
61     pSetupDiOpenClassRegKeyExA = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenClassRegKeyExA");
62     pSetupDiRegisterDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiRegisterDeviceInfo");
63 }
64
65 static void test_SetupDiCreateDeviceInfoListEx(void) 
66 {
67     HDEVINFO devlist;
68     BOOL ret;
69     DWORD error;
70     static CHAR notnull[] = "NotNull";
71     static const WCHAR machine[] = { 'd','u','m','m','y',0 };
72
73     SetLastError(0xdeadbeef);
74     /* create empty DeviceInfoList, but set Reserved to a value, which is not NULL */
75     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, notnull);
76
77     error = GetLastError();
78     if (error == ERROR_CALL_NOT_IMPLEMENTED)
79     {
80         skip("SetupDiCreateDeviceInfoListExW is not implemented\n");
81         return;
82     }
83     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
84     ok(error == ERROR_INVALID_PARAMETER, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_PARAMETER);
85
86     SetLastError(0xdeadbeef);
87     /* create empty DeviceInfoList, but set MachineName to something */
88     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, machine, NULL);
89
90     error = GetLastError();
91     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
92     ok(error == ERROR_INVALID_MACHINENAME, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_MACHINENAME);
93
94     /* create empty DeviceInfoList */
95     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
96     ok(devlist && devlist != INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected != %p)\n", devlist, error, INVALID_HANDLE_VALUE);
97
98     /* destroy DeviceInfoList */
99     ret = pSetupDiDestroyDeviceInfoList(devlist);
100     ok(ret, "SetupDiDestroyDeviceInfoList failed : %d\n", error);
101 }
102
103 static void test_SetupDiOpenClassRegKeyExA(void)
104 {
105     /* This is a unique guid for testing purposes */
106     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
107         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
108     static const CHAR guidString[] = "{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
109     HKEY hkey;
110
111     /* Check return value for nonexistent key */
112     hkey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
113         DIOCR_INSTALLER, NULL, NULL);
114     ok(hkey == INVALID_HANDLE_VALUE,
115         "returned %p (expected INVALID_HANDLE_VALUE)\n", hkey);
116
117     /* Test it for a key that exists */
118     hkey = SetupDiOpenClassRegKey(NULL, KEY_ALL_ACCESS);
119     if (hkey != INVALID_HANDLE_VALUE)
120     {
121         HKEY classKey;
122         if (RegCreateKeyA(hkey, guidString, &classKey) == ERROR_SUCCESS)
123         {
124             RegCloseKey(classKey);
125             SetLastError(0xdeadbeef);
126             classKey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
127                 DIOCR_INSTALLER, NULL, NULL);
128             ok(classKey != INVALID_HANDLE_VALUE,
129                 "opening class registry key failed with error %d\n",
130                 GetLastError());
131             if (classKey != INVALID_HANDLE_VALUE)
132                 RegCloseKey(classKey);
133             RegDeleteKeyA(hkey, guidString);
134         }
135         else
136             trace("failed to create registry key for test\n");
137     }
138     else
139         trace("failed to open classes key\n");
140 }
141
142 static void testCreateDeviceInfo(void)
143 {
144     BOOL ret;
145     HDEVINFO set;
146     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
147         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
148
149     if (!pSetupDiCreateDeviceInfoList || !pSetupDiEnumDeviceInfo ||
150      !pSetupDiDestroyDeviceInfoList || !pSetupDiCreateDeviceInfoA)
151     {
152         skip("No SetupDiCreateDeviceInfoA\n");
153         return;
154     }
155     SetLastError(0xdeadbeef);
156     ret = pSetupDiCreateDeviceInfoA(NULL, NULL, NULL, NULL, NULL, 0, NULL);
157     ok(!ret && GetLastError() == ERROR_INVALID_DEVINST_NAME,
158      "Expected ERROR_INVALID_DEVINST_NAME, got %08x\n", GetLastError());
159     SetLastError(0xdeadbeef);
160     ret = pSetupDiCreateDeviceInfoA(NULL, "Root\\LEGACY_BOGUS\\0000", NULL,
161      NULL, NULL, 0, NULL);
162     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
163      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
164     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
165     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
166      GetLastError());
167     if (set)
168     {
169         SP_DEVINFO_DATA devInfo = { 0 };
170         DWORD i;
171
172         SetLastError(0xdeadbeef);
173         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", NULL,
174          NULL, NULL, 0, NULL);
175         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
176             "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
177         /* Finally, with all three required parameters, this succeeds: */
178         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
179          NULL, NULL, 0, NULL);
180         ok(ret, "pSetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
181         /* This fails because the device ID already exists.. */
182         SetLastError(0xdeadbeef);
183         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
184          NULL, NULL, 0, &devInfo);
185         ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
186          "Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError());
187         /* whereas this "fails" because cbSize is wrong.. */
188         SetLastError(0xdeadbeef);
189         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
190          DICD_GENERATE_ID, &devInfo);
191         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
192          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
193         devInfo.cbSize = sizeof(devInfo);
194         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
195          DICD_GENERATE_ID, &devInfo);
196         /* and this finally succeeds. */
197         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
198         /* There were three devices added, however - the second failure just
199          * resulted in the SP_DEVINFO_DATA not getting copied.
200          */
201         SetLastError(0xdeadbeef);
202         i = 0;
203         while (pSetupDiEnumDeviceInfo(set, i, &devInfo))
204             i++;
205         ok(i == 3, "Expected 3 devices, got %d\n", i);
206         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
207          "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
208         pSetupDiDestroyDeviceInfoList(set);
209     }
210 }
211
212 static void testGetDeviceInstanceId(void)
213 {
214     BOOL ret;
215     HDEVINFO set;
216     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
217         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
218     SP_DEVINFO_DATA devInfo = { 0 };
219
220     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
221      !pSetupDiCreateDeviceInfoA || !pSetupDiGetDeviceInstanceIdA)
222     {
223         skip("No SetupDiGetDeviceInstanceIdA\n");
224         return;
225     }
226     SetLastError(0xdeadbeef);
227     ret = pSetupDiGetDeviceInstanceIdA(NULL, NULL, NULL, 0, NULL);
228     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
229      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
230     SetLastError(0xdeadbeef);
231     ret = pSetupDiGetDeviceInstanceIdA(NULL, &devInfo, NULL, 0, NULL);
232     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
233      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
234     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
235     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
236      GetLastError());
237     if (set)
238     {
239         char instanceID[MAX_PATH];
240         DWORD size;
241
242         SetLastError(0xdeadbeef);
243         ret = pSetupDiGetDeviceInstanceIdA(set, NULL, NULL, 0, NULL);
244         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
245          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
246         SetLastError(0xdeadbeef);
247         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, NULL);
248         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
249          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
250         SetLastError(0xdeadbeef);
251         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
252         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
253          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
254         devInfo.cbSize = sizeof(devInfo);
255         SetLastError(0xdeadbeef);
256         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
257         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
258          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
259         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
260          NULL, NULL, 0, &devInfo);
261         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
262         SetLastError(0xdeadbeef);
263         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
264         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
265          "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
266         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
267          sizeof(instanceID), NULL);
268         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
269         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0000"),
270          "Unexpected instance ID %s\n", instanceID);
271         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid,
272          NULL, NULL, DICD_GENERATE_ID, &devInfo);
273         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
274         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
275          sizeof(instanceID), NULL);
276         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
277         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"),
278          "Unexpected instance ID %s\n", instanceID);
279         pSetupDiDestroyDeviceInfoList(set);
280     }
281 }
282
283 static void testRegisterDeviceInfo(void)
284 {
285     BOOL ret;
286     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
287         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
288     HDEVINFO set;
289
290     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
291      !pSetupDiRegisterDeviceInfo)
292     {
293         skip("No SetupDiRegisterDeviceInfo\n");
294         return;
295     }
296     SetLastError(0xdeadbeef);
297     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
298     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
299      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
300     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
301     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
302     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
303     if (set)
304     {
305         SP_DEVINFO_DATA devInfo = { 0 };
306
307         SetLastError(0xdeadbeef);
308         ret = pSetupDiRegisterDeviceInfo(set, NULL, 0, NULL, NULL, NULL);
309         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
310          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
311         SetLastError(0xdeadbeef);
312         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
313         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
314          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
315         devInfo.cbSize = sizeof(devInfo);
316         SetLastError(0xdeadbeef);
317         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
318         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
319          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
320         ret = pSetupDiCreateDeviceInfoA(set, "USB\\BOGUS\\0000", &guid,
321          NULL, NULL, 0, &devInfo);
322         ok(ret || GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
323                 "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
324         if (ret)
325         {
326             /* If it already existed, registering it again will fail */
327             ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL,
328              NULL);
329             ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
330         }
331         /* FIXME: On Win2K+ systems, this is now persisted to registry in
332          * HKLM\System\CCS\Enum\USB\Bogus\0000.  I don't check because the
333          * Win9x location is different.
334          * FIXME: the key also becomes undeletable.  How to get rid of it?
335          */
336         pSetupDiDestroyDeviceInfoList(set);
337     }
338 }
339
340 static void testCreateDeviceInterface(void)
341 {
342     BOOL ret;
343     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
344         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
345     HDEVINFO set;
346
347     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
348      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
349      !pSetupDiEnumDeviceInterfaces)
350     {
351         skip("No SetupDiCreateDeviceInterfaceA\n");
352         return;
353     }
354     SetLastError(0xdeadbeef);
355     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, NULL, NULL, 0, NULL);
356     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
357      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
358     SetLastError(0xdeadbeef);
359     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, &guid, NULL, 0, NULL);
360     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
361      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
362     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
363     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
364     if (set)
365     {
366         SP_DEVINFO_DATA devInfo = { 0 };
367         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
368             { 0 } };
369         DWORD i;
370
371         SetLastError(0xdeadbeef);
372         ret = pSetupDiCreateDeviceInterfaceA(set, NULL, NULL, NULL, 0, NULL);
373         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
374          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
375         SetLastError(0xdeadbeef);
376         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
377                 NULL);
378         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
379          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
380         devInfo.cbSize = sizeof(devInfo);
381         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
382                 NULL, NULL, 0, &devInfo);
383         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
384         SetLastError(0xdeadbeef);
385         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
386                 NULL);
387         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
388          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
389         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
390                 NULL);
391         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
392         /* Creating the same interface a second time succeeds */
393         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
394                 NULL);
395         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
396         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0,
397                 NULL);
398         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
399         ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0,
400                 &interfaceData);
401         ok(ret, "SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError());
402         i = 0;
403         while (pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, i,
404                     &interfaceData))
405             i++;
406         ok(i == 2, "expected 2 interfaces, got %d\n", i);
407         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
408          "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
409         pSetupDiDestroyDeviceInfoList(set);
410     }
411 }
412
413 static void testGetDeviceInterfaceDetail(void)
414 {
415     BOOL ret;
416     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
417         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
418     HDEVINFO set;
419
420     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
421      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
422      !pSetupDiGetDeviceInterfaceDetailA)
423     {
424         skip("No SetupDiGetDeviceInterfaceDetailA\n");
425         return;
426     }
427     SetLastError(0xdeadbeef);
428     ret = pSetupDiGetDeviceInterfaceDetailA(NULL, NULL, NULL, 0, NULL, NULL);
429     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
430      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
431     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
432     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
433     if (set)
434     {
435         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
436         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
437             { 0 } };
438         DWORD size = 0;
439
440         SetLastError(0xdeadbeef);
441         ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL,
442                 NULL);
443         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
444          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
445         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
446                 NULL, NULL, 0, &devInfo);
447         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
448         SetLastError(0xdeadbeef);
449         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
450                 &interfaceData);
451         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
452         SetLastError(0xdeadbeef);
453         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
454                 0, NULL, NULL);
455         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
456          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
457         SetLastError(0xdeadbeef);
458         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
459                 100, NULL, NULL);
460         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
461          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
462         SetLastError(0xdeadbeef);
463         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
464                 0, &size, NULL);
465         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
466          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
467         if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
468         {
469             static const char path[] =
470              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
471             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
472             SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail =
473                 (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf;
474
475             detail->cbSize = 0;
476             SetLastError(0xdeadbeef);
477             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
478                     size, &size, NULL);
479             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
480              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
481             detail->cbSize = size;
482             SetLastError(0xdeadbeef);
483             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
484                     size, &size, NULL);
485             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
486              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
487             detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
488             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
489                     size, &size, NULL);
490             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n",
491                     GetLastError());
492             ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n",
493                     detail->DevicePath);
494             HeapFree(GetProcessHeap(), 0, buf);
495         }
496         pSetupDiDestroyDeviceInfoList(set);
497     }
498 }
499
500 START_TEST(devinst)
501 {
502     init_function_pointers();
503
504     if (pSetupDiCreateDeviceInfoListExW && pSetupDiDestroyDeviceInfoList)
505         test_SetupDiCreateDeviceInfoListEx();
506     else
507         skip("SetupDiCreateDeviceInfoListExW and/or SetupDiDestroyDeviceInfoList not available\n");
508
509     if (pSetupDiOpenClassRegKeyExA)
510         test_SetupDiOpenClassRegKeyExA();
511     else
512         skip("SetupDiOpenClassRegKeyExA is not available\n");
513     testCreateDeviceInfo();
514     testGetDeviceInstanceId();
515     testRegisterDeviceInfo();
516     testCreateDeviceInterface();
517     testGetDeviceInterfaceDetail();
518 }