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