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