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