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