mshtml: Fix a few test failures in win2k3.
[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, "Expected failure\n");
353     ok(GetLastError() == ERROR_INVALID_DEVINST_NAME ||
354       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */ ||
355       GetLastError() == ERROR_INVALID_HANDLE /* Win9x */,
356      "Unexpected last error, got %08x\n", GetLastError());
357
358     /* If we are running on win9x we should skip these tests. Win95
359      * fails most tests anyway and win98 pops up the "Add New Hardware
360      * Wizard".
361      */
362     if (GetLastError() == ERROR_INVALID_HANDLE)
363     {
364         skip("We are on win9x where the tests introduce issues\n");
365         return;
366     }
367
368     SetLastError(0xdeadbeef);
369     ret = pSetupDiCreateDeviceInfoA(NULL, "Root\\LEGACY_BOGUS\\0000", NULL,
370      NULL, NULL, 0, NULL);
371     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
372      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
373     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
374     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
375      GetLastError());
376     if (set)
377     {
378         SP_DEVINFO_DATA devInfo = { 0 };
379         DWORD i;
380
381         SetLastError(0xdeadbeef);
382         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", NULL,
383          NULL, NULL, 0, NULL);
384         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
385             "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
386         /* Finally, with all three required parameters, this succeeds: */
387         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
388          NULL, NULL, 0, NULL);
389         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
390         /* This fails because the device ID already exists.. */
391         SetLastError(0xdeadbeef);
392         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
393          NULL, NULL, 0, &devInfo);
394         ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
395          "Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError());
396         /* whereas this "fails" because cbSize is wrong.. */
397         SetLastError(0xdeadbeef);
398         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
399          DICD_GENERATE_ID, &devInfo);
400         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
401          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
402         devInfo.cbSize = sizeof(devInfo);
403         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
404          DICD_GENERATE_ID, &devInfo);
405         /* and this finally succeeds. */
406         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
407         /* There were three devices added, however - the second failure just
408          * resulted in the SP_DEVINFO_DATA not getting copied.
409          */
410         SetLastError(0xdeadbeef);
411         i = 0;
412         while (pSetupDiEnumDeviceInfo(set, i, &devInfo))
413             i++;
414         ok(i == 3, "Expected 3 devices, got %d\n", i);
415         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
416          "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
417         pSetupDiDestroyDeviceInfoList(set);
418     }
419 }
420
421 static void testGetDeviceInstanceId(void)
422 {
423     BOOL ret;
424     HDEVINFO set;
425     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
426         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
427     SP_DEVINFO_DATA devInfo = { 0 };
428
429     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
430      !pSetupDiCreateDeviceInfoA || !pSetupDiGetDeviceInstanceIdA)
431     {
432         skip("No SetupDiGetDeviceInstanceIdA\n");
433         return;
434     }
435     SetLastError(0xdeadbeef);
436     ret = pSetupDiGetDeviceInstanceIdA(NULL, NULL, NULL, 0, NULL);
437     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
438      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
439     SetLastError(0xdeadbeef);
440     ret = pSetupDiGetDeviceInstanceIdA(NULL, &devInfo, NULL, 0, NULL);
441     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
442      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
443     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
444     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
445      GetLastError());
446     if (set)
447     {
448         char instanceID[MAX_PATH];
449         DWORD size;
450
451         SetLastError(0xdeadbeef);
452         ret = pSetupDiGetDeviceInstanceIdA(set, NULL, NULL, 0, NULL);
453         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
454          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
455         SetLastError(0xdeadbeef);
456         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, NULL);
457         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
458          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
459         SetLastError(0xdeadbeef);
460         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
461         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
462          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
463         devInfo.cbSize = sizeof(devInfo);
464         SetLastError(0xdeadbeef);
465         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
466         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
467          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
468         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
469          NULL, NULL, 0, &devInfo);
470         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
471         SetLastError(0xdeadbeef);
472         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
473         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
474          "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
475         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
476          sizeof(instanceID), NULL);
477         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
478         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0000"),
479          "Unexpected instance ID %s\n", instanceID);
480         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid,
481          NULL, NULL, DICD_GENERATE_ID, &devInfo);
482         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
483         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
484          sizeof(instanceID), NULL);
485         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
486         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"),
487          "Unexpected instance ID %s\n", instanceID);
488         pSetupDiDestroyDeviceInfoList(set);
489     }
490 }
491
492 static void testRegisterDeviceInfo(void)
493 {
494     BOOL ret;
495     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
496         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
497     HDEVINFO set;
498
499     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
500      !pSetupDiRegisterDeviceInfo)
501     {
502         skip("No SetupDiRegisterDeviceInfo\n");
503         return;
504     }
505     SetLastError(0xdeadbeef);
506     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
507     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
508      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
509     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
510     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
511     if (set)
512     {
513         SP_DEVINFO_DATA devInfo = { 0 };
514
515         SetLastError(0xdeadbeef);
516         ret = pSetupDiRegisterDeviceInfo(set, NULL, 0, NULL, NULL, NULL);
517         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
518          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
519         SetLastError(0xdeadbeef);
520         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
521         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
522          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
523         devInfo.cbSize = sizeof(devInfo);
524         SetLastError(0xdeadbeef);
525         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
526         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
527          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
528         ret = pSetupDiCreateDeviceInfoA(set, "USB\\BOGUS\\0000", &guid,
529          NULL, NULL, 0, &devInfo);
530         ok(ret || GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
531                 "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
532         if (ret)
533         {
534             /* If it already existed, registering it again will fail */
535             ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL,
536              NULL);
537             ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
538         }
539         /* FIXME: On Win2K+ systems, this is now persisted to registry in
540          * HKLM\System\CCS\Enum\USB\Bogus\0000.  I don't check because the
541          * Win9x location is different.
542          * FIXME: the key also becomes undeletable.  How to get rid of it?
543          */
544         pSetupDiDestroyDeviceInfoList(set);
545     }
546 }
547
548 static void testCreateDeviceInterface(void)
549 {
550     BOOL ret;
551     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
552         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
553     HDEVINFO set;
554
555     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
556      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
557      !pSetupDiEnumDeviceInterfaces)
558     {
559         skip("No SetupDiCreateDeviceInterfaceA\n");
560         return;
561     }
562     SetLastError(0xdeadbeef);
563     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, NULL, NULL, 0, NULL);
564     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
565      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
566     SetLastError(0xdeadbeef);
567     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, &guid, NULL, 0, NULL);
568     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
569      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
570     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
571     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
572     if (set)
573     {
574         SP_DEVINFO_DATA devInfo = { 0 };
575         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
576             { 0 } };
577         DWORD i;
578
579         SetLastError(0xdeadbeef);
580         ret = pSetupDiCreateDeviceInterfaceA(set, NULL, NULL, NULL, 0, NULL);
581         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
582          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
583         SetLastError(0xdeadbeef);
584         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
585                 NULL);
586         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
587          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
588         devInfo.cbSize = sizeof(devInfo);
589         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
590                 NULL, NULL, 0, &devInfo);
591         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
592         SetLastError(0xdeadbeef);
593         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
594                 NULL);
595         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
596          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
597         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
598                 NULL);
599         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
600         /* Creating the same interface a second time succeeds */
601         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
602                 NULL);
603         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
604         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0,
605                 NULL);
606         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
607         ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0,
608                 &interfaceData);
609         ok(ret, "SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError());
610         i = 0;
611         while (pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, i,
612                     &interfaceData))
613             i++;
614         ok(i == 2, "expected 2 interfaces, got %d\n", i);
615         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
616          "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
617         pSetupDiDestroyDeviceInfoList(set);
618     }
619 }
620
621 static void testGetDeviceInterfaceDetail(void)
622 {
623     BOOL ret;
624     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
625         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
626     HDEVINFO set;
627
628     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
629      !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA ||
630      !pSetupDiGetDeviceInterfaceDetailA)
631     {
632         skip("No SetupDiGetDeviceInterfaceDetailA\n");
633         return;
634     }
635     SetLastError(0xdeadbeef);
636     ret = pSetupDiGetDeviceInterfaceDetailA(NULL, NULL, NULL, 0, NULL, NULL);
637     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
638      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
639     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
640     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
641     if (set)
642     {
643         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
644         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
645             { 0 } };
646         DWORD size = 0;
647
648         SetLastError(0xdeadbeef);
649         ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL,
650                 NULL);
651         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
652          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
653         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
654                 NULL, NULL, 0, &devInfo);
655         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
656         SetLastError(0xdeadbeef);
657         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
658                 &interfaceData);
659         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
660         SetLastError(0xdeadbeef);
661         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
662                 0, NULL, NULL);
663         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
664          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
665         SetLastError(0xdeadbeef);
666         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
667                 100, NULL, NULL);
668         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
669          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
670         SetLastError(0xdeadbeef);
671         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
672                 0, &size, NULL);
673         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
674          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
675         if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
676         {
677             static const char path[] =
678              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
679             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
680             SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail =
681                 (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf;
682             DWORD expectedsize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path));
683
684             detail->cbSize = 0;
685             SetLastError(0xdeadbeef);
686             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
687                     size, &size, NULL);
688             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
689              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
690             detail->cbSize = size;
691             SetLastError(0xdeadbeef);
692             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
693                     size, &size, NULL);
694             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
695              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
696             detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
697             SetLastError(0xdeadbeef);
698             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
699                     size, &size, NULL);
700             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
701              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
702             /* Windows 2000 and up check for the exact size. Win9x returns ERROR_INVALID_PARAMETER
703              * on every call (so doesn't get here) and NT4 doesn't have this function.
704              */
705             detail->cbSize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
706             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
707                     size, &size, NULL);
708             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n",
709                     GetLastError());
710             ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n",
711                     detail->DevicePath);
712             /* Check SetupDiGetDeviceInterfaceDetailW */
713             if (pSetupDiGetDeviceInterfaceDetailW)
714             {
715                 ret = pSetupDiGetDeviceInterfaceDetailW(set, &interfaceData, NULL, 0, &size, NULL);
716                 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError());
717                 ok(expectedsize == size, "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize: expected %d, got %d\n", expectedsize, size);
718             }
719             else
720                 skip("SetupDiGetDeviceInterfaceDetailW is not available\n");
721
722             HeapFree(GetProcessHeap(), 0, buf);
723         }
724         pSetupDiDestroyDeviceInfoList(set);
725     }
726 }
727
728 static void testDevRegKey(void)
729 {
730     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
731      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
732      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
733      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
734      '1','1','d','b','-','b','7','0','4','-',
735      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
736     BOOL ret;
737     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
738         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
739     HDEVINFO set;
740
741     if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList ||
742      !pSetupDiCreateDeviceInfoA || !pSetupDiOpenDevRegKey ||
743      !pSetupDiRegisterDeviceInfo || !pSetupDiCreateDevRegKeyW ||
744      !pSetupDiCallClassInstaller)
745     {
746         skip("No SetupDiOpenDevRegKey\n");
747         return;
748     }
749     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
750     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
751     if (set)
752     {
753         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
754         HKEY key = INVALID_HANDLE_VALUE;
755
756         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
757                 NULL, NULL, 0, &devInfo);
758         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
759         SetLastError(0xdeadbeef);
760         key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
761         ok(key == INVALID_HANDLE_VALUE &&
762          GetLastError() == ERROR_INVALID_HANDLE,
763          "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
764         SetLastError(0xdeadbeef);
765         key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
766         ok(key == INVALID_HANDLE_VALUE &&
767          GetLastError() == ERROR_INVALID_PARAMETER,
768          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
769         SetLastError(0xdeadbeef);
770         key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0);
771         ok(key == INVALID_HANDLE_VALUE &&
772          GetLastError() == ERROR_INVALID_FLAGS,
773          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
774         SetLastError(0xdeadbeef);
775         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0);
776         ok(key == INVALID_HANDLE_VALUE &&
777          GetLastError() == ERROR_INVALID_FLAGS,
778          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
779         SetLastError(0xdeadbeef);
780         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
781          DIREG_BOTH, 0);
782         ok(key == INVALID_HANDLE_VALUE &&
783          GetLastError() == ERROR_INVALID_FLAGS,
784          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
785         SetLastError(0xdeadbeef);
786         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
787          DIREG_DRV, 0);
788         ok(key == INVALID_HANDLE_VALUE &&
789          GetLastError() == ERROR_DEVINFO_NOT_REGISTERED,
790          "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError());
791         SetLastError(0xdeadbeef);
792         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
793         ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
794         SetLastError(0xdeadbeef);
795         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
796          DIREG_DRV, 0);
797         /* The software key isn't created by default */
798         todo_wine
799         ok(key == INVALID_HANDLE_VALUE &&
800          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
801          "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError());
802         SetLastError(0xdeadbeef);
803         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
804          DIREG_DEV, 0);
805         todo_wine
806         ok(key == INVALID_HANDLE_VALUE &&
807          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
808          "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError());
809         SetLastError(0xdeadbeef);
810         key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0,
811          DIREG_DRV, NULL, NULL);
812         ok(key != INVALID_HANDLE_VALUE, "SetupDiCreateDevRegKey failed: %08x\n",
813          GetLastError());
814         RegCloseKey(key);
815         SetLastError(0xdeadbeef);
816         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
817          DIREG_DRV, 0);
818         todo_wine
819         ok(key == INVALID_HANDLE_VALUE &&
820          (GetLastError() == ERROR_INVALID_DATA ||
821          GetLastError() == ERROR_ACCESS_DENIED), /* win2k3 */
822          "Expected ERROR_INVALID_DATA or ERROR_ACCESS_DENIED, got %08x\n", GetLastError());
823         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
824          DIREG_DRV, KEY_READ);
825         ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n",
826          GetLastError());
827         ret = pSetupDiCallClassInstaller(DIF_REMOVE, set, &devInfo);
828         pSetupDiDestroyDeviceInfoList(set);
829     }
830     devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
831 }
832
833 static void testRegisterAndGetDetail(void)
834 {
835     HDEVINFO set;
836     BOOL ret;
837     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
838         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
839     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
840     SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } };
841     DWORD dwSize = 0;
842
843     SetLastError(0xdeadbeef);
844     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES);
845     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
846      GetLastError());
847
848     SetLastError(0xdeadbeef);
849     ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, 0,
850      DICD_GENERATE_ID, &devInfo);
851     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
852     SetLastError(0xdeadbeef);
853     ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, &interfaceData);
854     ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
855     SetLastError(0xdeadbeef);
856     ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
857     ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
858
859     pSetupDiDestroyDeviceInfoList(set);
860
861     SetLastError(0xdeadbeef);
862     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
863     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
864      GetLastError());
865
866     SetLastError(0xdeadbeef);
867     ret = pSetupDiEnumDeviceInterfaces(set, NULL, &guid, 0, &interfaceData);
868     ok(ret, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
869     SetLastError(0xdeadbeef);
870     ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, 0, &dwSize, NULL);
871     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
872      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
873     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
874     {
875         static const char path[] =
876             "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
877         PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL;
878
879         detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)HeapAlloc(GetProcessHeap(), 0, dwSize);
880         if (detail)
881         {
882             detail->cbSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char);
883             SetLastError(0xdeadbeef);
884             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData,
885              detail, dwSize, &dwSize, NULL);
886             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError());
887             ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n",
888                     detail->DevicePath);
889             HeapFree(GetProcessHeap(), 0, detail);
890         }
891     }
892
893     pSetupDiDestroyDeviceInfoList(set);
894 }
895
896 static void testDeviceRegistryPropertyA()
897 {
898     HDEVINFO set;
899     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
900         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
901     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
902     CHAR devName[] = "LEGACY_BOGUS";
903     CHAR friendlyName[] = "Bogus";
904     CHAR buf[6] = "";
905     DWORD buflen = 6;
906     DWORD size;
907     DWORD regType;
908     BOOL ret;
909
910     SetLastError(0xdeadbeef);
911     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
912     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
913      GetLastError());
914     SetLastError(0xdeadbeef);
915     ret = pSetupDiCreateDeviceInfoA(set, devName, &guid, NULL, NULL,
916      DICD_GENERATE_ID, &devInfo);
917     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
918     SetLastError(0xdeadbeef);
919     ret = pSetupDiSetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, 0);
920     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
921      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
922     SetLastError(0xdeadbeef);
923     ret = pSetupDiSetDeviceRegistryPropertyA(set, NULL, -1, NULL, 0);
924     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
925      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
926     SetLastError(0xdeadbeef);
927     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, 0);
928     todo_wine
929     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
930      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
931     /* GetLastError() returns nonsense in win2k3 */
932     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
933      NULL, 0);
934     todo_wine
935     ok(!ret, "Expected failure, got %d\n", ret);
936     SetLastError(0xdeadbeef);
937     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
938      (PBYTE)friendlyName, buflen);
939     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
940     SetLastError(0xdeadbeef);
941     ret = pSetupDiGetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, NULL, 0, NULL);
942     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
943      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
944     SetLastError(0xdeadbeef);
945     ret = pSetupDiGetDeviceRegistryPropertyA(set, NULL, -1, NULL, NULL, 0, NULL);
946     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
947      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
948     SetLastError(0xdeadbeef);
949     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, NULL, 0, NULL);
950     todo_wine
951     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
952      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
953     /* GetLastError() returns nonsense in win2k3 */
954     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
955      NULL, NULL, buflen, NULL);
956     ok(!ret, "Expected failure, got %d\n", ret);
957     SetLastError(0xdeadbeef);
958     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
959      NULL, NULL, 0, &size);
960     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
961      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
962     ok(buflen == size, "Unexpected size: %d\n", size);
963     SetLastError(0xdeadbeef);
964     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
965      NULL, (PBYTE)buf, buflen, NULL);
966     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
967     ok(!lstrcmpiA(friendlyName, buf), "Unexpected property\n");
968     SetLastError(0xdeadbeef);
969     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
970      &regType, (PBYTE)buf, buflen, NULL);
971     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
972     ok(!lstrcmpiA(friendlyName, buf), "Unexpected value of property\n");
973     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
974     SetLastError(0xdeadbeef);
975     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
976      NULL, 0);
977     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
978     SetLastError(0xdeadbeef);
979     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
980      NULL, (PBYTE)buf, buflen, &size);
981     todo_wine
982     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
983      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
984     pSetupDiDestroyDeviceInfoList(set);
985 }
986
987 static void testDeviceRegistryPropertyW()
988 {
989     HDEVINFO set;
990     GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,
991         0x00,0x11,0x95,0x5c,0x2b,0xdb}};
992     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
993     WCHAR devName[] = {'L','E','G','A','C','Y','_','B','O','G','U','S',0};
994     WCHAR friendlyName[] = {'B','o','g','u','s',0};
995     WCHAR buf[6] = {0};
996     DWORD buflen = 6 * sizeof(WCHAR);
997     DWORD size;
998     DWORD regType;
999     BOOL ret;
1000
1001     SetLastError(0xdeadbeef);
1002     set = pSetupDiGetClassDevsW(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1003     if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1004     {
1005         skip("W-functions are not implemented\n");
1006         return;
1007     }
1008     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %08x\n",
1009      GetLastError());
1010     SetLastError(0xdeadbeef);
1011     ret = pSetupDiCreateDeviceInfoW(set, devName, &guid, NULL, NULL,
1012      DICD_GENERATE_ID, &devInfo);
1013     ok(ret, "SetupDiCreateDeviceInfoW failed: %08x\n", GetLastError());
1014     SetLastError(0xdeadbeef);
1015     ret = pSetupDiSetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, 0);
1016     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1017      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1018     SetLastError(0xdeadbeef);
1019     ret = pSetupDiSetDeviceRegistryPropertyW(set, NULL, -1, NULL, 0);
1020     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1021      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1022     SetLastError(0xdeadbeef);
1023     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, 0);
1024     todo_wine
1025     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1026      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1027     /* GetLastError() returns nonsense in win2k3 */
1028     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1029      NULL, 0);
1030     todo_wine
1031     ok(!ret, "Expected failure, got %d\n", ret);
1032     SetLastError(0xdeadbeef);
1033     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1034      (PBYTE)friendlyName, buflen);
1035     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1036     SetLastError(0xdeadbeef);
1037     ret = pSetupDiGetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, NULL, 0, NULL);
1038     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1039      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1040     SetLastError(0xdeadbeef);
1041     ret = pSetupDiGetDeviceRegistryPropertyW(set, NULL, -1, NULL, NULL, 0, NULL);
1042     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1043      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1044     SetLastError(0xdeadbeef);
1045     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, NULL, 0, NULL);
1046     todo_wine
1047     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1048      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1049     /* GetLastError() returns nonsense in win2k3 */
1050     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1051      NULL, NULL, buflen, NULL);
1052     ok(!ret, "Expected failure, got %d\n", ret);
1053     SetLastError(0xdeadbeef);
1054     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1055      NULL, NULL, 0, &size);
1056     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1057      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1058     ok(buflen == size, "Unexpected size: %d\n", size);
1059     SetLastError(0xdeadbeef);
1060     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1061      NULL, (PBYTE)buf, buflen, NULL);
1062     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1063     ok(!lstrcmpiW(friendlyName, buf), "Unexpected property\n");
1064     SetLastError(0xdeadbeef);
1065     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1066      &regType, (PBYTE)buf, buflen, NULL);
1067     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1068     ok(!lstrcmpiW(friendlyName, buf), "Unexpected value of property\n");
1069     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1070     SetLastError(0xdeadbeef);
1071     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1072      NULL, 0);
1073     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1074     SetLastError(0xdeadbeef);
1075     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1076      NULL, (PBYTE)buf, buflen, &size);
1077     todo_wine
1078     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1079      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1080     pSetupDiDestroyDeviceInfoList(set);
1081 }
1082
1083 START_TEST(devinst)
1084 {
1085     init_function_pointers();
1086
1087     if (pSetupDiCreateDeviceInfoListExW && pSetupDiDestroyDeviceInfoList)
1088         test_SetupDiCreateDeviceInfoListEx();
1089     else
1090         skip("SetupDiCreateDeviceInfoListExW and/or SetupDiDestroyDeviceInfoList not available\n");
1091
1092     if (pSetupDiOpenClassRegKeyExA)
1093         test_SetupDiOpenClassRegKeyExA();
1094     else
1095         skip("SetupDiOpenClassRegKeyExA is not available\n");
1096     testInstallClass();
1097     testCreateDeviceInfo();
1098     testGetDeviceInstanceId();
1099     testRegisterDeviceInfo();
1100     testCreateDeviceInterface();
1101     testGetDeviceInterfaceDetail();
1102     testDevRegKey();
1103     testRegisterAndGetDetail();
1104     testDeviceRegistryPropertyA();
1105     testDeviceRegistryPropertyW();
1106 }