1 /* 2 * New device installer (newdev.dll) 3 * 4 * Copyright 2005-2006 Herv� Poussineau (hpoussin@reactos.org) 5 * 2005 Christoph von Wittich (Christoph@ActiveVB.de) 6 * 2009 Colin Finck (colin@reactos.org) 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23 #include "newdev_private.h" 24 25 #include <stdio.h> 26 #include <winnls.h> 27 28 /* Global variables */ 29 HINSTANCE hDllInstance; 30 31 static BOOL 32 SearchDriver( 33 IN PDEVINSTDATA DevInstData, 34 IN LPCWSTR Directory OPTIONAL, 35 IN LPCWSTR InfFile OPTIONAL); 36 37 /* 38 * @implemented 39 */ 40 BOOL WINAPI 41 UpdateDriverForPlugAndPlayDevicesW( 42 IN HWND hwndParent, 43 IN LPCWSTR HardwareId, 44 IN LPCWSTR FullInfPath, 45 IN DWORD InstallFlags, 46 OUT PBOOL bRebootRequired OPTIONAL) 47 { 48 DEVINSTDATA DevInstData; 49 DWORD i; 50 LPWSTR Buffer = NULL; 51 DWORD BufferSize; 52 LPCWSTR CurrentHardwareId; /* Pointer into Buffer */ 53 BOOL FoundHardwareId, FoundAtLeastOneDevice = FALSE; 54 BOOL ret = FALSE; 55 56 DevInstData.hDevInfo = INVALID_HANDLE_VALUE; 57 58 TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %s %s 0x%x %p)\n", 59 hwndParent, debugstr_w(HardwareId), debugstr_w(FullInfPath), InstallFlags, bRebootRequired); 60 61 /* FIXME: InstallFlags bRebootRequired ignored! */ 62 63 /* Check flags */ 64 if (InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE)) 65 { 66 TRACE("Unknown flags: 0x%08lx\n", InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE)); 67 SetLastError(ERROR_INVALID_FLAGS); 68 goto cleanup; 69 } 70 71 /* Enumerate all devices of the system */ 72 DevInstData.hDevInfo = SetupDiGetClassDevsW(NULL, NULL, hwndParent, DIGCF_ALLCLASSES | DIGCF_PRESENT); 73 if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE) 74 goto cleanup; 75 DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 76 for (i = 0; ; i++) 77 { 78 if (!SetupDiEnumDeviceInfo(DevInstData.hDevInfo, i, &DevInstData.devInfoData)) 79 { 80 if (GetLastError() != ERROR_NO_MORE_ITEMS) 81 { 82 TRACE("SetupDiEnumDeviceInfo() failed with error 0x%x\n", GetLastError()); 83 goto cleanup; 84 } 85 /* This error was expected */ 86 break; 87 } 88 89 /* Get Hardware ID */ 90 HeapFree(GetProcessHeap(), 0, Buffer); 91 Buffer = NULL; 92 BufferSize = 0; 93 while (!SetupDiGetDeviceRegistryPropertyW( 94 DevInstData.hDevInfo, 95 &DevInstData.devInfoData, 96 SPDRP_HARDWAREID, 97 NULL, 98 (PBYTE)Buffer, 99 BufferSize, 100 &BufferSize)) 101 { 102 if (GetLastError() == ERROR_FILE_NOT_FOUND) 103 { 104 Buffer = NULL; 105 break; 106 } 107 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 108 { 109 TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%x\n", GetLastError()); 110 goto cleanup; 111 } 112 /* This error was expected */ 113 HeapFree(GetProcessHeap(), 0, Buffer); 114 Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize); 115 if (!Buffer) 116 { 117 TRACE("HeapAlloc() failed\n", GetLastError()); 118 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 119 goto cleanup; 120 } 121 } 122 if (Buffer == NULL) 123 continue; 124 125 /* Check if we match the given hardware ID */ 126 FoundHardwareId = FALSE; 127 for (CurrentHardwareId = Buffer; *CurrentHardwareId != UNICODE_NULL; CurrentHardwareId += wcslen(CurrentHardwareId) + 1) 128 { 129 if (wcscmp(CurrentHardwareId, HardwareId) == 0) 130 { 131 FoundHardwareId = TRUE; 132 break; 133 } 134 } 135 if (!FoundHardwareId) 136 continue; 137 138 /* We need to try to update the driver of this device */ 139 140 /* Get Instance ID */ 141 HeapFree(GetProcessHeap(), 0, Buffer); 142 Buffer = NULL; 143 if (SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, NULL, 0, &BufferSize)) 144 { 145 /* Error, as the output buffer should be too small */ 146 SetLastError(ERROR_GEN_FAILURE); 147 goto cleanup; 148 } 149 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 150 { 151 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError()); 152 goto cleanup; 153 } 154 else if ((Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize * sizeof(WCHAR))) == NULL) 155 { 156 TRACE("HeapAlloc() failed\n", GetLastError()); 157 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 158 goto cleanup; 159 } 160 else if (!SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, Buffer, BufferSize, NULL)) 161 { 162 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError()); 163 goto cleanup; 164 } 165 TRACE("Trying to update the driver of %s\n", debugstr_w(Buffer)); 166 167 /* Search driver in the specified .inf file */ 168 if (!SearchDriver(&DevInstData, NULL, FullInfPath)) 169 { 170 TRACE("SearchDriver() failed with error 0x%x\n", GetLastError()); 171 continue; 172 } 173 174 /* FIXME: HACK! We shouldn't check of ERROR_PRIVILEGE_NOT_HELD */ 175 //if (!InstallCurrentDriver(&DevInstData)) 176 if (!InstallCurrentDriver(&DevInstData) && GetLastError() != ERROR_PRIVILEGE_NOT_HELD) 177 { 178 TRACE("InstallCurrentDriver() failed with error 0x%x\n", GetLastError()); 179 continue; 180 } 181 182 FoundAtLeastOneDevice = TRUE; 183 } 184 185 if (FoundAtLeastOneDevice) 186 { 187 SetLastError(NO_ERROR); 188 ret = TRUE; 189 } 190 else 191 { 192 TRACE("No device found with HardwareID %s\n", debugstr_w(HardwareId)); 193 SetLastError(ERROR_NO_SUCH_DEVINST); 194 } 195 196 cleanup: 197 if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE) 198 SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo); 199 HeapFree(GetProcessHeap(), 0, Buffer); 200 return ret; 201 } 202 203 /* 204 * @implemented 205 */ 206 BOOL WINAPI 207 UpdateDriverForPlugAndPlayDevicesA( 208 IN HWND hwndParent, 209 IN LPCSTR HardwareId, 210 IN LPCSTR FullInfPath, 211 IN DWORD InstallFlags, 212 OUT PBOOL bRebootRequired OPTIONAL) 213 { 214 BOOL Result; 215 LPWSTR HardwareIdW = NULL; 216 LPWSTR FullInfPathW = NULL; 217 218 int len = MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, NULL, 0); 219 HardwareIdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 220 if (!HardwareIdW) 221 { 222 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 223 return FALSE; 224 } 225 MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, HardwareIdW, len); 226 227 len = MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, NULL, 0); 228 FullInfPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 229 if (!FullInfPathW) 230 { 231 HeapFree(GetProcessHeap(), 0, HardwareIdW); 232 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 233 return FALSE; 234 } 235 MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, FullInfPathW, len); 236 237 Result = UpdateDriverForPlugAndPlayDevicesW( 238 hwndParent, 239 HardwareIdW, 240 FullInfPathW, 241 InstallFlags, 242 bRebootRequired); 243 244 HeapFree(GetProcessHeap(), 0, HardwareIdW); 245 HeapFree(GetProcessHeap(), 0, FullInfPathW); 246 247 return Result; 248 } 249 250 /* Directory and InfFile MUST NOT be specified simultaneously */ 251 static BOOL 252 SearchDriver( 253 IN PDEVINSTDATA DevInstData, 254 IN LPCWSTR Directory OPTIONAL, 255 IN LPCWSTR InfFile OPTIONAL) 256 { 257 SP_DEVINSTALL_PARAMS_W DevInstallParams = {0,}; 258 BOOL ret; 259 260 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); 261 if (!SetupDiGetDeviceInstallParamsW(DevInstData->hDevInfo, &DevInstData->devInfoData, &DevInstallParams)) 262 { 263 TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%x\n", GetLastError()); 264 return FALSE; 265 } 266 DevInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS; 267 268 if (InfFile) 269 { 270 DevInstallParams.Flags |= DI_ENUMSINGLEINF; 271 wcsncpy(DevInstallParams.DriverPath, InfFile, MAX_PATH); 272 } 273 else if (Directory) 274 { 275 DevInstallParams.Flags &= ~DI_ENUMSINGLEINF; 276 wcsncpy(DevInstallParams.DriverPath, Directory, MAX_PATH); 277 } 278 else 279 { 280 DevInstallParams.Flags &= ~DI_ENUMSINGLEINF; 281 *DevInstallParams.DriverPath = '\0'; 282 } 283 284 ret = SetupDiSetDeviceInstallParamsW( 285 DevInstData->hDevInfo, 286 &DevInstData->devInfoData, 287 &DevInstallParams); 288 if (!ret) 289 { 290 TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%x\n", GetLastError()); 291 return FALSE; 292 } 293 294 ret = SetupDiBuildDriverInfoList( 295 DevInstData->hDevInfo, 296 &DevInstData->devInfoData, 297 SPDIT_COMPATDRIVER); 298 if (!ret) 299 { 300 TRACE("SetupDiBuildDriverInfoList() failed with error 0x%x\n", GetLastError()); 301 return FALSE; 302 } 303 304 DevInstData->drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA); 305 ret = SetupDiEnumDriverInfoW( 306 DevInstData->hDevInfo, 307 &DevInstData->devInfoData, 308 SPDIT_COMPATDRIVER, 309 0, 310 &DevInstData->drvInfoData); 311 if (!ret) 312 { 313 if (GetLastError() == ERROR_NO_MORE_ITEMS) 314 return FALSE; 315 TRACE("SetupDiEnumDriverInfo() failed with error 0x%x\n", GetLastError()); 316 return FALSE; 317 } 318 319 return TRUE; 320 } 321 322 static BOOL 323 IsDots(IN LPCWSTR str) 324 { 325 if(wcscmp(str, L".") && wcscmp(str, L"..")) return FALSE; 326 return TRUE; 327 } 328 329 static LPCWSTR 330 GetFileExt(IN LPWSTR FileName) 331 { 332 LPCWSTR Dot; 333 334 Dot = wcsrchr(FileName, '.'); 335 if (!Dot) 336 return L""; 337 338 return Dot; 339 } 340 341 static BOOL 342 SearchDriverRecursive( 343 IN PDEVINSTDATA DevInstData, 344 IN LPCWSTR Path) 345 { 346 WIN32_FIND_DATAW wfd; 347 WCHAR DirPath[MAX_PATH]; 348 WCHAR FileName[MAX_PATH]; 349 WCHAR FullPath[MAX_PATH]; 350 WCHAR LastDirPath[MAX_PATH] = L""; 351 WCHAR PathWithPattern[MAX_PATH]; 352 BOOL ok = TRUE; 353 BOOL retval = FALSE; 354 HANDLE hFindFile = INVALID_HANDLE_VALUE; 355 356 wcscpy(DirPath, Path); 357 358 if (DirPath[wcslen(DirPath) - 1] != '\\') 359 wcscat(DirPath, L"\\"); 360 361 wcscpy(PathWithPattern, DirPath); 362 wcscat(PathWithPattern, L"*"); 363 364 for (hFindFile = FindFirstFileW(PathWithPattern, &wfd); 365 ok && hFindFile != INVALID_HANDLE_VALUE; 366 ok = FindNextFileW(hFindFile, &wfd)) 367 { 368 369 wcscpy(FileName, wfd.cFileName); 370 if (IsDots(FileName)) 371 continue; 372 373 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 374 { 375 /* Recursive search */ 376 wcscpy(FullPath, DirPath); 377 wcscat(FullPath, FileName); 378 if (SearchDriverRecursive(DevInstData, FullPath)) 379 { 380 retval = TRUE; 381 /* We continue the search for a better driver */ 382 } 383 } 384 else 385 { 386 LPCWSTR pszExtension = GetFileExt(FileName); 387 388 if ((_wcsicmp(pszExtension, L".inf") == 0) && (wcscmp(LastDirPath, DirPath) != 0)) 389 { 390 wcscpy(LastDirPath, DirPath); 391 392 if (wcslen(DirPath) > MAX_PATH) 393 /* Path is too long to be searched */ 394 continue; 395 396 if (SearchDriver(DevInstData, DirPath, NULL)) 397 { 398 retval = TRUE; 399 /* We continue the search for a better driver */ 400 } 401 402 } 403 } 404 } 405 406 if (hFindFile != INVALID_HANDLE_VALUE) 407 FindClose(hFindFile); 408 return retval; 409 } 410 411 BOOL 412 CheckBestDriver( 413 _In_ PDEVINSTDATA DevInstData, 414 _In_ PCWSTR pszDir) 415 { 416 return SearchDriverRecursive(DevInstData, pszDir); 417 } 418 419 BOOL 420 ScanFoldersForDriver( 421 IN PDEVINSTDATA DevInstData) 422 { 423 BOOL result; 424 425 /* Search in default location */ 426 result = SearchDriver(DevInstData, NULL, NULL); 427 428 if (DevInstData->CustomSearchPath) 429 { 430 /* Search only in specified paths */ 431 /* We need to check all specified directories to be 432 * sure to find the best driver for the device. 433 */ 434 LPCWSTR Path; 435 for (Path = DevInstData->CustomSearchPath; *Path != '\0'; Path += wcslen(Path) + 1) 436 { 437 TRACE("Search driver in %s\n", debugstr_w(Path)); 438 if (wcslen(Path) == 2 && Path[1] == ':') 439 { 440 if (SearchDriverRecursive(DevInstData, Path)) 441 result = TRUE; 442 } 443 else 444 { 445 if (SearchDriver(DevInstData, Path, NULL)) 446 result = TRUE; 447 } 448 } 449 } 450 451 return result; 452 } 453 454 BOOL 455 PrepareFoldersToScan( 456 IN PDEVINSTDATA DevInstData, 457 IN BOOL IncludeRemovableDevices, 458 IN BOOL IncludeCustomPath, 459 IN HWND hwndCombo OPTIONAL) 460 { 461 WCHAR drive[] = {'?',':',0}; 462 DWORD dwDrives = 0; 463 DWORD i; 464 UINT nType; 465 DWORD CustomTextLength = 0; 466 DWORD LengthNeeded = 0; 467 LPWSTR Buffer; 468 469 /* Calculate length needed to store the search paths */ 470 if (IncludeRemovableDevices) 471 { 472 dwDrives = GetLogicalDrives(); 473 for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1) 474 { 475 if (dwDrives & i) 476 { 477 nType = GetDriveTypeW(drive); 478 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM) 479 { 480 LengthNeeded += 3; 481 } 482 } 483 } 484 } 485 if (IncludeCustomPath) 486 { 487 CustomTextLength = 1 + ComboBox_GetTextLength(hwndCombo); 488 LengthNeeded += CustomTextLength; 489 } 490 491 /* Allocate space for search paths */ 492 HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath); 493 DevInstData->CustomSearchPath = Buffer = HeapAlloc( 494 GetProcessHeap(), 495 0, 496 (LengthNeeded + 1) * sizeof(WCHAR)); 497 if (!Buffer) 498 { 499 TRACE("HeapAlloc() failed\n"); 500 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 501 return FALSE; 502 } 503 504 /* Fill search paths */ 505 if (IncludeRemovableDevices) 506 { 507 for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1) 508 { 509 if (dwDrives & i) 510 { 511 nType = GetDriveTypeW(drive); 512 if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM) 513 { 514 Buffer += 1 + swprintf(Buffer, drive); 515 } 516 } 517 } 518 } 519 if (IncludeCustomPath) 520 { 521 Buffer += 1 + GetWindowTextW(hwndCombo, Buffer, CustomTextLength); 522 } 523 *Buffer = '\0'; 524 525 return TRUE; 526 } 527 528 BOOL 529 InstallCurrentDriver( 530 IN PDEVINSTDATA DevInstData) 531 { 532 BOOL ret; 533 534 TRACE("Installing driver %s: %s\n", 535 debugstr_w(DevInstData->drvInfoData.MfgName), 536 debugstr_w(DevInstData->drvInfoData.Description)); 537 538 ret = SetupDiCallClassInstaller( 539 DIF_SELECTBESTCOMPATDRV, 540 DevInstData->hDevInfo, 541 &DevInstData->devInfoData); 542 if (!ret) 543 { 544 TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%x\n", GetLastError()); 545 return FALSE; 546 } 547 548 ret = SetupDiCallClassInstaller( 549 DIF_ALLOW_INSTALL, 550 DevInstData->hDevInfo, 551 &DevInstData->devInfoData); 552 if (!ret) 553 { 554 TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%x\n", GetLastError()); 555 return FALSE; 556 } 557 558 ret = SetupDiCallClassInstaller( 559 DIF_NEWDEVICEWIZARD_PREANALYZE, 560 DevInstData->hDevInfo, 561 &DevInstData->devInfoData); 562 if (!ret) 563 { 564 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%x\n", GetLastError()); 565 return FALSE; 566 } 567 568 ret = SetupDiCallClassInstaller( 569 DIF_NEWDEVICEWIZARD_POSTANALYZE, 570 DevInstData->hDevInfo, 571 &DevInstData->devInfoData); 572 if (!ret) 573 { 574 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%x\n", GetLastError()); 575 return FALSE; 576 } 577 578 ret = SetupDiCallClassInstaller( 579 DIF_INSTALLDEVICEFILES, 580 DevInstData->hDevInfo, 581 &DevInstData->devInfoData); 582 if (!ret) 583 { 584 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%x\n", GetLastError()); 585 return FALSE; 586 } 587 588 ret = SetupDiCallClassInstaller( 589 DIF_REGISTER_COINSTALLERS, 590 DevInstData->hDevInfo, 591 &DevInstData->devInfoData); 592 if (!ret) 593 { 594 TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%x\n", GetLastError()); 595 return FALSE; 596 } 597 598 ret = SetupDiCallClassInstaller( 599 DIF_INSTALLINTERFACES, 600 DevInstData->hDevInfo, 601 &DevInstData->devInfoData); 602 if (!ret) 603 { 604 TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%x\n", GetLastError()); 605 return FALSE; 606 } 607 608 ret = SetupDiCallClassInstaller( 609 DIF_INSTALLDEVICE, 610 DevInstData->hDevInfo, 611 &DevInstData->devInfoData); 612 if (!ret) 613 { 614 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%x\n", GetLastError()); 615 return FALSE; 616 } 617 618 ret = SetupDiCallClassInstaller( 619 DIF_NEWDEVICEWIZARD_FINISHINSTALL, 620 DevInstData->hDevInfo, 621 &DevInstData->devInfoData); 622 if (!ret) 623 { 624 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%x\n", GetLastError()); 625 return FALSE; 626 } 627 628 ret = SetupDiCallClassInstaller( 629 DIF_DESTROYPRIVATEDATA, 630 DevInstData->hDevInfo, 631 &DevInstData->devInfoData); 632 if (!ret) 633 { 634 TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%x\n", GetLastError()); 635 return FALSE; 636 } 637 638 return TRUE; 639 } 640 641 /* 642 * @implemented 643 */ 644 BOOL WINAPI 645 DevInstallW( 646 IN HWND hWndParent, 647 IN HINSTANCE hInstance, 648 IN LPCWSTR InstanceId, 649 IN INT Show) 650 { 651 PDEVINSTDATA DevInstData = NULL; 652 BOOL ret; 653 DWORD config_flags; 654 BOOL retval = FALSE; 655 656 TRACE("(%p, %p, %s, %d)\n", hWndParent, hInstance, debugstr_w(InstanceId), Show); 657 658 if (!IsUserAdmin()) 659 { 660 /* XP kills the process... */ 661 ExitProcess(ERROR_ACCESS_DENIED); 662 } 663 664 DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA)); 665 if (!DevInstData) 666 { 667 TRACE("HeapAlloc() failed\n"); 668 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 669 goto cleanup; 670 } 671 672 /* Clear devinst data */ 673 ZeroMemory(DevInstData, sizeof(DEVINSTDATA)); 674 DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */ 675 676 /* Fill devinst data */ 677 DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); 678 if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE) 679 { 680 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError()); 681 goto cleanup; 682 } 683 684 DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 685 ret = SetupDiOpenDeviceInfoW( 686 DevInstData->hDevInfo, 687 InstanceId, 688 NULL, 689 0, /* Open flags */ 690 &DevInstData->devInfoData); 691 if (!ret) 692 { 693 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n", 694 GetLastError(), debugstr_w(InstanceId)); 695 DevInstData->devInfoData.cbSize = 0; 696 goto cleanup; 697 } 698 699 SetLastError(ERROR_GEN_FAILURE); 700 ret = SetupDiGetDeviceRegistryProperty( 701 DevInstData->hDevInfo, 702 &DevInstData->devInfoData, 703 SPDRP_DEVICEDESC, 704 &DevInstData->regDataType, 705 NULL, 0, 706 &DevInstData->requiredSize); 707 708 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ) 709 { 710 DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize); 711 if (!DevInstData->buffer) 712 { 713 TRACE("HeapAlloc() failed\n"); 714 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 715 } 716 else 717 { 718 ret = SetupDiGetDeviceRegistryPropertyW( 719 DevInstData->hDevInfo, 720 &DevInstData->devInfoData, 721 SPDRP_DEVICEDESC, 722 &DevInstData->regDataType, 723 DevInstData->buffer, DevInstData->requiredSize, 724 &DevInstData->requiredSize); 725 } 726 } 727 if (!ret) 728 { 729 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n", 730 GetLastError(), debugstr_w(InstanceId)); 731 goto cleanup; 732 } 733 734 if (SetupDiGetDeviceRegistryPropertyW( 735 DevInstData->hDevInfo, 736 &DevInstData->devInfoData, 737 SPDRP_CONFIGFLAGS, 738 NULL, 739 (BYTE *)&config_flags, 740 sizeof(config_flags), 741 NULL)) 742 { 743 if (config_flags & CONFIGFLAG_FAILEDINSTALL) 744 { 745 /* The device is disabled */ 746 TRACE("Device is disabled\n"); 747 retval = TRUE; 748 goto cleanup; 749 } 750 } 751 752 TRACE("Installing %s (%s)\n", debugstr_w((PCWSTR)DevInstData->buffer), debugstr_w(InstanceId)); 753 754 /* Search driver in default location and removable devices */ 755 if (!PrepareFoldersToScan(DevInstData, FALSE, FALSE, NULL)) 756 { 757 TRACE("PrepareFoldersToScan() failed with error 0x%lx\n", GetLastError()); 758 goto cleanup; 759 } 760 if (ScanFoldersForDriver(DevInstData)) 761 { 762 /* Driver found ; install it */ 763 retval = InstallCurrentDriver(DevInstData); 764 TRACE("InstallCurrentDriver() returned %d\n", retval); 765 if (retval && Show != SW_HIDE) 766 { 767 /* Should we display the 'Need to reboot' page? */ 768 SP_DEVINSTALL_PARAMS installParams; 769 installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); 770 if (SetupDiGetDeviceInstallParams( 771 DevInstData->hDevInfo, 772 &DevInstData->devInfoData, 773 &installParams)) 774 { 775 if (installParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) 776 { 777 TRACE("Displaying 'Reboot' wizard page\n"); 778 retval = DisplayWizard(DevInstData, hWndParent, IDD_NEEDREBOOT); 779 } 780 } 781 } 782 goto cleanup; 783 } 784 else if (Show == SW_HIDE) 785 { 786 /* We can't show the wizard. Fail the install */ 787 TRACE("No wizard\n"); 788 goto cleanup; 789 } 790 791 /* Prepare the wizard, and display it */ 792 TRACE("Need to show install wizard\n"); 793 retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE); 794 795 cleanup: 796 if (DevInstData) 797 { 798 if (DevInstData->devInfoData.cbSize != 0) 799 { 800 if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER)) 801 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError()); 802 } 803 if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE) 804 { 805 if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo)) 806 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError()); 807 } 808 HeapFree(GetProcessHeap(), 0, DevInstData->buffer); 809 HeapFree(GetProcessHeap(), 0, DevInstData); 810 } 811 812 return retval; 813 } 814 815 816 BOOL 817 WINAPI 818 InstallDevInstEx( 819 IN HWND hWndParent, 820 IN LPCWSTR InstanceId, 821 IN BOOL bUpdate, 822 OUT LPDWORD lpReboot, 823 IN DWORD Unknown) 824 { 825 PDEVINSTDATA DevInstData = NULL; 826 BOOL ret; 827 BOOL retval = FALSE; 828 829 TRACE("InstllDevInstEx(%p, %s, %d, %p, %lx)\n", 830 hWndParent, debugstr_w(InstanceId), bUpdate, lpReboot, Unknown); 831 832 DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA)); 833 if (!DevInstData) 834 { 835 TRACE("HeapAlloc() failed\n"); 836 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 837 goto cleanup; 838 } 839 840 /* Clear devinst data */ 841 ZeroMemory(DevInstData, sizeof(DEVINSTDATA)); 842 DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */ 843 DevInstData->bUpdate = bUpdate; 844 845 /* Fill devinst data */ 846 DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); 847 if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE) 848 { 849 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError()); 850 goto cleanup; 851 } 852 853 DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 854 ret = SetupDiOpenDeviceInfoW( 855 DevInstData->hDevInfo, 856 InstanceId, 857 NULL, 858 0, /* Open flags */ 859 &DevInstData->devInfoData); 860 if (!ret) 861 { 862 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n", 863 GetLastError(), debugstr_w(InstanceId)); 864 DevInstData->devInfoData.cbSize = 0; 865 goto cleanup; 866 } 867 868 SetLastError(ERROR_GEN_FAILURE); 869 ret = SetupDiGetDeviceRegistryProperty( 870 DevInstData->hDevInfo, 871 &DevInstData->devInfoData, 872 SPDRP_DEVICEDESC, 873 &DevInstData->regDataType, 874 NULL, 0, 875 &DevInstData->requiredSize); 876 877 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ) 878 { 879 DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize); 880 if (!DevInstData->buffer) 881 { 882 TRACE("HeapAlloc() failed\n"); 883 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 884 } 885 else 886 { 887 ret = SetupDiGetDeviceRegistryPropertyW( 888 DevInstData->hDevInfo, 889 &DevInstData->devInfoData, 890 SPDRP_DEVICEDESC, 891 &DevInstData->regDataType, 892 DevInstData->buffer, DevInstData->requiredSize, 893 &DevInstData->requiredSize); 894 } 895 } 896 897 if (!ret) 898 { 899 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n", 900 GetLastError(), debugstr_w(InstanceId)); 901 goto cleanup; 902 } 903 904 /* Prepare the wizard, and display it */ 905 TRACE("Need to show install wizard\n"); 906 retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE); 907 908 cleanup: 909 if (DevInstData) 910 { 911 if (DevInstData->devInfoData.cbSize != 0) 912 { 913 if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER)) 914 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError()); 915 } 916 if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE) 917 { 918 if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo)) 919 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError()); 920 } 921 HeapFree(GetProcessHeap(), 0, DevInstData->buffer); 922 HeapFree(GetProcessHeap(), 0, DevInstData); 923 } 924 925 return retval; 926 } 927 928 929 /* 930 * @implemented 931 */ 932 BOOL 933 WINAPI 934 InstallDevInst( 935 IN HWND hWndParent, 936 IN LPCWSTR InstanceId, 937 IN BOOL bUpdate, 938 OUT LPDWORD lpReboot) 939 { 940 return InstallDevInstEx(hWndParent, InstanceId, bUpdate, lpReboot, 0); 941 } 942 943 944 /* 945 * @implemented 946 */ 947 BOOL WINAPI 948 ClientSideInstallW( 949 IN HWND hWndOwner, 950 IN HINSTANCE hInstance, 951 IN LPWSTR lpNamedPipeName, 952 IN INT Show) 953 { 954 BOOL ReturnValue = FALSE; 955 BOOL ShowWizard; 956 DWORD BytesRead; 957 DWORD Value; 958 HANDLE hPipe = INVALID_HANDLE_VALUE; 959 PWSTR DeviceInstance = NULL; 960 PWSTR InstallEventName = NULL; 961 HANDLE hInstallEvent; 962 963 /* Open the pipe */ 964 hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 965 966 if(hPipe == INVALID_HANDLE_VALUE) 967 { 968 ERR("CreateFileW failed with error %u\n", GetLastError()); 969 goto cleanup; 970 } 971 972 /* Read the data. Some is just included for compatibility with Windows right now and not yet used by ReactOS. 973 See umpnpmgr for more details. */ 974 if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL)) 975 { 976 ERR("ReadFile failed with error %u\n", GetLastError()); 977 goto cleanup; 978 } 979 980 InstallEventName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value); 981 982 if(!ReadFile(hPipe, InstallEventName, Value, &BytesRead, NULL)) 983 { 984 ERR("ReadFile failed with error %u\n", GetLastError()); 985 goto cleanup; 986 } 987 988 /* I couldn't figure out what the following value means under Windows XP. 989 Therefore I used it in umpnpmgr to pass the ShowWizard variable. */ 990 if(!ReadFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesRead, NULL)) 991 { 992 ERR("ReadFile failed with error %u\n", GetLastError()); 993 goto cleanup; 994 } 995 996 /* Next one is again size in bytes of the following string */ 997 if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL)) 998 { 999 ERR("ReadFile failed with error %u\n", GetLastError()); 1000 goto cleanup; 1001 } 1002 1003 DeviceInstance = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value); 1004 1005 if(!ReadFile(hPipe, DeviceInstance, Value, &BytesRead, NULL)) 1006 { 1007 ERR("ReadFile failed with error %u\n", GetLastError()); 1008 goto cleanup; 1009 } 1010 1011 ReturnValue = DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE); 1012 if(!ReturnValue) 1013 { 1014 ERR("DevInstallW failed with error %lu\n", GetLastError()); 1015 goto cleanup; 1016 } 1017 1018 hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName); 1019 if(!hInstallEvent) 1020 { 1021 TRACE("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError()); 1022 goto cleanup; 1023 } 1024 1025 SetEvent(hInstallEvent); 1026 CloseHandle(hInstallEvent); 1027 1028 cleanup: 1029 if(hPipe != INVALID_HANDLE_VALUE) 1030 CloseHandle(hPipe); 1031 1032 if(InstallEventName) 1033 HeapFree(GetProcessHeap(), 0, InstallEventName); 1034 1035 if(DeviceInstance) 1036 HeapFree(GetProcessHeap(), 0, DeviceInstance); 1037 1038 return ReturnValue; 1039 } 1040 1041 BOOL WINAPI 1042 DllMain( 1043 IN HINSTANCE hInstance, 1044 IN DWORD dwReason, 1045 IN LPVOID lpReserved) 1046 { 1047 if (dwReason == DLL_PROCESS_ATTACH) 1048 { 1049 INITCOMMONCONTROLSEX InitControls; 1050 1051 DisableThreadLibraryCalls(hInstance); 1052 1053 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX); 1054 InitControls.dwICC = ICC_PROGRESS_CLASS; 1055 InitCommonControlsEx(&InitControls); 1056 hDllInstance = hInstance; 1057 } 1058 1059 return TRUE; 1060 } 1061