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 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
26 /* Unicode constants */
27 static const WCHAR AddInterface
[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
28 static const WCHAR ClassGUID
[] = {'C','l','a','s','s','G','U','I','D',0};
29 static const WCHAR Control
[] = {'C','o','n','t','r','o','l',0};
30 static const WCHAR DeviceInstance
[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
31 static const WCHAR DotInterfaces
[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
32 static const WCHAR Linked
[] = {'L','i','n','k','e','d',0};
33 static const WCHAR SymbolicLink
[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
36 CreateDeviceInterface(
37 IN
struct DeviceInfo
* deviceInfo
,
38 IN LPCWSTR SymbolicLink
,
39 IN LPCGUID pInterfaceGuid
,
40 OUT
struct DeviceInterface
**pDeviceInterface
)
42 struct DeviceInterface
*deviceInterface
;
44 *pDeviceInterface
= NULL
;
46 deviceInterface
= HeapAlloc(GetProcessHeap(), 0,
47 FIELD_OFFSET(struct DeviceInterface
, SymbolicLink
) + (strlenW(SymbolicLink
) + 1) * sizeof(WCHAR
));
50 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
53 deviceInterface
->DeviceInfo
= deviceInfo
;
54 strcpyW(deviceInterface
->SymbolicLink
, SymbolicLink
);
55 deviceInterface
->Flags
= 0; /* Flags will be updated later */
56 memcpy(&deviceInterface
->InterfaceClassGuid
, pInterfaceGuid
, sizeof(GUID
));
58 *pDeviceInterface
= deviceInterface
;
63 DestroyDeviceInterface(
64 struct DeviceInterface
* deviceInterface
)
66 return HeapFree(GetProcessHeap(), 0, deviceInterface
);
70 SETUP_CreateInterfaceList(
71 struct DeviceInfoSet
*list
,
73 CONST GUID
*InterfaceGuid
,
74 PCWSTR DeviceInstanceW
/* OPTIONAL */,
75 BOOL OnlyPresentInterfaces
)
77 HKEY hInterfaceKey
; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
78 HKEY hDeviceInstanceKey
; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
79 HKEY hReferenceKey
; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
80 HKEY hControlKey
; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString}\Control */
81 HKEY hEnumKey
; /* HKLM\SYSTEM\CurrentControlSet\Enum */
82 HKEY hKey
; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
84 WCHAR KeyBuffer
[max(MAX_PATH
, MAX_GUID_STRING_LEN
) + 1];
85 PWSTR pSymbolicLink
= NULL
;
86 PWSTR InstancePath
= NULL
;
88 DWORD dwLength
, dwInstancePathLength
;
92 struct DeviceInfo
*deviceInfo
;
94 hInterfaceKey
= INVALID_HANDLE_VALUE
;
95 hDeviceInstanceKey
= NULL
;
98 /* Open registry key related to this interface */
99 hInterfaceKey
= SetupDiOpenClassRegKeyExW(InterfaceGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, MachineName
, NULL
);
100 if (hInterfaceKey
== INVALID_HANDLE_VALUE
)
106 /* Enumerate sub keys of hInterfaceKey */
110 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
111 rc
= RegEnumKeyExW(hInterfaceKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
112 if (rc
== ERROR_NO_MORE_ITEMS
)
114 if (rc
!= ERROR_SUCCESS
)
119 if (hDeviceInstanceKey
!= NULL
)
120 RegCloseKey(hDeviceInstanceKey
);
121 rc
= RegOpenKeyExW(hInterfaceKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, &hDeviceInstanceKey
);
122 if (rc
!= ERROR_SUCCESS
)
125 /* Read DeviceInstance */
126 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, &dwRegType
, NULL
, &dwInstancePathLength
);
127 if (rc
!= ERROR_SUCCESS
)
129 if (dwRegType
!= REG_SZ
)
131 rc
= ERROR_GEN_FAILURE
;
134 HeapFree(GetProcessHeap(), 0, InstancePath
);
135 InstancePath
= HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength
+ sizeof(WCHAR
));
138 rc
= ERROR_NOT_ENOUGH_MEMORY
;
141 rc
= RegQueryValueExW(hDeviceInstanceKey
, DeviceInstance
, NULL
, NULL
, (LPBYTE
)InstancePath
, &dwInstancePathLength
);
142 if (rc
!= ERROR_SUCCESS
)
144 InstancePath
[dwInstancePathLength
/ sizeof(WCHAR
)] = '\0';
145 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath
));
149 /* Check if device enumerator is not the right one */
150 if (strcmpW(DeviceInstanceW
, InstancePath
) != 0)
154 /* Find class GUID associated to the device instance */
157 REGSTR_PATH_SYSTEMENUM
,
161 if (rc
!= ERROR_SUCCESS
)
169 RegCloseKey(hEnumKey
);
170 if (rc
!= ERROR_SUCCESS
)
172 dwLength
= sizeof(KeyBuffer
) - sizeof(WCHAR
);
173 rc
= RegQueryValueExW(hKey
, ClassGUID
, NULL
, NULL
, (LPBYTE
)KeyBuffer
, &dwLength
);
175 if (rc
!= ERROR_SUCCESS
)
177 KeyBuffer
[dwLength
/ sizeof(WCHAR
)] = '\0';
178 KeyBuffer
[37] = '\0'; /* Replace the } by a NULL character */
179 if (UuidFromStringW(&KeyBuffer
[1], &ClassGuid
) != RPC_S_OK
)
181 rc
= ERROR_GEN_FAILURE
;
184 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid
));
186 /* If current device doesn't match the list GUID (if any), skip this entry */
187 if (!IsEqualIID(&list
->ClassGuid
, &GUID_NULL
) && !IsEqualIID(&list
->ClassGuid
, &ClassGuid
))
190 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
194 struct DeviceInterface
*interfaceInfo
;
196 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
197 rc
= RegEnumKeyExW(hDeviceInstanceKey
, j
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
198 if (rc
== ERROR_NO_MORE_ITEMS
)
200 if (rc
!= ERROR_SUCCESS
)
203 if (KeyBuffer
[0] != '#')
204 /* This entry doesn't represent an interesting entry */
208 if (hReferenceKey
!= NULL
)
209 RegCloseKey(hReferenceKey
);
210 rc
= RegOpenKeyExW(hDeviceInstanceKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hReferenceKey
);
211 if (rc
!= ERROR_SUCCESS
)
214 /* Read SymbolicLink value */
215 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, &dwRegType
, NULL
, &dwLength
);
216 if (rc
!= ERROR_SUCCESS
)
218 if (dwRegType
!= REG_SZ
)
220 rc
= ERROR_GEN_FAILURE
;
224 /* We have found a device */
225 /* Step 1. Create a device info element */
226 if (!CreateDeviceInfo(list
, InstancePath
, &ClassGuid
, &deviceInfo
))
231 TRACE("Adding device %s to list\n", debugstr_w(InstancePath
));
232 InsertTailList(&list
->ListHead
, &deviceInfo
->ListEntry
);
234 /* Step 2. Create an interface list for this element */
235 HeapFree(GetProcessHeap(), 0, pSymbolicLink
);
236 pSymbolicLink
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ 1) * sizeof(WCHAR
));
239 rc
= ERROR_NOT_ENOUGH_MEMORY
;
242 rc
= RegQueryValueExW(hReferenceKey
, SymbolicLink
, NULL
, NULL
, (LPBYTE
)pSymbolicLink
, &dwLength
);
243 pSymbolicLink
[dwLength
/ sizeof(WCHAR
)] = '\0';
244 if (rc
!= ERROR_SUCCESS
)
246 if (!CreateDeviceInterface(deviceInfo
, pSymbolicLink
, InterfaceGuid
, &interfaceInfo
))
252 /* Step 3. Update flags */
253 if (KeyBuffer
[1] == '\0')
254 interfaceInfo
->Flags
|= SPINT_DEFAULT
;
255 rc
= RegOpenKeyExW(hReferenceKey
, Control
, 0, KEY_QUERY_VALUE
, &hControlKey
);
256 if (rc
!= ERROR_SUCCESS
)
259 if (OnlyPresentInterfaces
)
261 DestroyDeviceInterface(interfaceInfo
);
265 interfaceInfo
->Flags
|= SPINT_REMOVED
;
270 dwLength
= sizeof(DWORD
);
271 if (RegQueryValueExW(hControlKey
, Linked
, NULL
, &dwRegType
, (LPBYTE
)&LinkedValue
, &dwLength
) == ERROR_SUCCESS
272 && dwRegType
== REG_DWORD
&& LinkedValue
)
273 interfaceInfo
->Flags
|= SPINT_ACTIVE
;
274 RegCloseKey(hControlKey
);
277 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink
));
278 InsertTailList(&deviceInfo
->InterfaceListHead
, &interfaceInfo
->ListEntry
);
284 if (hReferenceKey
!= NULL
)
285 RegCloseKey(hReferenceKey
);
286 if (hDeviceInstanceKey
!= NULL
)
287 RegCloseKey(hDeviceInstanceKey
);
288 if (hInterfaceKey
!= INVALID_HANDLE_VALUE
)
289 RegCloseKey(hInterfaceKey
);
290 HeapFree(GetProcessHeap(), 0, InstancePath
);
291 HeapFree(GetProcessHeap(), 0, pSymbolicLink
);
297 IN LPGUID InterfaceGuid
,
298 IN LPCWSTR ReferenceString
,
299 IN
struct DeviceInfo
*devInfo
)
301 DWORD Length
, Index
, Offset
;
304 Length
= wcslen(devInfo
->instanceId
) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */;
306 Key
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, Length
* sizeof(WCHAR
));
310 wcscpy(Key
, L
"##?#");
311 wcscat(Key
, devInfo
->instanceId
);
313 for(Index
= 4; Index
< Length
; Index
++)
315 if (Key
[Index
] == L
'\\')
323 Offset
= wcslen(Key
);
324 pSetupStringFromGuid(InterfaceGuid
, Key
+ Offset
, Length
- Offset
);
332 IN LPGUID InterfaceGuid
,
333 IN LPCWSTR ReferenceString
,
334 IN LPCWSTR InterfaceSection
,
335 IN UINT InterfaceFlags
,
337 IN HDEVINFO DeviceInfoSet
,
338 IN
struct DeviceInfo
*devInfo
)
342 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData
;
343 struct DeviceInterface
*DevItf
= NULL
;
345 if (InterfaceFlags
!= 0)
347 SetLastError(ERROR_INVALID_PARAMETER
);
351 TRACE("Need to InstallOneInterface(%s %s %s %u) hInf %p DeviceInfoSet %p devInfo %p instanceId %s\n", debugstr_guid(InterfaceGuid
),
352 debugstr_w(ReferenceString
), debugstr_w(InterfaceSection
), InterfaceFlags
, hInf
, DeviceInfoSet
, devInfo
, debugstr_w(devInfo
->instanceId
));
355 Path
= CreateSymbolicLink(InterfaceGuid
, ReferenceString
, devInfo
);
359 CreateDeviceInterface(devInfo
, Path
, InterfaceGuid
, &DevItf
);
360 HeapFree(GetProcessHeap(), 0, Path
);
366 memcpy(&DeviceInterfaceData
.InterfaceClassGuid
, &DevItf
->InterfaceClassGuid
, sizeof(GUID
));
367 DeviceInterfaceData
.cbSize
= sizeof(SP_DEVICE_INTERFACE_DATA
);
368 DeviceInterfaceData
.Flags
= DevItf
->Flags
;
369 DeviceInterfaceData
.Reserved
= (ULONG_PTR
)DevItf
;
371 hKey
= SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet
, &DeviceInterfaceData
, 0, KEY_ALL_ACCESS
, NULL
, 0);
372 HeapFree(GetProcessHeap(), 0, DevItf
);
373 if (hKey
== INVALID_HANDLE_VALUE
)
380 Path
= HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString
) + 2) * sizeof(WCHAR
));
388 wcscat(Path
, ReferenceString
);
390 if (RegCreateKeyExW(hKey
, Path
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hRefKey
, NULL
) != ERROR_SUCCESS
)
392 ERR("failed to create key %s %lx\n", debugstr_w(Path
), GetLastError());
393 HeapFree(GetProcessHeap(), 0, Path
);
399 HeapFree(GetProcessHeap(), 0, Path
);
402 if (RegCreateKeyExW(hKey
, L
"Device Parameters", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hRefKey
, NULL
) != ERROR_SUCCESS
)
408 return SetupInstallFromInfSectionW(NULL
, /* FIXME */ hInf
, InterfaceSection
, SPINST_REGISTRY
, hRefKey
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
411 /***********************************************************************
412 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
415 SetupDiInstallDeviceInterfaces(
416 IN HDEVINFO DeviceInfoSet
,
417 IN PSP_DEVINFO_DATA DeviceInfoData
)
419 struct DeviceInfoSet
*list
= NULL
;
422 TRACE("%p %p\n", DeviceInfoSet
, DeviceInfoData
);
425 SetLastError(ERROR_INVALID_PARAMETER
);
426 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
427 SetLastError(ERROR_INVALID_HANDLE
);
428 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
429 SetLastError(ERROR_INVALID_HANDLE
);
430 else if (!DeviceInfoData
)
431 SetLastError(ERROR_INVALID_PARAMETER
);
432 else if (DeviceInfoData
&& DeviceInfoData
->Reserved
== 0)
433 SetLastError(ERROR_INVALID_USER_BUFFER
);
434 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
435 SetLastError(ERROR_INVALID_USER_BUFFER
);
438 struct DeviceInfo
*devInfo
;
439 struct DriverInfoElement
*SelectedDriver
= NULL
;
440 SP_DEVINSTALL_PARAMS_W InstallParams
;
441 WCHAR SectionName
[MAX_PATH
];
442 DWORD SectionNameLength
= 0;
443 INFCONTEXT ContextInterface
;
444 LPWSTR InterfaceGuidString
= NULL
;
445 LPWSTR ReferenceString
= NULL
;
446 LPWSTR InterfaceSection
= NULL
;
451 devInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
453 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
454 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
458 SelectedDriver
= (struct DriverInfoElement
*)InstallParams
.Reserved
;
459 if (SelectedDriver
== NULL
)
461 SetLastError(ERROR_NO_DRIVER_SELECTED
);
466 /* Get .Interfaces section name */
467 Result
= SetupDiGetActualSectionToInstallW(
468 SelectedDriver
->InfFileDetails
->hInf
,
469 SelectedDriver
->Details
.SectionName
,
470 SectionName
, MAX_PATH
, &SectionNameLength
, NULL
);
471 if (!Result
|| SectionNameLength
> MAX_PATH
- strlenW(DotInterfaces
) - 1)
473 strcatW(SectionName
, DotInterfaces
);
476 Result
= SetupFindFirstLineW(
477 SelectedDriver
->InfFileDetails
->hInf
,
481 while (ret
&& Result
)
483 ret
= GetStringField(&ContextInterface
, 1, &InterfaceGuidString
);
486 else if (strlenW(InterfaceGuidString
) != MAX_GUID_STRING_LEN
- 1)
488 SetLastError(ERROR_INVALID_PARAMETER
);
493 InterfaceGuidString
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
494 if (UuidFromStringW(&InterfaceGuidString
[1], &InterfaceGuid
) != RPC_S_OK
)
496 /* Bad GUID, skip the entry */
497 SetLastError(ERROR_INVALID_PARAMETER
);
502 ret
= GetStringField(&ContextInterface
, 2, &ReferenceString
);
506 ret
= GetStringField(&ContextInterface
, 3, &InterfaceSection
);
509 /* ReferenceString is optional */
510 InterfaceSection
= ReferenceString
;
511 ReferenceString
= NULL
;
514 ret
= SetupGetIntField(
516 (ReferenceString
? 4 : 3), /* Field index */
520 if (GetLastError() == ERROR_INVALID_PARAMETER
)
522 /* The field may be empty. Ignore the error */
530 /* Install Interface */
531 ret
= InstallOneInterface(&InterfaceGuid
, ReferenceString
, InterfaceSection
, InterfaceFlags
, SelectedDriver
->InfFileDetails
->hInf
, DeviceInfoSet
, devInfo
);
534 MyFree(InterfaceGuidString
);
536 MyFree(ReferenceString
);
537 MyFree(InterfaceSection
);
538 InterfaceGuidString
= ReferenceString
= InterfaceSection
= NULL
;
539 Result
= SetupFindNextMatchLineW(&ContextInterface
, AddInterface
, &ContextInterface
);
543 TRACE("Returning %d\n", ret
);
548 SetupDiOpenDeviceInterfaceRegKey(
549 IN HDEVINFO DeviceInfoSet
, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
, IN DWORD Reserved
, IN REGSAM samDesired
)
551 HKEY hKey
= INVALID_HANDLE_VALUE
, hDevKey
;
552 struct DeviceInfoSet
* list
;
554 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet
, DeviceInterfaceData
, Reserved
, samDesired
);
557 SetLastError(ERROR_INVALID_PARAMETER
);
558 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
559 SetLastError(ERROR_INVALID_HANDLE
);
560 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
561 SetLastError(ERROR_INVALID_HANDLE
);
562 else if (!DeviceInterfaceData
)
563 SetLastError(ERROR_INVALID_PARAMETER
);
564 else if (DeviceInterfaceData
&& DeviceInterfaceData
->Reserved
== 0)
565 SetLastError(ERROR_INVALID_USER_BUFFER
);
566 else if (DeviceInterfaceData
&& DeviceInterfaceData
->cbSize
!= sizeof(SP_DEVICE_INTERFACE_DATA
))
567 SetLastError(ERROR_INVALID_USER_BUFFER
);
570 struct DeviceInterface
*DevItf
;
571 LPWSTR Path
, Guid
, Slash
;
573 DevItf
= (struct DeviceInterface
*)DeviceInterfaceData
->Reserved
;
575 Length
= wcslen(DevItf
->SymbolicLink
);
577 Path
= HeapAlloc(GetProcessHeap(), 0, (Length
+2) * sizeof(WCHAR
));
580 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
581 return INVALID_HANDLE_VALUE
;
584 wcscpy(Path
, DevItf
->SymbolicLink
);
586 Guid
= wcsrchr(Path
, '}');
587 Slash
= wcsrchr(Path
, '\\');
590 SetLastError(ERROR_INVALID_PARAMETER
);
591 return INVALID_HANDLE_VALUE
;
594 if ((ULONG_PTR
)Slash
> (ULONG_PTR
)Guid
)
596 /* Create an extra slash */
597 memmove(Slash
+1, Slash
, (wcslen(Slash
) + 1) * sizeof(WCHAR
));
602 while((ULONG_PTR
)Guid
< (ULONG_PTR
)Slash
)
610 hKey
= SetupDiOpenClassRegKeyExW(&DeviceInterfaceData
->InterfaceClassGuid
, samDesired
, DIOCR_INTERFACE
, NULL
, NULL
);
611 if (hKey
!= INVALID_HANDLE_VALUE
)
613 if (RegOpenKeyExW(hKey
, Path
, 0, samDesired
, &hDevKey
) == ERROR_SUCCESS
)
621 hKey
= INVALID_HANDLE_VALUE
;
625 HeapFree(GetProcessHeap(), 0, Path
);