fc9f89076b7b881584fbd89f32d1ae879caabde1
[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 InsertTailList(&devInfo->InterfaceListHead, &DevItf->ListEntry);
369
370 memcpy(&DeviceInterfaceData.InterfaceClassGuid, &DevItf->InterfaceClassGuid, sizeof(GUID));
371 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
372 DeviceInterfaceData.Flags = DevItf->Flags;
373 DeviceInterfaceData.Reserved = (ULONG_PTR)DevItf;
374
375 hKey = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet, &DeviceInterfaceData, 0, KEY_ALL_ACCESS, NULL, 0);
376 HeapFree(GetProcessHeap(), 0, DevItf);
377 if (hKey == INVALID_HANDLE_VALUE)
378 {
379 return FALSE;
380 }
381
382 if (ReferenceString)
383 {
384 Path = HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString) + 2) * sizeof(WCHAR));
385 if (!Path)
386 {
387 RegCloseKey(hKey);
388 return FALSE;
389 }
390
391 wcscpy(Path, L"#");
392 wcscat(Path, ReferenceString);
393
394 if (RegCreateKeyExW(hKey, Path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS)
395 {
396 ERR("failed to create key %s %lx\n", debugstr_w(Path), GetLastError());
397 HeapFree(GetProcessHeap(), 0, Path);
398 return FALSE;
399 }
400
401 RegCloseKey(hKey);
402 hKey = hRefKey;
403 HeapFree(GetProcessHeap(), 0, Path);
404 }
405
406 return SetupInstallFromInfSectionW(NULL, /* FIXME */ hInf, InterfaceSection, SPINST_REGISTRY, hKey, NULL, 0, NULL, NULL, NULL, NULL);
407 }
408
409 /***********************************************************************
410 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
411 */
412 BOOL WINAPI
413 SetupDiInstallDeviceInterfaces(
414 IN HDEVINFO DeviceInfoSet,
415 IN PSP_DEVINFO_DATA DeviceInfoData)
416 {
417 struct DeviceInfoSet *list = NULL;
418 BOOL ret = FALSE;
419
420 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
421
422 if (!DeviceInfoSet)
423 SetLastError(ERROR_INVALID_PARAMETER);
424 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
425 SetLastError(ERROR_INVALID_HANDLE);
426 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
427 SetLastError(ERROR_INVALID_HANDLE);
428 else if (!DeviceInfoData)
429 SetLastError(ERROR_INVALID_PARAMETER);
430 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
431 SetLastError(ERROR_INVALID_USER_BUFFER);
432 else
433 {
434 struct DeviceInfo *devInfo;
435 struct DriverInfoElement *SelectedDriver = NULL;
436 SP_DEVINSTALL_PARAMS_W InstallParams;
437 WCHAR SectionName[MAX_PATH];
438 DWORD SectionNameLength = 0;
439 INFCONTEXT ContextInterface;
440 LPWSTR InterfaceGuidString = NULL;
441 LPWSTR ReferenceString = NULL;
442 LPWSTR InterfaceSection = NULL;
443 INT InterfaceFlags;
444 GUID InterfaceGuid;
445 BOOL Result;
446
447 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
448
449 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
450 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
451 if (!Result)
452 goto cleanup;
453
454 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
455 if (SelectedDriver == NULL)
456 {
457 SetLastError(ERROR_NO_DRIVER_SELECTED);
458 ret = FALSE;
459 goto cleanup;
460 }
461
462 /* Get .Interfaces section name */
463 Result = SetupDiGetActualSectionToInstallW(
464 SelectedDriver->InfFileDetails->hInf,
465 SelectedDriver->Details.SectionName,
466 SectionName, MAX_PATH, &SectionNameLength, NULL);
467 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
468 goto cleanup;
469 strcatW(SectionName, DotInterfaces);
470
471 ret = TRUE;
472 Result = SetupFindFirstLineW(
473 SelectedDriver->InfFileDetails->hInf,
474 SectionName,
475 AddInterface,
476 &ContextInterface);
477 while (ret && Result)
478 {
479 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
480 if (!ret)
481 goto cleanup;
482 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
483 {
484 SetLastError(ERROR_INVALID_PARAMETER);
485 ret = FALSE;
486 goto cleanup;
487 }
488
489 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
490 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
491 {
492 /* Bad GUID, skip the entry */
493 SetLastError(ERROR_INVALID_PARAMETER);
494 ret = FALSE;
495 goto cleanup;
496 }
497
498 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
499 if (!ret)
500 goto cleanup;
501
502 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
503 if (!ret)
504 {
505 /* ReferenceString is optional */
506 InterfaceSection = ReferenceString;
507 ReferenceString = NULL;
508 }
509
510 ret = SetupGetIntField(
511 &ContextInterface,
512 (ReferenceString ? 4 : 3), /* Field index */
513 &InterfaceFlags);
514 if (!ret)
515 {
516 if (GetLastError() == ERROR_INVALID_PARAMETER)
517 {
518 /* The field may be empty. Ignore the error */
519 InterfaceFlags = 0;
520 ret = TRUE;
521 }
522 else
523 goto cleanup;
524 }
525
526 /* Install Interface */
527 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags, SelectedDriver->InfFileDetails->hInf, DeviceInfoSet, devInfo);
528
529 cleanup:
530 MyFree(InterfaceGuidString);
531 if (ReferenceString)
532 MyFree(ReferenceString);
533 MyFree(InterfaceSection);
534 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
535 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
536 }
537 }
538
539 TRACE("Returning %d\n", ret);
540 return ret;
541 }