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
)
258 if (OnlyPresentInterfaces
)
260 DestroyDeviceInterface(interfaceInfo
);
264 interfaceInfo
->Flags
|= SPINT_REMOVED
;
268 dwLength
= sizeof(DWORD
);
269 if (RegQueryValueExW(hControlKey
, Linked
, NULL
, &dwRegType
, (LPBYTE
)&LinkedValue
, &dwLength
)
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 LPCWSTR InterfaceSection
,
298 IN UINT InterfaceFlags
)
300 if (InterfaceFlags
!= 0)
302 SetLastError(ERROR_INVALID_PARAMETER
);
306 FIXME("Need to InstallOneInterface(%s %s %s %u)\n", debugstr_guid(InterfaceGuid
),
307 debugstr_w(ReferenceString
), debugstr_w(InterfaceSection
), InterfaceFlags
);
311 /***********************************************************************
312 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
315 SetupDiInstallDeviceInterfaces(
316 IN HDEVINFO DeviceInfoSet
,
317 IN PSP_DEVINFO_DATA DeviceInfoData
)
319 struct DeviceInfoSet
*list
= NULL
;
322 TRACE("%p %p\n", DeviceInfoSet
, DeviceInfoData
);
325 SetLastError(ERROR_INVALID_PARAMETER
);
326 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
327 SetLastError(ERROR_INVALID_HANDLE
);
328 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
329 SetLastError(ERROR_INVALID_HANDLE
);
330 else if (!DeviceInfoData
)
331 SetLastError(ERROR_INVALID_PARAMETER
);
332 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
333 SetLastError(ERROR_INVALID_USER_BUFFER
);
336 struct DriverInfoElement
*SelectedDriver
;
337 SP_DEVINSTALL_PARAMS_W InstallParams
;
338 WCHAR SectionName
[MAX_PATH
];
339 DWORD SectionNameLength
= 0;
340 INFCONTEXT ContextInterface
;
341 LPWSTR InterfaceGuidString
= NULL
;
342 LPWSTR ReferenceString
= NULL
;
343 LPWSTR InterfaceSection
= NULL
;
348 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
349 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
353 SelectedDriver
= (struct DriverInfoElement
*)InstallParams
.Reserved
;
354 if (SelectedDriver
== NULL
)
356 SetLastError(ERROR_NO_DRIVER_SELECTED
);
361 /* Get .Interfaces section name */
362 Result
= SetupDiGetActualSectionToInstallW(
363 SelectedDriver
->InfFileDetails
->hInf
,
364 SelectedDriver
->Details
.SectionName
,
365 SectionName
, MAX_PATH
, &SectionNameLength
, NULL
);
366 if (!Result
|| SectionNameLength
> MAX_PATH
- strlenW(DotInterfaces
) - 1)
368 strcatW(SectionName
, DotInterfaces
);
371 Result
= SetupFindFirstLineW(
372 SelectedDriver
->InfFileDetails
->hInf
,
376 while (ret
&& Result
)
378 ret
= GetStringField(&ContextInterface
, 1, &InterfaceGuidString
);
381 else if (strlenW(InterfaceGuidString
) != MAX_GUID_STRING_LEN
- 1)
383 SetLastError(ERROR_INVALID_PARAMETER
);
388 InterfaceGuidString
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
389 if (UuidFromStringW(&InterfaceGuidString
[1], &InterfaceGuid
) != RPC_S_OK
)
391 /* Bad GUID, skip the entry */
392 SetLastError(ERROR_INVALID_PARAMETER
);
397 ret
= GetStringField(&ContextInterface
, 2, &ReferenceString
);
401 ret
= GetStringField(&ContextInterface
, 3, &InterfaceSection
);
405 ret
= SetupGetIntField(
411 if (GetLastError() == ERROR_INVALID_PARAMETER
)
413 /* The field may be empty. Ignore the error */
421 /* Install Interface */
422 ret
= InstallOneInterface(&InterfaceGuid
, ReferenceString
, InterfaceSection
, InterfaceFlags
);
425 MyFree(InterfaceGuidString
);
426 MyFree(ReferenceString
);
427 MyFree(InterfaceSection
);
428 InterfaceGuidString
= ReferenceString
= InterfaceSection
= NULL
;
429 Result
= SetupFindNextMatchLineW(&ContextInterface
, AddInterface
, &ContextInterface
);
433 TRACE("Returning %d\n", ret
);