[SETUPAPI]
[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 LPWSTR
296 CreateSymbolicLink(
297 IN LPGUID InterfaceGuid,
298 IN LPCWSTR ReferenceString,
299 IN struct DeviceInfo *devInfo)
300 {
301 DWORD Length, Index, Offset;
302 LPWSTR Key;
303
304 Length = wcslen(devInfo->instanceId) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */;
305
306 Key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length * sizeof(WCHAR));
307 if (!Key)
308 return NULL;
309
310 wcscpy(Key, L"##?#");
311 wcscat(Key, devInfo->instanceId);
312
313 for(Index = 4; Index < Length; Index++)
314 {
315 if (Key[Index] == L'\\')
316 {
317 Key[Index] = L'#';
318 }
319 }
320
321 wcscat(Key, L"#");
322
323 Offset = wcslen(Key);
324 pSetupStringFromGuid(InterfaceGuid, Key + Offset, Length - Offset);
325
326 return Key;
327 }
328
329
330 static BOOL
331 InstallOneInterface(
332 IN LPGUID InterfaceGuid,
333 IN LPCWSTR ReferenceString,
334 IN LPCWSTR InterfaceSection,
335 IN UINT InterfaceFlags,
336 IN HINF hInf,
337 IN HDEVINFO DeviceInfoSet,
338 IN struct DeviceInfo *devInfo)
339 {
340 BOOL ret;
341 HKEY hKey, hRefKey;
342 LPWSTR Path;
343 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
344 PLIST_ENTRY InterfaceListEntry;
345 struct DeviceInterface *DevItf = NULL;
346
347 if (InterfaceFlags != 0)
348 {
349 SetLastError(ERROR_INVALID_PARAMETER);
350 return FALSE;
351 }
352
353 TRACE("Need to InstallOneInterface(%s %s %s %u) hInf %p DeviceInfoSet %p devInfo %p instanceId %s\n", debugstr_guid(InterfaceGuid),
354 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags, hInf, DeviceInfoSet, devInfo, debugstr_w(devInfo->instanceId));
355
356
357 Path = CreateSymbolicLink(InterfaceGuid, ReferenceString, devInfo);
358 if (!Path)
359 return FALSE;
360
361 CreateDeviceInterface(devInfo, Path, InterfaceGuid, &DevItf);
362 HeapFree(GetProcessHeap(), 0, Path);
363 if (!DevItf)
364 {
365 return FALSE;
366 }
367
368 memcpy(&DeviceInterfaceData.InterfaceClassGuid, &DevItf->InterfaceClassGuid, sizeof(GUID));
369 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
370 DeviceInterfaceData.Flags = DevItf->Flags;
371 DeviceInterfaceData.Reserved = (ULONG_PTR)DevItf;
372
373 hKey = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet, &DeviceInterfaceData, 0, KEY_ALL_ACCESS, NULL, 0);
374 HeapFree(GetProcessHeap(), 0, DevItf);
375 if (hKey == INVALID_HANDLE_VALUE)
376 {
377 return FALSE;
378 }
379
380 if (ReferenceString)
381 {
382 Path = HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString) + 2) * sizeof(WCHAR));
383 if (!Path)
384 {
385 RegCloseKey(hKey);
386 return FALSE;
387 }
388
389 wcscpy(Path, L"#");
390 wcscat(Path, ReferenceString);
391
392 if (RegCreateKeyExW(hKey, Path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
393 {
394 ERR("failed to create key %s %lx\n", debugstr_w(Path), GetLastError());
395 HeapFree(GetProcessHeap(), 0, Path);
396 return FALSE;
397 }
398
399 RegCloseKey(hKey);
400 hKey = hRefKey;
401 HeapFree(GetProcessHeap(), 0, Path);
402 }
403
404 return SetupInstallFromInfSectionW(NULL, /* FIXME */ hInf, InterfaceSection, SPINST_REGISTRY, hKey, NULL, 0, NULL, NULL, NULL, NULL);
405 }
406
407 /***********************************************************************
408 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
409 */
410 BOOL WINAPI
411 SetupDiInstallDeviceInterfaces(
412 IN HDEVINFO DeviceInfoSet,
413 IN PSP_DEVINFO_DATA DeviceInfoData)
414 {
415 struct DeviceInfoSet *list = NULL;
416 BOOL ret = FALSE;
417
418 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
419
420 if (!DeviceInfoSet)
421 SetLastError(ERROR_INVALID_PARAMETER);
422 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
423 SetLastError(ERROR_INVALID_HANDLE);
424 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
425 SetLastError(ERROR_INVALID_HANDLE);
426 else if (!DeviceInfoData)
427 SetLastError(ERROR_INVALID_PARAMETER);
428 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
429 SetLastError(ERROR_INVALID_USER_BUFFER);
430 else
431 {
432 struct DeviceInfo *devInfo;
433 struct DriverInfoElement *SelectedDriver = NULL;
434 SP_DEVINSTALL_PARAMS_W InstallParams;
435 WCHAR SectionName[MAX_PATH];
436 DWORD SectionNameLength = 0;
437 INFCONTEXT ContextInterface;
438 LPWSTR InterfaceGuidString = NULL;
439 LPWSTR ReferenceString = NULL;
440 LPWSTR InterfaceSection = NULL;
441 INT InterfaceFlags;
442 GUID InterfaceGuid;
443 BOOL Result;
444
445 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
446
447 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
448 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
449 if (!Result)
450 goto cleanup;
451
452 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
453 if (SelectedDriver == NULL)
454 {
455 SetLastError(ERROR_NO_DRIVER_SELECTED);
456 ret = FALSE;
457 goto cleanup;
458 }
459
460 /* Get .Interfaces section name */
461 Result = SetupDiGetActualSectionToInstallW(
462 SelectedDriver->InfFileDetails->hInf,
463 SelectedDriver->Details.SectionName,
464 SectionName, MAX_PATH, &SectionNameLength, NULL);
465 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
466 goto cleanup;
467 strcatW(SectionName, DotInterfaces);
468
469 ret = TRUE;
470 Result = SetupFindFirstLineW(
471 SelectedDriver->InfFileDetails->hInf,
472 SectionName,
473 AddInterface,
474 &ContextInterface);
475 while (ret && Result)
476 {
477 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
478 if (!ret)
479 goto cleanup;
480 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
481 {
482 SetLastError(ERROR_INVALID_PARAMETER);
483 ret = FALSE;
484 goto cleanup;
485 }
486
487 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
488 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
489 {
490 /* Bad GUID, skip the entry */
491 SetLastError(ERROR_INVALID_PARAMETER);
492 ret = FALSE;
493 goto cleanup;
494 }
495
496 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
497 if (!ret)
498 goto cleanup;
499
500 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
501 if (!ret)
502 {
503 /* ReferenceString is optional */
504 InterfaceSection = ReferenceString;
505 ReferenceString = NULL;
506 }
507
508 ret = SetupGetIntField(
509 &ContextInterface,
510 (ReferenceString ? 4 : 3), /* Field index */
511 &InterfaceFlags);
512 if (!ret)
513 {
514 if (GetLastError() == ERROR_INVALID_PARAMETER)
515 {
516 /* The field may be empty. Ignore the error */
517 InterfaceFlags = 0;
518 ret = TRUE;
519 }
520 else
521 goto cleanup;
522 }
523
524 /* Install Interface */
525 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags, SelectedDriver->InfFileDetails->hInf, DeviceInfoSet, devInfo);
526
527 cleanup:
528 MyFree(InterfaceGuidString);
529 if (ReferenceString)
530 MyFree(ReferenceString);
531 MyFree(InterfaceSection);
532 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
533 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
534 }
535 }
536
537 TRACE("Returning %d\n", ret);
538 return ret;
539 }