Merging r37048, r37051, r37052, r37055 from the-real-msvc branch
[reactos.git] / reactos / dll / win32 / setupapi / interface.c
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 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
25
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};
34
35 static BOOL
36 CreateDeviceInterface(
37 IN struct DeviceInfo* deviceInfo,
38 IN LPCWSTR SymbolicLink,
39 IN LPCGUID pInterfaceGuid,
40 OUT struct DeviceInterface **pDeviceInterface)
41 {
42 struct DeviceInterface *deviceInterface;
43
44 *pDeviceInterface = NULL;
45
46 deviceInterface = HeapAlloc(GetProcessHeap(), 0,
47 FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (strlenW(SymbolicLink) + 1) * sizeof(WCHAR));
48 if (!deviceInterface)
49 {
50 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
51 return FALSE;
52 }
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));
57
58 *pDeviceInterface = deviceInterface;
59 return TRUE;
60 }
61
62 BOOL
63 DestroyDeviceInterface(
64 struct DeviceInterface* deviceInterface)
65 {
66 return HeapFree(GetProcessHeap(), 0, deviceInterface);
67 }
68
69 LONG
70 SETUP_CreateInterfaceList(
71 struct DeviceInfoSet *list,
72 PCWSTR MachineName,
73 CONST GUID *InterfaceGuid,
74 PCWSTR DeviceInstanceW /* OPTIONAL */,
75 BOOL OnlyPresentInterfaces)
76 {
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} */
83 LONG rc;
84 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
85 PWSTR pSymbolicLink = NULL;
86 PWSTR InstancePath = NULL;
87 DWORD i, j;
88 DWORD dwLength, dwInstancePathLength;
89 DWORD dwRegType;
90 DWORD LinkedValue;
91 GUID ClassGuid;
92 struct DeviceInfo *deviceInfo;
93
94 hInterfaceKey = INVALID_HANDLE_VALUE;
95 hDeviceInstanceKey = NULL;
96 hReferenceKey = NULL;
97
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)
101 {
102 rc = GetLastError();
103 goto cleanup;
104 }
105
106 /* Enumerate sub keys of hInterfaceKey */
107 i = 0;
108 while (TRUE)
109 {
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)
113 break;
114 if (rc != ERROR_SUCCESS)
115 goto cleanup;
116 i++;
117
118 /* Open sub key */
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)
123 goto cleanup;
124
125 /* Read DeviceInstance */
126 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
127 if (rc != ERROR_SUCCESS)
128 goto cleanup;
129 if (dwRegType != REG_SZ)
130 {
131 rc = ERROR_GEN_FAILURE;
132 goto cleanup;
133 }
134 HeapFree(GetProcessHeap(), 0, InstancePath);
135 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
136 if (!InstancePath)
137 {
138 rc = ERROR_NOT_ENOUGH_MEMORY;
139 goto cleanup;
140 }
141 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
142 if (rc != ERROR_SUCCESS)
143 goto cleanup;
144 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
145 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
146
147 if (DeviceInstanceW)
148 {
149 /* Check if device enumerator is not the right one */
150 if (strcmpW(DeviceInstanceW, InstancePath) != 0)
151 continue;
152 }
153
154 /* Find class GUID associated to the device instance */
155 rc = RegOpenKeyExW(
156 list->HKLM,
157 REGSTR_PATH_SYSTEMENUM,
158 0, /* Options */
159 0,
160 &hEnumKey);
161 if (rc != ERROR_SUCCESS)
162 goto cleanup;
163 rc = RegOpenKeyExW(
164 hEnumKey,
165 InstancePath,
166 0, /* Options */
167 KEY_QUERY_VALUE,
168 &hKey);
169 RegCloseKey(hEnumKey);
170 if (rc != ERROR_SUCCESS)
171 goto cleanup;
172 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
173 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
174 RegCloseKey(hKey);
175 if (rc != ERROR_SUCCESS)
176 goto cleanup;
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)
180 {
181 rc = ERROR_GEN_FAILURE;
182 goto cleanup;
183 }
184 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
185
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))
188 continue;
189
190 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
191 j = 0;
192 while (TRUE)
193 {
194 struct DeviceInterface *interfaceInfo;
195
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)
199 break;
200 if (rc != ERROR_SUCCESS)
201 goto cleanup;
202 j++;
203 if (KeyBuffer[0] != '#')
204 /* This entry doesn't represent an interesting entry */
205 continue;
206
207 /* Open sub key */
208 if (hReferenceKey != NULL)
209 RegCloseKey(hReferenceKey);
210 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
211 if (rc != ERROR_SUCCESS)
212 goto cleanup;
213
214 /* Read SymbolicLink value */
215 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
216 if (rc != ERROR_SUCCESS )
217 goto cleanup;
218 if (dwRegType != REG_SZ)
219 {
220 rc = ERROR_GEN_FAILURE;
221 goto cleanup;
222 }
223
224 /* We have found a device */
225 /* Step 1. Create a device info element */
226 if (!CreateDeviceInfo(list, InstancePath, &ClassGuid, &deviceInfo))
227 {
228 rc = GetLastError();
229 goto cleanup;
230 }
231 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
232 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
233
234 /* Step 2. Create an interface list for this element */
235 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
236 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
237 if (!pSymbolicLink)
238 {
239 rc = ERROR_NOT_ENOUGH_MEMORY;
240 goto cleanup;
241 }
242 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
243 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
244 if (rc != ERROR_SUCCESS)
245 goto cleanup;
246 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
247 {
248 rc = GetLastError();
249 goto cleanup;
250 }
251
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)
257 {
258 if (OnlyPresentInterfaces)
259 {
260 DestroyDeviceInterface(interfaceInfo);
261 continue;
262 }
263 else
264 interfaceInfo->Flags |= SPINT_REMOVED;
265 }
266 else
267 {
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);
273 }
274
275 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
276 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
277 }
278 }
279 rc = ERROR_SUCCESS;
280
281 cleanup:
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);
290 return rc;
291 }
292
293 static BOOL
294 InstallOneInterface(
295 IN LPGUID InterfaceGuid,
296 IN LPCWSTR ReferenceString,
297 IN LPCWSTR InterfaceSection,
298 IN UINT InterfaceFlags)
299 {
300 if (InterfaceFlags != 0)
301 {
302 SetLastError(ERROR_INVALID_PARAMETER);
303 return FALSE;
304 }
305
306 FIXME("Need to InstallOneInterface(%s %s %s %u)\n", debugstr_guid(InterfaceGuid),
307 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags);
308 return TRUE;
309 }
310
311 /***********************************************************************
312 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
313 */
314 BOOL WINAPI
315 SetupDiInstallDeviceInterfaces(
316 IN HDEVINFO DeviceInfoSet,
317 IN PSP_DEVINFO_DATA DeviceInfoData)
318 {
319 struct DeviceInfoSet *list = NULL;
320 BOOL ret = FALSE;
321
322 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
323
324 if (!DeviceInfoSet)
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);
334 else
335 {
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;
344 INT InterfaceFlags;
345 GUID InterfaceGuid;
346 BOOL Result;
347
348 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
349 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
350 if (!Result)
351 goto cleanup;
352
353 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
354 if (SelectedDriver == NULL)
355 {
356 SetLastError(ERROR_NO_DRIVER_SELECTED);
357 ret = FALSE;
358 goto cleanup;
359 }
360
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)
367 goto cleanup;
368 strcatW(SectionName, DotInterfaces);
369
370 ret = TRUE;
371 Result = SetupFindFirstLineW(
372 SelectedDriver->InfFileDetails->hInf,
373 SectionName,
374 AddInterface,
375 &ContextInterface);
376 while (ret && Result)
377 {
378 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
379 if (!ret)
380 goto cleanup;
381 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
382 {
383 SetLastError(ERROR_INVALID_PARAMETER);
384 ret = FALSE;
385 goto cleanup;
386 }
387
388 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
389 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
390 {
391 /* Bad GUID, skip the entry */
392 SetLastError(ERROR_INVALID_PARAMETER);
393 ret = FALSE;
394 goto cleanup;
395 }
396
397 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
398 if (!ret)
399 goto cleanup;
400
401 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
402 if (!ret)
403 goto cleanup;
404
405 ret = SetupGetIntField(
406 &ContextInterface,
407 4, /* Field index */
408 &InterfaceFlags);
409 if (!ret)
410 {
411 if (GetLastError() == ERROR_INVALID_PARAMETER)
412 {
413 /* The field may be empty. Ignore the error */
414 InterfaceFlags = 0;
415 ret = TRUE;
416 }
417 else
418 goto cleanup;
419 }
420
421 /* Install Interface */
422 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags);
423
424 cleanup:
425 MyFree(InterfaceGuidString);
426 MyFree(ReferenceString);
427 MyFree(InterfaceSection);
428 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
429 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
430 }
431 }
432
433 TRACE("Returning %d\n", ret);
434 return ret;
435 }