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