setupapi/tests: Add tests to show that SetupIterateCabinet handles callback exception...
[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 /* This is a unique guid for testing purposes */
61 static GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c,0x2b,0xdb}};
62
63 static void init_function_pointers(void)
64 {
65     hSetupAPI = GetModuleHandleA("setupapi.dll");
66
67     pSetupDiCreateDeviceInfoA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoA");
68     pSetupDiCreateDeviceInfoW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoW");
69     pSetupDiCreateDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoList");
70     pSetupDiCreateDeviceInfoListExW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInfoListExW");
71     pSetupDiCreateDeviceInterfaceA = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDeviceInterfaceA");
72     pSetupDiDestroyDeviceInfoList = (void *)GetProcAddress(hSetupAPI, "SetupDiDestroyDeviceInfoList");
73     pSetupDiCallClassInstaller = (void *)GetProcAddress(hSetupAPI, "SetupDiCallClassInstaller");
74     pSetupDiEnumDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInfo");
75     pSetupDiEnumDeviceInterfaces = (void *)GetProcAddress(hSetupAPI, "SetupDiEnumDeviceInterfaces");
76     pSetupDiGetDeviceInstanceIdA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInstanceIdA");
77     pSetupDiGetDeviceInterfaceDetailA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailA");
78     pSetupDiGetDeviceInterfaceDetailW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceInterfaceDetailW");
79     pSetupDiInstallClassA = (void *)GetProcAddress(hSetupAPI, "SetupDiInstallClassA");
80     pSetupDiOpenClassRegKeyExA = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenClassRegKeyExA");
81     pSetupDiOpenDevRegKey = (void *)GetProcAddress(hSetupAPI, "SetupDiOpenDevRegKey");
82     pSetupDiCreateDevRegKeyW = (void *)GetProcAddress(hSetupAPI, "SetupDiCreateDevRegKeyW");
83     pSetupDiRegisterDeviceInfo = (void *)GetProcAddress(hSetupAPI, "SetupDiRegisterDeviceInfo");
84     pSetupDiGetClassDevsA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsA");
85     pSetupDiGetClassDevsW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetClassDevsW");
86     pSetupDiSetDeviceRegistryPropertyA = (void *)GetProcAddress(hSetupAPI, "SetupDiSetDeviceRegistryPropertyA");
87     pSetupDiSetDeviceRegistryPropertyW = (void *)GetProcAddress(hSetupAPI, "SetupDiSetDeviceRegistryPropertyW");
88     pSetupDiGetDeviceRegistryPropertyA = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceRegistryPropertyA");
89     pSetupDiGetDeviceRegistryPropertyW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceRegistryPropertyW");
90 }
91
92 static void change_reg_permissions(const WCHAR *regkey)
93 {
94     HKEY hkey;
95     SID_IDENTIFIER_AUTHORITY ident = { SECURITY_WORLD_SID_AUTHORITY };
96     SECURITY_DESCRIPTOR sd;
97     PSID EveryoneSid;
98     PACL pacl = NULL;
99
100     RegOpenKeyExW(HKEY_LOCAL_MACHINE, regkey, 0, WRITE_DAC, &hkey);
101
102     /* Initialize the 'Everyone' sid */
103     AllocateAndInitializeSid(&ident, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &EveryoneSid);
104
105     pacl = HeapAlloc(GetProcessHeap(), 0, 256);
106     InitializeAcl(pacl, 256, ACL_REVISION);
107
108     /* Add 'Full Control' for 'Everyone' */
109     AddAccessAllowedAce(pacl, ACL_REVISION, KEY_ALL_ACCESS, EveryoneSid);
110
111     InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
112
113     SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE);
114
115     /* Set the new security on the registry key */
116     RegSetKeySecurity(hkey, DACL_SECURITY_INFORMATION, &sd);
117
118     RegCloseKey(hkey);
119
120     HeapFree(GetProcessHeap(), 0, pacl);
121     if (EveryoneSid)
122         FreeSid(EveryoneSid);
123 }
124
125 static BOOL remove_device(void)
126 {
127     HDEVINFO set;
128     SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
129     BOOL ret;
130
131     SetLastError(0xdeadbeef);
132     set = pSetupDiGetClassDevsA(&guid, NULL, 0, 0);
133     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
134      GetLastError());
135
136     SetLastError(0xdeadbeef);
137     ok(pSetupDiEnumDeviceInfo(set, 0, &devInfo),
138      "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
139
140     SetLastError(0xdeadbeef);
141     ret = pSetupDiCallClassInstaller(DIF_REMOVE, set, &devInfo);
142     todo_wine
143     ok(ret, "SetupDiCallClassInstaller(DIF_REMOVE...) failed: %08x\n", GetLastError());
144
145     SetLastError(0xdeadbeef);
146     ok(pSetupDiDestroyDeviceInfoList(set),
147      "SetupDiDestroyDeviceInfoList failed: %08x\n", GetLastError());
148
149     return ret;
150 }
151
152 /* RegDeleteTreeW from dlls/advapi32/registry.c */
153 static LSTATUS devinst_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
154 {
155     LONG ret;
156     DWORD dwMaxSubkeyLen, dwMaxValueLen;
157     DWORD dwMaxLen, dwSize;
158     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
159     HKEY hSubKey = hKey;
160
161     if(lpszSubKey)
162     {
163         ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
164         if (ret) return ret;
165     }
166
167     /* Get highest length for keys, values */
168     ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
169             &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
170     if (ret) goto cleanup;
171
172     dwMaxSubkeyLen++;
173     dwMaxValueLen++;
174     dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
175     if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
176     {
177         /* Name too big: alloc a buffer for it */
178         if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
179         {
180             ret = ERROR_NOT_ENOUGH_MEMORY;
181             goto cleanup;
182         }
183     }
184
185
186     /* Recursively delete all the subkeys */
187     while (TRUE)
188     {
189         dwSize = dwMaxLen;
190         if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
191                           NULL, NULL, NULL)) break;
192
193         ret = devinst_RegDeleteTreeW(hSubKey, lpszName);
194         if (ret) goto cleanup;
195     }
196
197     if (lpszSubKey)
198         ret = RegDeleteKeyW(hKey, lpszSubKey);
199     else
200         while (TRUE)
201         {
202             dwSize = dwMaxLen;
203             if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
204                   NULL, NULL, NULL, NULL)) break;
205
206             ret = RegDeleteValueW(hKey, lpszName);
207             if (ret) goto cleanup;
208         }
209
210 cleanup:
211     /* Free buffer if allocated */
212     if (lpszName != szNameBuf)
213         HeapFree( GetProcessHeap(), 0, lpszName);
214     if(lpszSubKey)
215         RegCloseKey(hSubKey);
216     return ret;
217 }
218
219 static void clean_devclass_key(void)
220 {
221     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
222      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
223      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
224      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
225      '1','1','d','b','-','b','7','0','4','-',
226      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
227     HKEY key;
228     DWORD subkeys;
229
230     /* Check if we have subkeys as Windows 2000 doesn't delete
231      * the keys under the DeviceClasses key after a SetupDiDestroyDeviceInfoList.
232      */
233     RegOpenKeyW(HKEY_LOCAL_MACHINE, devclass, &key);
234     RegQueryInfoKey(key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
235     if (subkeys > 0)
236     {
237         trace("We are most likely on Windows 2000\n");
238         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
239     }
240     else
241     {
242         ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, devclass),
243          "Couldn't delete deviceclass key\n");
244     }
245 }
246
247 static void test_SetupDiCreateDeviceInfoListEx(void) 
248 {
249     HDEVINFO devlist;
250     BOOL ret;
251     DWORD error;
252     static CHAR notnull[] = "NotNull";
253     static const WCHAR machine[] = { 'd','u','m','m','y',0 };
254
255     SetLastError(0xdeadbeef);
256     /* create empty DeviceInfoList, but set Reserved to a value, which is not NULL */
257     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, notnull);
258
259     error = GetLastError();
260     if (error == ERROR_CALL_NOT_IMPLEMENTED)
261     {
262         win_skip("SetupDiCreateDeviceInfoListExW is not implemented\n");
263         return;
264     }
265     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
266     ok(error == ERROR_INVALID_PARAMETER, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_PARAMETER);
267
268     SetLastError(0xdeadbeef);
269     /* create empty DeviceInfoList, but set MachineName to something */
270     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, machine, NULL);
271
272     error = GetLastError();
273     ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE);
274     ok(error == ERROR_INVALID_MACHINENAME || error == ERROR_MACHINE_UNAVAILABLE, "GetLastError returned wrong value : %d, (expected %d or %d)\n", error, ERROR_INVALID_MACHINENAME, ERROR_MACHINE_UNAVAILABLE);
275
276     /* create empty DeviceInfoList */
277     devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
278     ok(devlist && devlist != INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected != %p)\n", devlist, error, INVALID_HANDLE_VALUE);
279
280     /* destroy DeviceInfoList */
281     ret = pSetupDiDestroyDeviceInfoList(devlist);
282     ok(ret, "SetupDiDestroyDeviceInfoList failed : %d\n", error);
283 }
284
285 static void test_SetupDiOpenClassRegKeyExA(void)
286 {
287     static const CHAR guidString[] = "{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
288     HKEY hkey;
289
290     /* Check return value for nonexistent key */
291     hkey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
292         DIOCR_INSTALLER, NULL, NULL);
293     ok(hkey == INVALID_HANDLE_VALUE,
294         "returned %p (expected INVALID_HANDLE_VALUE)\n", hkey);
295
296     /* Test it for a key that exists */
297     hkey = SetupDiOpenClassRegKey(NULL, KEY_ALL_ACCESS);
298     if (hkey != INVALID_HANDLE_VALUE)
299     {
300         HKEY classKey;
301         if (RegCreateKeyA(hkey, guidString, &classKey) == ERROR_SUCCESS)
302         {
303             RegCloseKey(classKey);
304             SetLastError(0xdeadbeef);
305             classKey = pSetupDiOpenClassRegKeyExA(&guid, KEY_ALL_ACCESS,
306                 DIOCR_INSTALLER, NULL, NULL);
307             ok(classKey != INVALID_HANDLE_VALUE,
308                 "opening class registry key failed with error %d\n",
309                 GetLastError());
310             if (classKey != INVALID_HANDLE_VALUE)
311                 RegCloseKey(classKey);
312             RegDeleteKeyA(hkey, guidString);
313         }
314         else
315             trace("failed to create registry key for test\n");
316
317         RegCloseKey(hkey);
318     }
319     else
320         trace("failed to open classes key\n");
321 }
322
323 static void create_inf_file(LPCSTR filename)
324 {
325     DWORD dwNumberOfBytesWritten;
326     HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
327                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
328
329     static const char data[] =
330         "[Version]\n"
331         "Signature=\"$Chicago$\"\n"
332         "Class=Bogus\n"
333         "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n"
334         "[ClassInstall32]\n"
335         "AddReg=BogusClass.NT.AddReg\n"
336         "[BogusClass.NT.AddReg]\n"
337         "HKR,,,,\"Wine test devices\"\n";
338
339     WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL);
340     CloseHandle(hf);
341 }
342
343 static void get_temp_filename(LPSTR path)
344 {
345     static char curr[MAX_PATH] = { 0 };
346     char temp[MAX_PATH];
347     LPSTR ptr;
348
349     if (!*curr)
350         GetCurrentDirectoryA(MAX_PATH, curr);
351     GetTempFileNameA(curr, "set", 0, temp);
352     ptr = strrchr(temp, '\\');
353
354     lstrcpyA(path, ptr + 1);
355 }
356
357 static void testInstallClass(void)
358 {
359     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
360      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
361      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
362      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
363      '1','1','d','b','-','b','7','0','4','-',
364      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
365     char tmpfile[MAX_PATH];
366     BOOL ret;
367
368     tmpfile[0] = '.';
369     tmpfile[1] = '\\';
370     get_temp_filename(tmpfile + 2);
371     create_inf_file(tmpfile + 2);
372
373     ret = pSetupDiInstallClassA(NULL, NULL, 0, NULL);
374     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
375      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
376     ret = pSetupDiInstallClassA(NULL, NULL, DI_NOVCP, NULL);
377     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
378      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
379     ret = pSetupDiInstallClassA(NULL, tmpfile + 2, DI_NOVCP, NULL);
380     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
381      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
382     ret = pSetupDiInstallClassA(NULL, tmpfile + 2, 0, NULL);
383     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
384      "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
385     /* The next call will succeed. Information is put into the registry but the
386      * location(s) is/are depending on the Windows version.
387      */
388     ret = pSetupDiInstallClassA(NULL, tmpfile, 0, NULL);
389     ok(ret, "SetupDiInstallClassA failed: %08x\n", GetLastError());
390
391     ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey),
392      "Couldn't delete classkey\n");
393
394     DeleteFile(tmpfile);
395 }
396
397 static void testCreateDeviceInfo(void)
398 {
399     BOOL ret;
400     HDEVINFO set;
401     HKEY key;
402     LONG res;
403     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
404      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
405      'E','n','u','m','\\','R','o','o','t','\\',
406      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
407
408     SetLastError(0xdeadbeef);
409     ret = pSetupDiCreateDeviceInfoA(NULL, NULL, NULL, NULL, NULL, 0, NULL);
410     ok(!ret, "Expected failure\n");
411     ok(GetLastError() == ERROR_INVALID_DEVINST_NAME ||
412       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
413      "Unexpected last error, got %08x\n", GetLastError());
414
415     SetLastError(0xdeadbeef);
416     ret = pSetupDiCreateDeviceInfoA(NULL, "Root\\LEGACY_BOGUS\\0000", NULL,
417      NULL, NULL, 0, NULL);
418     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
419      "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError());
420     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
421     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
422      GetLastError());
423     if (set)
424     {
425         SP_DEVINFO_DATA devInfo = { 0 };
426         DWORD i;
427         static GUID deadbeef =
428          {0xdeadbeef, 0xdead, 0xbeef, {0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
429         LONG res;
430         HKEY key;
431         static const WCHAR bogus0000[] = {'S','y','s','t','e','m','\\',
432          'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
433          'E','n','u','m','\\','R','o','o','t','\\',
434          'L','E','G','A','C','Y','_','B','O','G','U','S','\\','0','0','0','0',0};
435
436         /* So we know we have a clean start */
437         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus0000, &key);
438         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
439         /* No GUID given */
440         SetLastError(0xdeadbeef);
441         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", NULL,
442          NULL, NULL, 0, NULL);
443         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
444             "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
445         /* Even though NT4 fails it still adds some stuff to the registry that
446          * can't be deleted via normal setupapi functions. As the registry is written
447          * by a different user (SYSTEM) we have to do some magic to get rid of the key
448          */
449         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus0000, &key))
450         {
451             trace("NT4 created a bogus key on failure, will be removed now\n");
452             change_reg_permissions(bogus0000);
453             ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus0000),
454              "Could not delete LEGACY_BOGUS\\0000 key\n");
455         }
456         /* We can't add device information to the set with a different GUID */
457         SetLastError(0xdeadbeef);
458         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000",
459          &deadbeef, NULL, NULL, 0, NULL);
460         ok(!ret && GetLastError() == ERROR_CLASS_MISMATCH,
461          "Expected ERROR_CLASS_MISMATCH, got %08x\n", GetLastError());
462         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus0000, &key))
463         {
464             trace("NT4 created a bogus key on failure, will be removed now\n");
465             change_reg_permissions(bogus0000);
466             ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus0000),
467              "Could not delete LEGACY_BOGUS\\0000 key\n");
468         }
469         /* Finally, with all three required parameters, this succeeds: */
470         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
471          NULL, NULL, 0, NULL);
472         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
473         /* This fails because the device ID already exists.. */
474         SetLastError(0xdeadbeef);
475         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
476          NULL, NULL, 0, &devInfo);
477         ok(!ret && GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
478          "Expected ERROR_DEVINST_ALREADY_EXISTS, got %08x\n", GetLastError());
479         /* whereas this "fails" because cbSize is wrong.. */
480         SetLastError(0xdeadbeef);
481         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
482          DICD_GENERATE_ID, &devInfo);
483         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
484          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
485         /* and this finally succeeds. */
486         devInfo.cbSize = sizeof(devInfo);
487         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL,
488          DICD_GENERATE_ID, &devInfo);
489         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
490         /* There were three devices added, however - the second failure just
491          * resulted in the SP_DEVINFO_DATA not getting copied.
492          */
493         SetLastError(0xdeadbeef);
494         i = 0;
495         while (pSetupDiEnumDeviceInfo(set, i, &devInfo))
496             i++;
497         ok(i == 3, "Expected 3 devices, got %d\n", i);
498         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
499          "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError());
500         pSetupDiDestroyDeviceInfoList(set);
501     }
502
503     /* The bogus registry key shouldn't be there after this test. The only
504      * reasons this key would still be present:
505      *
506      * - We are running on Wine which has to be fixed
507      * - We have leftovers from old tests
508      */
509     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
510     todo_wine
511     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
512     if (res == ERROR_SUCCESS)
513     {
514         DWORD subkeys;
515
516         /* Check if we have subkeys */
517         RegQueryInfoKey(key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
518         if (subkeys > 0)
519         {
520             int i;
521
522             /* Leftovers from old tests */
523             trace("Going to remove %d devices\n", subkeys);
524             for (i = 0; i < subkeys; i++)
525             {
526                 BOOL ret;
527
528                 ret = remove_device();
529                 ok(ret, "Expected a device to be removed\n");
530             }
531         }
532         else
533         {
534             /* Wine doesn't delete the bogus key itself currently */
535             trace("We are most likely on Wine\n");
536             RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus);
537         }
538     }
539 }
540
541 static void testGetDeviceInstanceId(void)
542 {
543     BOOL ret;
544     HDEVINFO set;
545     SP_DEVINFO_DATA devInfo = { 0 };
546
547     SetLastError(0xdeadbeef);
548     ret = pSetupDiGetDeviceInstanceIdA(NULL, NULL, NULL, 0, NULL);
549     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
550      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
551     SetLastError(0xdeadbeef);
552     ret = pSetupDiGetDeviceInstanceIdA(NULL, &devInfo, NULL, 0, NULL);
553     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
554      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
555     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
556     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n",
557      GetLastError());
558     if (set)
559     {
560         char instanceID[MAX_PATH];
561         DWORD size;
562
563         SetLastError(0xdeadbeef);
564         ret = pSetupDiGetDeviceInstanceIdA(set, NULL, NULL, 0, NULL);
565         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
566          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
567         SetLastError(0xdeadbeef);
568         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, NULL);
569         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
570          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
571         SetLastError(0xdeadbeef);
572         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
573         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
574          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
575         devInfo.cbSize = sizeof(devInfo);
576         SetLastError(0xdeadbeef);
577         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
578         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
579          "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
580         ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid,
581          NULL, NULL, 0, &devInfo);
582         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
583         SetLastError(0xdeadbeef);
584         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, NULL, 0, &size);
585         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
586          "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
587         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
588          sizeof(instanceID), NULL);
589         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
590         ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0000"),
591          "Unexpected instance ID %s\n", instanceID);
592         ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid,
593          NULL, NULL, DICD_GENERATE_ID, &devInfo);
594         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
595         ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID,
596          sizeof(instanceID), NULL);
597         ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError());
598         /* NT4 returns 'Root' and W2K and above 'ROOT' */
599         ok(!lstrcmpiA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"),
600          "Unexpected instance ID %s\n", instanceID);
601         pSetupDiDestroyDeviceInfoList(set);
602     }
603 }
604
605 static void testRegisterDeviceInfo(void)
606 {
607     BOOL ret;
608     HDEVINFO set;
609
610     SetLastError(0xdeadbeef);
611     ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL);
612     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
613      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
614     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
615     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
616     if (set)
617     {
618         SP_DEVINFO_DATA devInfo = { 0 };
619
620         SetLastError(0xdeadbeef);
621         ret = pSetupDiRegisterDeviceInfo(set, NULL, 0, NULL, NULL, NULL);
622         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
623          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
624         SetLastError(0xdeadbeef);
625         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
626         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
627          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
628         devInfo.cbSize = sizeof(devInfo);
629         SetLastError(0xdeadbeef);
630         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
631         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
632          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
633         ret = pSetupDiCreateDeviceInfoA(set, "USB\\BOGUS\\0000", &guid,
634          NULL, NULL, 0, &devInfo);
635         ok(ret || GetLastError() == ERROR_DEVINST_ALREADY_EXISTS,
636                 "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
637         if (ret)
638         {
639             /* If it already existed, registering it again will fail */
640             ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL,
641              NULL);
642             ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError());
643         }
644         /* FIXME: On Win2K+ systems, this is now persisted to registry in
645          * HKLM\System\CCS\Enum\USB\Bogus\0000.
646          * FIXME: the key also becomes undeletable.  How to get rid of it?
647          */
648         pSetupDiDestroyDeviceInfoList(set);
649     }
650 }
651
652 static void testCreateDeviceInterface(void)
653 {
654     BOOL ret;
655     HDEVINFO set;
656     HKEY key;
657     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
658      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
659      'E','n','u','m','\\','R','o','o','t','\\',
660      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
661     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
662      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
663      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
664      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
665      '1','1','d','b','-','b','7','0','4','-',
666      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
667
668     if (!pSetupDiCreateDeviceInterfaceA || !pSetupDiEnumDeviceInterfaces)
669     {
670         win_skip("SetupDiCreateDeviceInterfaceA and/or SetupDiEnumDeviceInterfaces are not available\n");
671         return;
672     }
673     SetLastError(0xdeadbeef);
674     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, NULL, NULL, 0, NULL);
675     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
676      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
677     SetLastError(0xdeadbeef);
678     ret = pSetupDiCreateDeviceInterfaceA(NULL, NULL, &guid, NULL, 0, NULL);
679     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
680      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
681     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
682     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
683     if (set)
684     {
685         SP_DEVINFO_DATA devInfo = { 0 };
686         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
687             { 0 } };
688         DWORD i;
689
690         SetLastError(0xdeadbeef);
691         ret = pSetupDiCreateDeviceInterfaceA(set, NULL, NULL, NULL, 0, NULL);
692         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
693          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
694         SetLastError(0xdeadbeef);
695         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
696                 NULL);
697         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
698          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
699         devInfo.cbSize = sizeof(devInfo);
700         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
701                 NULL, NULL, 0, &devInfo);
702         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
703         SetLastError(0xdeadbeef);
704         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, NULL, NULL, 0,
705                 NULL);
706         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
707          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
708         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
709                 NULL);
710         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
711         /* Creating the same interface a second time succeeds */
712         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
713                 NULL);
714         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
715         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, "Oogah", 0,
716                 NULL);
717         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
718         ret = pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, 0,
719                 &interfaceData);
720         ok(ret, "SetupDiEnumDeviceInterfaces failed: %d\n", GetLastError());
721         i = 0;
722         while (pSetupDiEnumDeviceInterfaces(set, &devInfo, &guid, i,
723                     &interfaceData))
724             i++;
725         ok(i == 2, "expected 2 interfaces, got %d\n", i);
726         ok(GetLastError() == ERROR_NO_MORE_ITEMS,
727          "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
728         ret = pSetupDiDestroyDeviceInfoList(set);
729         ok(ret, "SetupDiDestroyDeviceInfoList failed: %08x\n", GetLastError());
730
731         /* Cleanup */
732         /* FIXME: On Wine we still have the bogus entry in Enum\Root and
733          * subkeys, as well as the deviceclass key with subkeys.
734          * Only clean the deviceclass key once Wine if fixed.
735          */
736         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key))
737         {
738             /* Wine doesn't delete the information currently */
739             trace("We are most likely on Wine\n");
740             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
741             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
742         }
743         else
744         {
745             clean_devclass_key();
746         }
747     }
748 }
749
750 static void testGetDeviceInterfaceDetail(void)
751 {
752     BOOL ret;
753     HDEVINFO set;
754     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
755      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
756      'E','n','u','m','\\','R','o','o','t','\\',
757      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
758     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
759      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
760      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
761      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
762      '1','1','d','b','-','b','7','0','4','-',
763      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
764
765     if (!pSetupDiCreateDeviceInterfaceA || !pSetupDiGetDeviceInterfaceDetailA)
766     {
767         win_skip("SetupDiCreateDeviceInterfaceA and/or SetupDiGetDeviceInterfaceDetailA are not available\n");
768         return;
769     }
770     SetLastError(0xdeadbeef);
771     ret = pSetupDiGetDeviceInterfaceDetailA(NULL, NULL, NULL, 0, NULL, NULL);
772     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
773      "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
774     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
775     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
776     if (set)
777     {
778         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
779         SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData),
780             { 0 } };
781         DWORD size = 0;
782         HKEY key;
783
784         SetLastError(0xdeadbeef);
785         ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL,
786                 NULL);
787         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
788          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
789         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
790                 NULL, NULL, 0, &devInfo);
791         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
792         SetLastError(0xdeadbeef);
793         ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0,
794                 &interfaceData);
795         ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
796         SetLastError(0xdeadbeef);
797         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
798                 0, NULL, NULL);
799         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
800          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
801         SetLastError(0xdeadbeef);
802         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
803                 100, NULL, NULL);
804         ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
805          "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
806         SetLastError(0xdeadbeef);
807         ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL,
808                 0, &size, NULL);
809         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
810          "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
811         if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
812         {
813             static const char path[] =
814              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
815             static const char path_w2k[] =
816              "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\";
817             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
818             SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail =
819                 (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf;
820             DWORD expectedsize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path));
821
822             detail->cbSize = 0;
823             SetLastError(0xdeadbeef);
824             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
825                     size, &size, NULL);
826             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
827              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
828             detail->cbSize = size;
829             SetLastError(0xdeadbeef);
830             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
831                     size, &size, NULL);
832             ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER,
833              "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError());
834             detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
835             SetLastError(0xdeadbeef);
836             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail,
837                     size, &size, NULL);
838             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n",
839                     GetLastError());
840             ok(!lstrcmpiA(path, detail->DevicePath) ||
841              !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n",
842              detail->DevicePath);
843             /* Check SetupDiGetDeviceInterfaceDetailW */
844             ret = pSetupDiGetDeviceInterfaceDetailW(set, &interfaceData, NULL, 0, &size, NULL);
845             ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
846              "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError());
847             ok(expectedsize == size ||
848              (expectedsize + sizeof(WCHAR)) == size /* W2K adds a backslash */,
849              "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize, got %d\n",
850              size);
851
852             HeapFree(GetProcessHeap(), 0, buf);
853         }
854         pSetupDiDestroyDeviceInfoList(set);
855
856         /* Cleanup */
857         /* FIXME: On Wine we still have the bogus entry in Enum\Root and
858          * subkeys, as well as the deviceclass key with subkeys.
859          * Only do the RegDeleteKey, once Wine is fixed.
860          */
861         if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key))
862         {
863             /* Wine doesn't delete the information currently */
864             trace("We are most likely on Wine\n");
865             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
866             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
867         }
868         else
869         {
870             clean_devclass_key();
871         }
872     }
873 }
874
875 static void testDevRegKey(void)
876 {
877     static const WCHAR classKey[] = {'S','y','s','t','e','m','\\',
878      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
879      'C','o','n','t','r','o','l','\\','C','l','a','s','s','\\',
880      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
881      '1','1','d','b','-','b','7','0','4','-',
882      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
883     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
884      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
885      'E','n','u','m','\\','R','o','o','t','\\',
886      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
887     BOOL ret;
888     HDEVINFO set;
889     HKEY key = NULL;
890     BOOL classKeyCreated;
891
892     SetLastError(0xdeadbeef);
893     key = pSetupDiCreateDevRegKeyW(NULL, NULL, 0, 0, 0, NULL, NULL);
894     ok(key == INVALID_HANDLE_VALUE,
895      "Expected INVALID_HANDLE_VALUE, got %p\n", key);
896     ok(GetLastError() == ERROR_INVALID_HANDLE,
897      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
898
899     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
900     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
901     if (set)
902     {
903         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
904         LONG res;
905
906         /* The device info key shouldn't be there */
907         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
908         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
909         RegCloseKey(key);
910         /* Create the device information */
911         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
912                 NULL, NULL, 0, &devInfo);
913         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
914         /* The device info key should have been created */
915         ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key),
916          "Expected registry key to exist\n");
917         RegCloseKey(key);
918         SetLastError(0xdeadbeef);
919         key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
920         ok(!key || key == INVALID_HANDLE_VALUE,
921          "Expected INVALID_HANDLE_VALUE or a NULL key (NT4)\n");
922         ok(GetLastError() == ERROR_INVALID_HANDLE,
923          "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
924         SetLastError(0xdeadbeef);
925         key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
926         ok(key == INVALID_HANDLE_VALUE &&
927          GetLastError() == ERROR_INVALID_PARAMETER,
928          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
929         SetLastError(0xdeadbeef);
930         key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0);
931         ok(key == INVALID_HANDLE_VALUE &&
932          GetLastError() == ERROR_INVALID_FLAGS,
933          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
934         SetLastError(0xdeadbeef);
935         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0);
936         ok(key == INVALID_HANDLE_VALUE &&
937          GetLastError() == ERROR_INVALID_FLAGS,
938          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
939         SetLastError(0xdeadbeef);
940         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
941          DIREG_BOTH, 0);
942         ok(key == INVALID_HANDLE_VALUE &&
943          GetLastError() == ERROR_INVALID_FLAGS,
944          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
945         SetLastError(0xdeadbeef);
946         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
947          DIREG_DRV, 0);
948         ok(key == INVALID_HANDLE_VALUE &&
949          GetLastError() == ERROR_DEVINFO_NOT_REGISTERED,
950          "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError());
951         SetLastError(0xdeadbeef);
952         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
953         ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
954         SetLastError(0xdeadbeef);
955         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
956          DIREG_DRV, 0);
957         /* The software key isn't created by default */
958         todo_wine
959         ok(key == INVALID_HANDLE_VALUE &&
960          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
961          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
962         SetLastError(0xdeadbeef);
963         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
964          DIREG_DEV, 0);
965         todo_wine
966         ok(key == INVALID_HANDLE_VALUE &&
967          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
968          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
969         SetLastError(0xdeadbeef);
970         /* The class key shouldn't be there */
971         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key);
972         todo_wine
973         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
974         RegCloseKey(key);
975         /* Create the device reg key */
976         key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0,
977          DIREG_DRV, NULL, NULL);
978         /* Vista and higher don't actually create the key */
979         ok(key != INVALID_HANDLE_VALUE || GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
980          "SetupDiCreateDevRegKey failed: %08x\n", GetLastError());
981         if (key != INVALID_HANDLE_VALUE)
982         {
983             classKeyCreated = TRUE;
984             RegCloseKey(key);
985             /* The class key should have been created */
986             ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key),
987              "Expected registry key to exist\n");
988             RegCloseKey(key);
989             SetLastError(0xdeadbeef);
990             key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
991              DIREG_DRV, 0);
992             todo_wine
993             ok(key == INVALID_HANDLE_VALUE &&
994              (GetLastError() == ERROR_INVALID_DATA ||
995              GetLastError() == ERROR_ACCESS_DENIED), /* win2k3 */
996              "Expected ERROR_INVALID_DATA or ERROR_ACCESS_DENIED, got %08x\n", GetLastError());
997             key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
998              DIREG_DRV, KEY_READ);
999             ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n",
1000              GetLastError());
1001             pSetupDiDestroyDeviceInfoList(set);
1002         }
1003         else
1004             classKeyCreated = FALSE;
1005
1006         /* Cleanup */
1007         ret = remove_device();
1008         todo_wine
1009         ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1010
1011         /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1012         if (!ret)
1013         {
1014             /* Wine doesn't delete the information currently */
1015             trace("We are most likely on Wine\n");
1016             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1017             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
1018         }
1019         else if (classKeyCreated)
1020         {
1021             /* There should only be a class key entry, so a simple
1022              * RegDeleteKey should work
1023              *
1024              * This could fail if it's the first time for this new test
1025              * after running the old tests.
1026              */
1027             ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey),
1028              "Couldn't delete classkey\n");
1029         }
1030     }
1031 }
1032
1033 static void testRegisterAndGetDetail(void)
1034 {
1035     HDEVINFO set;
1036     BOOL ret;
1037     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1038     SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } };
1039     DWORD dwSize = 0;
1040     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1041      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1042      'E','n','u','m','\\','R','o','o','t','\\',
1043      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1044     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
1045      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1046      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
1047      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
1048      '1','1','d','b','-','b','7','0','4','-',
1049      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
1050
1051     if (!pSetupDiCreateDeviceInterfaceA || !pSetupDiEnumDeviceInterfaces ||
1052         !pSetupDiGetDeviceInterfaceDetailA)
1053     {
1054         win_skip("Needed functions are not available\n");
1055         return;
1056     }
1057
1058     SetLastError(0xdeadbeef);
1059     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES);
1060     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1061      GetLastError());
1062
1063     SetLastError(0xdeadbeef);
1064     ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, 0,
1065      DICD_GENERATE_ID, &devInfo);
1066     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1067     SetLastError(0xdeadbeef);
1068     ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, &interfaceData);
1069     ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
1070     SetLastError(0xdeadbeef);
1071     ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
1072     ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
1073
1074     pSetupDiDestroyDeviceInfoList(set);
1075
1076     SetLastError(0xdeadbeef);
1077     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1078     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1079      GetLastError());
1080
1081     SetLastError(0xdeadbeef);
1082     ret = pSetupDiEnumDeviceInterfaces(set, NULL, &guid, 0, &interfaceData);
1083     ok(ret, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
1084     SetLastError(0xdeadbeef);
1085     ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, 0, &dwSize, NULL);
1086     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1087      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1088     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1089     {
1090         static const char path[] =
1091             "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
1092         static const char path_w2k[] =
1093          "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\";
1094         PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL;
1095
1096         detail = HeapAlloc(GetProcessHeap(), 0, dwSize);
1097         if (detail)
1098         {
1099             detail->cbSize = sizeof(*detail);
1100             SetLastError(0xdeadbeef);
1101             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData,
1102              detail, dwSize, &dwSize, NULL);
1103             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError());
1104             /* FIXME: This one only worked because old data wasn't removed properly. As soon
1105              * as all the tests are cleaned up correctly this has to be (or should be) fixed
1106              */
1107             todo_wine
1108             ok(!lstrcmpiA(path, detail->DevicePath) ||
1109              !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n",
1110              detail->DevicePath);
1111             HeapFree(GetProcessHeap(), 0, detail);
1112         }
1113     }
1114
1115     pSetupDiDestroyDeviceInfoList(set);
1116
1117     /* Cleanup */
1118     ret = remove_device();
1119     todo_wine
1120     ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1121
1122     /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1123     if (!ret)
1124     {
1125         /* Wine doesn't delete the information currently */
1126         trace("We are most likely on Wine\n");
1127         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1128         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
1129     }
1130     else
1131     {
1132         clean_devclass_key();
1133     }
1134 }
1135
1136 static void testDeviceRegistryPropertyA(void)
1137 {
1138     HDEVINFO set;
1139     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1140     CHAR devName[] = "LEGACY_BOGUS";
1141     CHAR friendlyName[] = "Bogus";
1142     CHAR buf[6] = "";
1143     DWORD buflen = 6;
1144     DWORD size;
1145     DWORD regType;
1146     BOOL ret;
1147     LONG res;
1148     HKEY key;
1149     static const CHAR bogus[] =
1150      "System\\CurrentControlSet\\Enum\\Root\\LEGACY_BOGUS";
1151
1152     SetLastError(0xdeadbeef);
1153     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1154     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1155      GetLastError());
1156     SetLastError(0xdeadbeef);
1157     ret = pSetupDiCreateDeviceInfoA(set, devName, &guid, NULL, NULL,
1158      DICD_GENERATE_ID, &devInfo);
1159     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1160     SetLastError(0xdeadbeef);
1161     ret = pSetupDiSetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, 0);
1162     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1163      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1164     SetLastError(0xdeadbeef);
1165     ret = pSetupDiSetDeviceRegistryPropertyA(set, NULL, -1, NULL, 0);
1166     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1167      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1168     SetLastError(0xdeadbeef);
1169     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, 0);
1170     todo_wine
1171     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1172      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1173     /* GetLastError() returns nonsense in win2k3 */
1174     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1175      NULL, 0);
1176     todo_wine
1177     ok(!ret, "Expected failure, got %d\n", ret);
1178     SetLastError(0xdeadbeef);
1179     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1180      (PBYTE)friendlyName, buflen);
1181     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1182     SetLastError(0xdeadbeef);
1183     ret = pSetupDiGetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, NULL, 0, NULL);
1184     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1185      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1186     SetLastError(0xdeadbeef);
1187     ret = pSetupDiGetDeviceRegistryPropertyA(set, NULL, -1, NULL, NULL, 0, NULL);
1188     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1189      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1190     SetLastError(0xdeadbeef);
1191     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, NULL, 0, NULL);
1192     todo_wine
1193     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1194      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1195     /* GetLastError() returns nonsense in win2k3 */
1196     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1197      NULL, NULL, buflen, NULL);
1198     ok(!ret, "Expected failure, got %d\n", ret);
1199     SetLastError(0xdeadbeef);
1200     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1201      NULL, NULL, 0, &size);
1202     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1203      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1204     ok(buflen == size, "Unexpected size: %d\n", size);
1205     SetLastError(0xdeadbeef);
1206     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1207      NULL, (PBYTE)buf, buflen, NULL);
1208     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1209     ok(!lstrcmpiA(friendlyName, buf), "Unexpected property\n");
1210     SetLastError(0xdeadbeef);
1211     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1212      &regType, (PBYTE)buf, buflen, NULL);
1213     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1214     ok(!lstrcmpiA(friendlyName, buf), "Unexpected value of property\n");
1215     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1216     SetLastError(0xdeadbeef);
1217     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1218      NULL, 0);
1219     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1220     SetLastError(0xdeadbeef);
1221     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1222      NULL, (PBYTE)buf, buflen, &size);
1223     todo_wine
1224     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1225      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1226     pSetupDiDestroyDeviceInfoList(set);
1227
1228     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, bogus, &key);
1229     todo_wine
1230     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1231     /* FIXME: Remove when Wine is fixed */
1232     if (res == ERROR_SUCCESS)
1233     {
1234         /* Wine doesn't delete the information currently */
1235         trace("We are most likely on Wine\n");
1236         RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus);
1237     }
1238 }
1239
1240 static void testDeviceRegistryPropertyW(void)
1241 {
1242     HDEVINFO set;
1243     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1244     WCHAR devName[] = {'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1245     WCHAR friendlyName[] = {'B','o','g','u','s',0};
1246     WCHAR buf[6] = {0};
1247     DWORD buflen = 6 * sizeof(WCHAR);
1248     DWORD size;
1249     DWORD regType;
1250     BOOL ret;
1251     LONG res;
1252     HKEY key;
1253     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1254      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1255      'E','n','u','m','\\','R','o','o','t','\\',
1256      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1257
1258     SetLastError(0xdeadbeef);
1259     set = pSetupDiGetClassDevsW(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1260     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %08x\n",
1261      GetLastError());
1262     SetLastError(0xdeadbeef);
1263     ret = pSetupDiCreateDeviceInfoW(set, devName, &guid, NULL, NULL,
1264      DICD_GENERATE_ID, &devInfo);
1265     ok(ret, "SetupDiCreateDeviceInfoW failed: %08x\n", GetLastError());
1266     SetLastError(0xdeadbeef);
1267     ret = pSetupDiSetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, 0);
1268     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1269      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1270     SetLastError(0xdeadbeef);
1271     ret = pSetupDiSetDeviceRegistryPropertyW(set, NULL, -1, NULL, 0);
1272     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1273      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1274     SetLastError(0xdeadbeef);
1275     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, 0);
1276     todo_wine
1277     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1278      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1279     /* GetLastError() returns nonsense in win2k3 */
1280     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1281      NULL, 0);
1282     todo_wine
1283     ok(!ret, "Expected failure, got %d\n", ret);
1284     SetLastError(0xdeadbeef);
1285     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1286      (PBYTE)friendlyName, buflen);
1287     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1288     SetLastError(0xdeadbeef);
1289     ret = pSetupDiGetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, NULL, 0, NULL);
1290     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1291      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1292     SetLastError(0xdeadbeef);
1293     ret = pSetupDiGetDeviceRegistryPropertyW(set, NULL, -1, NULL, NULL, 0, NULL);
1294     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1295      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1296     SetLastError(0xdeadbeef);
1297     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, NULL, 0, NULL);
1298     todo_wine
1299     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1300      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1301     /* GetLastError() returns nonsense in win2k3 */
1302     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1303      NULL, NULL, buflen, NULL);
1304     ok(!ret, "Expected failure, got %d\n", ret);
1305     SetLastError(0xdeadbeef);
1306     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1307      NULL, NULL, 0, &size);
1308     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1309      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1310     ok(buflen == size, "Unexpected size: %d\n", size);
1311     SetLastError(0xdeadbeef);
1312     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1313      NULL, (PBYTE)buf, buflen, NULL);
1314     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1315     ok(!lstrcmpiW(friendlyName, buf), "Unexpected property\n");
1316     SetLastError(0xdeadbeef);
1317     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1318      &regType, (PBYTE)buf, buflen, NULL);
1319     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1320     ok(!lstrcmpiW(friendlyName, buf), "Unexpected value of property\n");
1321     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1322     SetLastError(0xdeadbeef);
1323     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1324      NULL, 0);
1325     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1326     SetLastError(0xdeadbeef);
1327     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1328      NULL, (PBYTE)buf, buflen, &size);
1329     todo_wine
1330     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1331      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1332     pSetupDiDestroyDeviceInfoList(set);
1333
1334     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
1335     todo_wine
1336     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1337     /* FIXME: Remove when Wine is fixed */
1338     if (res == ERROR_SUCCESS)
1339     {
1340         /* Wine doesn't delete the information currently */
1341         trace("We are most likely on Wine\n");
1342         RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus);
1343     }
1344 }
1345
1346 START_TEST(devinst)
1347 {
1348     HDEVINFO set;
1349
1350      init_function_pointers();
1351
1352     /* Win9x/WinMe does things totally different so we skip all the tests
1353      *
1354      * We don't want to exclude NT4 so hence this check.
1355      */
1356     SetLastError(0xdeadbeef);
1357     set = pSetupDiGetClassDevsW(NULL, NULL, 0, 0);
1358     if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1359     {
1360         win_skip("Win9x/WinMe has totally different behavior\n");
1361         return;
1362     }
1363
1364     if (pSetupDiCreateDeviceInfoListExW)
1365         test_SetupDiCreateDeviceInfoListEx();
1366     else
1367         win_skip("SetupDiCreateDeviceInfoListExW is not available\n");
1368
1369     if (pSetupDiOpenClassRegKeyExA)
1370         test_SetupDiOpenClassRegKeyExA();
1371     else
1372         win_skip("SetupDiOpenClassRegKeyExA is not available\n");
1373
1374     testInstallClass();
1375     testCreateDeviceInfo();
1376     testGetDeviceInstanceId();
1377     testRegisterDeviceInfo();
1378     testCreateDeviceInterface();
1379     testGetDeviceInterfaceDetail();
1380     testDevRegKey();
1381     testRegisterAndGetDetail();
1382     testDeviceRegistryPropertyA();
1383     testDeviceRegistryPropertyW();
1384 }