xref: /reactos/dll/win32/setupapi/interface.c (revision 61e35141)
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
CreateDeviceInterface(IN struct DeviceInfo * deviceInfo,IN LPCWSTR SymbolicLink,IN LPCGUID pInterfaceGuid,OUT struct DeviceInterface ** pDeviceInterface)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
DestroyDeviceInterface(struct DeviceInterface * deviceInterface)61 DestroyDeviceInterface(
62     struct DeviceInterface* deviceInterface)
63 {
64     return HeapFree(GetProcessHeap(), 0, deviceInterface);
65 }
66 
67 LONG
SETUP_CreateInterfaceList(struct DeviceInfoSet * list,PCWSTR MachineName,CONST GUID * InterfaceGuid,PCWSTR DeviceInstanceW,BOOL OnlyPresentInterfaces)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
CreateSymbolicLink(IN LPGUID InterfaceGuid,IN LPCWSTR ReferenceString,IN struct DeviceInfo * devInfo)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
InstallOneInterface(IN LPGUID InterfaceGuid,IN LPCWSTR ReferenceString,IN LPCWSTR InterfaceSection,IN UINT InterfaceFlags,IN HINF hInf,IN HDEVINFO DeviceInfoSet,IN struct DeviceInfo * devInfo)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
SetupDiInstallDeviceInterfaces(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData)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
SetupDiOpenDeviceInterfaceRegKey(IN HDEVINFO DeviceInfoSet,IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,IN DWORD Reserved,IN REGSAM samDesired)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
SetupDiDeleteDeviceInterfaceData(HDEVINFO DeviceInfoSet,PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)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