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
)
100 /* Key doesn't exist. Let's keep it empty */
105 /* Enumerate sub keys of hInterfaceKey */
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
)
113 if (rc
!= ERROR_SUCCESS
)
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
)
124 /* Read DeviceInstance */
125 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, &dwRegType
, NULL
, &dwInstancePathLength
);
126 if (rc
!= ERROR_SUCCESS
)
128 if (dwRegType
!= REG_SZ
)
130 rc
= ERROR_GEN_FAILURE
;
133 HeapFree(GetProcessHeap(), 0, InstancePath
);
134 InstancePath
= HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength
+ sizeof(WCHAR
));
137 rc
= ERROR_NOT_ENOUGH_MEMORY
;
140 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, NULL
, (LPBYTE
)InstancePath
, &dwInstancePathLength
);
141 if (rc
!= ERROR_SUCCESS
)
143 InstancePath
[dwInstancePathLength
/ sizeof(WCHAR
)] = '\0';
144 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath
));
148 /* Check if device enumerator is not the right one */
149 if (strcmpW(DeviceInstanceW
, InstancePath
) != 0)
153 /* Find class GUID associated to the device instance */
156 REGSTR_PATH_SYSTEMENUM
,
160 if (rc
!= ERROR_SUCCESS
)
168 RegCloseKey(hEnumKey
);
169 if (rc
!= ERROR_SUCCESS
)
171 dwLength
= sizeof(KeyBuffer
) - sizeof(WCHAR
);
172 rc
= RegQueryValueExW(hKey
, ClassGUID
, NULL
, NULL
, (LPBYTE
)KeyBuffer
, &dwLength
);
174 if (rc
!= ERROR_SUCCESS
)
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
)
180 rc
= ERROR_GEN_FAILURE
;
183 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid
));
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
))
189 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
193 struct DeviceInterface
*interfaceInfo
;
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
)
199 if (rc
!= ERROR_SUCCESS
)
202 if (KeyBuffer
[0] != '#')
203 /* This entry doesn't represent an interesting entry */
207 if (hReferenceKey
!= NULL
)
208 RegCloseKey(hReferenceKey
);
209 rc
= RegOpenKeyExW(hDeviceInstanceKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hReferenceKey
);
210 if (rc
!= ERROR_SUCCESS
)
213 /* Read SymbolicLink value */
214 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, &dwRegType
, NULL
, &dwLength
);
215 if (rc
!= ERROR_SUCCESS
)
217 if (dwRegType
!= REG_SZ
)
219 rc
= ERROR_GEN_FAILURE
;
223 /* We have found a device */
224 /* Step 1. Create a device info element */
225 if (!CreateDeviceInfo(list
, InstancePath
, &ClassGuid
, &deviceInfo
))
230 TRACE("Adding device %s to list\n", debugstr_w(InstancePath
));
231 InsertTailList(&list
->ListHead
, &deviceInfo
->ListEntry
);
233 /* Step 2. Create an interface list for this element */
234 HeapFree(GetProcessHeap(), 0, pSymbolicLink
);
235 pSymbolicLink
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ 1) * sizeof(WCHAR
));
238 rc
= ERROR_NOT_ENOUGH_MEMORY
;
241 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, NULL
, (LPBYTE
)pSymbolicLink
, &dwLength
);
242 pSymbolicLink
[dwLength
/ sizeof(WCHAR
)] = '\0';
243 if (rc
!= ERROR_SUCCESS
)
245 if (!CreateDeviceInterface(deviceInfo
, pSymbolicLink
, InterfaceGuid
, &interfaceInfo
))
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
)
258 if (OnlyPresentInterfaces
)
260 DestroyDeviceInterface(interfaceInfo
);
264 interfaceInfo
->Flags
|= SPINT_REMOVED
;
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
);
276 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink
));
277 InsertTailList(&deviceInfo
->InterfaceListHead
, &interfaceInfo
->ListEntry
);
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
);
296 IN LPGUID InterfaceGuid
,
297 IN LPCWSTR ReferenceString
,
298 IN
struct DeviceInfo
*devInfo
)
300 DWORD Length
, Index
, Offset
;
303 Length
= wcslen(devInfo
->instanceId
) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */;
305 Key
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, Length
* sizeof(WCHAR
));
309 wcscpy(Key
, L
"##?#");
310 wcscat(Key
, devInfo
->instanceId
);
312 for(Index
= 4; Index
< Length
; Index
++)
314 if (Key
[Index
] == L
'\\')
322 Offset
= wcslen(Key
);
323 pSetupStringFromGuid(InterfaceGuid
, Key
+ Offset
, Length
- Offset
);
331 IN LPGUID InterfaceGuid
,
332 IN LPCWSTR ReferenceString
,
333 IN LPCWSTR InterfaceSection
,
334 IN UINT InterfaceFlags
,
336 IN HDEVINFO DeviceInfoSet
,
337 IN
struct DeviceInfo
*devInfo
)
341 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData
;
342 struct DeviceInterface
*DevItf
= NULL
;
344 if (InterfaceFlags
!= 0)
346 SetLastError(ERROR_INVALID_PARAMETER
);
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
));
354 Path
= CreateSymbolicLink(InterfaceGuid
, ReferenceString
, devInfo
);
358 CreateDeviceInterface(devInfo
, Path
, InterfaceGuid
, &DevItf
);
359 HeapFree(GetProcessHeap(), 0, Path
);
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
;
370 hKey
= SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet
, &DeviceInterfaceData
, 0, KEY_ALL_ACCESS
, NULL
, 0);
371 HeapFree(GetProcessHeap(), 0, DevItf
);
372 if (hKey
== INVALID_HANDLE_VALUE
)
379 Path
= HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString
) + 2) * sizeof(WCHAR
));
387 wcscat(Path
, ReferenceString
);
389 if (RegCreateKeyExW(hKey
, Path
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hRefKey
, NULL
) != ERROR_SUCCESS
)
391 ERR("failed to create key %s %lx\n", debugstr_w(Path
), GetLastError());
392 HeapFree(GetProcessHeap(), 0, Path
);
398 HeapFree(GetProcessHeap(), 0, Path
);
401 if (RegCreateKeyExW(hKey
, L
"Device Parameters", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hRefKey
, NULL
) != ERROR_SUCCESS
)
407 return SetupInstallFromInfSectionW(NULL
, /* FIXME */ hInf
, InterfaceSection
, SPINST_REGISTRY
, hRefKey
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
410 /***********************************************************************
411 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
414 SetupDiInstallDeviceInterfaces(
415 IN HDEVINFO DeviceInfoSet
,
416 IN PSP_DEVINFO_DATA DeviceInfoData
)
418 struct DeviceInfoSet
*list
= NULL
;
421 TRACE("%p %p\n", DeviceInfoSet
, DeviceInfoData
);
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
);
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
;
450 devInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
452 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
453 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
457 SelectedDriver
= (struct DriverInfoElement
*)InstallParams
.Reserved
;
458 if (SelectedDriver
== NULL
)
460 SetLastError(ERROR_NO_DRIVER_SELECTED
);
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)
472 strcatW(SectionName
, DotInterfaces
);
475 Result
= SetupFindFirstLineW(
476 SelectedDriver
->InfFileDetails
->hInf
,
480 while (ret
&& Result
)
482 ret
= GetStringField(&ContextInterface
, 1, &InterfaceGuidString
);
485 else if (strlenW(InterfaceGuidString
) != MAX_GUID_STRING_LEN
- 1)
487 SetLastError(ERROR_INVALID_PARAMETER
);
492 InterfaceGuidString
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
493 if (UuidFromStringW(&InterfaceGuidString
[1], &InterfaceGuid
) != RPC_S_OK
)
495 /* Bad GUID, skip the entry */
496 SetLastError(ERROR_INVALID_PARAMETER
);
501 ret
= GetStringField(&ContextInterface
, 2, &ReferenceString
);
505 ret
= GetStringField(&ContextInterface
, 3, &InterfaceSection
);
508 /* ReferenceString is optional */
509 InterfaceSection
= ReferenceString
;
510 ReferenceString
= NULL
;
513 ret
= SetupGetIntField(
515 (ReferenceString
? 4 : 3), /* Field index */
519 if (GetLastError() == ERROR_INVALID_PARAMETER
)
521 /* The field may be empty. Ignore the error */
529 /* Install Interface */
530 ret
= InstallOneInterface(&InterfaceGuid
, ReferenceString
, InterfaceSection
, InterfaceFlags
, SelectedDriver
->InfFileDetails
->hInf
, DeviceInfoSet
, devInfo
);
533 MyFree(InterfaceGuidString
);
535 MyFree(ReferenceString
);
536 MyFree(InterfaceSection
);
537 InterfaceGuidString
= ReferenceString
= InterfaceSection
= NULL
;
538 Result
= SetupFindNextMatchLineW(&ContextInterface
, AddInterface
, &ContextInterface
);
542 TRACE("Returning %d\n", ret
);
547 SetupDiOpenDeviceInterfaceRegKey(
548 IN HDEVINFO DeviceInfoSet
, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
, IN DWORD Reserved
, IN REGSAM samDesired
)
550 HKEY hKey
= INVALID_HANDLE_VALUE
, hDevKey
;
551 struct DeviceInfoSet
* list
;
553 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet
, DeviceInterfaceData
, Reserved
, samDesired
);
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
);
569 struct DeviceInterface
*DevItf
;
570 LPWSTR Path
, Guid
, Slash
;
572 DevItf
= (struct DeviceInterface
*)DeviceInterfaceData
->Reserved
;
574 Length
= wcslen(DevItf
->SymbolicLink
);
576 Path
= HeapAlloc(GetProcessHeap(), 0, (Length
+2) * sizeof(WCHAR
));
579 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
580 return INVALID_HANDLE_VALUE
;
583 wcscpy(Path
, DevItf
->SymbolicLink
);
585 Guid
= wcsrchr(Path
, '}');
586 Slash
= wcsrchr(Path
, '\\');
589 SetLastError(ERROR_INVALID_PARAMETER
);
590 return INVALID_HANDLE_VALUE
;
593 if ((ULONG_PTR
)Slash
> (ULONG_PTR
)Guid
)
595 /* Create an extra slash */
596 memmove(Slash
+1, Slash
, (wcslen(Slash
) + 1) * sizeof(WCHAR
));
601 while((ULONG_PTR
)Guid
< (ULONG_PTR
)Slash
)
609 hKey
= SetupDiOpenClassRegKeyExW(&DeviceInterfaceData
->InterfaceClassGuid
, samDesired
, DIOCR_INTERFACE
, NULL
, NULL
);
610 if (hKey
!= INVALID_HANDLE_VALUE
)
612 if (RegOpenKeyExW(hKey
, Path
, 0, samDesired
, &hDevKey
) == ERROR_SUCCESS
)
620 hKey
= INVALID_HANDLE_VALUE
;
624 HeapFree(GetProcessHeap(), 0, Path
);