Reactos
1/*
2 * SetupAPI interface-related functions
3 *
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005-2006 Herv� Poussineau (hpoussin@reactos.org)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include "setupapi_private.h"
23
24/* Unicode constants */
25static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
26static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
27static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
28static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
29static const WCHAR DotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
30static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
31static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
32
33static BOOL
34CreateDeviceInterface(
35 IN struct DeviceInfo* deviceInfo,
36 IN LPCWSTR SymbolicLink,
37 IN LPCGUID pInterfaceGuid,
38 OUT struct DeviceInterface **pDeviceInterface)
39{
40 struct DeviceInterface *deviceInterface;
41
42 *pDeviceInterface = NULL;
43
44 deviceInterface = HeapAlloc(GetProcessHeap(), 0,
45 FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (strlenW(SymbolicLink) + 1) * sizeof(WCHAR));
46 if (!deviceInterface)
47 {
48 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
49 return FALSE;
50 }
51 deviceInterface->DeviceInfo = deviceInfo;
52 strcpyW(deviceInterface->SymbolicLink, SymbolicLink);
53 deviceInterface->Flags = 0; /* Flags will be updated later */
54 memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
55
56 *pDeviceInterface = deviceInterface;
57 return TRUE;
58}
59
60BOOL
61DestroyDeviceInterface(
62 struct DeviceInterface* deviceInterface)
63{
64 return HeapFree(GetProcessHeap(), 0, deviceInterface);
65}
66
67LONG
68SETUP_CreateInterfaceList(
69 struct DeviceInfoSet *list,
70 PCWSTR MachineName,
71 CONST GUID *InterfaceGuid,
72 PCWSTR DeviceInstanceW /* OPTIONAL */,
73 BOOL OnlyPresentInterfaces)
74{
75 HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
76 HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
77 HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
78 HKEY hControlKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString}\Control */
79 HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */
80 HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
81 LONG rc;
82 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
83 PWSTR pSymbolicLink = NULL;
84 PWSTR InstancePath = NULL;
85 DWORD i, j;
86 DWORD dwLength, dwInstancePathLength;
87 DWORD dwRegType;
88 DWORD LinkedValue;
89 GUID ClassGuid;
90 struct DeviceInfo *deviceInfo;
91
92 hInterfaceKey = INVALID_HANDLE_VALUE;
93 hDeviceInstanceKey = NULL;
94 hReferenceKey = NULL;
95
96 /* Open registry key related to this interface */
97 hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
98 if (hInterfaceKey == INVALID_HANDLE_VALUE)
99 {
100 /* Key doesn't exist. Let's keep it empty */
101 rc = ERROR_SUCCESS;
102 goto cleanup;
103 }
104
105 /* Enumerate sub keys of hInterfaceKey */
106 i = 0;
107 while (TRUE)
108 {
109 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
110 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
111 if (rc == ERROR_NO_MORE_ITEMS)
112 break;
113 if (rc != ERROR_SUCCESS)
114 goto cleanup;
115 i++;
116
117 /* Open sub key */
118 if (hDeviceInstanceKey != NULL)
119 RegCloseKey(hDeviceInstanceKey);
120 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
121 if (rc != ERROR_SUCCESS)
122 goto cleanup;
123
124 /* Read DeviceInstance */
125 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
126 if (rc != ERROR_SUCCESS)
127 goto cleanup;
128 if (dwRegType != REG_SZ)
129 {
130 rc = ERROR_GEN_FAILURE;
131 goto cleanup;
132 }
133 HeapFree(GetProcessHeap(), 0, InstancePath);
134 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
135 if (!InstancePath)
136 {
137 rc = ERROR_NOT_ENOUGH_MEMORY;
138 goto cleanup;
139 }
140 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
141 if (rc != ERROR_SUCCESS)
142 goto cleanup;
143 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
144 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
145
146 if (DeviceInstanceW)
147 {
148 /* Check if device enumerator is not the right one */
149 if (strcmpW(DeviceInstanceW, InstancePath) != 0)
150 continue;
151 }
152
153 /* Find class GUID associated to the device instance */
154 rc = RegOpenKeyExW(
155 list->HKLM,
156 REGSTR_PATH_SYSTEMENUM,
157 0, /* Options */
158 READ_CONTROL,
159 &hEnumKey);
160 if (rc != ERROR_SUCCESS)
161 goto cleanup;
162 rc = RegOpenKeyExW(
163 hEnumKey,
164 InstancePath,
165 0, /* Options */
166 KEY_QUERY_VALUE,
167 &hKey);
168 RegCloseKey(hEnumKey);
169 if (rc != ERROR_SUCCESS)
170 goto cleanup;
171 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
172 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
173 RegCloseKey(hKey);
174 if (rc != ERROR_SUCCESS)
175 goto cleanup;
176 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
177 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
178 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
179 {
180 rc = ERROR_GEN_FAILURE;
181 goto cleanup;
182 }
183 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
184
185 /* If current device doesn't match the list GUID (if any), skip this entry */
186 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
187 continue;
188
189 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
190 j = 0;
191 while (TRUE)
192 {
193 struct DeviceInterface *interfaceInfo;
194
195 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
196 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
197 if (rc == ERROR_NO_MORE_ITEMS)
198 break;
199 if (rc != ERROR_SUCCESS)
200 goto cleanup;
201 j++;
202 if (KeyBuffer[0] != '#')
203 /* This entry doesn't represent an interesting entry */
204 continue;
205
206 /* Open sub key */
207 if (hReferenceKey != NULL)
208 RegCloseKey(hReferenceKey);
209 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
210 if (rc != ERROR_SUCCESS)
211 goto cleanup;
212
213 /* Read SymbolicLink value */
214 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
215 if (rc != ERROR_SUCCESS)
216 {
217 /* Skip device interface with invalid reference value (i.e. interface not actually available for this device) */
218 RegCloseKey(hReferenceKey);
219 continue;
220 }
221 if (dwRegType != REG_SZ)
222 {
223 rc = ERROR_GEN_FAILURE;
224 goto cleanup;
225 }
226
227 /* We have found a device */
228 /* Step 1. Create a device info element */
229 if (!CreateDeviceInfo(list, InstancePath, &ClassGuid, &deviceInfo))
230 {
231 rc = GetLastError();
232 goto cleanup;
233 }
234 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
235 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
236
237 /* Step 2. Create an interface list for this element */
238 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
239 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
240 if (!pSymbolicLink)
241 {
242 rc = ERROR_NOT_ENOUGH_MEMORY;
243 goto cleanup;
244 }
245 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
246 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
247 if (rc != ERROR_SUCCESS)
248 goto cleanup;
249 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
250 {
251 rc = GetLastError();
252 goto cleanup;
253 }
254
255 /* Step 3. Update flags */
256 if (KeyBuffer[1] == '\0')
257 interfaceInfo->Flags |= SPINT_DEFAULT;
258 rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
259 if (rc != ERROR_SUCCESS)
260 {
261#if 0
262 if (OnlyPresentInterfaces)
263 {
264 DestroyDeviceInterface(interfaceInfo);
265 continue;
266 }
267 else
268 interfaceInfo->Flags |= SPINT_REMOVED;
269#endif
270 }
271 else
272 {
273 dwLength = sizeof(DWORD);
274 if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength) == ERROR_SUCCESS
275 && dwRegType == REG_DWORD && LinkedValue)
276 interfaceInfo->Flags |= SPINT_ACTIVE;
277 RegCloseKey(hControlKey);
278 }
279
280 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
281 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
282 }
283 }
284 rc = ERROR_SUCCESS;
285
286cleanup:
287 if (hReferenceKey != NULL)
288 RegCloseKey(hReferenceKey);
289 if (hDeviceInstanceKey != NULL)
290 RegCloseKey(hDeviceInstanceKey);
291 if (hInterfaceKey != INVALID_HANDLE_VALUE)
292 RegCloseKey(hInterfaceKey);
293 HeapFree(GetProcessHeap(), 0, InstancePath);
294 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
295 return rc;
296}
297
298static LPWSTR
299CreateSymbolicLink(
300 IN LPGUID InterfaceGuid,
301 IN LPCWSTR ReferenceString,
302 IN struct DeviceInfo *devInfo)
303{
304 DWORD Length, Index, Offset;
305 LPWSTR Key;
306
307 Length = wcslen(devInfo->instanceId) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */;
308
309 Key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length * sizeof(WCHAR));
310 if (!Key)
311 return NULL;
312
313 wcscpy(Key, L"##?#");
314 wcscat(Key, devInfo->instanceId);
315
316 for(Index = 4; Index < Length; Index++)
317 {
318 if (Key[Index] == L'\\')
319 {
320 Key[Index] = L'#';
321 }
322 }
323
324 wcscat(Key, L"#");
325
326 Offset = wcslen(Key);
327 pSetupStringFromGuid(InterfaceGuid, Key + Offset, Length - Offset);
328
329 return Key;
330}
331
332
333static BOOL
334InstallOneInterface(
335 IN LPGUID InterfaceGuid,
336 IN LPCWSTR ReferenceString,
337 IN LPCWSTR InterfaceSection,
338 IN UINT InterfaceFlags,
339 IN HINF hInf,
340 IN HDEVINFO DeviceInfoSet,
341 IN struct DeviceInfo *devInfo)
342{
343 HKEY hKey, hRefKey;
344 LPWSTR Path;
345 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
346 struct DeviceInterface *DevItf = NULL;
347
348 if (InterfaceFlags != 0)
349 {
350 SetLastError(ERROR_INVALID_PARAMETER);
351 return FALSE;
352 }
353
354 TRACE("Need to InstallOneInterface(%s %s %s %u) hInf %p DeviceInfoSet %p devInfo %p instanceId %s\n", debugstr_guid(InterfaceGuid),
355 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags, hInf, DeviceInfoSet, devInfo, debugstr_w(devInfo->instanceId));
356
357
358 Path = CreateSymbolicLink(InterfaceGuid, ReferenceString, devInfo);
359 if (!Path)
360 return FALSE;
361
362 CreateDeviceInterface(devInfo, Path, InterfaceGuid, &DevItf);
363 HeapFree(GetProcessHeap(), 0, Path);
364 if (!DevItf)
365 {
366 return FALSE;
367 }
368
369 memcpy(&DeviceInterfaceData.InterfaceClassGuid, &DevItf->InterfaceClassGuid, sizeof(GUID));
370 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
371 DeviceInterfaceData.Flags = DevItf->Flags;
372 DeviceInterfaceData.Reserved = (ULONG_PTR)DevItf;
373
374 hKey = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet, &DeviceInterfaceData, 0, KEY_ALL_ACCESS, NULL, 0);
375 HeapFree(GetProcessHeap(), 0, DevItf);
376 if (hKey == INVALID_HANDLE_VALUE)
377 {
378 return FALSE;
379 }
380
381 if (ReferenceString)
382 {
383 Path = HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString) + 2) * sizeof(WCHAR));
384 if (!Path)
385 {
386 RegCloseKey(hKey);
387 return FALSE;
388 }
389
390 wcscpy(Path, L"#");
391 wcscat(Path, ReferenceString);
392
393 if (RegCreateKeyExW(hKey, Path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
394 {
395 ERR("failed to create key %s %lx\n", debugstr_w(Path), GetLastError());
396 HeapFree(GetProcessHeap(), 0, Path);
397 return FALSE;
398 }
399
400 RegCloseKey(hKey);
401 hKey = hRefKey;
402 HeapFree(GetProcessHeap(), 0, Path);
403 }
404
405 if (RegCreateKeyExW(hKey, L"Device Parameters", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
406 {
407 RegCloseKey(hKey);
408 return FALSE;
409 }
410
411 return SetupInstallFromInfSectionW(NULL, /* FIXME */ hInf, InterfaceSection, SPINST_REGISTRY, hRefKey, NULL, 0, NULL, NULL, NULL, NULL);
412}
413
414/***********************************************************************
415 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
416 */
417BOOL WINAPI
418SetupDiInstallDeviceInterfaces(
419 IN HDEVINFO DeviceInfoSet,
420 IN PSP_DEVINFO_DATA DeviceInfoData)
421{
422 struct DeviceInfoSet *list = NULL;
423 BOOL ret = FALSE;
424
425 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
426
427 if (!DeviceInfoSet)
428 SetLastError(ERROR_INVALID_PARAMETER);
429 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
430 SetLastError(ERROR_INVALID_HANDLE);
431 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
432 SetLastError(ERROR_INVALID_HANDLE);
433 else if (!DeviceInfoData)
434 SetLastError(ERROR_INVALID_PARAMETER);
435 else if (DeviceInfoData && DeviceInfoData->Reserved == 0)
436 SetLastError(ERROR_INVALID_USER_BUFFER);
437 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
438 SetLastError(ERROR_INVALID_USER_BUFFER);
439 else
440 {
441 struct DeviceInfo *devInfo;
442 struct DriverInfoElement *SelectedDriver = NULL;
443 SP_DEVINSTALL_PARAMS_W InstallParams;
444 WCHAR SectionName[MAX_PATH];
445 DWORD SectionNameLength = 0;
446 INFCONTEXT ContextInterface;
447 LPWSTR InterfaceGuidString = NULL;
448 LPWSTR ReferenceString = NULL;
449 LPWSTR InterfaceSection = NULL;
450 INT InterfaceFlags;
451 GUID InterfaceGuid;
452 BOOL Result;
453
454 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
455
456 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
457 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
458 if (!Result)
459 goto cleanup;
460
461 SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved;
462 if (SelectedDriver == NULL)
463 {
464 SetLastError(ERROR_NO_DRIVER_SELECTED);
465 ret = FALSE;
466 goto cleanup;
467 }
468
469 /* Get .Interfaces section name */
470 Result = SetupDiGetActualSectionToInstallW(
471 SelectedDriver->InfFileDetails->hInf,
472 SelectedDriver->Details.SectionName,
473 SectionName, MAX_PATH, &SectionNameLength, NULL);
474 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
475 goto cleanup;
476 strcatW(SectionName, DotInterfaces);
477
478 ret = TRUE;
479 Result = SetupFindFirstLineW(
480 SelectedDriver->InfFileDetails->hInf,
481 SectionName,
482 AddInterface,
483 &ContextInterface);
484 while (ret && Result)
485 {
486 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
487 if (!ret)
488 goto cleanup;
489 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
490 {
491 SetLastError(ERROR_INVALID_PARAMETER);
492 ret = FALSE;
493 goto cleanup;
494 }
495
496 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
497 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
498 {
499 /* Bad GUID, skip the entry */
500 SetLastError(ERROR_INVALID_PARAMETER);
501 ret = FALSE;
502 goto cleanup;
503 }
504
505 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
506 if (!ret)
507 goto cleanup;
508
509 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
510 if (!ret)
511 {
512 /* ReferenceString is optional */
513 InterfaceSection = ReferenceString;
514 ReferenceString = NULL;
515 }
516
517 ret = SetupGetIntField(
518 &ContextInterface,
519 (ReferenceString ? 4 : 3), /* Field index */
520 &InterfaceFlags);
521 if (!ret)
522 {
523 if (GetLastError() == ERROR_INVALID_PARAMETER)
524 {
525 /* The field may be empty. Ignore the error */
526 InterfaceFlags = 0;
527 ret = TRUE;
528 }
529 else
530 goto cleanup;
531 }
532
533 /* Install Interface */
534 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags, SelectedDriver->InfFileDetails->hInf, DeviceInfoSet, devInfo);
535
536cleanup:
537 MyFree(InterfaceGuidString);
538 if (ReferenceString)
539 MyFree(ReferenceString);
540 MyFree(InterfaceSection);
541 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
542 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
543 }
544 }
545
546 TRACE("Returning %d\n", ret);
547 return ret;
548}
549
550HKEY WINAPI
551SetupDiOpenDeviceInterfaceRegKey(
552 IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IN DWORD Reserved, IN REGSAM samDesired)
553{
554 HKEY hKey = INVALID_HANDLE_VALUE, hDevKey;
555 struct DeviceInfoSet * list;
556
557 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet, DeviceInterfaceData, Reserved, samDesired);
558
559 if (!DeviceInfoSet)
560 SetLastError(ERROR_INVALID_PARAMETER);
561 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
562 SetLastError(ERROR_INVALID_HANDLE);
563 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
564 SetLastError(ERROR_INVALID_HANDLE);
565 else if (!DeviceInterfaceData)
566 SetLastError(ERROR_INVALID_PARAMETER);
567 else if (DeviceInterfaceData && DeviceInterfaceData->Reserved == 0)
568 SetLastError(ERROR_INVALID_USER_BUFFER);
569 else if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
570 SetLastError(ERROR_INVALID_USER_BUFFER);
571 else
572 {
573 struct DeviceInterface *DevItf;
574 LPWSTR Path, Guid, Slash;
575 DWORD Length;
576 DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
577
578 Length = wcslen(DevItf->SymbolicLink);
579
580 Path = HeapAlloc(GetProcessHeap(), 0, (Length+2) * sizeof(WCHAR));
581 if (!Path)
582 {
583 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
584 return INVALID_HANDLE_VALUE;
585 }
586
587 wcscpy(Path, DevItf->SymbolicLink);
588
589 Guid = wcsrchr(Path, '}');
590 Slash = wcsrchr(Path, '\\');
591 if (!Guid || !Slash)
592 {
593 HeapFree(GetProcessHeap(), 0, Path);
594 SetLastError(ERROR_INVALID_PARAMETER);
595 return INVALID_HANDLE_VALUE;
596 }
597
598 if ((ULONG_PTR)Slash > (ULONG_PTR)Guid)
599 {
600 /* Create an extra slash */
601 memmove(Slash+1, Slash, (wcslen(Slash) + 1) * sizeof(WCHAR));
602 Slash[1] = L'#';
603 }
604
605 Guid = Path;
606 while((ULONG_PTR)Guid < (ULONG_PTR)Slash)
607 {
608 if (*Guid == L'\\')
609 *Guid = L'#';
610
611 Guid++;
612 }
613
614 hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
615 if (hKey != INVALID_HANDLE_VALUE)
616 {
617 if (RegOpenKeyExW(hKey, Path, 0, samDesired, &hDevKey) == ERROR_SUCCESS)
618 {
619 RegCloseKey(hKey);
620 hKey = hDevKey;
621 }
622 else
623 {
624 RegCloseKey(hKey);
625 hKey = INVALID_HANDLE_VALUE;
626 }
627 }
628
629 HeapFree(GetProcessHeap(), 0, Path);
630 }
631
632 return hKey;
633}
634
635/***********************************************************************
636 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
637 */
638BOOL
639WINAPI
640SetupDiDeleteDeviceInterfaceData(
641 HDEVINFO DeviceInfoSet,
642 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
643{
644 FIXME("SetupDiDeleteDeviceInterfaceData(%p %p) stub\n",
645 DeviceInfoSet, DeviceInterfaceData);
646 return TRUE;
647}