* Sync up to trunk HEAD (r62975).
[reactos.git] / dll / win32 / setupapi / interface.c
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 */
25 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
26 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
27 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
28 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
29 static const WCHAR DotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
30 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
31 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
32
33 static BOOL
34 CreateDeviceInterface(
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
60 BOOL
61 DestroyDeviceInterface(
62 struct DeviceInterface* deviceInterface)
63 {
64 return HeapFree(GetProcessHeap(), 0, deviceInterface);
65 }
66
67 LONG
68 SETUP_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 rc = GetLastError();
101 goto cleanup;
102 }
103
104 /* Enumerate sub keys of hInterfaceKey */
105 i = 0;
106 while (TRUE)
107 {
108 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
109 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
110 if (rc == ERROR_NO_MORE_ITEMS)
111 break;
112 if (rc != ERROR_SUCCESS)
113 goto cleanup;
114 i++;
115
116 /* Open sub key */
117 if (hDeviceInstanceKey != NULL)
118 RegCloseKey(hDeviceInstanceKey);
119 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
120 if (rc != ERROR_SUCCESS)
121 goto cleanup;
122
123 /* Read DeviceInstance */
124 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
125 if (rc != ERROR_SUCCESS)
126 goto cleanup;
127 if (dwRegType != REG_SZ)
128 {
129 rc = ERROR_GEN_FAILURE;
130 goto cleanup;
131 }
132 HeapFree(GetProcessHeap(), 0, InstancePath);
133 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
134 if (!InstancePath)
135 {
136 rc = ERROR_NOT_ENOUGH_MEMORY;
137 goto cleanup;
138 }
139 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
140 if (rc != ERROR_SUCCESS)
141 goto cleanup;
142 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
143 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
144
145 if (DeviceInstanceW)
146 {
147 /* Check if device enumerator is not the right one */
148 if (strcmpW(DeviceInstanceW, InstancePath) != 0)
149 continue;
150 }
151
152 /* Find class GUID associated to the device instance */
153 rc = RegOpenKeyExW(
154 list->HKLM,
155 REGSTR_PATH_SYSTEMENUM,
156 0, /* Options */
157 0,
158 &hEnumKey);
159 if (rc != ERROR_SUCCESS)
160 goto cleanup;
161 rc = RegOpenKeyExW(
162 hEnumKey,
163 InstancePath,
164 0, /* Options */
165 KEY_QUERY_VALUE,
166 &hKey);
167 RegCloseKey(hEnumKey);
168 if (rc != ERROR_SUCCESS)
169 goto cleanup;
170 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
171 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
172 RegCloseKey(hKey);
173 if (rc != ERROR_SUCCESS)
174 goto cleanup;
175 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
176 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
177 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
178 {
179 rc = ERROR_GEN_FAILURE;
180 goto cleanup;
181 }
182 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
183
184 /* If current device doesn't match the list GUID (if any), skip this entry */
185 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
186 continue;
187
188 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
189 j = 0;
190 while (TRUE)
191 {
192 struct DeviceInterface *interfaceInfo;
193
194 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
195 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
196 if (rc == ERROR_NO_MORE_ITEMS)
197 break;
198 if (rc != ERROR_SUCCESS)
199 goto cleanup;
200 j++;
201 if (KeyBuffer[0] != '#')
202 /* This entry doesn't represent an interesting entry */
203 continue;
204
205 /* Open sub key */
206 if (hReferenceKey != NULL)
207 RegCloseKey(hReferenceKey);
208 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
209 if (rc != ERROR_SUCCESS)
210 goto cleanup;
211
212 /* Read SymbolicLink value */
213 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
214 if (rc != ERROR_SUCCESS )
215 goto cleanup;
216 if (dwRegType != REG_SZ)
217 {
218 rc = ERROR_GEN_FAILURE;
219 goto cleanup;
220 }
221
222 /* We have found a device */
223 /* Step 1. Create a device info element */
224 if (!CreateDeviceInfo(list, InstancePath, &ClassGuid, &deviceInfo))
225 {
226 rc = GetLastError();
227 goto cleanup;
228 }
229 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
230 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
231
232 /* Step 2. Create an interface list for this element */
233 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
234 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
235 if (!pSymbolicLink)
236 {
237 rc = ERROR_NOT_ENOUGH_MEMORY;
238 goto cleanup;
239 }
240 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
241 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
242 if (rc != ERROR_SUCCESS)
243 goto cleanup;
244 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
245 {
246 rc = GetLastError();
247 goto cleanup;
248 }
249
250 /* Step 3. Update flags */
251 if (KeyBuffer[1] == '\0')
252 interfaceInfo->Flags |= SPINT_DEFAULT;
253 rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
254 if (rc != ERROR_SUCCESS)
255 {
256 #if 0
257 if (OnlyPresentInterfaces)
258 {
259 DestroyDeviceInterface(interfaceInfo);
260 continue;
261 }
262 else
263 interfaceInfo->Flags |= SPINT_REMOVED;
264 #endif
265 }
266 else
267 {
268 dwLength = sizeof(DWORD);
269 if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength) == ERROR_SUCCESS
270 && dwRegType == REG_DWORD && LinkedValue)
271 interfaceInfo->Flags |= SPINT_ACTIVE;
272 RegCloseKey(hControlKey);
273 }
274
275 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
276 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
277 }
278 }
279 rc = ERROR_SUCCESS;
280
281 cleanup:
282 if (hReferenceKey != NULL)
283 RegCloseKey(hReferenceKey);
284 if (hDeviceInstanceKey != NULL)
285 RegCloseKey(hDeviceInstanceKey);
286 if (hInterfaceKey != INVALID_HANDLE_VALUE)
287 RegCloseKey(hInterfaceKey);
288 HeapFree(GetProcessHeap(), 0, InstancePath);
289 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
290 return rc;
291 }
292
293 static LPWSTR
294 CreateSymbolicLink(
295 IN LPGUID InterfaceGuid,
296 IN LPCWSTR ReferenceString,
297 IN struct DeviceInfo *devInfo)
298 {
299 DWORD Length, Index, Offset;
300 LPWSTR Key;
301
302 Length = wcslen(devInfo->instanceId) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */;
303
304 Key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length * sizeof(WCHAR));
305 if (!Key)
306 return NULL;
307
308 wcscpy(Key, L"##?#");
309 wcscat(Key, devInfo->instanceId);
310
311 for(Index = 4; Index < Length; Index++)
312 {
313 if (Key[Index] == L'\\')
314 {
315 Key[Index] = L'#';
316 }
317 }
318
319 wcscat(Key, L"#");
320
321 Offset = wcslen(Key);
322 pSetupStringFromGuid(InterfaceGuid, Key + Offset, Length - Offset);
323
324 return Key;
325 }
326
327
328 static BOOL
329 InstallOneInterface(
330 IN LPGUID InterfaceGuid,
331 IN LPCWSTR ReferenceString,
332 IN LPCWSTR InterfaceSection,
333 IN UINT InterfaceFlags,
334 IN HINF hInf,
335 IN HDEVINFO DeviceInfoSet,
336 IN struct DeviceInfo *devInfo)
337 {
338 HKEY hKey, hRefKey;
339 LPWSTR Path;
340 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
341 struct DeviceInterface *DevItf = NULL;
342
343 if (InterfaceFlags != 0)
344 {
345 SetLastError(ERROR_INVALID_PARAMETER);
346 return FALSE;
347 }
348
349 TRACE("Need to InstallOneInterface(%s %s %s %u) hInf %p DeviceInfoSet %p devInfo %p instanceId %s\n", debugstr_guid(InterfaceGuid),
350 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags, hInf, DeviceInfoSet, devInfo, debugstr_w(devInfo->instanceId));
351
352
353 Path = CreateSymbolicLink(InterfaceGuid, ReferenceString, devInfo);
354 if (!Path)
355 return FALSE;
356
357 CreateDeviceInterface(devInfo, Path, InterfaceGuid, &DevItf);
358 HeapFree(GetProcessHeap(), 0, Path);
359 if (!DevItf)
360 {
361 return FALSE;
362 }
363
364 memcpy(&DeviceInterfaceData.InterfaceClassGuid, &DevItf->InterfaceClassGuid, sizeof(GUID));
365 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
366 DeviceInterfaceData.Flags = DevItf->Flags;
367 DeviceInterfaceData.Reserved = (ULONG_PTR)DevItf;
368
369 hKey = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet, &DeviceInterfaceData, 0, KEY_ALL_ACCESS, NULL, 0);
370 HeapFree(GetProcessHeap(), 0, DevItf);
371 if (hKey == INVALID_HANDLE_VALUE)
372 {
373 return FALSE;
374 }
375
376 if (ReferenceString)
377 {
378 Path = HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString) + 2) * sizeof(WCHAR));
379 if (!Path)
380 {
381 RegCloseKey(hKey);
382 return FALSE;
383 }
384
385 wcscpy(Path, L"#");
386 wcscat(Path, ReferenceString);
387
388 if (RegCreateKeyExW(hKey, Path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
389 {
390 ERR("failed to create key %s %lx\n", debugstr_w(Path), GetLastError());
391 HeapFree(GetProcessHeap(), 0, Path);
392 return FALSE;
393 }
394
395 RegCloseKey(hKey);
396 hKey = hRefKey;
397 HeapFree(GetProcessHeap(), 0, Path);
398 }
399
400 if (RegCreateKeyExW(hKey, L"Device Parameters", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
401 {
402 RegCloseKey(hKey);
403 return FALSE;
404 }
405
406 return SetupInstallFromInfSectionW(NULL, /* FIXME */ hInf, InterfaceSection, SPINST_REGISTRY, hRefKey, NULL, 0, NULL, NULL, NULL, NULL);
407 }
408
409 /***********************************************************************
410 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
411 */
412 BOOL WINAPI
413 SetupDiInstallDeviceInterfaces(
414 IN HDEVINFO DeviceInfoSet,
415 IN PSP_DEVINFO_DATA DeviceInfoData)
416 {
417 struct DeviceInfoSet *list = NULL;
418 BOOL ret = FALSE;
419
420 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
421
422 if (!DeviceInfoSet)
423 SetLastError(ERROR_INVALID_PARAMETER);
424 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
425 SetLastError(ERROR_INVALID_HANDLE);
426 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
427 SetLastError(ERROR_INVALID_HANDLE);
428 else if (!DeviceInfoData)
429 SetLastError(ERROR_INVALID_PARAMETER);
430 else if (DeviceInfoData && DeviceInfoData->Reserved == 0)
431 SetLastError(ERROR_INVALID_USER_BUFFER);
432 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
433 SetLastError(ERROR_INVALID_USER_BUFFER);
434 else
435 {
436 struct DeviceInfo *devInfo;
437 struct DriverInfoElement *SelectedDriver = NULL;
438 SP_DEVINSTALL_PARAMS_W InstallParams;
439 WCHAR SectionName[MAX_PATH];
440 DWORD SectionNameLength = 0;
441 INFCONTEXT ContextInterface;
442 LPWSTR InterfaceGuidString = NULL;
443 LPWSTR ReferenceString = NULL;
444 LPWSTR InterfaceSection = NULL;
445 INT InterfaceFlags;
446 GUID InterfaceGuid;
447 BOOL Result;
448
449 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
450
451 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
452 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
453 if (!Result)
454 goto cleanup;
455
456 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
457 if (SelectedDriver == NULL)
458 {
459 SetLastError(ERROR_NO_DRIVER_SELECTED);
460 ret = FALSE;
461 goto cleanup;
462 }
463
464 /* Get .Interfaces section name */
465 Result = SetupDiGetActualSectionToInstallW(
466 SelectedDriver->InfFileDetails->hInf,
467 SelectedDriver->Details.SectionName,
468 SectionName, MAX_PATH, &SectionNameLength, NULL);
469 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
470 goto cleanup;
471 strcatW(SectionName, DotInterfaces);
472
473 ret = TRUE;
474 Result = SetupFindFirstLineW(
475 SelectedDriver->InfFileDetails->hInf,
476 SectionName,
477 AddInterface,
478 &ContextInterface);
479 while (ret && Result)
480 {
481 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
482 if (!ret)
483 goto cleanup;
484 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
485 {
486 SetLastError(ERROR_INVALID_PARAMETER);
487 ret = FALSE;
488 goto cleanup;
489 }
490
491 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
492 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
493 {
494 /* Bad GUID, skip the entry */
495 SetLastError(ERROR_INVALID_PARAMETER);
496 ret = FALSE;
497 goto cleanup;
498 }
499
500 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
501 if (!ret)
502 goto cleanup;
503
504 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
505 if (!ret)
506 {
507 /* ReferenceString is optional */
508 InterfaceSection = ReferenceString;
509 ReferenceString = NULL;
510 }
511
512 ret = SetupGetIntField(
513 &ContextInterface,
514 (ReferenceString ? 4 : 3), /* Field index */
515 &InterfaceFlags);
516 if (!ret)
517 {
518 if (GetLastError() == ERROR_INVALID_PARAMETER)
519 {
520 /* The field may be empty. Ignore the error */
521 InterfaceFlags = 0;
522 ret = TRUE;
523 }
524 else
525 goto cleanup;
526 }
527
528 /* Install Interface */
529 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags, SelectedDriver->InfFileDetails->hInf, DeviceInfoSet, devInfo);
530
531 cleanup:
532 MyFree(InterfaceGuidString);
533 if (ReferenceString)
534 MyFree(ReferenceString);
535 MyFree(InterfaceSection);
536 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
537 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
538 }
539 }
540
541 TRACE("Returning %d\n", ret);
542 return ret;
543 }
544
545 HKEY WINAPI
546 SetupDiOpenDeviceInterfaceRegKey(
547 IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IN DWORD Reserved, IN REGSAM samDesired)
548 {
549 HKEY hKey = INVALID_HANDLE_VALUE, hDevKey;
550 struct DeviceInfoSet * list;
551
552 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet, DeviceInterfaceData, Reserved, samDesired);
553
554 if (!DeviceInfoSet)
555 SetLastError(ERROR_INVALID_PARAMETER);
556 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
557 SetLastError(ERROR_INVALID_HANDLE);
558 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
559 SetLastError(ERROR_INVALID_HANDLE);
560 else if (!DeviceInterfaceData)
561 SetLastError(ERROR_INVALID_PARAMETER);
562 else if (DeviceInterfaceData && DeviceInterfaceData->Reserved == 0)
563 SetLastError(ERROR_INVALID_USER_BUFFER);
564 else if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
565 SetLastError(ERROR_INVALID_USER_BUFFER);
566 else
567 {
568 struct DeviceInterface *DevItf;
569 LPWSTR Path, Guid, Slash;
570 DWORD Length;
571 DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
572
573 Length = wcslen(DevItf->SymbolicLink);
574
575 Path = HeapAlloc(GetProcessHeap(), 0, (Length+2) * sizeof(WCHAR));
576 if (!Path)
577 {
578 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
579 return INVALID_HANDLE_VALUE;
580 }
581
582 wcscpy(Path, DevItf->SymbolicLink);
583
584 Guid = wcsrchr(Path, '}');
585 Slash = wcsrchr(Path, '\\');
586 if (!Guid || !Slash)
587 {
588 SetLastError(ERROR_INVALID_PARAMETER);
589 return INVALID_HANDLE_VALUE;
590 }
591
592 if ((ULONG_PTR)Slash > (ULONG_PTR)Guid)
593 {
594 /* Create an extra slash */
595 memmove(Slash+1, Slash, (wcslen(Slash) + 1) * sizeof(WCHAR));
596 Slash[1] = L'#';
597 }
598
599 Guid = Path;
600 while((ULONG_PTR)Guid < (ULONG_PTR)Slash)
601 {
602 if (*Guid == L'\\')
603 *Guid = L'#';
604
605 Guid++;
606 }
607
608 hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
609 if (hKey != INVALID_HANDLE_VALUE)
610 {
611 if (RegOpenKeyExW(hKey, Path, 0, samDesired, &hDevKey) == ERROR_SUCCESS)
612 {
613 RegCloseKey(hKey);
614 hKey = hDevKey;
615 }
616 else
617 {
618 RegCloseKey(hKey);
619 hKey = INVALID_HANDLE_VALUE;
620 }
621 }
622
623 HeapFree(GetProcessHeap(), 0, Path);
624 }
625
626 return hKey;
627 }