xref: /reactos/dll/win32/setupapi/interface.c (revision 8a978a17)
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.ClassInstallReserved;
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 }
630 
631 /***********************************************************************
632  *		SetupDiDeleteDeviceInterfaceData (SETUPAPI.@)
633  */
634 BOOL
635 WINAPI
636 SetupDiDeleteDeviceInterfaceData(
637     HDEVINFO DeviceInfoSet,
638     PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
639 {
640     FIXME("SetupDiDeleteDeviceInterfaceData(%p %p) stub\n",
641           DeviceInfoSet, DeviceInterfaceData);
642     return TRUE;
643 }
644