1 /* 2 * SetupAPI device class-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 #include <wingdi.h> 25 #include <shellapi.h> 26 #include <strsafe.h> 27 28 /* Unicode constants */ 29 static const WCHAR BackSlash[] = {'\\',0}; 30 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0}; 31 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0}; 32 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0}; 33 static const WCHAR InterfaceInstall32[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0}; 34 static const WCHAR SetupapiDll[] = {'s','e','t','u','p','a','p','i','.','d','l','l',0}; 35 36 typedef BOOL 37 (WINAPI* PROPERTY_PAGE_PROVIDER) ( 38 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest, 39 IN LPFNADDPROPSHEETPAGE fAddFunc, 40 IN LPARAM lParam); 41 typedef BOOL 42 (*UPDATE_CLASS_PARAM_HANDLER) ( 43 IN HDEVINFO DeviceInfoSet, 44 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 45 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 46 IN DWORD ClassInstallParamsSize); 47 48 static BOOL 49 SETUP_PropertyChangeHandler( 50 IN HDEVINFO DeviceInfoSet, 51 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 52 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 53 IN DWORD ClassInstallParamsSize); 54 55 static BOOL 56 SETUP_PropertyAddPropertyAdvancedHandler( 57 IN HDEVINFO DeviceInfoSet, 58 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 59 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 60 IN DWORD ClassInstallParamsSize); 61 62 typedef struct _INSTALL_PARAMS_DATA 63 { 64 DI_FUNCTION Function; 65 UPDATE_CLASS_PARAM_HANDLER UpdateHandler; 66 ULONG ParamsSize; 67 LONG FieldOffset; 68 } INSTALL_PARAMS_DATA; 69 70 #define ADD_PARAM_HANDLER(Function, UpdateHandler, ParamsType, ParamsField) \ 71 { Function, UpdateHandler, sizeof(ParamsType), FIELD_OFFSET(struct ClassInstallParams, ParamsField) }, 72 73 static const INSTALL_PARAMS_DATA InstallParamsData[] = { 74 ADD_PARAM_HANDLER(DIF_PROPERTYCHANGE, SETUP_PropertyChangeHandler, SP_PROPCHANGE_PARAMS, PropChangeParams) 75 ADD_PARAM_HANDLER(DIF_ADDPROPERTYPAGE_ADVANCED, SETUP_PropertyAddPropertyAdvancedHandler, SP_ADDPROPERTYPAGE_DATA, AddPropertyPageData) 76 }; 77 #undef ADD_PARAM_HANDLER 78 79 #define UNKNOWN_ICON_INDEX 18 80 81 /*********************************************************************** 82 * SetupDiDestroyClassImageList(SETUPAPI.@) 83 */ 84 BOOL WINAPI 85 SetupDiDestroyClassImageList( 86 IN PSP_CLASSIMAGELIST_DATA ClassImageListData) 87 { 88 struct ClassImageList *list; 89 BOOL ret = FALSE; 90 91 TRACE("%p\n", ClassImageListData); 92 93 if (!ClassImageListData) 94 SetLastError(ERROR_INVALID_PARAMETER); 95 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) 96 SetLastError(ERROR_INVALID_USER_BUFFER); 97 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL) 98 SetLastError(ERROR_INVALID_USER_BUFFER); 99 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC) 100 SetLastError(ERROR_INVALID_USER_BUFFER); 101 else 102 { 103 /* If Reserved wasn't NULL, then this is valid too */ 104 if (ClassImageListData->ImageList) 105 { 106 ImageList_Destroy(ClassImageListData->ImageList); 107 ClassImageListData->ImageList = NULL; 108 } 109 110 MyFree(list); 111 ClassImageListData->Reserved = 0; 112 113 ret = TRUE; 114 } 115 116 TRACE("Returning %d\n", ret); 117 return ret; 118 } 119 120 /*********************************************************************** 121 * SETUP_CreateDevicesListFromEnumerator 122 * 123 * PARAMS 124 * list [IO] Device info set to fill with discovered devices. 125 * pClassGuid [I] If specified, only devices which belong to this class will be added. 126 * Enumerator [I] Location to search devices to add. 127 * hEnumeratorKey [I] Registry key corresponding to Enumerator key. Must have KEY_ENUMERATE_SUB_KEYS right. 128 * 129 * RETURNS 130 * Success: ERROR_SUCCESS. 131 * Failure: an error code. 132 */ 133 static LONG 134 SETUP_CreateDevicesListFromEnumerator( 135 IN OUT struct DeviceInfoSet *list, 136 IN CONST GUID *pClassGuid OPTIONAL, 137 IN LPCWSTR Enumerator, 138 IN HKEY hEnumeratorKey) /* handle to Enumerator registry key */ 139 { 140 HKEY hDeviceIdKey = NULL, hInstanceIdKey; 141 WCHAR KeyBuffer[MAX_PATH]; 142 WCHAR InstancePath[MAX_PATH]; 143 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */ 144 struct DeviceInfo *deviceInfo; 145 DWORD i = 0, j; 146 DWORD dwLength, dwRegType; 147 DWORD rc; 148 149 /* Enumerate device IDs (subkeys of hEnumeratorKey) */ 150 while (TRUE) 151 { 152 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]); 153 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL); 154 if (rc == ERROR_NO_MORE_ITEMS) 155 break; 156 if (rc != ERROR_SUCCESS) 157 goto cleanup; 158 i++; 159 160 /* Open device id sub key */ 161 if (hDeviceIdKey != NULL) 162 RegCloseKey(hDeviceIdKey); 163 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey); 164 if (rc != ERROR_SUCCESS) 165 goto cleanup; 166 167 if (FAILED(StringCchCopyW(InstancePath, _countof(InstancePath), Enumerator)) || 168 FAILED(StringCchCatW(InstancePath, _countof(InstancePath), BackSlash)) || 169 FAILED(StringCchCatW(InstancePath, _countof(InstancePath), KeyBuffer)) || 170 FAILED(StringCchCatW(InstancePath, _countof(InstancePath), BackSlash))) 171 { 172 rc = ERROR_GEN_FAILURE; 173 goto cleanup; 174 } 175 176 pEndOfInstancePath = &InstancePath[strlenW(InstancePath)]; 177 178 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */ 179 j = 0; 180 while (TRUE) 181 { 182 GUID KeyGuid; 183 184 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]); 185 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL); 186 if (rc == ERROR_NO_MORE_ITEMS) 187 break; 188 if (rc != ERROR_SUCCESS) 189 goto cleanup; 190 j++; 191 192 /* Open instance id sub key */ 193 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey); 194 if (rc != ERROR_SUCCESS) 195 goto cleanup; 196 *pEndOfInstancePath = '\0'; 197 strcatW(InstancePath, KeyBuffer); 198 199 /* Read ClassGUID value */ 200 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR); 201 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength); 202 RegCloseKey(hInstanceIdKey); 203 if (rc == ERROR_FILE_NOT_FOUND) 204 { 205 if (pClassGuid) 206 /* Skip this bad entry as we can't verify it */ 207 continue; 208 /* Set a default GUID for this device */ 209 memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID)); 210 } 211 else if (rc != ERROR_SUCCESS) 212 { 213 goto cleanup; 214 } 215 else if (dwRegType != REG_SZ || dwLength < MAX_GUID_STRING_LEN * sizeof(WCHAR)) 216 { 217 rc = ERROR_GEN_FAILURE; 218 goto cleanup; 219 } 220 else 221 { 222 KeyBuffer[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */ 223 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK) 224 /* Bad GUID, skip the entry */ 225 continue; 226 } 227 228 if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid)) 229 { 230 /* Skip this entry as it is not the right device class */ 231 continue; 232 } 233 234 /* Add the entry to the list */ 235 if (!CreateDeviceInfo(list, InstancePath, &KeyGuid, &deviceInfo)) 236 { 237 rc = GetLastError(); 238 goto cleanup; 239 } 240 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath), list); 241 InsertTailList(&list->ListHead, &deviceInfo->ListEntry); 242 } 243 } 244 245 rc = ERROR_SUCCESS; 246 247 cleanup: 248 if (hDeviceIdKey != NULL) 249 RegCloseKey(hDeviceIdKey); 250 return rc; 251 } 252 253 LONG 254 SETUP_CreateDevicesList( 255 IN OUT struct DeviceInfoSet *list, 256 IN PCWSTR MachineName OPTIONAL, 257 IN CONST GUID *Class OPTIONAL, 258 IN PCWSTR Enumerator OPTIONAL) 259 { 260 HKEY HKLM = HKEY_LOCAL_MACHINE; 261 HKEY hEnumKey = NULL; 262 HKEY hEnumeratorKey = NULL; 263 WCHAR KeyBuffer[MAX_PATH]; 264 DWORD i; 265 DWORD dwLength; 266 DWORD rc; 267 268 if (Class && IsEqualIID(Class, &GUID_NULL)) 269 Class = NULL; 270 271 /* Open Enum key (if applicable) */ 272 if (MachineName != NULL) 273 { 274 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM); 275 if (rc != ERROR_SUCCESS) 276 goto cleanup; 277 } 278 279 rc = RegOpenKeyExW( 280 HKLM, 281 REGSTR_PATH_SYSTEMENUM, 282 0, 283 KEY_ENUMERATE_SUB_KEYS, 284 &hEnumKey); 285 if (rc != ERROR_SUCCESS) 286 goto cleanup; 287 288 /* If enumerator is provided, call directly SETUP_CreateDevicesListFromEnumerator. 289 * Else, enumerate all enumerators and call SETUP_CreateDevicesListFromEnumerator 290 * for each one. 291 */ 292 if (Enumerator) 293 { 294 rc = RegOpenKeyExW( 295 hEnumKey, 296 Enumerator, 297 0, 298 KEY_ENUMERATE_SUB_KEYS, 299 &hEnumeratorKey); 300 if (rc != ERROR_SUCCESS) 301 { 302 if (rc == ERROR_FILE_NOT_FOUND) 303 rc = ERROR_INVALID_DATA; 304 goto cleanup; 305 } 306 rc = SETUP_CreateDevicesListFromEnumerator(list, Class, Enumerator, hEnumeratorKey); 307 } 308 else 309 { 310 /* Enumerate enumerators */ 311 i = 0; 312 while (TRUE) 313 { 314 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]); 315 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL); 316 if (rc == ERROR_NO_MORE_ITEMS) 317 break; 318 else if (rc != ERROR_SUCCESS) 319 goto cleanup; 320 i++; 321 322 /* Open sub key */ 323 if (hEnumeratorKey != NULL) 324 RegCloseKey(hEnumeratorKey); 325 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey); 326 if (rc != ERROR_SUCCESS) 327 goto cleanup; 328 329 /* Call SETUP_CreateDevicesListFromEnumerator */ 330 rc = SETUP_CreateDevicesListFromEnumerator(list, Class, KeyBuffer, hEnumeratorKey); 331 if (rc != ERROR_SUCCESS) 332 goto cleanup; 333 } 334 rc = ERROR_SUCCESS; 335 } 336 337 cleanup: 338 if (HKLM != HKEY_LOCAL_MACHINE) 339 RegCloseKey(HKLM); 340 if (hEnumKey != NULL) 341 RegCloseKey(hEnumKey); 342 if (hEnumeratorKey != NULL) 343 RegCloseKey(hEnumeratorKey); 344 return rc; 345 } 346 347 static BOOL 348 SETUP_GetIconIndex( 349 IN HKEY hClassKey, 350 OUT PINT ImageIndex) 351 { 352 LPWSTR Buffer = NULL; 353 DWORD dwRegType, dwLength; 354 LONG rc; 355 BOOL ret = FALSE; 356 357 /* Read icon registry key */ 358 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength); 359 if (rc != ERROR_SUCCESS) 360 { 361 SetLastError(rc); 362 goto cleanup; 363 } else if (dwRegType != REG_SZ) 364 { 365 SetLastError(ERROR_INVALID_INDEX); 366 goto cleanup; 367 } 368 Buffer = MyMalloc(dwLength + sizeof(WCHAR)); 369 if (!Buffer) 370 { 371 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 372 goto cleanup; 373 } 374 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength); 375 if (rc != ERROR_SUCCESS) 376 { 377 SetLastError(rc); 378 goto cleanup; 379 } 380 /* make sure the returned buffer is NULL-terminated */ 381 Buffer[dwLength / sizeof(WCHAR)] = 0; 382 383 /* Transform icon value to a INT */ 384 *ImageIndex = atoiW(Buffer); 385 ret = TRUE; 386 387 cleanup: 388 MyFree(Buffer); 389 return ret; 390 } 391 392 /*********************************************************************** 393 * SetupDiGetClassImageIndex (SETUPAPI.@) 394 */ 395 BOOL WINAPI 396 SetupDiGetClassImageIndex( 397 IN PSP_CLASSIMAGELIST_DATA ClassImageListData, 398 IN CONST GUID *ClassGuid, 399 OUT PINT ImageIndex) 400 { 401 struct ClassImageList *list; 402 BOOL ret = FALSE; 403 404 TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex); 405 406 if (!ClassImageListData || !ClassGuid || !ImageIndex) 407 SetLastError(ERROR_INVALID_PARAMETER); 408 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) 409 SetLastError(ERROR_INVALID_USER_BUFFER); 410 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL) 411 SetLastError(ERROR_INVALID_USER_BUFFER); 412 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC) 413 SetLastError(ERROR_INVALID_USER_BUFFER); 414 else 415 { 416 DWORD i; 417 418 for (i = 0; i < list->NumberOfGuids; i++) 419 { 420 if (IsEqualIID(ClassGuid, &list->Guids[i])) 421 break; 422 } 423 424 if (i == list->NumberOfGuids || list->IconIndexes[i] < 0) 425 SetLastError(ERROR_FILE_NOT_FOUND); 426 else 427 { 428 *ImageIndex = list->IconIndexes[i]; 429 ret = TRUE; 430 } 431 } 432 433 TRACE("Returning %d\n", ret); 434 return ret; 435 } 436 437 /*********************************************************************** 438 * SetupDiGetClassImageList(SETUPAPI.@) 439 */ 440 BOOL WINAPI 441 SetupDiGetClassImageList( 442 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData) 443 { 444 return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL); 445 } 446 447 /*********************************************************************** 448 * SetupDiGetClassImageListExA(SETUPAPI.@) 449 */ 450 BOOL WINAPI 451 SetupDiGetClassImageListExA( 452 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData, 453 IN PCSTR MachineName OPTIONAL, 454 IN PVOID Reserved) 455 { 456 PWSTR MachineNameW = NULL; 457 BOOL ret; 458 459 if (MachineName) 460 { 461 MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP); 462 if (MachineNameW == NULL) 463 return FALSE; 464 } 465 466 ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved); 467 468 MyFree(MachineNameW); 469 470 return ret; 471 } 472 473 static BOOL WINAPI 474 SETUP_GetClassIconInfo(IN CONST GUID *ClassGuid, OUT PINT OutIndex, OUT LPWSTR *OutDllName) 475 { 476 LPWSTR Buffer = NULL; 477 INT iconIndex = -UNKNOWN_ICON_INDEX; 478 HKEY hKey = INVALID_HANDLE_VALUE; 479 BOOL ret = FALSE; 480 481 if (ClassGuid) 482 { 483 hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE); 484 if (hKey != INVALID_HANDLE_VALUE) 485 { 486 SETUP_GetIconIndex(hKey, &iconIndex); 487 } 488 } 489 490 if (iconIndex > 0) 491 { 492 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */ 493 PWCHAR Comma; 494 LONG rc; 495 DWORD dwRegType, dwLength; 496 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength); 497 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ) 498 { 499 Buffer = MyMalloc(dwLength + sizeof(WCHAR)); 500 if (Buffer == NULL) 501 { 502 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 503 goto cleanup; 504 } 505 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength); 506 if (rc != ERROR_SUCCESS) 507 { 508 SetLastError(rc); 509 goto cleanup; 510 } 511 /* make sure the returned buffer is NULL-terminated */ 512 Buffer[dwLength / sizeof(WCHAR)] = 0; 513 } 514 else if 515 (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength)) 516 && dwRegType == REG_SZ) 517 { 518 Buffer = MyMalloc(dwLength + sizeof(WCHAR)); 519 if (Buffer == NULL) 520 { 521 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 522 goto cleanup; 523 } 524 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength); 525 if (rc != ERROR_SUCCESS) 526 { 527 SetLastError(rc); 528 goto cleanup; 529 } 530 /* make sure the returned buffer is NULL-terminated */ 531 Buffer[dwLength / sizeof(WCHAR)] = 0; 532 } 533 else 534 { 535 /* Unable to find where to load the icon */ 536 SetLastError(ERROR_FILE_NOT_FOUND); 537 goto cleanup; 538 } 539 Comma = strchrW(Buffer, ','); 540 if (!Comma) 541 { 542 SetLastError(ERROR_GEN_FAILURE); 543 goto cleanup; 544 } 545 *Comma = '\0'; 546 *OutDllName = Buffer; 547 } 548 else 549 { 550 /* Look up icon in setupapi.dll */ 551 iconIndex = -iconIndex; 552 *OutDllName = NULL; 553 } 554 555 *OutIndex = iconIndex; 556 ret = TRUE; 557 558 TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(*OutDllName ? *OutDllName : SetupapiDll)); 559 560 cleanup: 561 562 if (hKey != INVALID_HANDLE_VALUE) 563 RegCloseKey(hKey); 564 565 if (Buffer && !ret) 566 MyFree(Buffer); 567 568 return ret; 569 } 570 571 572 /*********************************************************************** 573 * SetupDiGetClassImageListExW(SETUPAPI.@) 574 */ 575 BOOL WINAPI 576 SetupDiGetClassImageListExW( 577 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData, 578 IN PCWSTR MachineName OPTIONAL, 579 IN PVOID Reserved) 580 { 581 BOOL ret = FALSE; 582 583 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved); 584 585 if (!ClassImageListData) 586 SetLastError(ERROR_INVALID_PARAMETER); 587 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA)) 588 SetLastError(ERROR_INVALID_USER_BUFFER); 589 else if (Reserved) 590 SetLastError(ERROR_INVALID_PARAMETER); 591 else 592 { 593 struct ClassImageList *list = NULL; 594 HDC hDC; 595 DWORD RequiredSize; 596 DWORD ilMask, bkColor; 597 HICON hIcon; 598 DWORD size; 599 INT i, bpp; 600 UINT idx; 601 602 /* Get list of all class GUIDs in given computer */ 603 ret = SetupDiBuildClassInfoListExW( 604 0, 605 NULL, 606 0, 607 &RequiredSize, 608 MachineName, 609 NULL); 610 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) 611 goto cleanup; 612 613 size = sizeof(struct ClassImageList) 614 + (sizeof(GUID) + sizeof(INT)) * RequiredSize; 615 list = HeapAlloc(GetProcessHeap(), 0, size); 616 if (!list) 617 { 618 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 619 goto cleanup; 620 } 621 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC; 622 list->NumberOfGuids = RequiredSize; 623 list->Guids = (GUID*)(list + 1); 624 list->IconIndexes = (INT*)((ULONG_PTR)(list + 1) + sizeof(GUID) * RequiredSize); 625 626 ret = SetupDiBuildClassInfoListExW( 627 0, 628 list->Guids, 629 list->NumberOfGuids, 630 &RequiredSize, 631 MachineName, 632 NULL); 633 if (!ret) 634 goto cleanup; 635 else if (RequiredSize != list->NumberOfGuids) 636 { 637 /* Hm. Class list changed since last call. Ignore 638 * this case as it should be very rare */ 639 SetLastError(ERROR_GEN_FAILURE); 640 ret = FALSE; 641 goto cleanup; 642 } 643 644 /* Prepare a HIMAGELIST */ 645 InitCommonControls(); 646 647 hDC = GetDC(NULL); 648 if (!hDC) 649 goto cleanup; 650 651 bpp = GetDeviceCaps(hDC, BITSPIXEL); 652 ReleaseDC(NULL, hDC); 653 654 if (bpp <= 4) 655 ilMask = ILC_COLOR4; 656 else if (bpp <= 8) 657 ilMask = ILC_COLOR8; 658 else if (bpp <= 16) 659 ilMask = ILC_COLOR16; 660 else if (bpp <= 24) 661 ilMask = ILC_COLOR24; 662 else if (bpp <= 32) 663 ilMask = ILC_COLOR32; 664 else 665 ilMask = ILC_COLOR; 666 667 ilMask |= ILC_MASK; 668 669 ClassImageListData->ImageList = ImageList_Create(16, 16, ilMask, 100, 10); 670 if (!ClassImageListData->ImageList) 671 goto cleanup; 672 673 ClassImageListData->Reserved = (ULONG_PTR)list; 674 675 /* For some reason, Windows sets the list background to COLOR_WINDOW */ 676 bkColor = GetSysColor(COLOR_WINDOW); 677 ImageList_SetBkColor(ClassImageListData->ImageList, bkColor); 678 679 /* Now, we "simply" need to load icons associated with all class guids, 680 * and put their index in the image list in the IconIndexes array */ 681 for (i = 0; i < list->NumberOfGuids; i++) 682 { 683 INT miniIconIndex; 684 LPWSTR DllName = NULL; 685 686 if (SETUP_GetClassIconInfo(&list->Guids[i], &miniIconIndex, &DllName)) 687 { 688 if (DllName && ExtractIconExW(DllName, -miniIconIndex, NULL, &hIcon, 1) == 1) 689 { 690 list->IconIndexes[i] = ImageList_AddIcon(ClassImageListData->ImageList, hIcon); 691 } 692 else if(!DllName) 693 { 694 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(miniIconIndex), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); 695 list->IconIndexes[i] = ImageList_AddIcon(ClassImageListData->ImageList, hIcon); 696 } 697 698 if(hIcon) 699 DestroyIcon(hIcon); 700 else 701 list->IconIndexes[i] = -1; 702 703 if(DllName) 704 MyFree(DllName); 705 } 706 else 707 { 708 list->IconIndexes[i] = -1; /* Special value to indicate that the icon is unavailable */ 709 } 710 } 711 712 /* Finally, add the overlay icons to the image list */ 713 for (i = 0; i <= 2; i++) 714 { 715 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(500 + i), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); 716 if (hIcon) 717 { 718 idx = ImageList_AddIcon(ClassImageListData->ImageList, hIcon); 719 if (idx != -1) 720 ImageList_SetOverlayImage(ClassImageListData->ImageList, idx, i + 1); 721 DestroyIcon(hIcon); 722 } 723 } 724 725 ret = TRUE; 726 727 cleanup: 728 if (!ret) 729 { 730 if (ClassImageListData->Reserved) 731 SetupDiDestroyClassImageList(ClassImageListData); 732 else if (list) 733 MyFree(list); 734 } 735 } 736 737 TRACE("Returning %d\n", ret); 738 return ret; 739 } 740 741 /*********************************************************************** 742 * SetupDiGetClassInstallParamsA(SETUPAPI.@) 743 */ 744 BOOL WINAPI 745 SetupDiGetClassInstallParamsA( 746 IN HDEVINFO DeviceInfoSet, 747 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 748 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 749 IN DWORD ClassInstallParamsSize, 750 OUT PDWORD RequiredSize OPTIONAL) 751 { 752 FIXME("SetupDiGetClassInstallParamsA(%p %p %p %lu %p) Stub\n", 753 DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize, RequiredSize); 754 return FALSE; 755 } 756 757 /*********************************************************************** 758 * SetupDiGetClassInstallParamsW(SETUPAPI.@) 759 */ 760 BOOL WINAPI 761 SetupDiGetClassInstallParamsW( 762 IN HDEVINFO DeviceInfoSet, 763 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 764 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 765 IN DWORD ClassInstallParamsSize, 766 OUT PDWORD RequiredSize OPTIONAL) 767 { 768 FIXME("SetupDiGetClassInstallParamsW(%p %p %p %lu %p) Stub\n", 769 DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize, RequiredSize); 770 return FALSE; 771 } 772 773 /*********************************************************************** 774 * SetupDiLoadClassIcon(SETUPAPI.@) 775 */ 776 BOOL WINAPI 777 SetupDiLoadClassIcon( 778 IN CONST GUID *ClassGuid, 779 OUT HICON *LargeIcon OPTIONAL, 780 OUT PINT MiniIconIndex OPTIONAL) 781 { 782 INT iconIndex = 0; 783 LPWSTR DllName = NULL; 784 BOOL ret = FALSE; 785 HICON hIcon = NULL; 786 787 if (LargeIcon) 788 { 789 if(!SETUP_GetClassIconInfo(ClassGuid, &iconIndex, &DllName)) 790 goto cleanup; 791 792 if (!DllName || ExtractIconExW(DllName, -iconIndex, &hIcon, NULL, 1) != 1 || hIcon == NULL) 793 { 794 /* load the default unknown device icon if ExtractIcon failed */ 795 if(DllName) 796 iconIndex = UNKNOWN_ICON_INDEX; 797 798 hIcon = LoadImage(hInstance, MAKEINTRESOURCE(iconIndex), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); 799 800 if(!hIcon) 801 goto cleanup; 802 } 803 804 *LargeIcon = hIcon; 805 } 806 807 if (MiniIconIndex) 808 *MiniIconIndex = iconIndex; 809 810 ret = TRUE; 811 812 cleanup: 813 814 if(DllName) 815 MyFree(DllName); 816 817 TRACE("Returning %d\n", ret); 818 return ret; 819 } 820 821 /*********************************************************************** 822 * SetupDiInstallClassExW (SETUPAPI.@) 823 */ 824 HKEY 825 SETUP_CreateClassKey(HINF hInf); 826 BOOL WINAPI 827 SetupDiInstallClassExW( 828 IN HWND hwndParent OPTIONAL, 829 IN PCWSTR InfFileName OPTIONAL, 830 IN DWORD Flags, 831 IN HSPFILEQ FileQueue OPTIONAL, 832 IN CONST GUID *InterfaceClassGuid OPTIONAL, 833 IN PVOID Reserved1, 834 IN PVOID Reserved2) 835 { 836 BOOL ret = FALSE; 837 838 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags, 839 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2); 840 841 if (!InfFileName) 842 { 843 FIXME("Case not implemented: InfFileName NULL\n"); 844 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 845 } 846 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL)) 847 { 848 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL)); 849 SetLastError(ERROR_INVALID_FLAGS); 850 } 851 else if ((Flags & DI_NOVCP) && FileQueue == NULL) 852 SetLastError(ERROR_INVALID_PARAMETER); 853 else if (Reserved1 != NULL) 854 SetLastError(ERROR_INVALID_PARAMETER); 855 else if (Reserved2 != NULL) 856 SetLastError(ERROR_INVALID_PARAMETER); 857 else 858 { 859 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE; 860 SP_DEVINSTALL_PARAMS_W InstallParams; 861 WCHAR SectionName[MAX_PATH]; 862 HINF hInf = INVALID_HANDLE_VALUE; 863 HKEY hRootKey = INVALID_HANDLE_VALUE; 864 PVOID callback_context = NULL; 865 866 hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL); 867 if (hDeviceInfo == INVALID_HANDLE_VALUE) 868 goto cleanup; 869 870 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); 871 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams)) 872 goto cleanup; 873 874 InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL); 875 InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL); 876 if (Flags & DI_NOVCP) 877 InstallParams.FileQueue = FileQueue; 878 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams)) 879 goto cleanup; 880 881 /* Open the .inf file */ 882 hInf = SetupOpenInfFileW( 883 InfFileName, 884 NULL, 885 INF_STYLE_WIN4, 886 NULL); 887 if (hInf == INVALID_HANDLE_VALUE) 888 goto cleanup; 889 890 /* Try to append a layout file */ 891 SetupOpenAppendInfFileW(NULL, hInf, NULL); 892 893 if (InterfaceClassGuid) 894 { 895 /* Retrieve the actual section name */ 896 ret = SetupDiGetActualSectionToInstallW( 897 hInf, 898 InterfaceInstall32, 899 SectionName, 900 MAX_PATH, 901 NULL, 902 NULL); 903 if (!ret) 904 goto cleanup; 905 906 /* Open registry key related to this interface */ 907 /* FIXME: What happens if the key doesn't exist? */ 908 hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL); 909 if (hRootKey == INVALID_HANDLE_VALUE) 910 goto cleanup; 911 912 /* SetupDiCreateDeviceInterface??? */ 913 FIXME("Installing an interface is not implemented\n"); 914 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 915 } 916 else 917 { 918 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */ 919 hRootKey = SETUP_CreateClassKey(hInf); 920 if (hRootKey == INVALID_HANDLE_VALUE) 921 goto cleanup; 922 923 /* Retrieve the actual section name */ 924 ret = SetupDiGetActualSectionToInstallW( 925 hInf, 926 ClassInstall32, 927 SectionName, 928 MAX_PATH - strlenW(DotServices), 929 NULL, 930 NULL); 931 if (!ret) 932 goto cleanup; 933 934 callback_context = SetupInitDefaultQueueCallback(hwndParent); 935 if (!callback_context) 936 goto cleanup; 937 938 ret = SetupInstallFromInfSectionW( 939 hwndParent, 940 hInf, 941 SectionName, 942 SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG, 943 hRootKey, 944 NULL, /* FIXME: SourceRootPath */ 945 !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */ 946 SetupDefaultQueueCallbackW, 947 callback_context, 948 hDeviceInfo, 949 NULL); 950 if (!ret) 951 goto cleanup; 952 953 /* OPTIONAL: Install .Services section */ 954 lstrcatW(SectionName, DotServices); 955 SetupInstallServicesFromInfSectionExW( 956 hInf, 957 SectionName, 958 0, 959 hDeviceInfo, 960 NULL, 961 NULL, 962 NULL); 963 ret = TRUE; 964 } 965 966 cleanup: 967 if (hDeviceInfo != INVALID_HANDLE_VALUE) 968 SetupDiDestroyDeviceInfoList(hDeviceInfo); 969 if (hInf != INVALID_HANDLE_VALUE) 970 SetupCloseInfFile(hInf); 971 if (hRootKey != INVALID_HANDLE_VALUE) 972 RegCloseKey(hRootKey); 973 SetupTermDefaultQueueCallback(callback_context); 974 } 975 976 TRACE("Returning %d\n", ret); 977 return ret; 978 } 979 980 /*********************************************************************** 981 * Helper functions for SetupDiSetClassInstallParamsW 982 */ 983 static BOOL 984 SETUP_PropertyChangeHandler( 985 IN HDEVINFO DeviceInfoSet, 986 IN PSP_DEVINFO_DATA DeviceInfoData, 987 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 988 IN DWORD ClassInstallParamsSize) 989 { 990 PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams; 991 BOOL ret = FALSE; 992 993 if (!DeviceInfoData) 994 SetLastError(ERROR_INVALID_PARAMETER); 995 else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS)) 996 SetLastError(ERROR_INVALID_PARAMETER); 997 else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE 998 && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE 999 && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP) 1000 SetLastError(ERROR_INVALID_FLAGS); 1001 else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL 1002 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC) 1003 SetLastError(ERROR_INVALID_FLAGS); 1004 else if (PropChangeParams 1005 && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP) 1006 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC) 1007 SetLastError(ERROR_INVALID_USER_BUFFER); 1008 else 1009 { 1010 PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams; 1011 struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; 1012 CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChangeParams; 1013 1014 if (*CurrentPropChangeParams) 1015 { 1016 MyFree(*CurrentPropChangeParams); 1017 *CurrentPropChangeParams = NULL; 1018 } 1019 if (PropChangeParams) 1020 { 1021 *CurrentPropChangeParams = MyMalloc(ClassInstallParamsSize); 1022 if (!*CurrentPropChangeParams) 1023 { 1024 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1025 goto done; 1026 } 1027 memcpy(*CurrentPropChangeParams, PropChangeParams, ClassInstallParamsSize); 1028 } 1029 ret = TRUE; 1030 } 1031 1032 done: 1033 return ret; 1034 } 1035 1036 static BOOL 1037 SETUP_PropertyAddPropertyAdvancedHandler( 1038 IN HDEVINFO DeviceInfoSet, 1039 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 1040 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 1041 IN DWORD ClassInstallParamsSize) 1042 { 1043 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData = (PSP_ADDPROPERTYPAGE_DATA)ClassInstallParams; 1044 BOOL ret = FALSE; 1045 1046 if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS)) 1047 SetLastError(ERROR_INVALID_PARAMETER); 1048 else if (AddPropertyPageData && AddPropertyPageData->Flags != 0) 1049 SetLastError(ERROR_INVALID_FLAGS); 1050 else if (AddPropertyPageData && AddPropertyPageData->NumDynamicPages >= MAX_INSTALLWIZARD_DYNAPAGES) 1051 SetLastError(ERROR_INVALID_USER_BUFFER); 1052 else 1053 { 1054 PSP_ADDPROPERTYPAGE_DATA *CurrentAddPropertyPageData; 1055 if (!DeviceInfoData) 1056 { 1057 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet; 1058 CurrentAddPropertyPageData = &list->ClassInstallParams.AddPropertyPageData; 1059 } 1060 else 1061 { 1062 struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; 1063 CurrentAddPropertyPageData = &deviceInfo->ClassInstallParams.AddPropertyPageData; 1064 } 1065 if (*CurrentAddPropertyPageData) 1066 { 1067 MyFree(*CurrentAddPropertyPageData); 1068 *CurrentAddPropertyPageData = NULL; 1069 } 1070 if (AddPropertyPageData) 1071 { 1072 *CurrentAddPropertyPageData = MyMalloc(ClassInstallParamsSize); 1073 if (!*CurrentAddPropertyPageData) 1074 { 1075 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1076 goto done; 1077 } 1078 memcpy(*CurrentAddPropertyPageData, AddPropertyPageData, ClassInstallParamsSize); 1079 } 1080 ret = TRUE; 1081 } 1082 1083 done: 1084 return ret; 1085 } 1086 1087 /*********************************************************************** 1088 * SetupDiSetClassInstallParamsW (SETUPAPI.@) 1089 */ 1090 BOOL WINAPI 1091 SetupDiSetClassInstallParamsW( 1092 IN HDEVINFO DeviceInfoSet, 1093 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 1094 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL, 1095 IN DWORD ClassInstallParamsSize) 1096 { 1097 struct DeviceInfoSet *list; 1098 BOOL ret = FALSE; 1099 1100 TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData, 1101 ClassInstallParams, ClassInstallParamsSize); 1102 1103 if (!DeviceInfoSet) 1104 SetLastError(ERROR_INVALID_PARAMETER); 1105 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) 1106 SetLastError(ERROR_INVALID_HANDLE); 1107 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC) 1108 SetLastError(ERROR_INVALID_HANDLE); 1109 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) 1110 SetLastError(ERROR_INVALID_USER_BUFFER); 1111 else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER)) 1112 SetLastError(ERROR_INVALID_USER_BUFFER); 1113 else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER)) 1114 SetLastError(ERROR_INVALID_PARAMETER); 1115 else if (!ClassInstallParams && ClassInstallParamsSize != 0) 1116 SetLastError(ERROR_INVALID_PARAMETER); 1117 else 1118 { 1119 SP_DEVINSTALL_PARAMS_W InstallParams; 1120 BOOL Result; 1121 1122 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); 1123 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); 1124 if (!Result) 1125 goto done; 1126 1127 if (ClassInstallParams) 1128 { 1129 DWORD i; 1130 /* Check parameters in ClassInstallParams */ 1131 for (i = 0; i < sizeof(InstallParamsData) / sizeof(InstallParamsData[0]); i++) 1132 { 1133 if (InstallParamsData[i].Function == ClassInstallParams->InstallFunction) 1134 { 1135 ret = InstallParamsData[i].UpdateHandler( 1136 DeviceInfoSet, 1137 DeviceInfoData, 1138 ClassInstallParams, 1139 ClassInstallParamsSize); 1140 if (ret) 1141 { 1142 InstallParams.Flags |= DI_CLASSINSTALLPARAMS; 1143 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); 1144 } 1145 goto done; 1146 } 1147 } 1148 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams->InstallFunction); 1149 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1150 goto done; 1151 } 1152 else 1153 { 1154 InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS; 1155 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams); 1156 } 1157 } 1158 1159 done: 1160 TRACE("Returning %d\n", ret); 1161 return ret; 1162 } 1163 1164 /*********************************************************************** 1165 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@) 1166 */ 1167 BOOL WINAPI 1168 SetupDiGetClassDevPropertySheetsA( 1169 IN HDEVINFO DeviceInfoSet, 1170 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 1171 IN LPPROPSHEETHEADERA PropertySheetHeader, 1172 IN DWORD PropertySheetHeaderPageListSize, 1173 OUT PDWORD RequiredSize OPTIONAL, 1174 IN DWORD PropertySheetType) 1175 { 1176 PROPSHEETHEADERW psh; 1177 BOOL ret = FALSE; 1178 1179 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, 1180 PropertySheetHeader, PropertySheetHeaderPageListSize, 1181 RequiredSize, PropertySheetType); 1182 1183 if(PropertySheetHeader) 1184 { 1185 psh.dwFlags = PropertySheetHeader->dwFlags; 1186 psh.phpage = PropertySheetHeader->phpage; 1187 psh.nPages = PropertySheetHeader->nPages; 1188 } 1189 1190 ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL, 1191 PropertySheetHeaderPageListSize, RequiredSize, 1192 PropertySheetType); 1193 if (ret) 1194 { 1195 PropertySheetHeader->nPages = psh.nPages; 1196 } 1197 1198 TRACE("Returning %d\n", ret); 1199 return ret; 1200 } 1201 1202 struct ClassDevPropertySheetsData 1203 { 1204 LPPROPSHEETHEADERW PropertySheetHeader; 1205 DWORD PropertySheetHeaderPageListSize; 1206 DWORD NumberOfPages; 1207 BOOL DontCancel; 1208 }; 1209 1210 static BOOL WINAPI 1211 SETUP_GetClassDevPropertySheetsCallback( 1212 IN HPROPSHEETPAGE hPropSheetPage, 1213 IN OUT LPARAM lParam) 1214 { 1215 struct ClassDevPropertySheetsData *PropPageData; 1216 1217 PropPageData = (struct ClassDevPropertySheetsData *)lParam; 1218 1219 PropPageData->NumberOfPages++; 1220 1221 if (PropPageData->PropertySheetHeader->nPages < PropPageData->PropertySheetHeaderPageListSize) 1222 { 1223 PropPageData->PropertySheetHeader->phpage[PropPageData->PropertySheetHeader->nPages] = hPropSheetPage; 1224 PropPageData->PropertySheetHeader->nPages++; 1225 return TRUE; 1226 } 1227 1228 return PropPageData->DontCancel; 1229 } 1230 1231 static DWORD 1232 SETUP_GetValueString( 1233 IN HKEY hKey, 1234 IN LPWSTR lpValueName, 1235 OUT LPWSTR *lpString) 1236 { 1237 LPWSTR lpBuffer; 1238 DWORD dwLength = 0; 1239 DWORD dwRegType; 1240 DWORD rc; 1241 1242 *lpString = NULL; 1243 1244 RegQueryValueExW(hKey, lpValueName, NULL, &dwRegType, NULL, &dwLength); 1245 1246 if (dwLength == 0 || dwRegType != REG_SZ) 1247 return ERROR_FILE_NOT_FOUND; 1248 1249 lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR)); 1250 if (lpBuffer == NULL) 1251 return ERROR_NOT_ENOUGH_MEMORY; 1252 1253 rc = RegQueryValueExW(hKey, lpValueName, NULL, NULL, (LPBYTE)lpBuffer, &dwLength); 1254 if (rc != ERROR_SUCCESS) 1255 { 1256 HeapFree(GetProcessHeap(), 0, lpBuffer); 1257 return rc; 1258 } 1259 1260 lpBuffer[dwLength / sizeof(WCHAR)] = UNICODE_NULL; 1261 1262 *lpString = lpBuffer; 1263 1264 return ERROR_SUCCESS; 1265 } 1266 1267 static 1268 BOOL 1269 SETUP_CallInstaller( 1270 IN DI_FUNCTION InstallFunction, 1271 IN HDEVINFO DeviceInfoSet, 1272 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 1273 IN PSP_ADDPROPERTYPAGE_DATA PageData) 1274 { 1275 PSP_CLASSINSTALL_HEADER pClassInstallParams = NULL; 1276 DWORD dwSize = 0; 1277 DWORD dwError; 1278 BOOL ret = TRUE; 1279 1280 /* Get the size of the old class install parameters */ 1281 if (!SetupDiGetClassInstallParams(DeviceInfoSet, 1282 DeviceInfoData, 1283 NULL, 1284 0, 1285 &dwSize)) 1286 { 1287 dwError = GetLastError(); 1288 if (dwError != ERROR_INSUFFICIENT_BUFFER) 1289 { 1290 ERR("SetupDiGetClassInstallParams failed (Error %lu)\n", dwError); 1291 return FALSE; 1292 } 1293 } 1294 1295 /* Allocate a buffer for the old class install parameters */ 1296 pClassInstallParams = HeapAlloc(GetProcessHeap(), 0, dwSize); 1297 if (pClassInstallParams == NULL) 1298 { 1299 ERR("Failed to allocate the parameters buffer!\n"); 1300 return FALSE; 1301 } 1302 1303 /* Save the old class install parameters */ 1304 if (!SetupDiGetClassInstallParams(DeviceInfoSet, 1305 DeviceInfoData, 1306 pClassInstallParams, 1307 dwSize, 1308 &dwSize)) 1309 { 1310 ERR("SetupDiGetClassInstallParams failed (Error %lu)\n", GetLastError()); 1311 ret = FALSE; 1312 goto done; 1313 } 1314 1315 /* Set the new class install parameters */ 1316 if (!SetupDiSetClassInstallParams(DeviceInfoSet, 1317 DeviceInfoData, 1318 &PageData->ClassInstallHeader, 1319 sizeof(SP_ADDPROPERTYPAGE_DATA))) 1320 { 1321 ERR("SetupDiSetClassInstallParams failed (Error %lu)\n", dwError); 1322 ret = FALSE; 1323 goto done; 1324 } 1325 1326 /* Call the installer */ 1327 ret = SetupDiCallClassInstaller(InstallFunction, 1328 DeviceInfoSet, 1329 DeviceInfoData); 1330 if (ret == FALSE) 1331 { 1332 ERR("SetupDiCallClassInstaller failed\n"); 1333 goto done; 1334 } 1335 1336 /* Read the new class installer parameters */ 1337 if (!SetupDiGetClassInstallParams(DeviceInfoSet, 1338 DeviceInfoData, 1339 &PageData->ClassInstallHeader, 1340 sizeof(SP_ADDPROPERTYPAGE_DATA), 1341 NULL)) 1342 { 1343 ERR("SetupDiGetClassInstallParams failed (Error %lu)\n", GetLastError()); 1344 ret = FALSE; 1345 goto done; 1346 } 1347 1348 done: 1349 /* Restore and free the old class install parameters */ 1350 if (pClassInstallParams != NULL) 1351 { 1352 SetupDiSetClassInstallParams(DeviceInfoSet, 1353 DeviceInfoData, 1354 pClassInstallParams, 1355 dwSize); 1356 1357 HeapFree(GetProcessHeap(), 0, pClassInstallParams); 1358 } 1359 1360 return ret; 1361 } 1362 1363 /*********************************************************************** 1364 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@) 1365 */ 1366 BOOL WINAPI 1367 SetupDiGetClassDevPropertySheetsW( 1368 IN HDEVINFO DeviceInfoSet, 1369 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, 1370 IN OUT LPPROPSHEETHEADERW PropertySheetHeader, 1371 IN DWORD PropertySheetHeaderPageListSize, 1372 OUT PDWORD RequiredSize OPTIONAL, 1373 IN DWORD PropertySheetType) 1374 { 1375 struct DeviceInfoSet *devInfoSet = NULL; 1376 struct DeviceInfo *devInfo = NULL; 1377 BOOL ret = FALSE; 1378 1379 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, 1380 PropertySheetHeader, PropertySheetHeaderPageListSize, 1381 RequiredSize, PropertySheetType); 1382 1383 if (!DeviceInfoSet) 1384 SetLastError(ERROR_INVALID_HANDLE); 1385 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC) 1386 SetLastError(ERROR_INVALID_HANDLE); 1387 else if ((devInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC) 1388 SetLastError(ERROR_INVALID_HANDLE); 1389 else if (!PropertySheetHeader) 1390 SetLastError(ERROR_INVALID_PARAMETER); 1391 else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE) 1392 SetLastError(ERROR_INVALID_FLAGS); 1393 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) 1394 SetLastError(ERROR_INVALID_USER_BUFFER); 1395 else if (!DeviceInfoData && IsEqualIID(&devInfoSet->ClassGuid, &GUID_NULL)) 1396 SetLastError(ERROR_INVALID_PARAMETER); 1397 else if (PropertySheetType != DIGCDP_FLAG_ADVANCED 1398 && PropertySheetType != DIGCDP_FLAG_BASIC 1399 && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED 1400 && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC) 1401 SetLastError(ERROR_INVALID_PARAMETER); 1402 else 1403 { 1404 HKEY hKey = INVALID_HANDLE_VALUE; 1405 SP_PROPSHEETPAGE_REQUEST Request; 1406 LPWSTR PropPageProvider = NULL; 1407 HMODULE hModule = NULL; 1408 PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL; 1409 struct ClassDevPropertySheetsData PropPageData; 1410 SP_ADDPROPERTYPAGE_DATA InstallerPropPageData; 1411 DWORD InitialNumberOfPages, i; 1412 DWORD rc; 1413 1414 if (DeviceInfoData) 1415 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; 1416 1417 /* Get the class property page provider */ 1418 if (devInfoSet->hmodClassPropPageProvider == NULL) 1419 { 1420 hKey = SetupDiOpenClassRegKeyExW(devInfo ? &devInfo->ClassGuid : &devInfoSet->ClassGuid, KEY_QUERY_VALUE, 1421 DIOCR_INSTALLER, NULL/*devInfoSet->MachineName + 2*/, NULL); 1422 if (hKey != INVALID_HANDLE_VALUE) 1423 { 1424 rc = SETUP_GetValueString(hKey, REGSTR_VAL_ENUMPROPPAGES_32, &PropPageProvider); 1425 if (rc == ERROR_SUCCESS) 1426 { 1427 rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider); 1428 if (rc != ERROR_SUCCESS) 1429 { 1430 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER); 1431 goto cleanup; 1432 } 1433 1434 devInfoSet->hmodClassPropPageProvider = hModule; 1435 devInfoSet->pClassPropPageProvider = pPropPageProvider; 1436 1437 HeapFree(GetProcessHeap(), 0, PropPageProvider); 1438 PropPageProvider = NULL; 1439 } 1440 1441 RegCloseKey(hKey); 1442 hKey = INVALID_HANDLE_VALUE; 1443 } 1444 } 1445 1446 /* Get the device property page provider */ 1447 if (devInfo != NULL && devInfo->hmodDevicePropPageProvider == NULL) 1448 { 1449 hKey = SETUPDI_OpenDrvKey(devInfoSet->HKLM, devInfo, KEY_QUERY_VALUE); 1450 if (hKey != INVALID_HANDLE_VALUE) 1451 { 1452 rc = SETUP_GetValueString(hKey, REGSTR_VAL_ENUMPROPPAGES_32, &PropPageProvider); 1453 if (rc == ERROR_SUCCESS) 1454 { 1455 rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider); 1456 if (rc != ERROR_SUCCESS) 1457 { 1458 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER); 1459 goto cleanup; 1460 } 1461 1462 devInfo->hmodDevicePropPageProvider = hModule; 1463 devInfo->pDevicePropPageProvider = pPropPageProvider; 1464 1465 HeapFree(GetProcessHeap(), 0, PropPageProvider); 1466 PropPageProvider = NULL; 1467 } 1468 1469 RegCloseKey(hKey); 1470 hKey = INVALID_HANDLE_VALUE; 1471 } 1472 } 1473 1474 InitialNumberOfPages = PropertySheetHeader->nPages; 1475 1476 Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST); 1477 Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES; 1478 Request.DeviceInfoSet = DeviceInfoSet; 1479 Request.DeviceInfoData = DeviceInfoData; 1480 1481 PropPageData.PropertySheetHeader = PropertySheetHeader; 1482 PropPageData.PropertySheetHeaderPageListSize = PropertySheetHeaderPageListSize; 1483 PropPageData.NumberOfPages = 0; 1484 PropPageData.DontCancel = (RequiredSize != NULL) ? TRUE : FALSE; 1485 1486 /* Call the class property page provider */ 1487 if (devInfoSet->pClassPropPageProvider != NULL) 1488 ((PROPERTY_PAGE_PROVIDER)devInfoSet->pClassPropPageProvider)(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData); 1489 1490 /* Call the device property page provider */ 1491 if (devInfo != NULL && devInfo->pDevicePropPageProvider != NULL) 1492 ((PROPERTY_PAGE_PROVIDER)devInfo->pDevicePropPageProvider)(&Request, SETUP_GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData); 1493 1494 /* Call the class installer and add the returned pages */ 1495 ZeroMemory(&InstallerPropPageData, sizeof(SP_ADDPROPERTYPAGE_DATA)); 1496 InstallerPropPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); 1497 InstallerPropPageData.ClassInstallHeader.InstallFunction = DIF_ADDPROPERTYPAGE_ADVANCED; 1498 InstallerPropPageData.hwndWizardDlg = PropertySheetHeader->hwndParent; 1499 1500 if (SETUP_CallInstaller(DIF_ADDPROPERTYPAGE_ADVANCED, 1501 DeviceInfoSet, 1502 DeviceInfoData, 1503 &InstallerPropPageData)) 1504 { 1505 for (i = 0; i < InstallerPropPageData.NumDynamicPages; i++) 1506 { 1507 if (PropPageData.PropertySheetHeader->nPages < PropertySheetHeaderPageListSize) 1508 { 1509 PropPageData.PropertySheetHeader->phpage[PropPageData.PropertySheetHeader->nPages] = 1510 InstallerPropPageData.DynamicPages[i]; 1511 PropPageData.PropertySheetHeader->nPages++; 1512 } 1513 } 1514 1515 PropPageData.NumberOfPages += InstallerPropPageData.NumDynamicPages; 1516 } 1517 1518 if (RequiredSize) 1519 *RequiredSize = PropPageData.NumberOfPages; 1520 1521 if (InitialNumberOfPages + PropPageData.NumberOfPages <= PropertySheetHeaderPageListSize) 1522 { 1523 ret = TRUE; 1524 } 1525 else 1526 { 1527 SetLastError(ERROR_INSUFFICIENT_BUFFER); 1528 } 1529 1530 cleanup: 1531 if (hKey != INVALID_HANDLE_VALUE) 1532 RegCloseKey(hKey); 1533 1534 if (PropPageProvider != NULL) 1535 HeapFree(GetProcessHeap(), 0, PropPageProvider); 1536 } 1537 1538 TRACE("Returning %d\n", ret); 1539 return ret; 1540 } 1541