Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[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 /* 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 goto cleanup;
217 if (dwRegType != REG_SZ)
218 {
219 rc = ERROR_GEN_FAILURE;
220 goto cleanup;
221 }
222
223 /* We have found a device */
224 /* Step 1. Create a device info element */
225 if (!CreateDeviceInfo(list, InstancePath, &ClassGuid, &deviceInfo))
226 {
227 rc = GetLastError();
228 goto cleanup;
229 }
230 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
231 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
232
233 /* Step 2. Create an interface list for this element */
234 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
235 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
236 if (!pSymbolicLink)
237 {
238 rc = ERROR_NOT_ENOUGH_MEMORY;
239 goto cleanup;
240 }
241 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
242 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
243 if (rc != ERROR_SUCCESS)
244 goto cleanup;
245 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
246 {
247 rc = GetLastError();
248 goto cleanup;
249 }
250
251 /* Step 3. Update flags */
252 if (KeyBuffer[1] == '\0')
253 interfaceInfo->Flags |= SPINT_DEFAULT;
254 rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
255 if (rc != ERROR_SUCCESS)
256 {
257 #if 0
258 if (OnlyPresentInterfaces)
259 {
260 DestroyDeviceInterface(interfaceInfo);
261 continue;
262 }
263 else
264 interfaceInfo->Flags |= SPINT_REMOVED;
265 #endif
266 }
267 else
268 {
269 dwLength = sizeof(DWORD);
270 if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength) == ERROR_SUCCESS
271 && dwRegType == REG_DWORD && LinkedValue)
272 interfaceInfo->Flags |= SPINT_ACTIVE;
273 RegCloseKey(hControlKey);
274 }
275
276 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
277 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
278 }
279 }
280 rc = ERROR_SUCCESS;
281
282 cleanup:
283 if (hReferenceKey != NULL)
284 RegCloseKey(hReferenceKey);
285 if (hDeviceInstanceKey != NULL)
286 RegCloseKey(hDeviceInstanceKey);
287 if (hInterfaceKey != INVALID_HANDLE_VALUE)
288 RegCloseKey(hInterfaceKey);
289 HeapFree(GetProcessHeap(), 0, InstancePath);
290 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
291 return rc;
292 }
293
294 static LPWSTR
295 CreateSymbolicLink(
296 IN LPGUID InterfaceGuid,
297 IN LPCWSTR ReferenceString,
298 IN struct DeviceInfo *devInfo)
299 {
300 DWORD Length, Index, Offset;
301 LPWSTR Key;
302
303 Length = wcslen(devInfo->instanceId) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */;
304
305 Key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length * sizeof(WCHAR));
306 if (!Key)
307 return NULL;
308
309 wcscpy(Key, L"##?#");
310 wcscat(Key, devInfo->instanceId);
311
312 for(Index = 4; Index < Length; Index++)
313 {
314 if (Key[Index] == L'\\')
315 {
316 Key[Index] = L'#';
317 }
318 }
319
320 wcscat(Key, L"#");
321
322 Offset = wcslen(Key);
323 pSetupStringFromGuid(InterfaceGuid, Key + Offset, Length - Offset);
324
325 return Key;
326 }
327
328
329 static BOOL
330 InstallOneInterface(
331 IN LPGUID InterfaceGuid,
332 IN LPCWSTR ReferenceString,
333 IN LPCWSTR InterfaceSection,
334 IN UINT InterfaceFlags,
335 IN HINF hInf,
336 IN HDEVINFO DeviceInfoSet,
337 IN struct DeviceInfo *devInfo)
338 {
339 HKEY hKey, hRefKey;
340 LPWSTR Path;
341 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
342 struct DeviceInterface *DevItf = NULL;
343
344 if (InterfaceFlags != 0)
345 {
346 SetLastError(ERROR_INVALID_PARAMETER);
347 return FALSE;
348 }
349
350 TRACE("Need to InstallOneInterface(%s %s %s %u) hInf %p DeviceInfoSet %p devInfo %p instanceId %s\n", debugstr_guid(InterfaceGuid),
351 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags, hInf, DeviceInfoSet, devInfo, debugstr_w(devInfo->instanceId));
352
353
354 Path = CreateSymbolicLink(InterfaceGuid, ReferenceString, devInfo);
355 if (!Path)
356 return FALSE;
357
358 CreateDeviceInterface(devInfo, Path, InterfaceGuid, &DevItf);
359 HeapFree(GetProcessHeap(), 0, Path);
360 if (!DevItf)
361 {
362 return FALSE;
363 }
364
365 memcpy(&DeviceInterfaceData.InterfaceClassGuid, &DevItf->InterfaceClassGuid, sizeof(GUID));
366 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
367 DeviceInterfaceData.Flags = DevItf->Flags;
368 DeviceInterfaceData.Reserved = (ULONG_PTR)DevItf;
369
370 hKey = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet, &DeviceInterfaceData, 0, KEY_ALL_ACCESS, NULL, 0);
371 HeapFree(GetProcessHeap(), 0, DevItf);
372 if (hKey == INVALID_HANDLE_VALUE)
373 {
374 return FALSE;
375 }
376
377 if (ReferenceString)
378 {
379 Path = HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString) + 2) * sizeof(WCHAR));
380 if (!Path)
381 {
382 RegCloseKey(hKey);
383 return FALSE;
384 }
385
386 wcscpy(Path, L"#");
387 wcscat(Path, ReferenceString);
388
389 if (RegCreateKeyExW(hKey, Path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
390 {
391 ERR("failed to create key %s %lx\n", debugstr_w(Path), GetLastError());
392 HeapFree(GetProcessHeap(), 0, Path);
393 return FALSE;
394 }
395
396 RegCloseKey(hKey);
397 hKey = hRefKey;
398 HeapFree(GetProcessHeap(), 0, Path);
399 }
400
401 if (RegCreateKeyExW(hKey, L"Device Parameters", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
402 {
403 RegCloseKey(hKey);
404 return FALSE;
405 }
406
407 return SetupInstallFromInfSectionW(NULL, /* FIXME */ hInf, InterfaceSection, SPINST_REGISTRY, hRefKey, NULL, 0, NULL, NULL, NULL, NULL);
408 }
409
410 /***********************************************************************
411 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
412 */
413 BOOL WINAPI
414 SetupDiInstallDeviceInterfaces(
415 IN HDEVINFO DeviceInfoSet,
416 IN PSP_DEVINFO_DATA DeviceInfoData)
417 {
418 struct DeviceInfoSet *list = NULL;
419 BOOL ret = FALSE;
420
421 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
422
423 if (!DeviceInfoSet)
424 SetLastError(ERROR_INVALID_PARAMETER);
425 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
426 SetLastError(ERROR_INVALID_HANDLE);
427 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
428 SetLastError(ERROR_INVALID_HANDLE);
429 else if (!DeviceInfoData)
430 SetLastError(ERROR_INVALID_PARAMETER);
431 else if (DeviceInfoData && DeviceInfoData->Reserved == 0)
432 SetLastError(ERROR_INVALID_USER_BUFFER);
433 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
434 SetLastError(ERROR_INVALID_USER_BUFFER);
435 else
436 {
437 struct DeviceInfo *devInfo;
438 struct DriverInfoElement *SelectedDriver = NULL;
439 SP_DEVINSTALL_PARAMS_W InstallParams;
440 WCHAR SectionName[MAX_PATH];
441 DWORD SectionNameLength = 0;
442 INFCONTEXT ContextInterface;
443 LPWSTR InterfaceGuidString = NULL;
444 LPWSTR ReferenceString = NULL;
445 LPWSTR InterfaceSection = NULL;
446 INT InterfaceFlags;
447 GUID InterfaceGuid;
448 BOOL Result;
449
450 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
451
452 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
453 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
454 if (!Result)
455 goto cleanup;
456
457 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
458 if (SelectedDriver == NULL)
459 {
460 SetLastError(ERROR_NO_DRIVER_SELECTED);
461 ret = FALSE;
462 goto cleanup;
463 }
464
465 /* Get .Interfaces section name */
466 Result = SetupDiGetActualSectionToInstallW(
467 SelectedDriver->InfFileDetails->hInf,
468 SelectedDriver->Details.SectionName,
469 SectionName, MAX_PATH, &SectionNameLength, NULL);
470 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
471 goto cleanup;
472 strcatW(SectionName, DotInterfaces);
473
474 ret = TRUE;
475 Result = SetupFindFirstLineW(
476 SelectedDriver->InfFileDetails->hInf,
477 SectionName,
478 AddInterface,
479 &ContextInterface);
480 while (ret && Result)
481 {
482 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
483 if (!ret)
484 goto cleanup;
485 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
486 {
487 SetLastError(ERROR_INVALID_PARAMETER);
488 ret = FALSE;
489 goto cleanup;
490 }
491
492 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
493 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
494 {
495 /* Bad GUID, skip the entry */
496 SetLastError(ERROR_INVALID_PARAMETER);
497 ret = FALSE;
498 goto cleanup;
499 }
500
501 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
502 if (!ret)
503 goto cleanup;
504
505 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
506 if (!ret)
507 {
508 /* ReferenceString is optional */
509 InterfaceSection = ReferenceString;
510 ReferenceString = NULL;
511 }
512
513 ret = SetupGetIntField(
514 &ContextInterface,
515 (ReferenceString ? 4 : 3), /* Field index */
516 &InterfaceFlags);
517 if (!ret)
518 {
519 if (GetLastError() == ERROR_INVALID_PARAMETER)
520 {
521 /* The field may be empty. Ignore the error */
522 InterfaceFlags = 0;
523 ret = TRUE;
524 }
525 else
526 goto cleanup;
527 }
528
529 /* Install Interface */
530 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags, SelectedDriver->InfFileDetails->hInf, DeviceInfoSet, devInfo);
531
532 cleanup:
533 MyFree(InterfaceGuidString);
534 if (ReferenceString)
535 MyFree(ReferenceString);
536 MyFree(InterfaceSection);
537 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
538 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
539 }
540 }
541
542 TRACE("Returning %d\n", ret);
543 return ret;
544 }
545
546 HKEY WINAPI
547 SetupDiOpenDeviceInterfaceRegKey(
548 IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IN DWORD Reserved, IN REGSAM samDesired)
549 {
550 HKEY hKey = INVALID_HANDLE_VALUE, hDevKey;
551 struct DeviceInfoSet * list;
552
553 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet, DeviceInterfaceData, Reserved, samDesired);
554
555 if (!DeviceInfoSet)
556 SetLastError(ERROR_INVALID_PARAMETER);
557 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
558 SetLastError(ERROR_INVALID_HANDLE);
559 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
560 SetLastError(ERROR_INVALID_HANDLE);
561 else if (!DeviceInterfaceData)
562 SetLastError(ERROR_INVALID_PARAMETER);
563 else if (DeviceInterfaceData && DeviceInterfaceData->Reserved == 0)
564 SetLastError(ERROR_INVALID_USER_BUFFER);
565 else if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
566 SetLastError(ERROR_INVALID_USER_BUFFER);
567 else
568 {
569 struct DeviceInterface *DevItf;
570 LPWSTR Path, Guid, Slash;
571 DWORD Length;
572 DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
573
574 Length = wcslen(DevItf->SymbolicLink);
575
576 Path = HeapAlloc(GetProcessHeap(), 0, (Length+2) * sizeof(WCHAR));
577 if (!Path)
578 {
579 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
580 return INVALID_HANDLE_VALUE;
581 }
582
583 wcscpy(Path, DevItf->SymbolicLink);
584
585 Guid = wcsrchr(Path, '}');
586 Slash = wcsrchr(Path, '\\');
587 if (!Guid || !Slash)
588 {
589 HeapFree(GetProcessHeap(), 0, Path);
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 }