1 /* 2 * New device installer (newdev.dll) 3 * 4 * Copyright 2006 Herv� Poussineau (hpoussin@reactos.org) 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 #include "newdev_private.h" 22 23 #include <wincon.h> 24 #include <cfgmgr32.h> 25 #include <shlobj.h> 26 27 HANDLE hThread; 28 29 static VOID 30 CenterWindow( 31 IN HWND hWnd) 32 { 33 HWND hWndParent; 34 RECT rcParent; 35 RECT rcWindow; 36 37 hWndParent = GetParent(hWnd); 38 if (hWndParent == NULL) 39 hWndParent = GetDesktopWindow(); 40 41 GetWindowRect(hWndParent, &rcParent); 42 GetWindowRect(hWnd, &rcWindow); 43 44 SetWindowPos( 45 hWnd, 46 HWND_TOP, 47 ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2, 48 ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2, 49 0, 50 0, 51 SWP_NOSIZE); 52 } 53 54 static BOOL 55 SetFailedInstall( 56 IN HDEVINFO DeviceInfoSet, 57 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL, 58 IN BOOLEAN Set) 59 { 60 DWORD dwType, dwSize, dwFlags = 0; 61 62 dwSize = sizeof(dwFlags); 63 if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet, 64 DevInfoData, 65 SPDRP_CONFIGFLAGS, 66 &dwType, 67 (PBYTE)&dwFlags, 68 dwSize, 69 &dwSize)) 70 { 71 return FALSE; 72 } 73 74 if (Set) 75 dwFlags |= CONFIGFLAG_FAILEDINSTALL; 76 else 77 dwFlags &= ~CONFIGFLAG_FAILEDINSTALL; 78 79 if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet, 80 DevInfoData, 81 SPDRP_CONFIGFLAGS, 82 (PBYTE)&dwFlags, 83 dwSize)) 84 { 85 86 return FALSE; 87 } 88 89 return TRUE; 90 } 91 92 static BOOL 93 CanDisableDevice( 94 IN DEVINST DevInst, 95 IN HMACHINE hMachine, 96 OUT BOOL *CanDisable) 97 { 98 CONFIGRET cr; 99 ULONG Status, ProblemNumber; 100 BOOL Ret = FALSE; 101 102 cr = CM_Get_DevNode_Status_Ex(&Status, 103 &ProblemNumber, 104 DevInst, 105 0, 106 hMachine); 107 if (cr == CR_SUCCESS) 108 { 109 *CanDisable = ((Status & DN_DISABLEABLE) != 0); 110 Ret = TRUE; 111 } 112 113 return Ret; 114 } 115 116 static BOOL 117 IsDeviceStarted( 118 IN DEVINST DevInst, 119 IN HMACHINE hMachine, 120 OUT BOOL *IsEnabled) 121 { 122 CONFIGRET cr; 123 ULONG Status, ProblemNumber; 124 BOOL Ret = FALSE; 125 126 cr = CM_Get_DevNode_Status_Ex( 127 &Status, 128 &ProblemNumber, 129 DevInst, 130 0, 131 hMachine); 132 if (cr == CR_SUCCESS) 133 { 134 *IsEnabled = ((Status & DN_STARTED) != 0); 135 Ret = TRUE; 136 } 137 138 return Ret; 139 } 140 141 static BOOL 142 StartDevice( 143 IN HDEVINFO DeviceInfoSet, 144 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL, 145 IN BOOL bEnable, 146 IN DWORD HardwareProfile OPTIONAL, 147 OUT BOOL *bNeedReboot OPTIONAL) 148 { 149 SP_PROPCHANGE_PARAMS pcp; 150 SP_DEVINSTALL_PARAMS dp; 151 DWORD LastErr; 152 BOOL Ret = FALSE; 153 154 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); 155 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; 156 pcp.HwProfile = HardwareProfile; 157 158 if (bEnable) 159 { 160 /* try to enable the device on the global profile */ 161 pcp.StateChange = DICS_ENABLE; 162 pcp.Scope = DICS_FLAG_GLOBAL; 163 164 /* ignore errors */ 165 LastErr = GetLastError(); 166 if (SetupDiSetClassInstallParams( 167 DeviceInfoSet, 168 DevInfoData, 169 &pcp.ClassInstallHeader, 170 sizeof(SP_PROPCHANGE_PARAMS))) 171 { 172 SetupDiCallClassInstaller( 173 DIF_PROPERTYCHANGE, 174 DeviceInfoSet, 175 DevInfoData); 176 } 177 SetLastError(LastErr); 178 } 179 180 /* try config-specific */ 181 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE); 182 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; 183 184 if (SetupDiSetClassInstallParams( 185 DeviceInfoSet, 186 DevInfoData, 187 &pcp.ClassInstallHeader, 188 sizeof(SP_PROPCHANGE_PARAMS)) && 189 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, 190 DeviceInfoSet, 191 DevInfoData)) 192 { 193 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS); 194 if (SetupDiGetDeviceInstallParams( 195 DeviceInfoSet, 196 DevInfoData, 197 &dp)) 198 { 199 if (bNeedReboot != NULL) 200 { 201 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0); 202 } 203 204 Ret = TRUE; 205 } 206 } 207 return Ret; 208 } 209 210 static DWORD WINAPI 211 FindDriverProc( 212 IN LPVOID lpParam) 213 { 214 PDEVINSTDATA DevInstData; 215 DWORD config_flags; 216 BOOL result = FALSE; 217 218 DevInstData = (PDEVINSTDATA)lpParam; 219 220 result = ScanFoldersForDriver(DevInstData); 221 222 if (result) 223 { 224 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 1, 0); 225 } 226 else 227 { 228 /* Update device configuration */ 229 if (SetupDiGetDeviceRegistryProperty( 230 DevInstData->hDevInfo, 231 &DevInstData->devInfoData, 232 SPDRP_CONFIGFLAGS, 233 NULL, 234 (BYTE *)&config_flags, 235 sizeof(config_flags), 236 NULL)) 237 { 238 config_flags |= CONFIGFLAG_FAILEDINSTALL; 239 SetupDiSetDeviceRegistryPropertyW( 240 DevInstData->hDevInfo, 241 &DevInstData->devInfoData, 242 SPDRP_CONFIGFLAGS, 243 (BYTE *)&config_flags, sizeof(config_flags)); 244 } 245 246 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 0, 0); 247 } 248 return 0; 249 } 250 251 static DWORD WINAPI 252 InstallDriverProc( 253 IN LPVOID lpParam) 254 { 255 PDEVINSTDATA DevInstData; 256 BOOL res; 257 258 DevInstData = (PDEVINSTDATA)lpParam; 259 res = InstallCurrentDriver(DevInstData); 260 PostMessage(DevInstData->hDialog, WM_INSTALL_FINISHED, res ? 0 : 1, 0); 261 return 0; 262 } 263 264 static VOID 265 PopulateCustomPathCombo( 266 IN HWND hwndCombo) 267 { 268 HKEY hKey = NULL; 269 DWORD dwRegType; 270 DWORD dwPathLength = 0; 271 LPWSTR Buffer = NULL; 272 LPCWSTR Path; 273 LONG rc; 274 275 (void)ComboBox_ResetContent(hwndCombo); 276 277 /* RegGetValue would have been better... */ 278 rc = RegOpenKeyEx( 279 HKEY_LOCAL_MACHINE, 280 REGSTR_PATH_SETUP REGSTR_KEY_SETUP, 281 0, 282 KEY_QUERY_VALUE, 283 &hKey); 284 if (rc != ERROR_SUCCESS) 285 { 286 TRACE("RegOpenKeyEx() failed with error 0x%lx\n", rc); 287 goto cleanup; 288 } 289 rc = RegQueryValueExW( 290 hKey, 291 L"Installation Sources", 292 NULL, 293 &dwRegType, 294 NULL, 295 &dwPathLength); 296 if (rc != ERROR_SUCCESS || dwRegType != REG_MULTI_SZ) 297 { 298 TRACE("RegQueryValueEx() failed with error 0x%lx\n", rc); 299 goto cleanup; 300 } 301 302 /* Allocate enough space to add 2 NULL chars at the end of the string */ 303 Buffer = HeapAlloc(GetProcessHeap(), 0, dwPathLength + 2 * sizeof(WCHAR)); 304 if (!Buffer) 305 { 306 TRACE("HeapAlloc() failed\n"); 307 goto cleanup; 308 } 309 rc = RegQueryValueExW( 310 hKey, 311 L"Installation Sources", 312 NULL, 313 NULL, 314 (LPBYTE)Buffer, 315 &dwPathLength); 316 if (rc != ERROR_SUCCESS) 317 { 318 TRACE("RegQueryValueEx() failed with error 0x%lx\n", rc); 319 goto cleanup; 320 } 321 322 Buffer[dwPathLength / sizeof(WCHAR)] = UNICODE_NULL; 323 Buffer[dwPathLength / sizeof(WCHAR) + 1] = UNICODE_NULL; 324 325 /* Populate combo box */ 326 for (Path = Buffer; *Path; Path += wcslen(Path) + 1) 327 { 328 (void)ComboBox_AddString(hwndCombo, Path); 329 if (Path == Buffer) 330 (void)ComboBox_SetCurSel(hwndCombo, 0); 331 } 332 333 cleanup: 334 if (hKey != NULL) 335 RegCloseKey(hKey); 336 HeapFree(GetProcessHeap(), 0, Buffer); 337 } 338 339 static VOID 340 SaveCustomPath( 341 IN HWND hwndCombo) 342 { 343 LPWSTR CustomPath = NULL; 344 DWORD CustomPathLength; 345 LPWSTR Buffer = NULL; 346 LPWSTR pBuffer; /* Pointer into Buffer */ 347 int ItemsCount, Length; 348 int i; 349 DWORD TotalLength = 0; 350 BOOL UseCustomPath = TRUE; 351 HKEY hKey = NULL; 352 LONG rc; 353 354 /* Get custom path */ 355 Length = ComboBox_GetTextLength(hwndCombo) + 1; 356 CustomPath = HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR)); 357 if (!CustomPath) 358 { 359 TRACE("HeapAlloc() failed\n"); 360 goto cleanup; 361 } 362 CustomPathLength = GetWindowTextW(hwndCombo, CustomPath, Length) + 1; 363 364 /* Calculate length of the buffer */ 365 ItemsCount = ComboBox_GetCount(hwndCombo); 366 if (ItemsCount == CB_ERR) 367 { 368 TRACE("ComboBox_GetCount() failed\n"); 369 goto cleanup; 370 } 371 for (i = 0; i < ItemsCount; i++) 372 { 373 Length = ComboBox_GetLBTextLen(hwndCombo, i); 374 if (Length == CB_ERR) 375 { 376 TRACE("ComboBox_GetLBTextLen() failed\n"); 377 goto cleanup; 378 } 379 TotalLength += Length + 1; 380 } 381 TotalLength++; /* Final NULL char */ 382 383 /* Allocate buffer */ 384 Buffer = HeapAlloc(GetProcessHeap(), 0, (CustomPathLength + TotalLength + 1) * sizeof(WCHAR)); 385 if (!Buffer) 386 { 387 TRACE("HeapAlloc() failed\n"); 388 goto cleanup; 389 } 390 391 /* Fill the buffer */ 392 pBuffer = &Buffer[CustomPathLength]; 393 for (i = 0; i < ItemsCount; i++) 394 { 395 Length = ComboBox_GetLBText(hwndCombo, i, pBuffer); 396 if (Length == CB_ERR) 397 { 398 TRACE("ComboBox_GetLBText() failed\n"); 399 goto cleanup; 400 } 401 else if (UseCustomPath && _wcsicmp(CustomPath, pBuffer) == 0) 402 UseCustomPath = FALSE; 403 pBuffer += 1 + Length; 404 } 405 *pBuffer = '\0'; /* Add final NULL char */ 406 407 if (!UseCustomPath) 408 { 409 /* Nothing to save to registry */ 410 goto cleanup; 411 } 412 413 TotalLength += CustomPathLength; 414 wcscpy(Buffer, CustomPath); 415 416 /* Save the buffer */ 417 /* RegSetKeyValue would have been better... */ 418 rc = RegOpenKeyEx( 419 HKEY_LOCAL_MACHINE, 420 REGSTR_PATH_SETUP REGSTR_KEY_SETUP, 421 0, 422 KEY_SET_VALUE, 423 &hKey); 424 if (rc != ERROR_SUCCESS) 425 { 426 TRACE("RegOpenKeyEx() failed with error 0x%lx\n", rc); 427 goto cleanup; 428 } 429 rc = RegSetValueExW( 430 hKey, 431 L"Installation Sources", 432 0, 433 REG_MULTI_SZ, 434 (const BYTE*)Buffer, 435 TotalLength * sizeof(WCHAR)); 436 if (rc != ERROR_SUCCESS) 437 { 438 TRACE("RegSetValueEx() failed with error 0x%lx\n", rc); 439 goto cleanup; 440 } 441 442 cleanup: 443 if (hKey != NULL) 444 RegCloseKey(hKey); 445 HeapFree(GetProcessHeap(), 0, CustomPath); 446 HeapFree(GetProcessHeap(), 0, Buffer); 447 } 448 449 static INT_PTR CALLBACK 450 WelcomeDlgProc( 451 IN HWND hwndDlg, 452 IN UINT uMsg, 453 IN WPARAM wParam, 454 IN LPARAM lParam) 455 { 456 PDEVINSTDATA DevInstData; 457 UNREFERENCED_PARAMETER(wParam); 458 459 /* Retrieve pointer to the global setup data */ 460 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 461 462 switch (uMsg) 463 { 464 case WM_INITDIALOG: 465 { 466 HWND hwndControl; 467 DWORD dwStyle; 468 469 /* Get pointer to the global setup data */ 470 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 471 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 472 473 hwndControl = GetParent(hwndDlg); 474 475 /* Center the wizard window */ 476 CenterWindow(hwndControl); 477 478 /* Hide the system menu */ 479 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE); 480 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU); 481 482 /* Set title font */ 483 SendDlgItemMessage( 484 hwndDlg, 485 IDC_WELCOMETITLE, 486 WM_SETFONT, 487 (WPARAM)DevInstData->hTitleFont, 488 (LPARAM)TRUE); 489 490 SendDlgItemMessage( 491 hwndDlg, 492 IDC_DEVICE, 493 WM_SETTEXT, 494 0, 495 (LPARAM)DevInstData->buffer); 496 497 SendDlgItemMessage( 498 hwndDlg, 499 IDC_RADIO_AUTO, 500 BM_SETCHECK, 501 (WPARAM)TRUE, 502 (LPARAM)0); 503 504 SetFailedInstall(DevInstData->hDevInfo, 505 &DevInstData->devInfoData, 506 TRUE); 507 break; 508 } 509 510 case WM_NOTIFY: 511 { 512 LPNMHDR lpnm = (LPNMHDR)lParam; 513 514 switch (lpnm->code) 515 { 516 case PSN_SETACTIVE: 517 /* Enable the Next button */ 518 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); 519 break; 520 521 case PSN_WIZNEXT: 522 /* Handle a Next button click, if necessary */ 523 if (SendDlgItemMessage(hwndDlg, IDC_RADIO_AUTO, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_CHECKED) 524 { 525 if (PrepareFoldersToScan(DevInstData, TRUE, FALSE, NULL)) 526 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV); 527 else 528 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED); 529 } 530 return TRUE; 531 532 default: 533 break; 534 } 535 break; 536 } 537 538 default: 539 break; 540 } 541 542 return FALSE; 543 } 544 545 static void 546 IncludePath(HWND Dlg, BOOL Enabled) 547 { 548 EnableWindow(GetDlgItem(Dlg, IDC_COMBO_PATH), Enabled); 549 EnableWindow(GetDlgItem(Dlg, IDC_BROWSE), Enabled); 550 } 551 552 static void 553 AutoDriver(HWND Dlg, BOOL Enabled) 554 { 555 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_MEDIA), Enabled); 556 EnableWindow(GetDlgItem(Dlg, IDC_CHECK_PATH), Enabled); 557 IncludePath(Dlg, Enabled & IsDlgButtonChecked(Dlg, IDC_CHECK_PATH)); 558 } 559 560 static INT_PTR CALLBACK 561 CHSourceDlgProc( 562 IN HWND hwndDlg, 563 IN UINT uMsg, 564 IN WPARAM wParam, 565 IN LPARAM lParam) 566 { 567 PDEVINSTDATA DevInstData; 568 569 /* Retrieve pointer to the global setup data */ 570 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 571 572 switch (uMsg) 573 { 574 case WM_INITDIALOG: 575 { 576 HWND hwndControl; 577 DWORD dwStyle; 578 579 /* Get pointer to the global setup data */ 580 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 581 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 582 583 hwndControl = GetParent(hwndDlg); 584 585 /* Center the wizard window */ 586 CenterWindow(hwndControl); 587 588 /* Hide the system menu */ 589 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE); 590 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU); 591 592 PopulateCustomPathCombo(GetDlgItem(hwndDlg, IDC_COMBO_PATH)); 593 594 SendDlgItemMessage( 595 hwndDlg, 596 IDC_RADIO_SEARCHHERE, 597 BM_SETCHECK, 598 (WPARAM)TRUE, 599 (LPARAM)0); 600 AutoDriver(hwndDlg, TRUE); 601 IncludePath(hwndDlg, FALSE); 602 603 /* Disable manual driver choice for now */ 604 EnableWindow(GetDlgItem(hwndDlg, IDC_RADIO_CHOOSE), FALSE); 605 606 break; 607 } 608 609 case WM_COMMAND: 610 { 611 switch (LOWORD(wParam)) 612 { 613 case IDC_RADIO_SEARCHHERE: 614 AutoDriver(hwndDlg, TRUE); 615 return TRUE; 616 617 case IDC_RADIO_CHOOSE: 618 AutoDriver(hwndDlg, FALSE); 619 return TRUE; 620 621 case IDC_CHECK_PATH: 622 IncludePath(hwndDlg, IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH)); 623 return TRUE; 624 625 case IDC_BROWSE: 626 { 627 BROWSEINFO bi = { 0 }; 628 LPITEMIDLIST pidl; 629 630 bi.hwndOwner = hwndDlg; 631 bi.ulFlags = BIF_RETURNONLYFSDIRS; 632 pidl = SHBrowseForFolder(&bi); 633 if (pidl) 634 { 635 WCHAR Directory[MAX_PATH]; 636 IMalloc* malloc; 637 638 if (SHGetPathFromIDListW(pidl, Directory)) 639 { 640 /* Set the IDC_COMBO_PATH text */ 641 SetWindowTextW(GetDlgItem(hwndDlg, IDC_COMBO_PATH), Directory); 642 } 643 644 /* Free memory, if possible */ 645 if (SUCCEEDED(SHGetMalloc(&malloc))) 646 { 647 IMalloc_Free(malloc, pidl); 648 IMalloc_Release(malloc); 649 } 650 return TRUE; 651 } 652 break; 653 } 654 } 655 break; 656 } 657 658 case WM_NOTIFY: 659 { 660 LPNMHDR lpnm = (LPNMHDR)lParam; 661 662 switch (lpnm->code) 663 { 664 case PSN_SETACTIVE: 665 /* Enable the Next and Back buttons */ 666 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK); 667 break; 668 669 case PSN_WIZNEXT: 670 /* Handle a Next button click, if necessary */ 671 if (IsDlgButtonChecked(hwndDlg, IDC_RADIO_SEARCHHERE)) 672 { 673 SaveCustomPath(GetDlgItem(hwndDlg, IDC_COMBO_PATH)); 674 HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath); 675 DevInstData->CustomSearchPath = NULL; 676 if (PrepareFoldersToScan( 677 DevInstData, 678 IsDlgButtonChecked(hwndDlg, IDC_CHECK_MEDIA), 679 IsDlgButtonChecked(hwndDlg, IDC_CHECK_PATH), 680 GetDlgItem(hwndDlg, IDC_COMBO_PATH))) 681 { 682 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SEARCHDRV); 683 } 684 else 685 { 686 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED); 687 } 688 } 689 else 690 { 691 /* FIXME */; 692 } 693 return TRUE; 694 695 default: 696 break; 697 } 698 break; 699 } 700 701 default: 702 break; 703 } 704 705 return FALSE; 706 } 707 708 static INT_PTR CALLBACK 709 SearchDrvDlgProc( 710 IN HWND hwndDlg, 711 IN UINT uMsg, 712 IN WPARAM wParam, 713 IN LPARAM lParam) 714 { 715 PDEVINSTDATA DevInstData; 716 DWORD dwThreadId; 717 718 /* Retrieve pointer to the global setup data */ 719 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 720 721 switch (uMsg) 722 { 723 case WM_INITDIALOG: 724 { 725 HWND hwndControl; 726 DWORD dwStyle; 727 728 /* Get pointer to the global setup data */ 729 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 730 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 731 732 DevInstData->hDialog = hwndDlg; 733 hwndControl = GetParent(hwndDlg); 734 735 /* Center the wizard window */ 736 CenterWindow(hwndControl); 737 738 SendDlgItemMessage( 739 hwndDlg, 740 IDC_DEVICE, 741 WM_SETTEXT, 742 0, 743 (LPARAM)DevInstData->buffer); 744 745 /* Hide the system menu */ 746 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE); 747 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU); 748 break; 749 } 750 751 case WM_SEARCH_FINISHED: 752 { 753 CloseHandle(hThread); 754 hThread = 0; 755 if (wParam == 0) 756 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_NODRIVER); 757 else 758 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLDRV); 759 break; 760 } 761 762 case WM_NOTIFY: 763 { 764 LPNMHDR lpnm = (LPNMHDR)lParam; 765 766 switch (lpnm->code) 767 { 768 case PSN_SETACTIVE: 769 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK); 770 /* Yes, we can safely ignore the problem (if any) */ 771 SetupDiDestroyDriverInfoList( 772 DevInstData->hDevInfo, 773 &DevInstData->devInfoData, 774 SPDIT_COMPATDRIVER); 775 hThread = CreateThread(NULL, 0, FindDriverProc, DevInstData, 0, &dwThreadId); 776 break; 777 778 case PSN_KILLACTIVE: 779 if (hThread != 0) 780 { 781 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); 782 return TRUE; 783 } 784 break; 785 786 case PSN_WIZNEXT: 787 /* Handle a Next button click, if necessary */ 788 break; 789 790 default: 791 break; 792 } 793 break; 794 } 795 796 default: 797 break; 798 } 799 800 return FALSE; 801 } 802 803 static INT_PTR CALLBACK 804 InstallDrvDlgProc( 805 IN HWND hwndDlg, 806 IN UINT uMsg, 807 IN WPARAM wParam, 808 IN LPARAM lParam) 809 { 810 PDEVINSTDATA DevInstData; 811 DWORD dwThreadId; 812 813 /* Retrieve pointer to the global setup data */ 814 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 815 816 switch (uMsg) 817 { 818 case WM_INITDIALOG: 819 { 820 HWND hwndControl; 821 DWORD dwStyle; 822 823 /* Get pointer to the global setup data */ 824 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 825 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 826 827 DevInstData->hDialog = hwndDlg; 828 hwndControl = GetParent(hwndDlg); 829 830 /* Center the wizard window */ 831 CenterWindow(hwndControl); 832 833 SendDlgItemMessage( 834 hwndDlg, 835 IDC_DEVICE, 836 WM_SETTEXT, 837 0, 838 (LPARAM)DevInstData->drvInfoData.Description); 839 840 /* Hide the system menu */ 841 dwStyle = GetWindowLongPtr(hwndControl, GWL_STYLE); 842 SetWindowLongPtr(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU); 843 break; 844 } 845 846 case WM_INSTALL_FINISHED: 847 { 848 CloseHandle(hThread); 849 hThread = 0; 850 if (wParam == 0) 851 { 852 SP_DEVINSTALL_PARAMS installParams; 853 854 SetFailedInstall(DevInstData->hDevInfo, 855 &DevInstData->devInfoData, 856 FALSE); 857 858 /* Should we reboot? */ 859 installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); 860 if (SetupDiGetDeviceInstallParams( 861 DevInstData->hDevInfo, 862 &DevInstData->devInfoData, 863 &installParams)) 864 { 865 if (installParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) 866 { 867 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_NEEDREBOOT); 868 } 869 else 870 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_FINISHPAGE); 871 break; 872 } 873 } 874 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_INSTALLFAILED); 875 break; 876 } 877 878 case WM_NOTIFY: 879 { 880 LPNMHDR lpnm = (LPNMHDR)lParam; 881 882 switch (lpnm->code) 883 { 884 case PSN_SETACTIVE: 885 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK); 886 hThread = CreateThread(NULL, 0, InstallDriverProc, DevInstData, 0, &dwThreadId); 887 break; 888 889 case PSN_KILLACTIVE: 890 if (hThread != 0) 891 { 892 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); 893 return TRUE; 894 } 895 break; 896 897 case PSN_WIZNEXT: 898 /* Handle a Next button click, if necessary */ 899 break; 900 901 default: 902 break; 903 } 904 break; 905 } 906 907 default: 908 break; 909 } 910 911 return FALSE; 912 } 913 914 static INT_PTR CALLBACK 915 NoDriverDlgProc( 916 IN HWND hwndDlg, 917 IN UINT uMsg, 918 IN WPARAM wParam, 919 IN LPARAM lParam) 920 { 921 PDEVINSTDATA DevInstData; 922 HWND hwndControl; 923 924 UNREFERENCED_PARAMETER(wParam); 925 926 /* Get pointer to the global setup data */ 927 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 928 929 switch (uMsg) 930 { 931 case WM_INITDIALOG: 932 { 933 BOOL DisableableDevice = FALSE; 934 935 /* Get pointer to the global setup data */ 936 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 937 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 938 939 /* Center the wizard window */ 940 CenterWindow(GetParent(hwndDlg)); 941 942 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL); 943 ShowWindow(hwndControl, SW_HIDE); 944 EnableWindow(hwndControl, FALSE); 945 946 /* Set title font */ 947 SendDlgItemMessage( 948 hwndDlg, 949 IDC_FINISHTITLE, 950 WM_SETFONT, 951 (WPARAM)DevInstData->hTitleFont, 952 (LPARAM)TRUE); 953 954 /* disable the "do not show this dialog anymore" checkbox 955 if the device cannot be disabled */ 956 CanDisableDevice( 957 DevInstData->devInfoData.DevInst, 958 NULL, 959 &DisableableDevice); 960 EnableWindow( 961 GetDlgItem(hwndDlg, IDC_DONOTSHOWDLG), 962 DisableableDevice); 963 break; 964 } 965 966 case WM_NOTIFY: 967 { 968 LPNMHDR lpnm = (LPNMHDR)lParam; 969 970 switch (lpnm->code) 971 { 972 case PSN_SETACTIVE: 973 /* Enable the correct buttons on for the active page */ 974 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH); 975 break; 976 977 case PSN_WIZBACK: 978 /* Handle a Back button click, if necessary */ 979 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL); 980 ShowWindow(hwndControl, SW_SHOW); 981 EnableWindow(hwndControl, TRUE); 982 PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_CHSOURCE); 983 return TRUE; 984 985 case PSN_WIZFINISH: 986 { 987 BOOL DisableableDevice = FALSE; 988 BOOL IsStarted = FALSE; 989 990 if (CanDisableDevice(DevInstData->devInfoData.DevInst, 991 NULL, 992 &DisableableDevice) && 993 DisableableDevice && 994 IsDeviceStarted( 995 DevInstData->devInfoData.DevInst, 996 NULL, 997 &IsStarted) && 998 !IsStarted && 999 SendDlgItemMessage( 1000 hwndDlg, 1001 IDC_DONOTSHOWDLG, 1002 BM_GETCHECK, 1003 (WPARAM)0, (LPARAM)0) == BST_CHECKED) 1004 { 1005 /* disable the device */ 1006 StartDevice( 1007 DevInstData->hDevInfo, 1008 &DevInstData->devInfoData, 1009 FALSE, 1010 0, 1011 NULL); 1012 } 1013 else 1014 { 1015 SetFailedInstall(DevInstData->hDevInfo, 1016 &DevInstData->devInfoData, 1017 FALSE); 1018 } 1019 break; 1020 } 1021 1022 default: 1023 break; 1024 } 1025 break; 1026 } 1027 1028 default: 1029 break; 1030 } 1031 1032 return FALSE; 1033 } 1034 1035 static INT_PTR CALLBACK 1036 InstallFailedDlgProc( 1037 IN HWND hwndDlg, 1038 IN UINT uMsg, 1039 IN WPARAM wParam, 1040 IN LPARAM lParam) 1041 { 1042 PDEVINSTDATA DevInstData; 1043 UNREFERENCED_PARAMETER(wParam); 1044 1045 /* Retrieve pointer to the global setup data */ 1046 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1047 1048 switch (uMsg) 1049 { 1050 case WM_INITDIALOG: 1051 { 1052 HWND hwndControl; 1053 1054 /* Get pointer to the global setup data */ 1055 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 1056 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 1057 1058 /* Center the wizard window */ 1059 CenterWindow(GetParent(hwndDlg)); 1060 1061 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL); 1062 ShowWindow(hwndControl, SW_HIDE); 1063 EnableWindow(hwndControl, FALSE); 1064 1065 SendDlgItemMessage( 1066 hwndDlg, 1067 IDC_DEVICE, 1068 WM_SETTEXT, 1069 0, 1070 (LPARAM)DevInstData->drvInfoData.Description); 1071 1072 /* Set title font */ 1073 SendDlgItemMessage( 1074 hwndDlg, 1075 IDC_FINISHTITLE, 1076 WM_SETFONT, 1077 (WPARAM)DevInstData->hTitleFont, 1078 (LPARAM)TRUE); 1079 break; 1080 } 1081 1082 case WM_NOTIFY: 1083 { 1084 LPNMHDR lpnm = (LPNMHDR)lParam; 1085 1086 switch (lpnm->code) 1087 { 1088 case PSN_SETACTIVE: 1089 /* Enable the correct buttons on for the active page */ 1090 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH); 1091 break; 1092 1093 case PSN_WIZBACK: 1094 /* Handle a Back button click, if necessary */ 1095 break; 1096 1097 case PSN_WIZFINISH: 1098 /* Handle a Finish button click, if necessary */ 1099 break; 1100 1101 default: 1102 break; 1103 } 1104 break; 1105 } 1106 1107 default: 1108 break; 1109 } 1110 1111 return FALSE; 1112 } 1113 1114 static INT_PTR CALLBACK 1115 NeedRebootDlgProc( 1116 IN HWND hwndDlg, 1117 IN UINT uMsg, 1118 IN WPARAM wParam, 1119 IN LPARAM lParam) 1120 { 1121 PDEVINSTDATA DevInstData; 1122 UNREFERENCED_PARAMETER(wParam); 1123 1124 /* Retrieve pointer to the global setup data */ 1125 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1126 1127 switch (uMsg) 1128 { 1129 case WM_INITDIALOG: 1130 { 1131 HWND hwndControl; 1132 1133 /* Get pointer to the global setup data */ 1134 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 1135 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 1136 1137 /* Center the wizard window */ 1138 CenterWindow(GetParent(hwndDlg)); 1139 1140 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL); 1141 ShowWindow(hwndControl, SW_HIDE); 1142 EnableWindow(hwndControl, FALSE); 1143 1144 SendDlgItemMessage( 1145 hwndDlg, 1146 IDC_DEVICE, 1147 WM_SETTEXT, 1148 0, 1149 (LPARAM)DevInstData->drvInfoData.Description); 1150 1151 /* Set title font */ 1152 SendDlgItemMessage( 1153 hwndDlg, 1154 IDC_FINISHTITLE, 1155 WM_SETFONT, 1156 (WPARAM)DevInstData->hTitleFont, 1157 (LPARAM)TRUE); 1158 break; 1159 } 1160 1161 case WM_NOTIFY: 1162 { 1163 LPNMHDR lpnm = (LPNMHDR)lParam; 1164 1165 switch (lpnm->code) 1166 { 1167 case PSN_SETACTIVE: 1168 /* Enable the correct buttons on for the active page */ 1169 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH); 1170 break; 1171 1172 case PSN_WIZBACK: 1173 /* Handle a Back button click, if necessary */ 1174 break; 1175 1176 case PSN_WIZFINISH: 1177 /* Handle a Finish button click, if necessary */ 1178 break; 1179 1180 default: 1181 break; 1182 } 1183 break; 1184 } 1185 1186 default: 1187 break; 1188 } 1189 1190 return FALSE; 1191 } 1192 1193 static INT_PTR CALLBACK 1194 FinishDlgProc( 1195 IN HWND hwndDlg, 1196 IN UINT uMsg, 1197 IN WPARAM wParam, 1198 IN LPARAM lParam) 1199 { 1200 PDEVINSTDATA DevInstData; 1201 UNREFERENCED_PARAMETER(wParam); 1202 1203 /* Retrieve pointer to the global setup data */ 1204 DevInstData = (PDEVINSTDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1205 1206 switch (uMsg) 1207 { 1208 case WM_INITDIALOG: 1209 { 1210 HWND hwndControl; 1211 1212 /* Get pointer to the global setup data */ 1213 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam; 1214 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (DWORD_PTR)DevInstData); 1215 1216 /* Center the wizard window */ 1217 CenterWindow(GetParent(hwndDlg)); 1218 1219 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL); 1220 ShowWindow(hwndControl, SW_HIDE); 1221 EnableWindow(hwndControl, FALSE); 1222 1223 SendDlgItemMessage( 1224 hwndDlg, 1225 IDC_DEVICE, 1226 WM_SETTEXT, 1227 0, 1228 (LPARAM)DevInstData->drvInfoData.Description); 1229 1230 /* Set title font */ 1231 SendDlgItemMessage( 1232 hwndDlg, 1233 IDC_FINISHTITLE, 1234 WM_SETFONT, 1235 (WPARAM)DevInstData->hTitleFont, 1236 (LPARAM)TRUE); 1237 break; 1238 } 1239 1240 case WM_NOTIFY: 1241 { 1242 LPNMHDR lpnm = (LPNMHDR)lParam; 1243 1244 switch (lpnm->code) 1245 { 1246 case PSN_SETACTIVE: 1247 /* Enable the correct buttons on for the active page */ 1248 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH); 1249 break; 1250 1251 case PSN_WIZBACK: 1252 /* Handle a Back button click, if necessary */ 1253 break; 1254 1255 case PSN_WIZFINISH: 1256 /* Handle a Finish button click, if necessary */ 1257 break; 1258 1259 default: 1260 break; 1261 } 1262 break; 1263 } 1264 1265 default: 1266 break; 1267 } 1268 1269 return FALSE; 1270 } 1271 1272 static HFONT 1273 CreateTitleFont(VOID) 1274 { 1275 NONCLIENTMETRICSW ncm; 1276 LOGFONTW LogFont; 1277 HDC hdc; 1278 INT FontSize; 1279 HFONT hFont; 1280 1281 ncm.cbSize = sizeof(NONCLIENTMETRICSW); 1282 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); 1283 1284 LogFont = ncm.lfMessageFont; 1285 LogFont.lfWeight = FW_BOLD; 1286 wcscpy(LogFont.lfFaceName, L"MS Shell Dlg"); 1287 1288 hdc = GetDC(NULL); 1289 FontSize = 12; 1290 LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72; 1291 hFont = CreateFontIndirectW(&LogFont); 1292 ReleaseDC(NULL, hdc); 1293 1294 return hFont; 1295 } 1296 1297 BOOL 1298 DisplayWizard( 1299 IN PDEVINSTDATA DevInstData, 1300 IN HWND hwndParent, 1301 IN UINT startPage) 1302 { 1303 PROPSHEETHEADER psh; 1304 HPROPSHEETPAGE ahpsp[IDD_MAXIMUMPAGE + 1]; 1305 PROPSHEETPAGE psp; 1306 1307 /* zero based index */ 1308 startPage -= IDD_FIRSTPAGE; 1309 1310 /* Create the Welcome page */ 1311 ZeroMemory(&psp, sizeof(PROPSHEETPAGE)); 1312 psp.dwSize = sizeof(PROPSHEETPAGE); 1313 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE; 1314 psp.hInstance = hDllInstance; 1315 psp.lParam = (LPARAM)DevInstData; 1316 psp.pszTitle = MAKEINTRESOURCE(DevInstData->bUpdate ? IDS_UPDATEWIZARDTITLE : IDS_INSTALLWIZARDTITLE); 1317 psp.pfnDlgProc = WelcomeDlgProc; 1318 psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE); 1319 ahpsp[IDD_WELCOMEPAGE-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1320 1321 /* Create the Select Source page */ 1322 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USETITLE; 1323 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_CHSOURCE_TITLE); 1324 psp.pfnDlgProc = CHSourceDlgProc; 1325 psp.pszTemplate = MAKEINTRESOURCE(IDD_CHSOURCE); 1326 ahpsp[IDD_CHSOURCE-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1327 1328 /* Create the Search driver page */ 1329 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USETITLE; 1330 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_SEARCHDRV_TITLE); 1331 psp.pfnDlgProc = SearchDrvDlgProc; 1332 psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHDRV); 1333 ahpsp[IDD_SEARCHDRV-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1334 1335 /* Create the Install driver page */ 1336 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USETITLE; 1337 psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_INSTALLDRV_TITLE); 1338 psp.pfnDlgProc = InstallDrvDlgProc; 1339 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLDRV); 1340 ahpsp[IDD_INSTALLDRV-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1341 1342 /* Create the No driver page */ 1343 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE; 1344 psp.pfnDlgProc = NoDriverDlgProc; 1345 psp.pszTemplate = MAKEINTRESOURCE(IDD_NODRIVER); 1346 ahpsp[IDD_NODRIVER-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1347 1348 /* Create the Install failed page */ 1349 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE; 1350 psp.pfnDlgProc = InstallFailedDlgProc; 1351 psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALLFAILED); 1352 ahpsp[IDD_INSTALLFAILED-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1353 1354 /* Create the Need reboot page */ 1355 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE; 1356 psp.pfnDlgProc = NeedRebootDlgProc; 1357 psp.pszTemplate = MAKEINTRESOURCE(IDD_NEEDREBOOT); 1358 ahpsp[IDD_NEEDREBOOT-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1359 1360 /* Create the Finish page */ 1361 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER | PSP_USETITLE; 1362 psp.pfnDlgProc = FinishDlgProc; 1363 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE); 1364 ahpsp[IDD_FINISHPAGE-IDD_FIRSTPAGE] = CreatePropertySheetPage(&psp); 1365 1366 /* Create the property sheet */ 1367 psh.dwSize = sizeof(PROPSHEETHEADER); 1368 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER; 1369 psh.hInstance = hDllInstance; 1370 psh.hwndParent = hwndParent; 1371 psh.nPages = IDD_MAXIMUMPAGE + 1; 1372 psh.nStartPage = startPage; 1373 psh.phpage = ahpsp; 1374 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); 1375 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER); 1376 1377 /* Create title font */ 1378 DevInstData->hTitleFont = CreateTitleFont(); 1379 1380 /* Display the wizard */ 1381 PropertySheet(&psh); 1382 1383 DeleteObject(DevInstData->hTitleFont); 1384 1385 return TRUE; 1386 } 1387