172917b1c061139261d33d87c220291db9cdce36
[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 0
259 if (OnlyPresentInterfaces)
260 {
261 DestroyDeviceInterface(interfaceInfo);
262 continue;
263 }
264 else
265 interfaceInfo->Flags |= SPINT_REMOVED;
266 #endif
267 }
268 else
269 {
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);
275 }
276
277 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
278 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
279 }
280 }
281 rc = ERROR_SUCCESS;
282
283 cleanup:
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);
292 return rc;
293 }
294
295 static BOOL
296 InstallOneInterface(
297 IN LPGUID InterfaceGuid,
298 IN LPCWSTR ReferenceString,
299 IN LPCWSTR InterfaceSection,
300 IN UINT InterfaceFlags)
301 {
302 if (InterfaceFlags != 0)
303 {
304 SetLastError(ERROR_INVALID_PARAMETER);
305 return FALSE;
306 }
307
308 FIXME("Need to InstallOneInterface(%s %s %s %u)\n", debugstr_guid(InterfaceGuid),
309 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags);
310 return TRUE;
311 }
312
313 /***********************************************************************
314 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
315 */
316 BOOL WINAPI
317 SetupDiInstallDeviceInterfaces(
318 IN HDEVINFO DeviceInfoSet,
319 IN PSP_DEVINFO_DATA DeviceInfoData)
320 {
321 struct DeviceInfoSet *list = NULL;
322 BOOL ret = FALSE;
323
324 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
325
326 if (!DeviceInfoSet)
327 SetLastError(ERROR_INVALID_PARAMETER);
328 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
329 SetLastError(ERROR_INVALID_HANDLE);
330 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
331 SetLastError(ERROR_INVALID_HANDLE);
332 else if (!DeviceInfoData)
333 SetLastError(ERROR_INVALID_PARAMETER);
334 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
335 SetLastError(ERROR_INVALID_USER_BUFFER);
336 else
337 {
338 struct DriverInfoElement *SelectedDriver;
339 SP_DEVINSTALL_PARAMS_W InstallParams;
340 WCHAR SectionName[MAX_PATH];
341 DWORD SectionNameLength = 0;
342 INFCONTEXT ContextInterface;
343 LPWSTR InterfaceGuidString = NULL;
344 LPWSTR ReferenceString = NULL;
345 LPWSTR InterfaceSection = NULL;
346 INT InterfaceFlags;
347 GUID InterfaceGuid;
348 BOOL Result;
349
350 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
351 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
352 if (!Result)
353 goto cleanup;
354
355 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
356 if (SelectedDriver == NULL)
357 {
358 SetLastError(ERROR_NO_DRIVER_SELECTED);
359 ret = FALSE;
360 goto cleanup;
361 }
362
363 /* Get .Interfaces section name */
364 Result = SetupDiGetActualSectionToInstallW(
365 SelectedDriver->InfFileDetails->hInf,
366 SelectedDriver->Details.SectionName,
367 SectionName, MAX_PATH, &SectionNameLength, NULL);
368 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
369 goto cleanup;
370 strcatW(SectionName, DotInterfaces);
371
372 ret = TRUE;
373 Result = SetupFindFirstLineW(
374 SelectedDriver->InfFileDetails->hInf,
375 SectionName,
376 AddInterface,
377 &ContextInterface);
378 while (ret && Result)
379 {
380 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
381 if (!ret)
382 goto cleanup;
383 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
384 {
385 SetLastError(ERROR_INVALID_PARAMETER);
386 ret = FALSE;
387 goto cleanup;
388 }
389
390 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
391 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
392 {
393 /* Bad GUID, skip the entry */
394 SetLastError(ERROR_INVALID_PARAMETER);
395 ret = FALSE;
396 goto cleanup;
397 }
398
399 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
400 if (!ret)
401 goto cleanup;
402
403 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
404 if (!ret)
405 goto cleanup;
406
407 ret = SetupGetIntField(
408 &ContextInterface,
409 4, /* Field index */
410 &InterfaceFlags);
411 if (!ret)
412 {
413 if (GetLastError() == ERROR_INVALID_PARAMETER)
414 {
415 /* The field may be empty. Ignore the error */
416 InterfaceFlags = 0;
417 ret = TRUE;
418 }
419 else
420 goto cleanup;
421 }
422
423 /* Install Interface */
424 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags);
425
426 cleanup:
427 MyFree(InterfaceGuidString);
428 MyFree(ReferenceString);
429 MyFree(InterfaceSection);
430 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
431 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
432 }
433 }
434
435 TRACE("Returning %d\n", ret);
436 return ret;
437 }