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