ddraw: Get rid of ddcomimpl.h.
[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         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, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_MACHINENAME);
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         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         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
891     SetLastError(0xdeadbeef);
892     key = pSetupDiCreateDevRegKeyW(NULL, NULL, 0, 0, 0, NULL, NULL);
893     ok(key == INVALID_HANDLE_VALUE,
894      "Expected INVALID_HANDLE_VALUE, got %p\n", key);
895     ok(GetLastError() == ERROR_INVALID_HANDLE,
896      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
897
898     set = pSetupDiCreateDeviceInfoList(&guid, NULL);
899     ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError());
900     if (set)
901     {
902         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
903         LONG res;
904
905         /* The device info key shouldn't be there */
906         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
907         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
908         RegCloseKey(key);
909         /* Create the device information */
910         ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid,
911                 NULL, NULL, 0, &devInfo);
912         ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
913         /* The device info key should have been created */
914         ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key),
915          "Expected registry key to exist\n");
916         RegCloseKey(key);
917         SetLastError(0xdeadbeef);
918         key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0);
919         ok(!key || key == INVALID_HANDLE_VALUE,
920          "Expected INVALID_HANDLE_VALUE or a NULL key (NT4)\n");
921         ok(GetLastError() == ERROR_INVALID_HANDLE,
922          "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
923         SetLastError(0xdeadbeef);
924         key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0);
925         ok(key == INVALID_HANDLE_VALUE &&
926          GetLastError() == ERROR_INVALID_PARAMETER,
927          "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
928         SetLastError(0xdeadbeef);
929         key = pSetupDiOpenDevRegKey(set, &devInfo, 0, 0, 0, 0);
930         ok(key == INVALID_HANDLE_VALUE &&
931          GetLastError() == ERROR_INVALID_FLAGS,
932          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
933         SetLastError(0xdeadbeef);
934         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, 0, 0);
935         ok(key == INVALID_HANDLE_VALUE &&
936          GetLastError() == ERROR_INVALID_FLAGS,
937          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
938         SetLastError(0xdeadbeef);
939         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
940          DIREG_BOTH, 0);
941         ok(key == INVALID_HANDLE_VALUE &&
942          GetLastError() == ERROR_INVALID_FLAGS,
943          "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
944         SetLastError(0xdeadbeef);
945         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
946          DIREG_DRV, 0);
947         ok(key == INVALID_HANDLE_VALUE &&
948          GetLastError() == ERROR_DEVINFO_NOT_REGISTERED,
949          "Expected ERROR_DEVINFO_NOT_REGISTERED, got %08x\n", GetLastError());
950         SetLastError(0xdeadbeef);
951         ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
952         ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
953         SetLastError(0xdeadbeef);
954         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
955          DIREG_DRV, 0);
956         /* The software key isn't created by default */
957         todo_wine
958         ok(key == INVALID_HANDLE_VALUE &&
959          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
960          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
961         SetLastError(0xdeadbeef);
962         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
963          DIREG_DEV, 0);
964         todo_wine
965         ok(key == INVALID_HANDLE_VALUE &&
966          GetLastError() == ERROR_KEY_DOES_NOT_EXIST,
967          "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError());
968         SetLastError(0xdeadbeef);
969         /* The class key shouldn't be there */
970         res = RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key);
971         todo_wine
972         ok(res != ERROR_SUCCESS, "Expected key to not exist\n");
973         RegCloseKey(key);
974         /* Create the device reg key */
975         key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0,
976          DIREG_DRV, NULL, NULL);
977         ok(key != INVALID_HANDLE_VALUE, "SetupDiCreateDevRegKey failed: %08x\n",
978          GetLastError());
979         RegCloseKey(key);
980         /* The class key should have been created */
981         ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key),
982          "Expected registry key to exist\n");
983         RegCloseKey(key);
984         SetLastError(0xdeadbeef);
985         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
986          DIREG_DRV, 0);
987         todo_wine
988         ok(key == INVALID_HANDLE_VALUE &&
989          (GetLastError() == ERROR_INVALID_DATA ||
990          GetLastError() == ERROR_ACCESS_DENIED), /* win2k3 */
991          "Expected ERROR_INVALID_DATA or ERROR_ACCESS_DENIED, got %08x\n", GetLastError());
992         key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0,
993          DIREG_DRV, KEY_READ);
994         ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n",
995          GetLastError());
996         pSetupDiDestroyDeviceInfoList(set);
997
998         /* Cleanup */
999         ret = remove_device();
1000         todo_wine
1001         ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1002
1003         /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1004         if (!ret)
1005         {
1006             /* Wine doesn't delete the information currently */
1007             trace("We are most likely on Wine\n");
1008             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1009             devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey);
1010         }
1011         else
1012         {
1013             /* There should only be a class key entry, so a simple
1014              * RegDeleteKey should work
1015              *
1016              * This could fail if it's the first time for this new test
1017              * after running the old tests.
1018              */
1019             ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey),
1020              "Couldn't delete classkey\n");
1021         }
1022     }
1023 }
1024
1025 static void testRegisterAndGetDetail(void)
1026 {
1027     HDEVINFO set;
1028     BOOL ret;
1029     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1030     SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } };
1031     DWORD dwSize = 0;
1032     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1033      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1034      'E','n','u','m','\\','R','o','o','t','\\',
1035      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1036     static const WCHAR devclass[] = {'S','y','s','t','e','m','\\',
1037      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1038      'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\',
1039      '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-',
1040      '1','1','d','b','-','b','7','0','4','-',
1041      '0','0','1','1','9','5','5','c','2','b','d','b','}',0};
1042
1043     if (!pSetupDiCreateDeviceInterfaceA || !pSetupDiEnumDeviceInterfaces ||
1044         !pSetupDiGetDeviceInterfaceDetailA)
1045     {
1046         skip("Needed functions are not available\n");
1047         return;
1048     }
1049
1050     SetLastError(0xdeadbeef);
1051     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES);
1052     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1053      GetLastError());
1054
1055     SetLastError(0xdeadbeef);
1056     ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, 0,
1057      DICD_GENERATE_ID, &devInfo);
1058     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1059     SetLastError(0xdeadbeef);
1060     ret = pSetupDiCreateDeviceInterfaceA(set, &devInfo, &guid, NULL, 0, &interfaceData);
1061     ok(ret, "SetupDiCreateDeviceInterfaceA failed: %08x\n", GetLastError());
1062     SetLastError(0xdeadbeef);
1063     ret = pSetupDiRegisterDeviceInfo(set, &devInfo, 0, NULL, NULL, NULL);
1064     ok(ret, "SetupDiRegisterDeviceInfo failed: %08x\n", GetLastError());
1065
1066     pSetupDiDestroyDeviceInfoList(set);
1067
1068     SetLastError(0xdeadbeef);
1069     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1070     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1071      GetLastError());
1072
1073     SetLastError(0xdeadbeef);
1074     ret = pSetupDiEnumDeviceInterfaces(set, NULL, &guid, 0, &interfaceData);
1075     ok(ret, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError());
1076     SetLastError(0xdeadbeef);
1077     ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, NULL, 0, &dwSize, NULL);
1078     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1079      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1080     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1081     {
1082         static const char path[] =
1083             "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}";
1084         static const char path_w2k[] =
1085          "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\";
1086         PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL;
1087
1088         detail = HeapAlloc(GetProcessHeap(), 0, dwSize);
1089         if (detail)
1090         {
1091             detail->cbSize = sizeof(*detail);
1092             SetLastError(0xdeadbeef);
1093             ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData,
1094              detail, dwSize, &dwSize, NULL);
1095             ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError());
1096             /* FIXME: This one only worked because old data wasn't removed properly. As soon
1097              * as all the tests are cleaned up correctly this has to be (or should be) fixed
1098              */
1099             todo_wine
1100             ok(!lstrcmpiA(path, detail->DevicePath) ||
1101              !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n",
1102              detail->DevicePath);
1103             HeapFree(GetProcessHeap(), 0, detail);
1104         }
1105     }
1106
1107     pSetupDiDestroyDeviceInfoList(set);
1108
1109     /* Cleanup */
1110     ret = remove_device();
1111     todo_wine
1112     ok(ret, "Expected the device to be removed: %08x\n", GetLastError());
1113
1114     /* FIXME: Only do the RegDeleteKey, once Wine is fixed */
1115     if (!ret)
1116     {
1117         /* Wine doesn't delete the information currently */
1118         trace("We are most likely on Wine\n");
1119         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus);
1120         devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass);
1121     }
1122     else
1123     {
1124         clean_devclass_key();
1125     }
1126 }
1127
1128 static void testDeviceRegistryPropertyA()
1129 {
1130     HDEVINFO set;
1131     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1132     CHAR devName[] = "LEGACY_BOGUS";
1133     CHAR friendlyName[] = "Bogus";
1134     CHAR buf[6] = "";
1135     DWORD buflen = 6;
1136     DWORD size;
1137     DWORD regType;
1138     BOOL ret;
1139     LONG res;
1140     HKEY key;
1141     static const CHAR bogus[] =
1142      "System\\CurrentControlSet\\Enum\\Root\\LEGACY_BOGUS";
1143
1144     SetLastError(0xdeadbeef);
1145     set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1146     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n",
1147      GetLastError());
1148     SetLastError(0xdeadbeef);
1149     ret = pSetupDiCreateDeviceInfoA(set, devName, &guid, NULL, NULL,
1150      DICD_GENERATE_ID, &devInfo);
1151     ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError());
1152     SetLastError(0xdeadbeef);
1153     ret = pSetupDiSetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, 0);
1154     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1155      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1156     SetLastError(0xdeadbeef);
1157     ret = pSetupDiSetDeviceRegistryPropertyA(set, NULL, -1, NULL, 0);
1158     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1159      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1160     SetLastError(0xdeadbeef);
1161     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, 0);
1162     todo_wine
1163     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1164      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1165     /* GetLastError() returns nonsense in win2k3 */
1166     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1167      NULL, 0);
1168     todo_wine
1169     ok(!ret, "Expected failure, got %d\n", ret);
1170     SetLastError(0xdeadbeef);
1171     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1172      (PBYTE)friendlyName, buflen);
1173     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1174     SetLastError(0xdeadbeef);
1175     ret = pSetupDiGetDeviceRegistryPropertyA(NULL, NULL, -1, NULL, NULL, 0, NULL);
1176     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1177      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1178     SetLastError(0xdeadbeef);
1179     ret = pSetupDiGetDeviceRegistryPropertyA(set, NULL, -1, NULL, NULL, 0, NULL);
1180     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1181      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1182     SetLastError(0xdeadbeef);
1183     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, -1, NULL, NULL, 0, NULL);
1184     todo_wine
1185     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1186      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1187     /* GetLastError() returns nonsense in win2k3 */
1188     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1189      NULL, NULL, buflen, NULL);
1190     ok(!ret, "Expected failure, got %d\n", ret);
1191     SetLastError(0xdeadbeef);
1192     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1193      NULL, NULL, 0, &size);
1194     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1195      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1196     ok(buflen == size, "Unexpected size: %d\n", size);
1197     SetLastError(0xdeadbeef);
1198     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1199      NULL, (PBYTE)buf, buflen, NULL);
1200     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1201     ok(!lstrcmpiA(friendlyName, buf), "Unexpected property\n");
1202     SetLastError(0xdeadbeef);
1203     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1204      &regType, (PBYTE)buf, buflen, NULL);
1205     ok(ret, "SetupDiGetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1206     ok(!lstrcmpiA(friendlyName, buf), "Unexpected value of property\n");
1207     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1208     SetLastError(0xdeadbeef);
1209     ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1210      NULL, 0);
1211     ok(ret, "SetupDiSetDeviceRegistryPropertyA failed: %08x\n", GetLastError());
1212     SetLastError(0xdeadbeef);
1213     ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME,
1214      NULL, (PBYTE)buf, buflen, &size);
1215     todo_wine
1216     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1217      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1218     pSetupDiDestroyDeviceInfoList(set);
1219
1220     res = RegOpenKeyA(HKEY_LOCAL_MACHINE, bogus, &key);
1221     todo_wine
1222     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1223     /* FIXME: Remove when Wine is fixed */
1224     if (res == ERROR_SUCCESS)
1225     {
1226         /* Wine doesn't delete the information currently */
1227         trace("We are most likely on Wine\n");
1228         RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus);
1229     }
1230 }
1231
1232 static void testDeviceRegistryPropertyW()
1233 {
1234     HDEVINFO set;
1235     SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } };
1236     WCHAR devName[] = {'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1237     WCHAR friendlyName[] = {'B','o','g','u','s',0};
1238     WCHAR buf[6] = {0};
1239     DWORD buflen = 6 * sizeof(WCHAR);
1240     DWORD size;
1241     DWORD regType;
1242     BOOL ret;
1243     LONG res;
1244     HKEY key;
1245     static const WCHAR bogus[] = {'S','y','s','t','e','m','\\',
1246      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1247      'E','n','u','m','\\','R','o','o','t','\\',
1248      'L','E','G','A','C','Y','_','B','O','G','U','S',0};
1249
1250     SetLastError(0xdeadbeef);
1251     set = pSetupDiGetClassDevsW(&guid, NULL, 0, DIGCF_DEVICEINTERFACE);
1252     ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %08x\n",
1253      GetLastError());
1254     SetLastError(0xdeadbeef);
1255     ret = pSetupDiCreateDeviceInfoW(set, devName, &guid, NULL, NULL,
1256      DICD_GENERATE_ID, &devInfo);
1257     ok(ret, "SetupDiCreateDeviceInfoW failed: %08x\n", GetLastError());
1258     SetLastError(0xdeadbeef);
1259     ret = pSetupDiSetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, 0);
1260     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1261      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1262     SetLastError(0xdeadbeef);
1263     ret = pSetupDiSetDeviceRegistryPropertyW(set, NULL, -1, NULL, 0);
1264     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1265      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1266     SetLastError(0xdeadbeef);
1267     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, 0);
1268     todo_wine
1269     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1270      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1271     /* GetLastError() returns nonsense in win2k3 */
1272     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1273      NULL, 0);
1274     todo_wine
1275     ok(!ret, "Expected failure, got %d\n", ret);
1276     SetLastError(0xdeadbeef);
1277     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1278      (PBYTE)friendlyName, buflen);
1279     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1280     SetLastError(0xdeadbeef);
1281     ret = pSetupDiGetDeviceRegistryPropertyW(NULL, NULL, -1, NULL, NULL, 0, NULL);
1282     ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
1283      "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError());
1284     SetLastError(0xdeadbeef);
1285     ret = pSetupDiGetDeviceRegistryPropertyW(set, NULL, -1, NULL, NULL, 0, NULL);
1286     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1287      "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1288     SetLastError(0xdeadbeef);
1289     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, -1, NULL, NULL, 0, NULL);
1290     todo_wine
1291     ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY,
1292      "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError());
1293     /* GetLastError() returns nonsense in win2k3 */
1294     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1295      NULL, NULL, buflen, NULL);
1296     ok(!ret, "Expected failure, got %d\n", ret);
1297     SetLastError(0xdeadbeef);
1298     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1299      NULL, NULL, 0, &size);
1300     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1301      "Expected ERROR_INSUFFICIENT_BUFFER, got %08x\n", GetLastError());
1302     ok(buflen == size, "Unexpected size: %d\n", size);
1303     SetLastError(0xdeadbeef);
1304     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1305      NULL, (PBYTE)buf, buflen, NULL);
1306     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1307     ok(!lstrcmpiW(friendlyName, buf), "Unexpected property\n");
1308     SetLastError(0xdeadbeef);
1309     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1310      &regType, (PBYTE)buf, buflen, NULL);
1311     ok(ret, "SetupDiGetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1312     ok(!lstrcmpiW(friendlyName, buf), "Unexpected value of property\n");
1313     ok(regType == REG_SZ, "Unexpected type of property: %d\n", regType);
1314     SetLastError(0xdeadbeef);
1315     ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1316      NULL, 0);
1317     ok(ret, "SetupDiSetDeviceRegistryPropertyW failed: %08x\n", GetLastError());
1318     SetLastError(0xdeadbeef);
1319     ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME,
1320      NULL, (PBYTE)buf, buflen, &size);
1321     todo_wine
1322     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
1323      "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
1324     pSetupDiDestroyDeviceInfoList(set);
1325
1326     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key);
1327     todo_wine
1328     ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n");
1329     /* FIXME: Remove when Wine is fixed */
1330     if (res == ERROR_SUCCESS)
1331     {
1332         /* Wine doesn't delete the information currently */
1333         trace("We are most likely on Wine\n");
1334         RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus);
1335     }
1336 }
1337
1338 START_TEST(devinst)
1339 {
1340     HDEVINFO set;
1341
1342      init_function_pointers();
1343
1344     /* Win9x/WinMe does things totally different so we skip all the tests
1345      *
1346      * We don't want to exclude NT4 so hence this check.
1347      */
1348     SetLastError(0xdeadbeef);
1349     set = pSetupDiGetClassDevsW(NULL, NULL, 0, 0);
1350     if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1351     {
1352         skip("Win9x/WinMe has totally different behavior\n");
1353         return;
1354     }
1355
1356     if (pSetupDiCreateDeviceInfoListExW)
1357         test_SetupDiCreateDeviceInfoListEx();
1358     else
1359         skip("SetupDiCreateDeviceInfoListExW is not available\n");
1360
1361     if (pSetupDiOpenClassRegKeyExA)
1362         test_SetupDiOpenClassRegKeyExA();
1363     else
1364         skip("SetupDiOpenClassRegKeyExA is not available\n");
1365
1366     testInstallClass();
1367     testCreateDeviceInfo();
1368     testGetDeviceInstanceId();
1369     testRegisterDeviceInfo();
1370     testCreateDeviceInterface();
1371     testGetDeviceInterfaceDetail();
1372     testDevRegKey();
1373     testRegisterAndGetDetail();
1374     testDeviceRegistryPropertyA();
1375     testDeviceRegistryPropertyW();
1376 }