[SETUPAPI]
[reactos.git] / reactos / 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 return SetupInstallFromInfSectionW(NULL, /* FIXME */ hInf, InterfaceSection, SPINST_REGISTRY, hKey, NULL, 0, NULL, NULL, NULL, NULL);
403 }
404
405 /***********************************************************************
406 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
407 */
408 BOOL WINAPI
409 SetupDiInstallDeviceInterfaces(
410 IN HDEVINFO DeviceInfoSet,
411 IN PSP_DEVINFO_DATA DeviceInfoData)
412 {
413 struct DeviceInfoSet *list = NULL;
414 BOOL ret = FALSE;
415
416 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
417
418 if (!DeviceInfoSet)
419 SetLastError(ERROR_INVALID_PARAMETER);
420 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
421 SetLastError(ERROR_INVALID_HANDLE);
422 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
423 SetLastError(ERROR_INVALID_HANDLE);
424 else if (!DeviceInfoData)
425 SetLastError(ERROR_INVALID_PARAMETER);
426 else if (DeviceInfoData && DeviceInfoData->Reserved == 0)
427 SetLastError(ERROR_INVALID_USER_BUFFER);
428 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
429 SetLastError(ERROR_INVALID_USER_BUFFER);
430 else
431 {
432 struct DeviceInfo *devInfo;
433 struct DriverInfoElement *SelectedDriver = NULL;
434 SP_DEVINSTALL_PARAMS_W InstallParams;
435 WCHAR SectionName[MAX_PATH];
436 DWORD SectionNameLength = 0;
437 INFCONTEXT ContextInterface;
438 LPWSTR InterfaceGuidString = NULL;
439 LPWSTR ReferenceString = NULL;
440 LPWSTR InterfaceSection = NULL;
441 INT InterfaceFlags;
442 GUID InterfaceGuid;
443 BOOL Result;
444
445 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
446
447 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
448 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
449 if (!Result)
450 goto cleanup;
451
452 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
453 if (SelectedDriver == NULL)
454 {
455 SetLastError(ERROR_NO_DRIVER_SELECTED);
456 ret = FALSE;
457 goto cleanup;
458 }
459
460 /* Get .Interfaces section name */
461 Result = SetupDiGetActualSectionToInstallW(
462 SelectedDriver->InfFileDetails->hInf,
463 SelectedDriver->Details.SectionName,
464 SectionName, MAX_PATH, &SectionNameLength, NULL);
465 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
466 goto cleanup;
467 strcatW(SectionName, DotInterfaces);
468
469 ret = TRUE;
470 Result = SetupFindFirstLineW(
471 SelectedDriver->InfFileDetails->hInf,
472 SectionName,
473 AddInterface,
474 &ContextInterface);
475 while (ret && Result)
476 {
477 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
478 if (!ret)
479 goto cleanup;
480 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
481 {
482 SetLastError(ERROR_INVALID_PARAMETER);
483 ret = FALSE;
484 goto cleanup;
485 }
486
487 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
488 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
489 {
490 /* Bad GUID, skip the entry */
491 SetLastError(ERROR_INVALID_PARAMETER);
492 ret = FALSE;
493 goto cleanup;
494 }
495
496 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
497 if (!ret)
498 goto cleanup;
499
500 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
501 if (!ret)
502 {
503 /* ReferenceString is optional */
504 InterfaceSection = ReferenceString;
505 ReferenceString = NULL;
506 }
507
508 ret = SetupGetIntField(
509 &ContextInterface,
510 (ReferenceString ? 4 : 3), /* Field index */
511 &InterfaceFlags);
512 if (!ret)
513 {
514 if (GetLastError() == ERROR_INVALID_PARAMETER)
515 {
516 /* The field may be empty. Ignore the error */
517 InterfaceFlags = 0;
518 ret = TRUE;
519 }
520 else
521 goto cleanup;
522 }
523
524 /* Install Interface */
525 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags, SelectedDriver->InfFileDetails->hInf, DeviceInfoSet, devInfo);
526
527 cleanup:
528 MyFree(InterfaceGuidString);
529 if (ReferenceString)
530 MyFree(ReferenceString);
531 MyFree(InterfaceSection);
532 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
533 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
534 }
535 }
536
537 TRACE("Returning %d\n", ret);
538 return ret;
539 }
540
541 HKEY WINAPI
542 SetupDiOpenDeviceInterfaceRegKey(
543 IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IN DWORD Reserved, IN REGSAM samDesired)
544 {
545 HKEY hKey = INVALID_HANDLE_VALUE, hDevKey;
546 struct DeviceInfoSet * list;
547
548 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet, DeviceInterfaceData, Reserved, samDesired);
549
550 if (!DeviceInfoSet)
551 SetLastError(ERROR_INVALID_PARAMETER);
552 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
553 SetLastError(ERROR_INVALID_HANDLE);
554 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
555 SetLastError(ERROR_INVALID_HANDLE);
556 else if (!DeviceInterfaceData)
557 SetLastError(ERROR_INVALID_PARAMETER);
558 else if (DeviceInterfaceData && DeviceInterfaceData->Reserved == 0)
559 SetLastError(ERROR_INVALID_USER_BUFFER);
560 else if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
561 SetLastError(ERROR_INVALID_USER_BUFFER);
562 else
563 {
564 struct DeviceInterface *DevItf;
565 LPWSTR Path, Guid, Slash;
566 DWORD Length;
567 DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
568
569 Length = wcslen(DevItf->SymbolicLink);
570
571 Path = HeapAlloc(GetProcessHeap(), 0, (Length+2) * sizeof(WCHAR));
572 if (!Path)
573 {
574 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
575 return INVALID_HANDLE_VALUE;
576 }
577
578 wcscpy(Path, DevItf->SymbolicLink);
579
580 Guid = wcsrchr(Path, '}');
581 Slash = wcsrchr(Path, '\\');
582 if (!Guid || !Slash)
583 {
584 SetLastError(ERROR_INVALID_PARAMETER);
585 return INVALID_HANDLE_VALUE;
586 }
587
588 if ((ULONG_PTR)Slash > (ULONG_PTR)Guid)
589 {
590 /* Create an extra slash */
591 memmove(Slash+1, Slash, (wcslen(Slash) + 1) * sizeof(WCHAR));
592 Slash[1] = L'#';
593 }
594
595 Guid = Path;
596 while((ULONG_PTR)Guid < (ULONG_PTR)Slash)
597 {
598 if (*Guid == L'\\')
599 *Guid = L'#';
600
601 Guid++;
602 }
603
604 hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
605 if (hKey != INVALID_HANDLE_VALUE)
606 {
607 if (RegOpenKeyExW(hKey, Path, 0, samDesired, &hDevKey) == ERROR_SUCCESS)
608 {
609 RegCloseKey(hKey);
610 hKey = hDevKey;
611 }
612 else
613 {
614 RegCloseKey(hKey);
615 hKey = INVALID_HANDLE_VALUE;
616 }
617 }
618
619 HeapFree(GetProcessHeap(), 0, Path);
620 }
621
622 return hKey;
623 }