2 * SetupAPI interface-related functions
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
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.
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.
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
22 #include "setupapi_private.h"
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};
34 CreateDeviceInterface(
35 IN
struct DeviceInfo
* deviceInfo
,
36 IN LPCWSTR SymbolicLink
,
37 IN LPCGUID pInterfaceGuid
,
38 OUT
struct DeviceInterface
**pDeviceInterface
)
40 struct DeviceInterface
*deviceInterface
;
42 *pDeviceInterface
= NULL
;
44 deviceInterface
= HeapAlloc(GetProcessHeap(), 0,
45 FIELD_OFFSET(struct DeviceInterface
, SymbolicLink
) + (strlenW(SymbolicLink
) + 1) * sizeof(WCHAR
));
48 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
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
));
56 *pDeviceInterface
= deviceInterface
;
61 DestroyDeviceInterface(
62 struct DeviceInterface
* deviceInterface
)
64 return HeapFree(GetProcessHeap(), 0, deviceInterface
);
68 SETUP_CreateInterfaceList(
69 struct DeviceInfoSet
*list
,
71 CONST GUID
*InterfaceGuid
,
72 PCWSTR DeviceInstanceW
/* OPTIONAL */,
73 BOOL OnlyPresentInterfaces
)
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} */
82 WCHAR KeyBuffer
[max(MAX_PATH
, MAX_GUID_STRING_LEN
) + 1];
83 PWSTR pSymbolicLink
= NULL
;
84 PWSTR InstancePath
= NULL
;
86 DWORD dwLength
, dwInstancePathLength
;
90 struct DeviceInfo
*deviceInfo
;
92 hInterfaceKey
= INVALID_HANDLE_VALUE
;
93 hDeviceInstanceKey
= NULL
;
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
)
104 /* Enumerate sub keys of hInterfaceKey */
108 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
109 rc
= RegEnumKeyExW(hInterfaceKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
110 if (rc
== ERROR_NO_MORE_ITEMS
)
112 if (rc
!= ERROR_SUCCESS
)
117 if (hDeviceInstanceKey
!= NULL
)
118 RegCloseKey(hDeviceInstanceKey
);
119 rc
= RegOpenKeyExW(hInterfaceKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, &hDeviceInstanceKey
);
120 if (rc
!= ERROR_SUCCESS
)
123 /* Read DeviceInstance */
124 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, &dwRegType
, NULL
, &dwInstancePathLength
);
125 if (rc
!= ERROR_SUCCESS
)
127 if (dwRegType
!= REG_SZ
)
129 rc
= ERROR_GEN_FAILURE
;
132 HeapFree(GetProcessHeap(), 0, InstancePath
);
133 InstancePath
= HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength
+ sizeof(WCHAR
));
136 rc
= ERROR_NOT_ENOUGH_MEMORY
;
139 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, NULL
, (LPBYTE
)InstancePath
, &dwInstancePathLength
);
140 if (rc
!= ERROR_SUCCESS
)
142 InstancePath
[dwInstancePathLength
/ sizeof(WCHAR
)] = '\0';
143 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath
));
147 /* Check if device enumerator is not the right one */
148 if (strcmpW(DeviceInstanceW
, InstancePath
) != 0)
152 /* Find class GUID associated to the device instance */
155 REGSTR_PATH_SYSTEMENUM
,
159 if (rc
!= ERROR_SUCCESS
)
167 RegCloseKey(hEnumKey
);
168 if (rc
!= ERROR_SUCCESS
)
170 dwLength
= sizeof(KeyBuffer
) - sizeof(WCHAR
);
171 rc
= RegQueryValueExW(hKey
, ClassGUID
, NULL
, NULL
, (LPBYTE
)KeyBuffer
, &dwLength
);
173 if (rc
!= ERROR_SUCCESS
)
175 KeyBuffer
[dwLength
/ sizeof(WCHAR
)] = '\0';
176 KeyBuffer
[37] = '\0'; /* Replace the } by a NULL character */
177 if (UuidFromStringW(&KeyBuffer
[1], &ClassGuid
) != RPC_S_OK
)
179 rc
= ERROR_GEN_FAILURE
;
182 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid
));
184 /* If current device doesn't match the list GUID (if any), skip this entry */
185 if (!IsEqualIID(&list
->ClassGuid
, &GUID_NULL
) && !IsEqualIID(&list
->ClassGuid
, &ClassGuid
))
188 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
192 struct DeviceInterface
*interfaceInfo
;
194 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
195 rc
= RegEnumKeyExW(hDeviceInstanceKey
, j
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
196 if (rc
== ERROR_NO_MORE_ITEMS
)
198 if (rc
!= ERROR_SUCCESS
)
201 if (KeyBuffer
[0] != '#')
202 /* This entry doesn't represent an interesting entry */
206 if (hReferenceKey
!= NULL
)
207 RegCloseKey(hReferenceKey
);
208 rc
= RegOpenKeyExW(hDeviceInstanceKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hReferenceKey
);
209 if (rc
!= ERROR_SUCCESS
)
212 /* Read SymbolicLink value */
213 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, &dwRegType
, NULL
, &dwLength
);
214 if (rc
!= ERROR_SUCCESS
)
216 if (dwRegType
!= REG_SZ
)
218 rc
= ERROR_GEN_FAILURE
;
222 /* We have found a device */
223 /* Step 1. Create a device info element */
224 if (!CreateDeviceInfo(list
, InstancePath
, &ClassGuid
, &deviceInfo
))
229 TRACE("Adding device %s to list\n", debugstr_w(InstancePath
));
230 InsertTailList(&list
->ListHead
, &deviceInfo
->ListEntry
);
232 /* Step 2. Create an interface list for this element */
233 HeapFree(GetProcessHeap(), 0, pSymbolicLink
);
234 pSymbolicLink
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ 1) * sizeof(WCHAR
));
237 rc
= ERROR_NOT_ENOUGH_MEMORY
;
240 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, NULL
, (LPBYTE
)pSymbolicLink
, &dwLength
);
241 pSymbolicLink
[dwLength
/ sizeof(WCHAR
)] = '\0';
242 if (rc
!= ERROR_SUCCESS
)
244 if (!CreateDeviceInterface(deviceInfo
, pSymbolicLink
, InterfaceGuid
, &interfaceInfo
))
250 /* Step 3. Update flags */
251 if (KeyBuffer
[1] == '\0')
252 interfaceInfo
->Flags
|= SPINT_DEFAULT
;
253 rc
= RegOpenKeyExW(hReferenceKey
, Control
, 0, KEY_QUERY_VALUE
, &hControlKey
);
254 if (rc
!= ERROR_SUCCESS
)
257 if (OnlyPresentInterfaces
)
259 DestroyDeviceInterface(interfaceInfo
);
263 interfaceInfo
->Flags
|= SPINT_REMOVED
;
268 dwLength
= sizeof(DWORD
);
269 if (RegQueryValueExW(hControlKey
, Linked
, NULL
, &dwRegType
, (LPBYTE
)&LinkedValue
, &dwLength
) == ERROR_SUCCESS
270 && dwRegType
== REG_DWORD
&& LinkedValue
)
271 interfaceInfo
->Flags
|= SPINT_ACTIVE
;
272 RegCloseKey(hControlKey
);
275 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink
));
276 InsertTailList(&deviceInfo
->InterfaceListHead
, &interfaceInfo
->ListEntry
);
282 if (hReferenceKey
!= NULL
)
283 RegCloseKey(hReferenceKey
);
284 if (hDeviceInstanceKey
!= NULL
)
285 RegCloseKey(hDeviceInstanceKey
);
286 if (hInterfaceKey
!= INVALID_HANDLE_VALUE
)
287 RegCloseKey(hInterfaceKey
);
288 HeapFree(GetProcessHeap(), 0, InstancePath
);
289 HeapFree(GetProcessHeap(), 0, pSymbolicLink
);
295 IN LPGUID InterfaceGuid
,
296 IN LPCWSTR ReferenceString
,
297 IN
struct DeviceInfo
*devInfo
)
299 DWORD Length
, Index
, Offset
;
302 Length
= wcslen(devInfo
->instanceId
) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */;
304 Key
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, Length
* sizeof(WCHAR
));
308 wcscpy(Key
, L
"##?#");
309 wcscat(Key
, devInfo
->instanceId
);
311 for(Index
= 4; Index
< Length
; Index
++)
313 if (Key
[Index
] == L
'\\')
321 Offset
= wcslen(Key
);
322 pSetupStringFromGuid(InterfaceGuid
, Key
+ Offset
, Length
- Offset
);
330 IN LPGUID InterfaceGuid
,
331 IN LPCWSTR ReferenceString
,
332 IN LPCWSTR InterfaceSection
,
333 IN UINT InterfaceFlags
,
335 IN HDEVINFO DeviceInfoSet
,
336 IN
struct DeviceInfo
*devInfo
)
340 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData
;
341 struct DeviceInterface
*DevItf
= NULL
;
343 if (InterfaceFlags
!= 0)
345 SetLastError(ERROR_INVALID_PARAMETER
);
349 TRACE("Need to InstallOneInterface(%s %s %s %u) hInf %p DeviceInfoSet %p devInfo %p instanceId %s\n", debugstr_guid(InterfaceGuid
),
350 debugstr_w(ReferenceString
), debugstr_w(InterfaceSection
), InterfaceFlags
, hInf
, DeviceInfoSet
, devInfo
, debugstr_w(devInfo
->instanceId
));
353 Path
= CreateSymbolicLink(InterfaceGuid
, ReferenceString
, devInfo
);
357 CreateDeviceInterface(devInfo
, Path
, InterfaceGuid
, &DevItf
);
358 HeapFree(GetProcessHeap(), 0, Path
);
364 memcpy(&DeviceInterfaceData
.InterfaceClassGuid
, &DevItf
->InterfaceClassGuid
, sizeof(GUID
));
365 DeviceInterfaceData
.cbSize
= sizeof(SP_DEVICE_INTERFACE_DATA
);
366 DeviceInterfaceData
.Flags
= DevItf
->Flags
;
367 DeviceInterfaceData
.Reserved
= (ULONG_PTR
)DevItf
;
369 hKey
= SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet
, &DeviceInterfaceData
, 0, KEY_ALL_ACCESS
, NULL
, 0);
370 HeapFree(GetProcessHeap(), 0, DevItf
);
371 if (hKey
== INVALID_HANDLE_VALUE
)
378 Path
= HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString
) + 2) * sizeof(WCHAR
));
386 wcscat(Path
, ReferenceString
);
388 if (RegCreateKeyExW(hKey
, Path
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hRefKey
, NULL
) != ERROR_SUCCESS
)
390 ERR("failed to create key %s %lx\n", debugstr_w(Path
), GetLastError());
391 HeapFree(GetProcessHeap(), 0, Path
);
397 HeapFree(GetProcessHeap(), 0, Path
);
400 if (RegCreateKeyExW(hKey
, L
"Device Parameters", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hRefKey
, NULL
) != ERROR_SUCCESS
)
406 return SetupInstallFromInfSectionW(NULL
, /* FIXME */ hInf
, InterfaceSection
, SPINST_REGISTRY
, hRefKey
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
409 /***********************************************************************
410 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
413 SetupDiInstallDeviceInterfaces(
414 IN HDEVINFO DeviceInfoSet
,
415 IN PSP_DEVINFO_DATA DeviceInfoData
)
417 struct DeviceInfoSet
*list
= NULL
;
420 TRACE("%p %p\n", DeviceInfoSet
, DeviceInfoData
);
423 SetLastError(ERROR_INVALID_PARAMETER
);
424 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
425 SetLastError(ERROR_INVALID_HANDLE
);
426 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
427 SetLastError(ERROR_INVALID_HANDLE
);
428 else if (!DeviceInfoData
)
429 SetLastError(ERROR_INVALID_PARAMETER
);
430 else if (DeviceInfoData
&& DeviceInfoData
->Reserved
== 0)
431 SetLastError(ERROR_INVALID_USER_BUFFER
);
432 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
433 SetLastError(ERROR_INVALID_USER_BUFFER
);
436 struct DeviceInfo
*devInfo
;
437 struct DriverInfoElement
*SelectedDriver
= NULL
;
438 SP_DEVINSTALL_PARAMS_W InstallParams
;
439 WCHAR SectionName
[MAX_PATH
];
440 DWORD SectionNameLength
= 0;
441 INFCONTEXT ContextInterface
;
442 LPWSTR InterfaceGuidString
= NULL
;
443 LPWSTR ReferenceString
= NULL
;
444 LPWSTR InterfaceSection
= NULL
;
449 devInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
451 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
452 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
456 SelectedDriver
= (struct DriverInfoElement
*)InstallParams
.Reserved
;
457 if (SelectedDriver
== NULL
)
459 SetLastError(ERROR_NO_DRIVER_SELECTED
);
464 /* Get .Interfaces section name */
465 Result
= SetupDiGetActualSectionToInstallW(
466 SelectedDriver
->InfFileDetails
->hInf
,
467 SelectedDriver
->Details
.SectionName
,
468 SectionName
, MAX_PATH
, &SectionNameLength
, NULL
);
469 if (!Result
|| SectionNameLength
> MAX_PATH
- strlenW(DotInterfaces
) - 1)
471 strcatW(SectionName
, DotInterfaces
);
474 Result
= SetupFindFirstLineW(
475 SelectedDriver
->InfFileDetails
->hInf
,
479 while (ret
&& Result
)
481 ret
= GetStringField(&ContextInterface
, 1, &InterfaceGuidString
);
484 else if (strlenW(InterfaceGuidString
) != MAX_GUID_STRING_LEN
- 1)
486 SetLastError(ERROR_INVALID_PARAMETER
);
491 InterfaceGuidString
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
492 if (UuidFromStringW(&InterfaceGuidString
[1], &InterfaceGuid
) != RPC_S_OK
)
494 /* Bad GUID, skip the entry */
495 SetLastError(ERROR_INVALID_PARAMETER
);
500 ret
= GetStringField(&ContextInterface
, 2, &ReferenceString
);
504 ret
= GetStringField(&ContextInterface
, 3, &InterfaceSection
);
507 /* ReferenceString is optional */
508 InterfaceSection
= ReferenceString
;
509 ReferenceString
= NULL
;
512 ret
= SetupGetIntField(
514 (ReferenceString
? 4 : 3), /* Field index */
518 if (GetLastError() == ERROR_INVALID_PARAMETER
)
520 /* The field may be empty. Ignore the error */
528 /* Install Interface */
529 ret
= InstallOneInterface(&InterfaceGuid
, ReferenceString
, InterfaceSection
, InterfaceFlags
, SelectedDriver
->InfFileDetails
->hInf
, DeviceInfoSet
, devInfo
);
532 MyFree(InterfaceGuidString
);
534 MyFree(ReferenceString
);
535 MyFree(InterfaceSection
);
536 InterfaceGuidString
= ReferenceString
= InterfaceSection
= NULL
;
537 Result
= SetupFindNextMatchLineW(&ContextInterface
, AddInterface
, &ContextInterface
);
541 TRACE("Returning %d\n", ret
);
546 SetupDiOpenDeviceInterfaceRegKey(
547 IN HDEVINFO DeviceInfoSet
, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
, IN DWORD Reserved
, IN REGSAM samDesired
)
549 HKEY hKey
= INVALID_HANDLE_VALUE
, hDevKey
;
550 struct DeviceInfoSet
* list
;
552 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet
, DeviceInterfaceData
, Reserved
, samDesired
);
555 SetLastError(ERROR_INVALID_PARAMETER
);
556 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
557 SetLastError(ERROR_INVALID_HANDLE
);
558 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
559 SetLastError(ERROR_INVALID_HANDLE
);
560 else if (!DeviceInterfaceData
)
561 SetLastError(ERROR_INVALID_PARAMETER
);
562 else if (DeviceInterfaceData
&& DeviceInterfaceData
->Reserved
== 0)
563 SetLastError(ERROR_INVALID_USER_BUFFER
);
564 else if (DeviceInterfaceData
&& DeviceInterfaceData
->cbSize
!= sizeof(SP_DEVICE_INTERFACE_DATA
))
565 SetLastError(ERROR_INVALID_USER_BUFFER
);
568 struct DeviceInterface
*DevItf
;
569 LPWSTR Path
, Guid
, Slash
;
571 DevItf
= (struct DeviceInterface
*)DeviceInterfaceData
->Reserved
;
573 Length
= wcslen(DevItf
->SymbolicLink
);
575 Path
= HeapAlloc(GetProcessHeap(), 0, (Length
+2) * sizeof(WCHAR
));
578 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
579 return INVALID_HANDLE_VALUE
;
582 wcscpy(Path
, DevItf
->SymbolicLink
);
584 Guid
= wcsrchr(Path
, '}');
585 Slash
= wcsrchr(Path
, '\\');
588 SetLastError(ERROR_INVALID_PARAMETER
);
589 return INVALID_HANDLE_VALUE
;
592 if ((ULONG_PTR
)Slash
> (ULONG_PTR
)Guid
)
594 /* Create an extra slash */
595 memmove(Slash
+1, Slash
, (wcslen(Slash
) + 1) * sizeof(WCHAR
));
600 while((ULONG_PTR
)Guid
< (ULONG_PTR
)Slash
)
608 hKey
= SetupDiOpenClassRegKeyExW(&DeviceInterfaceData
->InterfaceClassGuid
, samDesired
, DIOCR_INTERFACE
, NULL
, NULL
);
609 if (hKey
!= INVALID_HANDLE_VALUE
)
611 if (RegOpenKeyExW(hKey
, Path
, 0, samDesired
, &hDevKey
) == ERROR_SUCCESS
)
619 hKey
= INVALID_HANDLE_VALUE
;
623 HeapFree(GetProcessHeap(), 0, Path
);