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 /* Unicode constants */ 25 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0}; 26 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0}; 27 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0}; 28 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0}; 29 static const WCHAR DotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0}; 30 static const WCHAR Linked[] = {'L','i','n','k','e','d',0}; 31 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0}; 32 33 static BOOL 34 CreateDeviceInterface( 35 IN struct DeviceInfo* deviceInfo, 36 IN LPCWSTR SymbolicLink, 37 IN LPCGUID pInterfaceGuid, 38 OUT struct DeviceInterface **pDeviceInterface) 39 { 40 struct DeviceInterface *deviceInterface; 41 42 *pDeviceInterface = NULL; 43 44 deviceInterface = HeapAlloc(GetProcessHeap(), 0, 45 FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (strlenW(SymbolicLink) + 1) * sizeof(WCHAR)); 46 if (!deviceInterface) 47 { 48 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 49 return FALSE; 50 } 51 deviceInterface->DeviceInfo = deviceInfo; 52 strcpyW(deviceInterface->SymbolicLink, SymbolicLink); 53 deviceInterface->Flags = 0; /* Flags will be updated later */ 54 memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID)); 55 56 *pDeviceInterface = deviceInterface; 57 return TRUE; 58 } 59 60 BOOL 61 DestroyDeviceInterface( 62 struct DeviceInterface* deviceInterface) 63 { 64 return HeapFree(GetProcessHeap(), 0, deviceInterface); 65 } 66 67 LONG 68 SETUP_CreateInterfaceList( 69 struct DeviceInfoSet *list, 70 PCWSTR MachineName, 71 CONST GUID *InterfaceGuid, 72 PCWSTR DeviceInstanceW /* OPTIONAL */, 73 BOOL OnlyPresentInterfaces) 74 { 75 HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */ 76 HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */ 77 HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */ 78 HKEY hControlKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString}\Control */ 79 HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */ 80 HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */ 81 LONG rc; 82 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1]; 83 PWSTR pSymbolicLink = NULL; 84 PWSTR InstancePath = NULL; 85 DWORD i, j; 86 DWORD dwLength, dwInstancePathLength; 87 DWORD dwRegType; 88 DWORD LinkedValue; 89 GUID ClassGuid; 90 struct DeviceInfo *deviceInfo; 91 92 hInterfaceKey = INVALID_HANDLE_VALUE; 93 hDeviceInstanceKey = NULL; 94 hReferenceKey = NULL; 95 96 /* Open registry key related to this interface */ 97 hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL); 98 if (hInterfaceKey == INVALID_HANDLE_VALUE) 99 { 100 /* Key doesn't exist. Let's keep it empty */ 101 rc = ERROR_SUCCESS; 102 goto cleanup; 103 } 104 105 /* Enumerate sub keys of hInterfaceKey */ 106 i = 0; 107 while (TRUE) 108 { 109 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]); 110 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL); 111 if (rc == ERROR_NO_MORE_ITEMS) 112 break; 113 if (rc != ERROR_SUCCESS) 114 goto cleanup; 115 i++; 116 117 /* Open sub key */ 118 if (hDeviceInstanceKey != NULL) 119 RegCloseKey(hDeviceInstanceKey); 120 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey); 121 if (rc != ERROR_SUCCESS) 122 goto cleanup; 123 124 /* Read DeviceInstance */ 125 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength); 126 if (rc != ERROR_SUCCESS) 127 goto cleanup; 128 if (dwRegType != REG_SZ) 129 { 130 rc = ERROR_GEN_FAILURE; 131 goto cleanup; 132 } 133 HeapFree(GetProcessHeap(), 0, InstancePath); 134 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR)); 135 if (!InstancePath) 136 { 137 rc = ERROR_NOT_ENOUGH_MEMORY; 138 goto cleanup; 139 } 140 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength); 141 if (rc != ERROR_SUCCESS) 142 goto cleanup; 143 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0'; 144 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath)); 145 146 if (DeviceInstanceW) 147 { 148 /* Check if device enumerator is not the right one */ 149 if (strcmpW(DeviceInstanceW, InstancePath) != 0) 150 continue; 151 } 152 153 /* Find class GUID associated to the device instance */ 154 rc = RegOpenKeyExW( 155 list->HKLM, 156 REGSTR_PATH_SYSTEMENUM, 157 0, /* Options */ 158 READ_CONTROL, 159 &hEnumKey); 160 if (rc != ERROR_SUCCESS) 161 goto cleanup; 162 rc = RegOpenKeyExW( 163 hEnumKey, 164 InstancePath, 165 0, /* Options */ 166 KEY_QUERY_VALUE, 167 &hKey); 168 RegCloseKey(hEnumKey); 169 if (rc != ERROR_SUCCESS) 170 goto cleanup; 171 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR); 172 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength); 173 RegCloseKey(hKey); 174 if (rc != ERROR_SUCCESS) 175 goto cleanup; 176 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0'; 177 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */ 178 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK) 179 { 180 rc = ERROR_GEN_FAILURE; 181 goto cleanup; 182 } 183 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid)); 184 185 /* If current device doesn't match the list GUID (if any), skip this entry */ 186 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid)) 187 continue; 188 189 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */ 190 j = 0; 191 while (TRUE) 192 { 193 struct DeviceInterface *interfaceInfo; 194 195 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]); 196 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL); 197 if (rc == ERROR_NO_MORE_ITEMS) 198 break; 199 if (rc != ERROR_SUCCESS) 200 goto cleanup; 201 j++; 202 if (KeyBuffer[0] != '#') 203 /* This entry doesn't represent an interesting entry */ 204 continue; 205 206 /* Open sub key */ 207 if (hReferenceKey != NULL) 208 RegCloseKey(hReferenceKey); 209 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey); 210 if (rc != ERROR_SUCCESS) 211 goto cleanup; 212 213 /* Read SymbolicLink value */ 214 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength); 215 if (rc != ERROR_SUCCESS ) 216 goto cleanup; 217 if (dwRegType != REG_SZ) 218 { 219 rc = ERROR_GEN_FAILURE; 220 goto cleanup; 221 } 222 223 /* We have found a device */ 224 /* Step 1. Create a device info element */ 225 if (!CreateDeviceInfo(list, InstancePath, &ClassGuid, &deviceInfo)) 226 { 227 rc = GetLastError(); 228 goto cleanup; 229 } 230 TRACE("Adding device %s to list\n", debugstr_w(InstancePath)); 231 InsertTailList(&list->ListHead, &deviceInfo->ListEntry); 232 233 /* Step 2. Create an interface list for this element */ 234 HeapFree(GetProcessHeap(), 0, pSymbolicLink); 235 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR)); 236 if (!pSymbolicLink) 237 { 238 rc = ERROR_NOT_ENOUGH_MEMORY; 239 goto cleanup; 240 } 241 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength); 242 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0'; 243 if (rc != ERROR_SUCCESS) 244 goto cleanup; 245 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo)) 246 { 247 rc = GetLastError(); 248 goto cleanup; 249 } 250 251 /* Step 3. Update flags */ 252 if (KeyBuffer[1] == '\0') 253 interfaceInfo->Flags |= SPINT_DEFAULT; 254 rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey); 255 if (rc != ERROR_SUCCESS) 256 { 257 #if 0 258 if (OnlyPresentInterfaces) 259 { 260 DestroyDeviceInterface(interfaceInfo); 261 continue; 262 } 263 else 264 interfaceInfo->Flags |= SPINT_REMOVED; 265 #endif 266 } 267 else 268 { 269 dwLength = sizeof(DWORD); 270 if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength) == ERROR_SUCCESS 271 && dwRegType == REG_DWORD && LinkedValue) 272 interfaceInfo->Flags |= SPINT_ACTIVE; 273 RegCloseKey(hControlKey); 274 } 275 276 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink)); 277 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry); 278 } 279 } 280 rc = ERROR_SUCCESS; 281 282 cleanup: 283 if (hReferenceKey != NULL) 284 RegCloseKey(hReferenceKey); 285 if (hDeviceInstanceKey != NULL) 286 RegCloseKey(hDeviceInstanceKey); 287 if (hInterfaceKey != INVALID_HANDLE_VALUE) 288 RegCloseKey(hInterfaceKey); 289 HeapFree(GetProcessHeap(), 0, InstancePath); 290 HeapFree(GetProcessHeap(), 0, pSymbolicLink); 291 return rc; 292 } 293 294 static LPWSTR 295 CreateSymbolicLink( 296 IN LPGUID InterfaceGuid, 297 IN LPCWSTR ReferenceString, 298 IN struct DeviceInfo *devInfo) 299 { 300 DWORD Length, Index, Offset; 301 LPWSTR Key; 302 303 Length = wcslen(devInfo->instanceId) + 4 /* prepend ##?# */ + 41 /* #{GUID} + */ + 1 /* zero byte */; 304 305 Key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length * sizeof(WCHAR)); 306 if (!Key) 307 return NULL; 308 309 wcscpy(Key, L"##?#"); 310 wcscat(Key, devInfo->instanceId); 311 312 for(Index = 4; Index < Length; Index++) 313 { 314 if (Key[Index] == L'\\') 315 { 316 Key[Index] = L'#'; 317 } 318 } 319 320 wcscat(Key, L"#"); 321 322 Offset = wcslen(Key); 323 pSetupStringFromGuid(InterfaceGuid, Key + Offset, Length - Offset); 324 325 return Key; 326 } 327 328 329 static BOOL 330 InstallOneInterface( 331 IN LPGUID InterfaceGuid, 332 IN LPCWSTR ReferenceString, 333 IN LPCWSTR InterfaceSection, 334 IN UINT InterfaceFlags, 335 IN HINF hInf, 336 IN HDEVINFO DeviceInfoSet, 337 IN struct DeviceInfo *devInfo) 338 { 339 HKEY hKey, hRefKey; 340 LPWSTR Path; 341 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; 342 struct DeviceInterface *DevItf = NULL; 343 344 if (InterfaceFlags != 0) 345 { 346 SetLastError(ERROR_INVALID_PARAMETER); 347 return FALSE; 348 } 349 350 TRACE("Need to InstallOneInterface(%s %s %s %u) hInf %p DeviceInfoSet %p devInfo %p instanceId %s\n", debugstr_guid(InterfaceGuid), 351 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags, hInf, DeviceInfoSet, devInfo, debugstr_w(devInfo->instanceId)); 352 353 354 Path = CreateSymbolicLink(InterfaceGuid, ReferenceString, devInfo); 355 if (!Path) 356 return FALSE; 357 358 CreateDeviceInterface(devInfo, Path, InterfaceGuid, &DevItf); 359 HeapFree(GetProcessHeap(), 0, Path); 360 if (!DevItf) 361 { 362 return FALSE; 363 } 364 365 memcpy(&DeviceInterfaceData.InterfaceClassGuid, &DevItf->InterfaceClassGuid, sizeof(GUID)); 366 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 367 DeviceInterfaceData.Flags = DevItf->Flags; 368 DeviceInterfaceData.Reserved = (ULONG_PTR)DevItf; 369 370 hKey = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet, &DeviceInterfaceData, 0, KEY_ALL_ACCESS, NULL, 0); 371 HeapFree(GetProcessHeap(), 0, DevItf); 372 if (hKey == INVALID_HANDLE_VALUE) 373 { 374 return FALSE; 375 } 376 377 if (ReferenceString) 378 { 379 Path = HeapAlloc(GetProcessHeap(), 0, (wcslen(ReferenceString) + 2) * sizeof(WCHAR)); 380 if (!Path) 381 { 382 RegCloseKey(hKey); 383 return FALSE; 384 } 385 386 wcscpy(Path, L"#"); 387 wcscat(Path, ReferenceString); 388 389 if (RegCreateKeyExW(hKey, Path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS) 390 { 391 ERR("failed to create key %s %lx\n", debugstr_w(Path), GetLastError()); 392 HeapFree(GetProcessHeap(), 0, Path); 393 return FALSE; 394 } 395 396 RegCloseKey(hKey); 397 hKey = hRefKey; 398 HeapFree(GetProcessHeap(), 0, Path); 399 } 400 401 if (RegCreateKeyExW(hKey, L"Device Parameters", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hRefKey, NULL) != ERROR_SUCCESS) 402 { 403 RegCloseKey(hKey); 404 return FALSE; 405 } 406 407 return SetupInstallFromInfSectionW(NULL, /* FIXME */ hInf, InterfaceSection, SPINST_REGISTRY, hRefKey, NULL, 0, NULL, NULL, NULL, NULL); 408 } 409 410 /*********************************************************************** 411 * SetupDiInstallDeviceInterfaces (SETUPAPI.@) 412 */ 413 BOOL WINAPI 414 SetupDiInstallDeviceInterfaces( 415 IN HDEVINFO DeviceInfoSet, 416 IN PSP_DEVINFO_DATA DeviceInfoData) 417 { 418 struct DeviceInfoSet *list = NULL; 419 BOOL ret = FALSE; 420 421 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData); 422 423 if (!DeviceInfoSet) 424 SetLastError(ERROR_INVALID_PARAMETER); 425 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) 426 SetLastError(ERROR_INVALID_HANDLE); 427 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC) 428 SetLastError(ERROR_INVALID_HANDLE); 429 else if (!DeviceInfoData) 430 SetLastError(ERROR_INVALID_PARAMETER); 431 else if (DeviceInfoData && DeviceInfoData->Reserved == 0) 432 SetLastError(ERROR_INVALID_USER_BUFFER); 433 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) 434 SetLastError(ERROR_INVALID_USER_BUFFER); 435 else 436 { 437 struct DeviceInfo *devInfo; 438 struct DriverInfoElement *SelectedDriver = NULL; 439 SP_DEVINSTALL_PARAMS_W InstallParams; 440 WCHAR SectionName[MAX_PATH]; 441 DWORD SectionNameLength = 0; 442 INFCONTEXT ContextInterface; 443 LPWSTR InterfaceGuidString = NULL; 444 LPWSTR ReferenceString = NULL; 445 LPWSTR InterfaceSection = NULL; 446 INT InterfaceFlags; 447 GUID InterfaceGuid; 448 BOOL Result; 449 450 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; 451 452 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); 453 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); 454 if (!Result) 455 goto cleanup; 456 457 SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved; 458 if (SelectedDriver == NULL) 459 { 460 SetLastError(ERROR_NO_DRIVER_SELECTED); 461 ret = FALSE; 462 goto cleanup; 463 } 464 465 /* Get .Interfaces section name */ 466 Result = SetupDiGetActualSectionToInstallW( 467 SelectedDriver->InfFileDetails->hInf, 468 SelectedDriver->Details.SectionName, 469 SectionName, MAX_PATH, &SectionNameLength, NULL); 470 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1) 471 goto cleanup; 472 strcatW(SectionName, DotInterfaces); 473 474 ret = TRUE; 475 Result = SetupFindFirstLineW( 476 SelectedDriver->InfFileDetails->hInf, 477 SectionName, 478 AddInterface, 479 &ContextInterface); 480 while (ret && Result) 481 { 482 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString); 483 if (!ret) 484 goto cleanup; 485 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1) 486 { 487 SetLastError(ERROR_INVALID_PARAMETER); 488 ret = FALSE; 489 goto cleanup; 490 } 491 492 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */ 493 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK) 494 { 495 /* Bad GUID, skip the entry */ 496 SetLastError(ERROR_INVALID_PARAMETER); 497 ret = FALSE; 498 goto cleanup; 499 } 500 501 ret = GetStringField(&ContextInterface, 2, &ReferenceString); 502 if (!ret) 503 goto cleanup; 504 505 ret = GetStringField(&ContextInterface, 3, &InterfaceSection); 506 if (!ret) 507 { 508 /* ReferenceString is optional */ 509 InterfaceSection = ReferenceString; 510 ReferenceString = NULL; 511 } 512 513 ret = SetupGetIntField( 514 &ContextInterface, 515 (ReferenceString ? 4 : 3), /* Field index */ 516 &InterfaceFlags); 517 if (!ret) 518 { 519 if (GetLastError() == ERROR_INVALID_PARAMETER) 520 { 521 /* The field may be empty. Ignore the error */ 522 InterfaceFlags = 0; 523 ret = TRUE; 524 } 525 else 526 goto cleanup; 527 } 528 529 /* Install Interface */ 530 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags, SelectedDriver->InfFileDetails->hInf, DeviceInfoSet, devInfo); 531 532 cleanup: 533 MyFree(InterfaceGuidString); 534 if (ReferenceString) 535 MyFree(ReferenceString); 536 MyFree(InterfaceSection); 537 InterfaceGuidString = ReferenceString = InterfaceSection = NULL; 538 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface); 539 } 540 } 541 542 TRACE("Returning %d\n", ret); 543 return ret; 544 } 545 546 HKEY WINAPI 547 SetupDiOpenDeviceInterfaceRegKey( 548 IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IN DWORD Reserved, IN REGSAM samDesired) 549 { 550 HKEY hKey = INVALID_HANDLE_VALUE, hDevKey; 551 struct DeviceInfoSet * list; 552 553 TRACE("%p %p %p 0x%08x 0x%08x)\n", DeviceInfoSet, DeviceInterfaceData, Reserved, samDesired); 554 555 if (!DeviceInfoSet) 556 SetLastError(ERROR_INVALID_PARAMETER); 557 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) 558 SetLastError(ERROR_INVALID_HANDLE); 559 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC) 560 SetLastError(ERROR_INVALID_HANDLE); 561 else if (!DeviceInterfaceData) 562 SetLastError(ERROR_INVALID_PARAMETER); 563 else if (DeviceInterfaceData && DeviceInterfaceData->Reserved == 0) 564 SetLastError(ERROR_INVALID_USER_BUFFER); 565 else if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA)) 566 SetLastError(ERROR_INVALID_USER_BUFFER); 567 else 568 { 569 struct DeviceInterface *DevItf; 570 LPWSTR Path, Guid, Slash; 571 DWORD Length; 572 DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved; 573 574 Length = wcslen(DevItf->SymbolicLink); 575 576 Path = HeapAlloc(GetProcessHeap(), 0, (Length+2) * sizeof(WCHAR)); 577 if (!Path) 578 { 579 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 580 return INVALID_HANDLE_VALUE; 581 } 582 583 wcscpy(Path, DevItf->SymbolicLink); 584 585 Guid = wcsrchr(Path, '}'); 586 Slash = wcsrchr(Path, '\\'); 587 if (!Guid || !Slash) 588 { 589 HeapFree(GetProcessHeap(), 0, Path); 590 SetLastError(ERROR_INVALID_PARAMETER); 591 return INVALID_HANDLE_VALUE; 592 } 593 594 if ((ULONG_PTR)Slash > (ULONG_PTR)Guid) 595 { 596 /* Create an extra slash */ 597 memmove(Slash+1, Slash, (wcslen(Slash) + 1) * sizeof(WCHAR)); 598 Slash[1] = L'#'; 599 } 600 601 Guid = Path; 602 while((ULONG_PTR)Guid < (ULONG_PTR)Slash) 603 { 604 if (*Guid == L'\\') 605 *Guid = L'#'; 606 607 Guid++; 608 } 609 610 hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL); 611 if (hKey != INVALID_HANDLE_VALUE) 612 { 613 if (RegOpenKeyExW(hKey, Path, 0, samDesired, &hDevKey) == ERROR_SUCCESS) 614 { 615 RegCloseKey(hKey); 616 hKey = hDevKey; 617 } 618 else 619 { 620 RegCloseKey(hKey); 621 hKey = INVALID_HANDLE_VALUE; 622 } 623 } 624 625 HeapFree(GetProcessHeap(), 0, Path); 626 } 627 628 return hKey; 629 } 630 631 /*********************************************************************** 632 * SetupDiDeleteDeviceInterfaceData (SETUPAPI.@) 633 */ 634 BOOL 635 WINAPI 636 SetupDiDeleteDeviceInterfaceData( 637 HDEVINFO DeviceInfoSet, 638 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) 639 { 640 FIXME("SetupDiDeleteDeviceInterfaceData(%p %p) stub\n", 641 DeviceInfoSet, DeviceInterfaceData); 642 return TRUE; 643 } 644