/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Sean Su * Curt Patrick * Ben Goodger * Masayuki Nakano * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // needed to build with mingw #ifndef _WIN32_IE #define _WIN32_IE 0x0500 #endif #include "extern.h" #include "extra.h" #include "dialogs.h" #include "ifuncns.h" #include "xpistub.h" #include "xpi.h" #include "logging.h" #include #include #include #include #include // commdlg.h is needed to build with WIN32_LEAN_AND_MEAN #include // re-define PSH_WIZARD97 as per latest Platform SDK (below) #ifdef PSH_WIZARD97 #undef PSH_WIZARD97 #endif #if (_WIN32_IE >= 0x0400) //----- New flags for wizard97 ----------- #if (_WIN32_IE < 0x0500) #define PSH_WIZARD97 0x00002000 #else #define PSH_WIZARD97 0x01000000 #endif #endif #ifndef CSIDL_PROGRAM_FILES #define CSIDL_PROGRAM_FILES 0x0026 #endif // CSIDL_PROGRAM_FILES // Turn off default to safe upgrade for 0.8... until we can guarantee that we won't be deleting other files. #define DEFAULT_SAFE_UPGRADE FALSE static WNDPROC OldListBoxWndProc; static WNDPROC OldDialogWndProc; static DWORD gdwACFlag; static BOOL gDidShowUpgradePanel; // function prototype LRESULT CALLBACK NewDialogWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); /////////////////////////////////////////////////////////////////////////////// // INSTALL WIZARD SEQUENCER // void InitSequence(HINSTANCE hInstance) { // Wizard data structures PROPSHEETPAGE psp; HPROPSHEETPAGE pages[11] = {0}; PROPSHEETHEADER psh; int count = 0; ///////////////////////////////////////////////////////////////////////////// // Create the Wizard Sequence // psp.dwSize = sizeof(psp); psp.hInstance = hSetupRscInst; psp.lParam = 0; // Welcome Page if (diWelcome.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER; psp.pfnDlgProc = DlgProcWelcome; psp.pszTemplate = MAKEINTRESOURCE(DLG_WELCOME); pages[count++] = CreatePropertySheetPage(&psp); } // License Page if (diLicense.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diLicense.szTitle; psp.pszHeaderSubTitle = diLicense.szSubTitle; psp.pfnDlgProc = DlgProcLicense; psp.pszTemplate = MAKEINTRESOURCE(DLG_LICENSE); pages[count++] = CreatePropertySheetPage(&psp); } // License Page if (diSetupType.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diSetupType.szTitle; psp.pszHeaderSubTitle = diSetupType.szSubTitle; psp.pfnDlgProc = DlgProcSetupType; psp.pszTemplate = MAKEINTRESOURCE(DLG_SETUP_TYPE); pages[count++] = CreatePropertySheetPage(&psp); } if (diSelectInstallPath.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diSelectInstallPath.szTitle; psp.pszHeaderSubTitle = diSelectInstallPath.szSubTitle; psp.pfnDlgProc = DlgProcSelectInstallPath; psp.pszTemplate = MAKEINTRESOURCE(DLG_SELECT_INSTALL_PATH); pages[count++] = CreatePropertySheetPage(&psp); } if (diUpgrade.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diUpgrade.szTitle; psp.pszHeaderSubTitle = diUpgrade.szSubTitle; psp.pfnDlgProc = DlgProcUpgrade; psp.pszTemplate = MAKEINTRESOURCE(DLG_UPGRADE); pages[count++] = CreatePropertySheetPage(&psp); } else { // If we're not showing the Upgrade dialog, we need to set some state to // tell the installer to default to a Safe Install. sgProduct.doCleanupOnUpgrade = DEFAULT_SAFE_UPGRADE; } if (diSelectComponents.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diSelectComponents.szTitle; psp.pszHeaderSubTitle = diSelectComponents.szSubTitle; psp.pfnDlgProc = DlgProcSelectComponents; psp.pszTemplate = MAKEINTRESOURCE(DLG_SELECT_COMPONENTS); pages[count++] = CreatePropertySheetPage(&psp); } // Windows Integration Page if (diWindowsIntegration.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diWindowsIntegration.szTitle; psp.pszHeaderSubTitle = diWindowsIntegration.szSubTitle; psp.pfnDlgProc = DlgProcWindowsIntegration; psp.pszTemplate = MAKEINTRESOURCE(DLG_WINDOWS_INTEGRATION); pages[count++] = CreatePropertySheetPage(&psp); } if (diStartInstall.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diStartInstall.szTitle; psp.pszHeaderSubTitle = diStartInstall.szSubTitle; psp.pfnDlgProc = DlgProcSummary; psp.pszTemplate = MAKEINTRESOURCE(DLG_START_INSTALL); pages[count++] = CreatePropertySheetPage(&psp); } if (diDownloading.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diDownloading.szTitle; psp.pszHeaderSubTitle = diDownloading.szSubTitle; psp.pfnDlgProc = DlgProcDownloading; psp.pszTemplate = MAKEINTRESOURCE(DLG_DOWNLOADING); pages[count++] = CreatePropertySheetPage(&psp); } if (diInstalling.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; psp.pszHeaderTitle = diInstalling.szTitle; psp.pszHeaderSubTitle = diInstalling.szSubTitle; psp.pfnDlgProc = DlgProcInstalling; psp.pszTemplate = MAKEINTRESOURCE(DLG_EXTRACTING); pages[count++] = CreatePropertySheetPage(&psp); } // Successful Install Page if (diInstallSuccessful.bShowDialog) { psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER; psp.pfnDlgProc = DlgProcInstallSuccessful; psp.pszTemplate = MAKEINTRESOURCE(DLG_INSTALL_SUCCESSFUL); pages[count++] = CreatePropertySheetPage(&psp); } // Property Sheet psh.dwSize = sizeof(psh); psh.hInstance = hSetupRscInst; psh.hwndParent = NULL; psh.phpage = pages; psh.dwFlags = PSH_WIZARD97|PSH_HEADER; psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER); psh.nStartPage = 0; psh.nPages = count; // Start the Wizard. if (psh.nPages > 1) { PropertySheet(&psh); } else { if (psh.nPages == 1) { // Auto install CreateDialog(hSetupRscInst, MAKEINTRESOURCE(DLG_EXTRACTING), NULL, DlgProcInstalling); } else { // Silent install InstallFiles(NULL); } gbIgnoreRunAppX = TRUE; // Apply settings and close. if (sgProduct.bInstallFiles) UpdateJSProxyInfo(); /* POST_SMARTUPDATE process file manipulation functions */ ProcessFileOpsForAll(T_POST_SMARTUPDATE); if (sgProduct.bInstallFiles) { /* PRE_LAUNCHAPP process file manipulation functions */ ProcessFileOpsForAll(T_PRE_LAUNCHAPP); LaunchApps(); // Refresh system icons if necessary if (gSystemInfo.bRefreshIcons) RefreshIcons(); UnsetSetupState(); // clear setup state if (!gbIgnoreProgramFolderX) ProcessProgramFolderShowCmd(); CleanupArgsRegistry(); CleanupPreviousVersionRegKeys(); /* POST_LAUNCHAPP process file manipulation functions */ ProcessFileOpsForAll(T_POST_LAUNCHAPP); /* DEPEND_REBOOT process file manipulation functions */ ProcessFileOpsForAll(T_DEPEND_REBOOT); } } } HFONT MakeFont(TCHAR* aFaceName, int aFontSize, LONG aWeight) { // Welcome Page Header font data NONCLIENTMETRICS ncm = {0}; LOGFONT lf; HDC hDC; ncm.cbSize = sizeof(ncm); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); if (aFaceName) lstrcpy(lf.lfFaceName, aFaceName); lf = ncm.lfMessageFont; lf.lfWeight = aWeight; hDC = GetDC(NULL); lf.lfHeight = 0 - GetDeviceCaps(hDC, LOGPIXELSY) * aFontSize / 72; ReleaseDC(NULL, hDC); return CreateFontIndirect(&lf); } /////////////////////////////////////////////////////////////////////////////// // DIALOG: EXIT SETUP // BOOL ShouldExitSetup(HWND hDlg) { char szDlgQuitTitle[MAX_BUF]; char szDlgQuitMsg[MAX_BUF]; char szMsg[MAX_BUF]; BOOL rv = FALSE; if (sgProduct.mode != SILENT && sgProduct.mode != AUTO) { if (!GetPrivateProfileString("Messages", "DLGQUITTITLE", "", szDlgQuitTitle, sizeof(szDlgQuitTitle), szFileIniInstall) || !GetPrivateProfileString("Messages", "DLGQUITMSG", "", szDlgQuitMsg, sizeof(szDlgQuitMsg), szFileIniInstall)) PostQuitMessage(1); rv = MessageBox(GetParent(hDlg), szDlgQuitMsg, szDlgQuitTitle, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_APPLMODAL | MB_SETFOREGROUND) == IDYES; } else { GetConfigIniProfileString("Strings", "Message Cancel Setup AUTO mode", "", szMsg, sizeof(szMsg)); ShowMessage(szMsg, TRUE); Delay(5); ShowMessage(szMsg, FALSE); rv = TRUE; } if (!rv) SetWindowLong(hDlg, DWL_MSGRESULT, (LONG)TRUE); return rv; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: WELCOME // LRESULT CALLBACK DlgProcWelcome(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { char szBuf[MAX_BUF]; LPNMHDR notifyMessage; switch(msg) { case WM_INITDIALOG: // UI Text, from localized config files wsprintf(szBuf, diWelcome.szMessageWelcome, sgProduct.szProductName); SetDlgItemText(hDlg, IDC_STATIC_TITLE, szBuf); wsprintf(szBuf, diWelcome.szMessage0, sgProduct.szProductName); SetDlgItemText(hDlg, IDC_STATIC0, szBuf); SetDlgItemText(hDlg, IDC_STATIC1, diWelcome.szMessage1); SetDlgItemText(hDlg, IDC_STATIC2, diWelcome.szMessage2); wsprintf(szBuf, diWelcome.szMessage3, sgProduct.szProductName); SetDlgItemText(hDlg, IDC_STATIC3, szBuf); // The header on the welcome page uses another font. SendDlgItemMessage(hDlg, IDC_STATIC_TITLE, WM_SETFONT, (WPARAM)sgInstallGui.welcomeTitleFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC3, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); // Subclass dialog to paint all static controls white. OldDialogWndProc = SubclassWindow(hDlg, (WNDPROC)NewDialogWndProc); break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diWelcome.szTitle); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT); break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; } return 0; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: LICENSE // LRESULT CALLBACK DlgProcLicense(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { char szBuf[MAX_BUF]; LPSTR szLicenseFilenameBuf = NULL; WIN32_FIND_DATA wfdFindFileData; DWORD dwFileSize; DWORD dwBytesRead; HANDLE hFLicense; FILE *fLicense; LPNMHDR notifyMessage; switch(msg) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDC_MESSAGE0, diLicense.szMessage0); SetDlgItemText(hDlg, IDC_RADIO_ACCEPT, diLicense.szRadioAccept); SetDlgItemText(hDlg, IDC_RADIO_DECLINE, diLicense.szRadioDecline); SendDlgItemMessage(hDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_RADIO_ACCEPT, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_RADIO_DECLINE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); // Check the "Decline" Radio button by default. CheckDlgButton(hDlg, IDC_RADIO_DECLINE, BST_CHECKED); SendMessage(GetDlgItem(hDlg, IDC_RADIO_DECLINE), BM_SETCHECK, BST_CHECKED, 0); SendDlgItemMessage(hDlg, IDC_RADIO_DECLINE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); // License Text lstrcpy(szBuf, szSetupDir); AppendBackSlash(szBuf, sizeof(szBuf)); lstrcat(szBuf, diLicense.szLicenseFilename); if((hFLicense = FindFirstFile(szBuf, &wfdFindFileData)) != INVALID_HANDLE_VALUE) { dwFileSize = (wfdFindFileData.nFileSizeHigh * MAXDWORD) + wfdFindFileData.nFileSizeLow + 1; FindClose(hFLicense); if((szLicenseFilenameBuf = NS_GlobalAlloc(dwFileSize)) != NULL) { if((fLicense = fopen(szBuf, "rb")) != NULL) { dwBytesRead = fread(szLicenseFilenameBuf, sizeof(char), dwFileSize, fLicense); fclose(fLicense); SetDlgItemText(hDlg, IDC_EDIT_LICENSE, szLicenseFilenameBuf); } FreeMemory(&szLicenseFilenameBuf); } } SendDlgItemMessage(hDlg, IDC_EDIT_LICENSE, WM_SETFONT, (WPARAM)sgInstallGui.systemFont, 0L); break; case WM_COMMAND: switch (wParam) { case IDC_RADIO_ACCEPT: PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); break; case IDC_RADIO_DECLINE: PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK); break; } break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diLicense.szTitle); if (IsDlgButtonChecked(hDlg, IDC_RADIO_DECLINE) == BST_CHECKED) PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK); else PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); SendDlgItemMessage(hDlg, IDC_EDIT_LICENSE, EM_SETSEL, 0, 0); break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; } return 0; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: SETUP TYPE // LRESULT CALLBACK DlgProcSetupType(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { HWND hRadioSt0, hStaticSt0, hRadioSt1, hStaticSt1; LPNMHDR notifyMessage; BOOL skipNext = FALSE; static char defaultPath[MAX_BUF]; hRadioSt0 = GetDlgItem(hDlg, IDC_RADIO_ST0); hStaticSt0 = GetDlgItem(hDlg, IDC_STATIC_ST0_DESCRIPTION); hRadioSt1 = GetDlgItem(hDlg, IDC_RADIO_ST1); hStaticSt1 = GetDlgItem(hDlg, IDC_STATIC_ST1_DESCRIPTION); switch(msg) { case WM_INITDIALOG: lstrcpy(defaultPath, sgProduct.szPath); SetDlgItemText(hDlg, IDC_STATIC_MSG0, diSetupType.szMessage0); SendDlgItemMessage(hDlg, IDC_STATIC_MSG0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); if(diSetupType.stSetupType0.bVisible) { SetDlgItemText(hDlg, IDC_RADIO_ST0, diSetupType.stSetupType0.szDescriptionShort); SetDlgItemText(hDlg, IDC_STATIC_ST0_DESCRIPTION, diSetupType.stSetupType0.szDescriptionLong); SendDlgItemMessage(hDlg, IDC_RADIO_ST0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC_ST0_DESCRIPTION, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); ShowWindow(hRadioSt0, SW_SHOW); ShowWindow(hStaticSt0, SW_SHOW); } else { ShowWindow(hRadioSt0, SW_HIDE); ShowWindow(hStaticSt0, SW_HIDE); } if(diSetupType.stSetupType1.bVisible) { SetDlgItemText(hDlg, IDC_RADIO_ST1, diSetupType.stSetupType1.szDescriptionShort); SetDlgItemText(hDlg, IDC_STATIC_ST1_DESCRIPTION, diSetupType.stSetupType1.szDescriptionLong); SendDlgItemMessage(hDlg, IDC_RADIO_ST1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC_ST1_DESCRIPTION, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); ShowWindow(hRadioSt1, SW_SHOW); ShowWindow(hStaticSt1, SW_SHOW); } else { ShowWindow(hRadioSt1, SW_HIDE); ShowWindow(hStaticSt1, SW_HIDE); } break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diSetupType.szTitle); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); switch(dwTempSetupType) { case ST_RADIO0: CheckDlgButton(hDlg, IDC_RADIO_ST0, BST_CHECKED); SetFocus(hRadioSt0); break; case ST_RADIO1: CheckDlgButton(hDlg, IDC_RADIO_ST1, BST_CHECKED); SetFocus(hRadioSt1); break; } break; case PSN_WIZNEXT: case PSN_WIZBACK: // retrieve and save the state of the selected radio button if(IsDlgButtonChecked(hDlg, IDC_RADIO_ST0) == BST_CHECKED) dwSetupType = ST_RADIO0; else if(IsDlgButtonChecked(hDlg, IDC_RADIO_ST1) == BST_CHECKED) dwSetupType = ST_RADIO1; SiCNodeSetItemsSelected(dwSetupType); dwTempSetupType = dwSetupType; // If the user has selected "Standard" (easy install) no further data // collection is required, go right to the end. if (notifyMessage->code == PSN_WIZNEXT && dwSetupType == ST_RADIO0) { // Reset the path to the default value. lstrcpy(sgProduct.szPath, defaultPath); CheckForUpgrade(hDlg, DLG_START_INSTALL); skipNext = TRUE; } break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; } return skipNext; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: SELECT INSTALL PATH // #ifndef BIF_USENEWUI // BIF_USENEWUI isn't defined in the platform SDK that comes with // MSVC6.0. #define BIF_USENEWUI 0x50 #endif int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { if (uMsg == BFFM_INITIALIZED) { char * filePath = (char *) lpData; if (filePath) { SendMessage(hwnd, BFFM_SETSELECTION, TRUE /* true because lpData is a path string */, lpData); free(filePath); } } return 0; } void BrowseForDirectory(HWND hParent) { LPITEMIDLIST itemIDList; BROWSEINFO browseInfo; char currDir[MAX_PATH]; if(SHGetSpecialFolderLocation(hParent, CSIDL_PROGRAM_FILES, &itemIDList) == S_OK) SHGetPathFromIDList(itemIDList, (LPTSTR) currDir); else strncpy(currDir, "C:\\", sizeof(currDir)); browseInfo.hwndOwner = hParent; browseInfo.pidlRoot = NULL; browseInfo.pszDisplayName = currDir; browseInfo.lpszTitle = sgInstallGui.szBrowseInfo; browseInfo.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS; browseInfo.lpfn = NULL; browseInfo.lParam = 0; if (currDir[0]) { browseInfo.lParam = (LPARAM) strdup(currDir); browseInfo.lpfn = &BrowseCallbackProc; } else browseInfo.lParam = 0; // Show the dialog itemIDList = SHBrowseForFolder(&browseInfo); if (itemIDList) { if (SHGetPathFromIDList(itemIDList, currDir)) { InitPathDisplay(hParent, currDir, IDC_FOLDER_ICON, IDC_EDIT_DESTINATION); SetCurrentDirectory(currDir); lstrcpy(szTempSetupPath, currDir); } #if 0 // XXXben LEAK!!!! but this code won't compile for some unknown reason- // "Free is not a member of IMalloc, see objidl.h for details" // but that's a bald-faced lie! // The shell allocated an ITEMIDLIST, we need to free it. // I guess we'll just leak shell objects for now :-D LPMALLOC shellMalloc; if (SUCCEEDED(SHGetMalloc(&shellMalloc))) { shellMalloc->Free(itemIDList); shellMalloc->Release(); } #endif } } void RecoverFromPathError(HWND aPanel) { // Reset the displayed path to the previous, valid value. InitPathDisplay(aPanel, sgProduct.szPath, IDC_FOLDER_ICON, IDC_EDIT_DESTINATION); // Reset the temporary path string so we don't get stuck receiving // the error message. lstrcpy(szTempSetupPath, sgProduct.szPath); // Prevent the Wizard from advancing because of this error. SetWindowLong(aPanel, DWL_MSGRESULT, -1); } void CheckForUpgrade(HWND aPanel, int aNextPanel) { char buf[MAX_BUF]; int nextPanel = aNextPanel; // Check to see if we should show the "Safe Upgrade" dialog // The second part of the test is to see if the flag in config.ini // specifies whether or not this should be shown *specifically* in the // "Easy Install" mode. If that flag is set to FALSE, the Upgrade // panel is shown only in the "Custom"/"Advanced" pass. if (sgProduct.checkCleanupOnUpgrade && !(dwSetupType == ST_RADIO0 && !diUpgrade.bShowInEasyInstall) && !(dwSetupType == ST_RADIO1 && !diUpgrade.bShowDialog)) { // Found destination folder. check to see if we're upgrading ontop // of a previous installation. If so, we need to prompt the user // about removing the entire dir before installation happens. MozCopyStr(sgProduct.szPath, buf, sizeof(buf)); AppendBackSlash(buf, sizeof(buf)); lstrcat(buf, sgProduct.szProgramName); if (FileExists(buf)) { // Prompt user if deleting target path is okay. Only show // prompt if the setup is running in normal mode, else // assume user wants deletion. if(sgProduct.mode == NORMAL) nextPanel = DLG_UPGRADE; else { sgProduct.doCleanupOnUpgrade = DEFAULT_SAFE_UPGRADE; nextPanel = aNextPanel; } } else nextPanel = aNextPanel; } /* SiCNodeSetItemsSelected() is called from within DlgProcUpgrade(). * If DlgProcUpgrade is not called (in the case of a !NORMAL install), * then we need to call it here. */ if (sgProduct.mode != NORMAL) SiCNodeSetItemsSelected(dwSetupType); gDidShowUpgradePanel = nextPanel == DLG_UPGRADE; SetWindowLong(aPanel, DWL_MSGRESULT, nextPanel); } LRESULT CALLBACK DlgProcSelectInstallPath(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { char szBuf[MAX_BUF]; char szBufTemp[MAX_BUF]; LPNMHDR notifyMessage; BOOL rv = FALSE; switch(msg) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDC_STATIC_MSG0, diSelectInstallPath.szMessage0); EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_BROWSE), !sgProduct.bLockPath); SetCurrentDirectory(szTempSetupPath); InitPathDisplay(hDlg, szTempSetupPath, IDC_FOLDER_ICON, IDC_EDIT_DESTINATION); SetDlgItemText(hDlg, IDC_BUTTON_BROWSE, sgInstallGui.szBrowse_); SendDlgItemMessage(hDlg, IDC_STATIC_MSG0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_EDIT_DESTINATION, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_BUTTON_BROWSE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_BUTTON_BROWSE: BrowseForDirectory(hDlg); break; } break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diSelectInstallPath.szTitle); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); break; case PSN_WIZNEXT: /* Make sure that the path is not within the windows dir */ if(IsPathWithinWindir(szTempSetupPath)) { char errorMsg[MAX_BUF]; char errorMsgTitle[MAX_BUF]; GetPrivateProfileString("Messages", "ERROR_PATH_WITHIN_WINDIR", "", errorMsg, sizeof(errorMsg), szFileIniInstall); GetPrivateProfileString("Messages", "ERROR_MESSAGE_TITLE", "", errorMsgTitle, sizeof(errorMsgTitle), szFileIniInstall); MessageBox(hDlg, errorMsg, errorMsgTitle, MB_OK | MB_ICONERROR); RecoverFromPathError(hDlg); return TRUE; } lstrcpy(sgProduct.szPath, szTempSetupPath); /* append a backslash to the path because CreateDirectoriesAll() uses a backslash to determine directories */ lstrcpy(szBuf, sgProduct.szPath); AppendBackSlash(szBuf, sizeof(szBuf)); CheckForUpgrade(hDlg, DLG_SELECT_COMPONENTS); /* Create the path if it does not exist */ if (FileExists(szBuf) == FALSE) { char szBuf2[MAX_PATH]; if (CreateDirectoriesAll(szBuf, ADD_TO_UNINSTALL_LOG) != WIZ_OK) { char szECreateDirectory[MAX_BUF]; char szEMessageTitle[MAX_BUF]; lstrcpy(szBufTemp, "\n\n"); lstrcat(szBufTemp, sgProduct.szPath); RemoveBackSlash(szBufTemp); lstrcat(szBufTemp, "\n\n"); if (GetPrivateProfileString("Messages", "ERROR_CREATE_DIRECTORY", "", szECreateDirectory, sizeof(szECreateDirectory), szFileIniInstall)) wsprintf(szBuf, szECreateDirectory, szBufTemp); GetPrivateProfileString("Messages", "ERROR_MESSAGE_TITLE", "", szEMessageTitle, sizeof(szEMessageTitle), szFileIniInstall); MessageBox(hDlg, szBuf, szEMessageTitle, MB_OK | MB_ICONERROR); RecoverFromPathError(hDlg); // Prevent the page change if we failed to create the directory. SetWindowLong(hDlg, DWL_MSGRESULT, -1); return TRUE; } if(*sgProduct.szSubPath != '\0') { /* log the subpath for uninstallation. This subpath does not normally get logged * for uninstallation due to a chicken and egg problem with creating the log file * and the directory its in */ lstrcpy(szBuf2, szBuf); AppendBackSlash(szBuf2, sizeof(szBuf2)); lstrcat(szBuf2, sgProduct.szSubPath); UpdateInstallLog(KEY_CREATE_FOLDER, szBuf2, FALSE); } } // Need to return TRUE so we override the default wizard sequence. rv = TRUE; break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; } return rv; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: UPGRADE CONFIRMATION // void UpdateUpgradeModeMessage(HWND aPanel) { if (IsDlgButtonChecked(aPanel, IDC_CHECK_SAFE_INSTALL) == BST_CHECKED) SetDlgItemText(aPanel, IDC_MESSAGE_INFO, diUpgrade.szSafeInstallInfo); else SetDlgItemText(aPanel, IDC_MESSAGE_INFO, diUpgrade.szUnsafeInstallInfo); } LRESULT CALLBACK DlgProcUpgrade(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { LPNMHDR notifyMessage; BOOL pathInWinDir = FALSE; BOOL rv = FALSE; switch (msg) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDC_MESSAGE_UPGRADE, diUpgrade.szMessageCleanup); SetDlgItemText(hDlg, IDC_CHECK_SAFE_INSTALL, diUpgrade.szCheckboxSafeInstall); SendDlgItemMessage(hDlg, IDC_MESSAGE_UPGRADE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_CHECK_SAFE_INSTALL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); // Default to "Safe Upgrade". CheckDlgButton(hDlg, IDC_CHECK_SAFE_INSTALL, BST_CHECKED); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_CHECK_SAFE_INSTALL: UpdateUpgradeModeMessage(hDlg); break; } break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diUpgrade.szTitle); InitPathDisplay(hDlg, sgProduct.szPath, IDC_FOLDER_ICON, IDC_EDIT_DESTINATION); pathInWinDir = IsPathWithinWindir(sgProduct.szPath); if(pathInWinDir) { // Do not clean up sgProduct.doCleanupOnUpgrade = FALSE; // Disable UI and show an explanation. EnableWindow(GetDlgItem(hDlg, IDC_CHECK_SAFE_INSTALL), FALSE); SetDlgItemText(hDlg, IDC_MESSAGE_INFO, diUpgrade.szNoSafeUpgradeWindir); } CheckDlgButton(hDlg, IDC_CHECK_SAFE_INSTALL, sgProduct.doCleanupOnUpgrade ? BST_CHECKED : BST_UNCHECKED); if (!pathInWinDir) UpdateUpgradeModeMessage(hDlg); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); break; case PSN_WIZNEXT: if (dwSetupType == ST_RADIO0) { SetWindowLong(hDlg, DWL_MSGRESULT, DLG_START_INSTALL); rv = TRUE; } sgProduct.doCleanupOnUpgrade = IsDlgButtonChecked(hDlg, IDC_CHECK_SAFE_INSTALL) == BST_CHECKED; SiCNodeSetItemsSelected(dwSetupType); break; case PSN_WIZBACK: if (dwSetupType == ST_RADIO0) { SetWindowLong(hDlg, DWL_MSGRESULT, DLG_SETUP_TYPE); rv = TRUE; } sgProduct.doCleanupOnUpgrade = IsDlgButtonChecked(hDlg, IDC_CHECK_SAFE_INSTALL) == BST_CHECKED; SiCNodeSetItemsSelected(dwSetupType); break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; } return rv; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: SELECT COMPONENTS // void DrawLBText(LPDRAWITEMSTRUCT lpdis, DWORD dwACFlag) { siC *siCTemp = NULL; TCHAR tchBuffer[MAX_BUF]; TEXTMETRIC tm; DWORD y; siCTemp = SiCNodeGetObject(lpdis->itemID, FALSE, dwACFlag); if(siCTemp != NULL) { SendMessage(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, (LPARAM)tchBuffer); if((lpdis->itemAction & ODA_FOCUS) && (lpdis->itemState & ODS_SELECTED)) { // remove the focus rect on the previous selected item DrawFocusRect(lpdis->hDC, &(lpdis->rcItem)); } siCTemp = SiCNodeGetObject(lpdis->itemID, FALSE, dwACFlag); if(lpdis->itemAction & ODA_FOCUS) { if((lpdis->itemState & ODS_SELECTED) && !(lpdis->itemState & ODS_FOCUS)) { if(siCTemp->dwAttributes & SIC_DISABLED) SetTextColor(lpdis->hDC, GetSysColor(COLOR_GRAYTEXT)); else { SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW)); } } else { if(siCTemp->dwAttributes & SIC_DISABLED) SetTextColor(lpdis->hDC, GetSysColor(COLOR_GRAYTEXT)); else { SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT)); } } } else if(lpdis->itemAction & ODA_DRAWENTIRE) { if(siCTemp->dwAttributes & SIC_DISABLED) SetTextColor(lpdis->hDC, GetSysColor(COLOR_GRAYTEXT)); else SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT)); } // If a screen reader is being used we want to redraw the text whether // it has focus or not because the text changes whenever the checkbox // changes. if( gSystemInfo.bScreenReader || (lpdis->itemAction & (ODA_DRAWENTIRE | ODA_FOCUS)) ) { // Display the text associated with the item. GetTextMetrics(lpdis->hDC, &tm); y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2; ExtTextOut(lpdis->hDC, CX_CHECKBOX + 5, y, ETO_OPAQUE | ETO_CLIPPED, &(lpdis->rcItem), tchBuffer, strlen(tchBuffer), NULL); } } } void DrawCheck(LPDRAWITEMSTRUCT lpdis, DWORD dwACFlag) { siC *siCTemp = NULL; HDC hdcMem; HBITMAP hbmpCheckBox; siCTemp = SiCNodeGetObject(lpdis->itemID, FALSE, dwACFlag); if(siCTemp != NULL) { if(!(siCTemp->dwAttributes & SIC_SELECTED)) /* Component is not selected. Use the unchecked bitmap regardless if the * component is disabled or not. The unchecked bitmap looks the same if * it's disabled or enabled. */ hbmpCheckBox = hbmpBoxUnChecked; else if(siCTemp->dwAttributes & SIC_DISABLED) /* Component is checked and disabled */ hbmpCheckBox = hbmpBoxCheckedDisabled; else /* Component is checked and enabled */ hbmpCheckBox = hbmpBoxChecked; SendMessage(lpdis->hwndItem, LB_SETITEMDATA, lpdis->itemID, (LPARAM)hbmpCheckBox); if((hdcMem = CreateCompatibleDC(lpdis->hDC)) != NULL) { SelectObject(hdcMem, hbmpCheckBox); // BitBlt() is used to prepare the checkbox icon into the list box item's device context. // The SendMessage() function using LB_SETITEMDATA performs the drawing. BitBlt(lpdis->hDC, lpdis->rcItem.left + 2, lpdis->rcItem.top + 2, lpdis->rcItem.right - lpdis->rcItem.left, lpdis->rcItem.bottom - lpdis->rcItem.top, hdcMem, 0, 0, SRCCOPY); DeleteDC(hdcMem); } } } void lbAddItem(HWND hList, siC *siCComponent) { DWORD dwItem; TCHAR tchBuffer[MAX_BUF]; lstrcpy(tchBuffer, siCComponent->szDescriptionShort); if(gSystemInfo.bScreenReader) { lstrcat(tchBuffer, " - "); if(!(siCComponent->dwAttributes & SIC_SELECTED)) lstrcat(tchBuffer, sgInstallGui.szUnchecked); else lstrcat(tchBuffer, sgInstallGui.szChecked); } dwItem = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)tchBuffer); if(siCComponent->dwAttributes & SIC_DISABLED) SendMessage(hList, LB_SETITEMDATA, dwItem, (LPARAM)hbmpBoxCheckedDisabled); else if(siCComponent->dwAttributes & SIC_SELECTED) SendMessage(hList, LB_SETITEMDATA, dwItem, (LPARAM)hbmpBoxChecked); else SendMessage(hList, LB_SETITEMDATA, dwItem, (LPARAM)hbmpBoxUnChecked); } void InvalidateLBCheckbox(HWND hwndListBox) { RECT rcCheckArea; // retrieve the rectangle of all list items to update. GetClientRect(hwndListBox, &rcCheckArea); // Set the right coordinate of the rectangle to be the same // as the right edge of the bitmap drawn. // But if a screen reader is being used we want to redraw the text // as well as the checkbox so we do not set the right coordinate. if(!gSystemInfo.bScreenReader) rcCheckArea.right = CX_CHECKBOX; // It then invalidates the checkbox region to be redrawn. // Invalidating the region sends a WM_DRAWITEM message to // the dialog, which redraws the region given the // node attirbute, in this case it is a bitmap of a // checked/unchecked checkbox. InvalidateRect(hwndListBox, &rcCheckArea, TRUE); } void ToggleCheck(HWND hwndListBox, DWORD dwIndex, DWORD dwACFlag) { BOOL bMoreToResolve; LPSTR szToggledReferenceName = NULL; DWORD dwAttributes; // Checks to see if the checkbox is checked or not checked, and // toggles the node attributes appropriately. dwAttributes = SiCNodeGetAttributes(dwIndex, FALSE, dwACFlag); if(!(dwAttributes & SIC_DISABLED)) { if(dwAttributes & SIC_SELECTED) { SiCNodeSetAttributes(dwIndex, SIC_SELECTED, FALSE, FALSE, dwACFlag, hwndListBox); szToggledReferenceName = SiCNodeGetReferenceName(dwIndex, FALSE, dwACFlag); ResolveDependees(szToggledReferenceName, hwndListBox); } else { SiCNodeSetAttributes(dwIndex, SIC_SELECTED, TRUE, FALSE, dwACFlag, hwndListBox); bMoreToResolve = ResolveDependencies(dwIndex, hwndListBox); while(bMoreToResolve) bMoreToResolve = ResolveDependencies(-1, hwndListBox); szToggledReferenceName = SiCNodeGetReferenceName(dwIndex, FALSE, dwACFlag); ResolveDependees(szToggledReferenceName, hwndListBox); } InvalidateLBCheckbox(hwndListBox); } } // ************************************************************************ // FUNCTION : SubclassWindow( HWND, WNDPROC ) // PURPOSE : Subclasses a window procedure // COMMENTS : Returns the old window procedure // ************************************************************************ WNDPROC SubclassWindow( HWND hWnd, WNDPROC NewWndProc) { WNDPROC OldWndProc; OldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC); SetWindowLong(hWnd, GWL_WNDPROC, (LONG) NewWndProc); return OldWndProc; } // ************************************************************************ // FUNCTION : NewDialogWndProc( HWND, UINT, WPARAM, LPARAM ) // PURPOSE : Processes messages for the Welcome and Finish dialogs. // COMMENTS : Paints all static control backgrounds in white. // ************************************************************************ LRESULT CALLBACK NewDialogWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CTLCOLORSTATIC: return (HRESULT)GetStockObject(WHITE_BRUSH); } return(CallWindowProc(OldDialogWndProc, hWnd, uMsg, wParam, lParam)); } // ************************************************************************ // FUNCTION : NewListBoxWndProc( HWND, UINT, WPARAM, LPARAM ) // PURPOSE : Processes messages for "LISTBOX" class. // COMMENTS : Prevents the user from moving the window // by dragging the titlebar. // ************************************************************************ LRESULT CALLBACK NewListBoxWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DWORD dwPosX; DWORD dwPosY; DWORD dwIndex; switch(uMsg) { case WM_CHAR: /* check for the space key */ if((TCHAR)wParam == 32) { dwIndex = SendMessage(hWnd, LB_GETCURSEL, 0, 0); ToggleCheck(hWnd, dwIndex, gdwACFlag); } break; case WM_LBUTTONDOWN: if(wParam == MK_LBUTTON) { dwPosX = LOWORD(lParam); // x pos dwPosY = HIWORD(lParam); // y pos if((dwPosX > 1) && (dwPosX <= CX_CHECKBOX)) { dwIndex = LOWORD(SendMessage(hWnd, LB_ITEMFROMPOINT, 0, (LPARAM)MAKELPARAM(dwPosX, dwPosY))); ToggleCheck(hWnd, dwIndex, gdwACFlag); } } break; } return(CallWindowProc(OldListBoxWndProc, hWnd, uMsg, wParam, lParam)); } LRESULT CALLBACK DlgProcSelectComponents(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { siC *siCTemp; DWORD dwIndex; DWORD dwItems = MAX_BUF; HWND hwndLBComponents; LPDRAWITEMSTRUCT lpdis; #ifdef STUB_INSTALLER TCHAR tchBuffer[MAX_BUF]; ULONGLONG ullDSBuf; char szBuf[MAX_BUF]; #endif LPNMHDR notifyMessage; hwndLBComponents = GetDlgItem(hDlg, IDC_LIST_COMPONENTS); switch(msg) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDC_MESSAGE0, diSelectComponents.szMessage0); SendDlgItemMessage(hDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); siCTemp = siComponents; if(siCTemp != NULL) { if((!(siCTemp->dwAttributes & SIC_INVISIBLE)) && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) lbAddItem(hwndLBComponents, siCTemp); siCTemp = siCTemp->Next; while((siCTemp != siComponents) && (siCTemp != NULL)) { if((!(siCTemp->dwAttributes & SIC_INVISIBLE)) && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) lbAddItem(hwndLBComponents, siCTemp); siCTemp = siCTemp->Next; } SetFocus(hwndLBComponents); SendMessage(hwndLBComponents, LB_SETCURSEL, 0, 0); SetDlgItemText(hDlg, IDC_STATIC_DESCRIPTION, SiCNodeGetDescriptionLong(0, FALSE, AC_COMPONENTS)); SendDlgItemMessage(hDlg, IDC_STATIC_DESCRIPTION, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); } SetDlgItemText(hDlg, IDC_STATIC1, sgInstallGui.szComponents_); SetDlgItemText(hDlg, IDC_STATIC2, sgInstallGui.szDescription); SendDlgItemMessage(hDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); #ifdef STUB_INSTALLER // XXXben We don't support net stub installs yet. SetDlgItemText(hDlg, IDC_STATIC_DOWNLOAD_SIZE, sgInstallGui.szTotalDownloadSize); SendDlgItemMessage(hDlg, IDC_STATIC_DOWNLOAD_SIZE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); #endif SendDlgItemMessage(hDlg, IDC_LIST_COMPONENTS, WM_SETFONT, (WPARAM)sgInstallGui.systemFont, 0L); gdwACFlag = AC_COMPONENTS; OldListBoxWndProc = SubclassWindow(hwndLBComponents, (WNDPROC)NewListBoxWndProc); break; case WM_DRAWITEM: lpdis = (LPDRAWITEMSTRUCT)lParam; // If there are no list box items, skip this message. if(lpdis->itemID == -1) break; DrawLBText(lpdis, AC_COMPONENTS); DrawCheck(lpdis, AC_COMPONENTS); // draw the focus rect on the selected item if((lpdis->itemAction & ODA_FOCUS) && (lpdis->itemState & ODS_FOCUS)) DrawFocusRect(lpdis->hDC, &(lpdis->rcItem)); break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_LIST_COMPONENTS: /* to update the long description for each component the user selected */ if((dwIndex = SendMessage(hwndLBComponents, LB_GETCURSEL, 0, 0)) != LB_ERR) { SetDlgItemText(hDlg, IDC_STATIC_DESCRIPTION, SiCNodeGetDescriptionLong(dwIndex, FALSE, AC_COMPONENTS)); #ifdef STUB_INSTALLER // update the disk space required info in the dialog. It is already // in Kilobytes ullDSBuf = GetDiskSpaceRequired(DSR_DOWNLOAD_SIZE); _ui64toa(ullDSBuf, tchBuffer, 10); wsprintf(szBuf, sgInstallGui.szDownloadSize, tchBuffer); // XXXben We don't support net stub installs yet. // SetDlgItemText(hDlg, IDC_STATIC_DOWNLOAD_SIZE, szBuf); #endif } break; } break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diSelectComponents.szTitle); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); break; case PSN_WIZBACK: // If we showed the "Upgrade" panel, be sure to show it again in the sequence // on the way back, to not do so "feels" wrong/confusing. if (gDidShowUpgradePanel) SetWindowLong(hDlg, DWL_MSGRESULT, DLG_UPGRADE); else SetWindowLong(hDlg, DWL_MSGRESULT, DLG_SELECT_INSTALL_PATH); return TRUE; break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; } return 0; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: SUMMARY // BOOL IsSelectableComponent(siC* aComponent) { return !(aComponent->dwAttributes & SIC_INVISIBLE) && !(aComponent->dwAttributes & SIC_ADDITIONAL); } BOOL IsComponentSelected(siC* aComponent) { return aComponent->dwAttributes & SIC_SELECTED; } void GetRelativeRect(HWND aWindow, int aResourceID, RECT* aRect) { HWND ctrl; POINT pt; ctrl = GetDlgItem(aWindow, aResourceID); GetWindowRect(ctrl, aRect); pt.x = aRect->left; pt.y = aRect->top; ScreenToClient(aWindow, &pt); aRect->left = pt.x; aRect->top = pt.y; pt.x = aRect->right; pt.y = aRect->bottom; ScreenToClient(aWindow, &pt); aRect->right = pt.x; aRect->bottom = pt.y; } void PositionControl(HWND aWindow, int aResourceIDRelative, int aResourceIDControl, int aOffset) { HWND ctrl; RECT r1, r2; GetRelativeRect(aWindow, aResourceIDRelative, &r1); GetRelativeRect(aWindow, aResourceIDControl, &r2); ctrl = GetDlgItem(aWindow, aResourceIDControl); SetWindowPos(ctrl, NULL, r2.left, r1.bottom + aOffset, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } LRESULT CALLBACK DlgProcSummary(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { LPSTR szMessage = NULL; LPNMHDR notifyMessage; char szAddtlComps[MAX_BUF]; char szTemp[MAX_BUF]; char szFormat[MAX_BUF_TINY]; BOOL hasAddtlComps = FALSE; BOOL skipNext = FALSE; siC *currComponent, *mainComponent; HICON largeIcon, smallIcon; DWORD result; HKEY theKey; switch(msg) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDC_MESSAGE1, diStartInstall.szMessage0); SetDlgItemText(hDlg, IDC_MESSAGE2, sgInstallGui.szProxyMessage); SetDlgItemText(hDlg, IDC_CONNECTION_SETTINGS, sgInstallGui.szProxyButton); SetDlgItemText(hDlg, IDC_INSTALL_FOLDER_LABEL, sgInstallGui.szInstallFolder); SendDlgItemMessage(hDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_MESSAGE1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_MESSAGE2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_CONNECTION_SETTINGS, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_INSTALL_FOLDER_LABEL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_INSTALL_FOLDER, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_PRIMARY_COMPONENT, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_OPTIONAL_COMPONENTS, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); ExtractIconEx("setuprsc.dll", 1, &largeIcon, &smallIcon, 1); SendMessage(GetDlgItem(hDlg, IDC_APP_ICON), STM_SETICON, (LPARAM)smallIcon, 0); break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diSelectComponents.szTitle); // Set the user-determined fields here in case they go back and change // options - WM_INITDIALOG only gets called once, not every time the // panel is displayed. #ifdef STUB_INSTALLER // Update strings that relate to whether or not files will be downloaded. // The user may have selected additional components that require a download. if ((diAdvancedSettings.bShowDialog == FALSE) || (GetTotalArchivesToDownload() == 0)) { #endif SetDlgItemText(hDlg, IDC_MESSAGE0, diStartInstall.szMessageInstall); // Hide Download-related UI: ShowWindow(GetDlgItem(hDlg, IDC_MESSAGE2), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_CONNECTION_SETTINGS), SW_HIDE); #ifdef STUB_INSTALLER } else SetDlgItemText(hDlg, IDC_MESSAGE0, diStartInstall.szMessageDownload); #endif // Update the registry keys that the installer scripts use to determine // what shortcuts to create result = RegCreateKeyEx(HKEY_CURRENT_USER, diWindowsIntegration.szRegistryKey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &theKey, NULL); if (result == ERROR_SUCCESS) { RegSetValueEx(theKey, "Create Desktop Shortcut", 0, REG_DWORD, (LPBYTE)&(diWindowsIntegration.wiCB0.bCheckBoxState), sizeof(DWORD)); RegSetValueEx(theKey, "Create Start Menu Shortcut", 0, REG_DWORD, (LPBYTE)&(diWindowsIntegration.wiCB1.bCheckBoxState), sizeof(DWORD)); RegSetValueEx(theKey, "Create Quick Launch Shortcut", 0, REG_DWORD, (LPBYTE)&(diWindowsIntegration.wiCB2.bCheckBoxState), sizeof(DWORD)); RegCloseKey(theKey); } // Show the components we're going to install szAddtlComps[0] = '\0'; currComponent = siComponents; do { if (!currComponent) break; if (currComponent->dwAttributes & SIC_MAIN_COMPONENT) mainComponent = currComponent; else if (IsSelectableComponent(currComponent) && IsComponentSelected(currComponent)) { wsprintf(szFormat, "%s\r\n", sgInstallGui.szAddtlCompWrapper); wsprintf(szTemp, szFormat, currComponent->szDescriptionShort); lstrcat(szAddtlComps, szTemp); hasAddtlComps = TRUE; } currComponent = currComponent->Next; } while (currComponent && currComponent != siComponents); // Update the display to reflect whether or not additional components are going to // be installed. If none are, we shift the install folder detail up so that it's // neatly under the Primary Component name. if (hasAddtlComps) { wsprintf(szTemp, sgInstallGui.szPrimCompOthers, mainComponent->szDescriptionShort); ShowWindow(GetDlgItem(hDlg, IDC_OPTIONAL_COMPONENTS), SW_SHOW); SetDlgItemText(hDlg, IDC_OPTIONAL_COMPONENTS, szAddtlComps); PositionControl(hDlg, IDC_OPTIONAL_COMPONENTS, IDC_INSTALL_FOLDER_LABEL, 10); } else { wsprintf(szTemp, sgInstallGui.szPrimCompNoOthers, mainComponent->szDescriptionShort); ShowWindow(GetDlgItem(hDlg, IDC_OPTIONAL_COMPONENTS), SW_HIDE); // Shift the "Install Folder" text up in the "No Components" case PositionControl(hDlg, IDC_PRIMARY_COMPONENT, IDC_INSTALL_FOLDER_LABEL, 10); } PositionControl(hDlg, IDC_INSTALL_FOLDER_LABEL, IDC_INSTALL_FOLDER, 10); PositionControl(hDlg, IDC_INSTALL_FOLDER_LABEL, IDC_FOLDER_ICON, 7); SetDlgItemText(hDlg, IDC_PRIMARY_COMPONENT, szTemp); // Update the install folder. InitPathDisplay(hDlg, sgProduct.szPath, IDC_FOLDER_ICON, IDC_INSTALL_FOLDER); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); break; case PSN_WIZNEXT: SaveUserChanges(); if (!IsDownloadRequired()) { // No download required, bypass the download step and go directly to // the installing stage. SetWindowLong(hDlg, DWL_MSGRESULT, DLG_EXTRACTING); skipNext = TRUE; } break; case PSN_WIZBACK: // If the user selected Easy Install, go right back to the setup type // selection page, bypassing the advanced configuration steps. if (dwSetupType == ST_RADIO0) { // If we showed the "Upgrade" panel, be sure to show it again in the sequence // on the way back, to not do so "feels" wrong/confusing. if (gDidShowUpgradePanel) SetWindowLong(hDlg, DWL_MSGRESULT, DLG_UPGRADE); else SetWindowLong(hDlg, DWL_MSGRESULT, DLG_SETUP_TYPE); skipNext = TRUE; } break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_CONNECTION_SETTINGS: break; } break; } return skipNext; } void SaveUserChanges() { char szDestPath[MAX_BUF]; char szInstallLogFile[MAX_BUF]; LogISShared(); LogISDestinationPath(); LogISSetupType(); LogISComponentsSelected(); LogISComponentsToDownload(); LogISDiskSpace(gdsnComponentDSRequirement); lstrcpy(szDestPath, sgProduct.szPath); if(*sgProduct.szSubPath != '\0') { AppendBackSlash(szDestPath, sizeof(szDestPath)); lstrcat(szDestPath, sgProduct.szSubPath); } AppendBackSlash(szDestPath, sizeof(szDestPath)); // Create the destination path here in case it had not been created, // as in the case of silent or auto mode installs if(CreateDirectoriesAll(szDestPath, ADD_TO_UNINSTALL_LOG) != WIZ_OK) { char buf[MAX_BUF]; char errorCreateDir[MAX_BUF]; char pathToShow[MAX_PATH]; // reformat the path to display so that it'll be readable in the // error dialog shown _snprintf(pathToShow, sizeof(pathToShow), "\"%s\" ", szDestPath); pathToShow[sizeof(pathToShow) - 1] = '\0'; if(GetPrivateProfileString("Messages", "ERROR_CREATE_DIRECTORY", "", errorCreateDir, sizeof(errorCreateDir), szFileIniInstall)) wsprintf(buf, errorCreateDir, pathToShow); assert(*buf != '\0'); PrintError(buf, ERROR_CODE_HIDE); PostQuitMessage(1); return; } // Set global var, that determines where the log file is to update, to // not use the TEMP dir *before* the FileCopy() calls because we want // to log the FileCopy() calls to where the log files were copied to. // This is possible because the logging, that is done within the // FileCopy() function, is done after the actual copy // gbILUseTemp = FALSE; // copy the install_wizard.log file from the temp\ns_temp dir to // the destination dir and use the new destination file to continue // logging. // lstrcpy(szInstallLogFile, szTempDir); AppendBackSlash(szInstallLogFile, sizeof(szInstallLogFile)); lstrcat(szInstallLogFile, FILE_INSTALL_LOG); FileCopy(szInstallLogFile, szDestPath, FALSE, FALSE); DeleteFile(szInstallLogFile); // copy the install_status.log file from the temp\ns_temp dir to // the destination dir and use the new destination file to continue // logging. // lstrcpy(szInstallLogFile, szTempDir); AppendBackSlash(szInstallLogFile, sizeof(szInstallLogFile)); lstrcat(szInstallLogFile, FILE_INSTALL_STATUS_LOG); FileCopy(szInstallLogFile, szDestPath, FALSE, FALSE); DeleteFile(szInstallLogFile); } BOOL IsDownloadRequired() { DWORD dwIndex0; DWORD dwFileCounter; siC *siCObject = NULL; long result; char szFileIdiGetArchives[MAX_BUF]; char szSection[MAX_BUF]; char szCorruptedArchiveList[MAX_BUF]; char szPartiallyDownloadedFilename[MAX_BUF]; ZeroMemory(szCorruptedArchiveList, sizeof(szCorruptedArchiveList)); lstrcpy(szFileIdiGetArchives, szTempDir); AppendBackSlash(szFileIdiGetArchives, sizeof(szFileIdiGetArchives)); lstrcat(szFileIdiGetArchives, FILE_IDI_GETARCHIVES); GetSetupCurrentDownloadFile(szPartiallyDownloadedFilename, sizeof(szPartiallyDownloadedFilename)); gbDownloadTriggered= FALSE; result = WIZ_OK; dwIndex0 = 0; dwFileCounter = 0; siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL); while (siCObject) { if (siCObject->dwAttributes & SIC_SELECTED) { // If a previous unfinished setup was detected, then // include the TEMP dir when searching for archives. // Only download jars if not already in the local machine. // Also if the last file being downloaded should be resumed. // The resume detection is done automatically. if ((LocateJar(siCObject, NULL, 0, gbPreviousUnfinishedDownload) == AP_NOT_FOUND) || (lstrcmpi(szPartiallyDownloadedFilename, siCObject->szArchiveName) == 0)) { wsprintf(szSection, "File%d", dwFileCounter); result = AddArchiveToIdiFile(siCObject, szSection, szFileIdiGetArchives); if (result) return result; ++dwFileCounter; } } ++dwIndex0; siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL); } // The existence of the getarchives.idi file determines if there are // any archives needed to be downloaded. return FileExists(szFileIdiGetArchives); } #ifdef STUB_INSTALLER /////////////////////////////////////////////////////////////////////////////// // DIALOG: CONNECTION SETTINGS // void SaveDownloadProtocolOption(HWND hDlg) { if(IsDlgButtonChecked(hDlg, IDC_USE_FTP) == BST_CHECKED) diAdditionalOptions.dwUseProtocol = UP_FTP; else if(IsDlgButtonChecked(hDlg, IDC_USE_HTTP) == BST_CHECKED) diAdditionalOptions.dwUseProtocol = UP_HTTP; } LRESULT CALLBACK DlgProcAdvancedSettings(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { char szBuf[MAX_BUF]; switch(msg) { case WM_INITDIALOG: SetWindowText(hDlg, diAdvancedSettings.szTitle); SetDlgItemText(hDlg, IDC_MESSAGE0, diAdvancedSettings.szMessage0); SetDlgItemText(hDlg, IDC_EDIT_PROXY_SERVER, diAdvancedSettings.szProxyServer); SetDlgItemText(hDlg, IDC_EDIT_PROXY_PORT, diAdvancedSettings.szProxyPort); SetDlgItemText(hDlg, IDC_EDIT_PROXY_USER, diAdvancedSettings.szProxyUser); SetDlgItemText(hDlg, IDC_EDIT_PROXY_PASSWD, diAdvancedSettings.szProxyPasswd); GetIniConfigProfileString("Strings", "IDC Use Ftp", "", szBuf, sizeof(szBuf)); SetDlgItemText(hDlg, IDC_USE_FTP, szBuf); GetIniConfigProfileString("Strings", "IDC Use Http", "", szBuf, sizeof(szBuf)); SetDlgItemText(hDlg, IDC_USE_HTTP, szBuf); SetDlgItemText(hDlg, IDC_STATIC, sgInstallGui.szProxySettings); SetDlgItemText(hDlg, IDC_STATIC1, sgInstallGui.szServer); SetDlgItemText(hDlg, IDC_STATIC2, sgInstallGui.szPort); SetDlgItemText(hDlg, IDC_STATIC3, sgInstallGui.szUserId); SetDlgItemText(hDlg, IDC_STATIC4, sgInstallGui.szPassword); SetDlgItemText(hDlg, IDWIZNEXT, sgInstallGui.szOk_); SetDlgItemText(hDlg, IDCANCEL, sgInstallGui.szCancel_); SendDlgItemMessage (hDlg, IDC_STATIC, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDC_STATIC2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDC_STATIC3, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDC_STATIC4, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDWIZNEXT, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDCANCEL, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDC_EDIT_PROXY_SERVER, WM_SETFONT, (WPARAM)sgInstallGui.systemFont, 0L); SendDlgItemMessage (hDlg, IDC_EDIT_PROXY_PORT, WM_SETFONT, (WPARAM)sgInstallGui.systemFont, 0L); SendDlgItemMessage (hDlg, IDC_EDIT_PROXY_USER, WM_SETFONT, (WPARAM)sgInstallGui.systemFont, 0L); SendDlgItemMessage (hDlg, IDC_EDIT_PROXY_PASSWD, WM_SETFONT, (WPARAM)sgInstallGui.systemFont, 0L); SendDlgItemMessage (hDlg, IDC_USE_FTP, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage (hDlg, IDC_USE_HTTP, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); switch(diAdditionalOptions.dwUseProtocol) { case UP_HTTP: CheckDlgButton(hDlg, IDC_USE_FTP, BST_UNCHECKED); CheckDlgButton(hDlg, IDC_USE_HTTP, BST_CHECKED); break; case UP_FTP: default: CheckDlgButton(hDlg, IDC_USE_FTP, BST_CHECKED); CheckDlgButton(hDlg, IDC_USE_HTTP, BST_UNCHECKED); break; } if((diAdditionalOptions.bShowProtocols) && (diAdditionalOptions.bUseProtocolSettings)) { ShowWindow(GetDlgItem(hDlg, IDC_USE_FTP), SW_SHOW); ShowWindow(GetDlgItem(hDlg, IDC_USE_HTTP), SW_SHOW); } else { ShowWindow(GetDlgItem(hDlg, IDC_USE_FTP), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_USE_HTTP), SW_HIDE); } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDWIZNEXT: /* get the proxy server and port information */ GetDlgItemText(hDlg, IDC_EDIT_PROXY_SERVER, diAdvancedSettings.szProxyServer, MAX_BUF); GetDlgItemText(hDlg, IDC_EDIT_PROXY_PORT, diAdvancedSettings.szProxyPort, MAX_BUF); GetDlgItemText(hDlg, IDC_EDIT_PROXY_USER, diAdvancedSettings.szProxyUser, MAX_BUF); GetDlgItemText(hDlg, IDC_EDIT_PROXY_PASSWD, diAdvancedSettings.szProxyPasswd, MAX_BUF); SaveDownloadProtocolOption(hDlg); DestroyWindow(hDlg); break; case IDWIZBACK: case IDCANCEL: DestroyWindow(hDlg); break; default: break; } break; } return(0); } #endif /////////////////////////////////////////////////////////////////////////////// // DIALOG: DOWNLOADING FILES // LRESULT CALLBACK DlgProcDownloading(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { #ifdef STUB_INSTALLER switch(msg) { case WM_INITDIALOG: SetWindowText(hDlg, diDownloading.szTitle); SetDlgItemText(hDlg, IDC_MESSAGE0, diDownloading.szBlurb); SetDlgItemText(hDlg, IDC_STATIC0, diDownloading.szFileNameKey); SetDlgItemText(hDlg, IDC_STATIC1, diDownloading.szTimeRemainingKey); SendDlgItemMessage(hDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); break; case WM_COMMAND: switch(LOWORD(wParam)) { default: break; } break; } #endif return 0; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: INSTALLING FILES // #define BTN_CLSNAME_LEN 7 #define BTN_CANCEL_OFFSET 4 BOOL CALLBACK DisableCancelButton(HWND aWindow, LPARAM aData) { static int offset = 0; char className[BTN_CLSNAME_LEN]; char text[MAX_BUF]; GetClassName(aWindow, className, BTN_CLSNAME_LEN); if (!strcmp(className, "Button") && GetParent(aWindow) == (HWND)aData) { GetWindowText(aWindow, text, MAX_BUF-1); if (++offset == BTN_CANCEL_OFFSET) { offset = 0; EnableWindow(aWindow, FALSE); return FALSE; } } return TRUE; } LRESULT CALLBACK DlgProcInstalling(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { LPNMHDR notifyMessage; static BOOL initialized = FALSE; HWND parent = GetParent(hDlg); char installStart[MAX_BUF]; switch(msg) { case WM_INITDIALOG: SetWindowText(hDlg, diInstalling.szTitle); SetDlgItemText(hDlg, IDC_STATUS0, diInstalling.szStatusFile); SetDlgItemText(hDlg, IDC_STATUS3, diInstalling.szStatusComponent); SendDlgItemMessage(hDlg, IDC_STATUS0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATUS3, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); break; case WM_PAINT: if (initialized) break; initialized = TRUE; if (InstallFiles(hDlg)) { if (sgProduct.mode != AUTO) { PropSheet_SetCurSelByID(parent, DLG_INSTALL_SUCCESSFUL); } break; } else { // XXXben TODO: handle error. printf("Files NOT Installed...\n"); } break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(parent, 0, (LPTSTR)diInstalling.szTitle); GetPrivateProfileString("Messages", "MSG_SMARTUPDATE_START", "", installStart, sizeof(installStart), szFileIniInstall); SetDlgItemText(hDlg, IDC_STATUS0, installStart); if (sgProduct.mode != AUTO) { // Disable the Cancel button. This leaves the button disabled for // this page (Installing) and the final page (Finish) because it // is meaningless and potentially damaging in both places. EnumChildWindows(parent, DisableCancelButton, (LPARAM)parent); PropSheet_SetWizButtons(parent, 0); } break; case PSN_QUERYCANCEL: // Do NOT let the user cancel at this point. SetWindowLong(hDlg, DWL_MSGRESULT, (LONG)FALSE); return TRUE; } } return 0; } BOOL InstallFiles(HWND hDlg) { HRESULT err; // Clean up old versions of GRE previously installed. // These GREs should only be fully uninstalled if they were only // being used by the mozilla that we're installing over/ontop of // (upgrade scenario). // We should only do this type of cleanup if we're about to install' // GRE in shared mode. // // This should only be called when the installer is installing GRE! if (IsInstallerProductGRE()) CleanupOrphanedGREs(); if (sgProduct.bInstallFiles) { // POST_DOWNLOAD process file manipulation functions ProcessFileOpsForAll(T_POST_DOWNLOAD); // PRE_XPCOM process file manipulation functions ProcessFileOpsForAll(T_PRE_XPCOM); // save the installer files in the local machine if (diAdditionalOptions.bSaveInstaller) SaveInstallerFiles(); if (CheckInstances()) { bSDUserCanceled = TRUE; CleanupXpcomFile(); return FALSE; } // Remove the previous installation of the product here. // This should be done before processing the Xpinstall engine. if(sgProduct.doCleanupOnUpgrade) { SetSetupState(SETUP_STATE_REMOVING_PREV_INST); CleanupOnUpgrade(); } if(gbDownloadTriggered || gbPreviousUnfinishedDownload) SetSetupState(SETUP_STATE_UNPACK_XPCOM); if(ProcessXpinstallEngine() != WIZ_OK) { bSDUserCanceled = TRUE; CleanupXpcomFile(); return FALSE; } if (gbDownloadTriggered || gbPreviousUnfinishedDownload) SetSetupState(SETUP_STATE_INSTALL_XPI); // clears and sets new setup state // POST_XPCOM process file manipulation functions ProcessFileOpsForAll(T_POST_XPCOM); // PRE_SMARTUPDATE process file manipulation functions ProcessFileOpsForAll(T_PRE_SMARTUPDATE); //XXXben TODO - process this return result! err = SmartUpdateJars(hDlg); } else err = WIZ_OK; CleanupXpcomFile(); return err == WIZ_OK || err == 999; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: WINTEGRATION // Not actually used yet! LRESULT CALLBACK DlgProcWindowsIntegration(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { LPNMHDR notifyMessage; switch (msg) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDC_MESSAGE0, diWindowsIntegration.szMessage0); SendDlgItemMessage(hDlg, IDC_MESSAGE0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); if (diWindowsIntegration.wiCB0.bEnabled) { ShowWindow(GetDlgItem(hDlg, IDC_CHECK0), SW_SHOW); SetDlgItemText(hDlg, IDC_CHECK0, diWindowsIntegration.wiCB0.szDescription); SendDlgItemMessage(hDlg, IDC_CHECK0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); } else ShowWindow(GetDlgItem(hDlg, IDC_CHECK0), SW_HIDE); if (diWindowsIntegration.wiCB1.bEnabled) { ShowWindow(GetDlgItem(hDlg, IDC_CHECK1), SW_SHOW); SetDlgItemText(hDlg, IDC_CHECK1, diWindowsIntegration.wiCB1.szDescription); SendDlgItemMessage(hDlg, IDC_CHECK1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); } else ShowWindow(GetDlgItem(hDlg, IDC_CHECK1), SW_HIDE); if (diWindowsIntegration.wiCB2.bEnabled) { ShowWindow(GetDlgItem(hDlg, IDC_CHECK2), SW_SHOW); SetDlgItemText(hDlg, IDC_CHECK2, diWindowsIntegration.wiCB2.szDescription); SendDlgItemMessage(hDlg, IDC_CHECK2, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); } else ShowWindow(GetDlgItem(hDlg, IDC_CHECK2), SW_HIDE); break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diWindowsIntegration.szTitle); // Restore state from default or cached value. CheckDlgButton(hDlg, IDC_CHECK0, diWindowsIntegration.wiCB0.bCheckBoxState); CheckDlgButton(hDlg, IDC_CHECK1, diWindowsIntegration.wiCB1.bCheckBoxState); CheckDlgButton(hDlg, IDC_CHECK2, diWindowsIntegration.wiCB2.bCheckBoxState); PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT|PSWIZB_BACK); break; case PSN_WIZNEXT: diWindowsIntegration.wiCB0.bCheckBoxState = IsDlgButtonChecked(hDlg, IDC_CHECK0) == BST_CHECKED; diWindowsIntegration.wiCB1.bCheckBoxState = IsDlgButtonChecked(hDlg, IDC_CHECK1) == BST_CHECKED; diWindowsIntegration.wiCB2.bCheckBoxState = IsDlgButtonChecked(hDlg, IDC_CHECK2) == BST_CHECKED; break; case PSN_QUERYCANCEL: return !ShouldExitSetup(hDlg); } break; } return 0; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: SUCCESSFUL INSTALL // LRESULT CALLBACK DlgProcInstallSuccessful(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { char szBuf[MAX_BUF]; LPNMHDR notifyMessage; static BOOL launchAppChecked = TRUE; DWORD result; switch(msg) { case WM_INITDIALOG: // UI Text, from localized config files SetDlgItemText(hDlg, IDC_STATIC_TITLE, diInstallSuccessful.szMessageHeader); wsprintf(szBuf, diInstallSuccessful.szMessage0, sgProduct.szProductName); SetDlgItemText(hDlg, IDC_STATIC0, szBuf); SetDlgItemText(hDlg, IDC_STATIC1, diInstallSuccessful.szMessage1); wsprintf(szBuf, diInstallSuccessful.szLaunchApp, sgProduct.szProductName); SetDlgItemText(hDlg, IDC_START_APP, szBuf); // The header on the welcome page uses another font. SendDlgItemMessage(hDlg, IDC_STATIC_TITLE, WM_SETFONT, (WPARAM)sgInstallGui.welcomeTitleFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC0, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); SendDlgItemMessage(hDlg, IDC_START_APP, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); launchAppChecked = diInstallSuccessful.bLaunchAppChecked; // Subclass dialog to paint all static controls white. OldDialogWndProc = SubclassWindow(hDlg, (WNDPROC)NewDialogWndProc); break; case WM_NOTIFY: notifyMessage = (LPNMHDR)lParam; switch (notifyMessage->code) { case PSN_SETACTIVE: // Wizard dialog title PropSheet_SetTitle(GetParent(hDlg), 0, (LPTSTR)diInstallSuccessful.szTitle); // Restore state from default or cached value. CheckDlgButton(hDlg, IDC_START_APP, launchAppChecked ? BST_CHECKED : BST_UNCHECKED); // Don't show the back button here UNLESS the previous // page was Windows Integration - and that only happens on a custom // install. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH); break; case PSN_WIZBACK: // Store the checkbox state in case the user goes back to any post-install // pages that we might add. launchAppChecked = IsDlgButtonChecked(hDlg, IDC_START_APP) == BST_CHECKED; break; case PSN_WIZFINISH: // Store state from the "Run App Now" checkbox. ProcessFileOpsForAll // uses this variable to decide whether or not to launch the browser. gbIgnoreRunAppX = IsDlgButtonChecked(hDlg, IDC_START_APP) != BST_CHECKED; // Apply settings and close. if (sgProduct.bInstallFiles) UpdateJSProxyInfo(); /* POST_SMARTUPDATE process file manipulation functions */ ProcessFileOpsForAll(T_POST_SMARTUPDATE); if (sgProduct.bInstallFiles) { /* PRE_LAUNCHAPP process file manipulation functions */ ProcessFileOpsForAll(T_PRE_LAUNCHAPP); LaunchApps(); // Refresh system icons if necessary if (gSystemInfo.bRefreshIcons) RefreshIcons(); UnsetSetupState(); // clear setup state if (!gbIgnoreProgramFolderX) ProcessProgramFolderShowCmd(); CleanupArgsRegistry(); CleanupPreviousVersionRegKeys(); /* POST_LAUNCHAPP process file manipulation functions */ ProcessFileOpsForAll(T_POST_LAUNCHAPP); /* DEPEND_REBOOT process file manipulation functions */ ProcessFileOpsForAll(T_DEPEND_REBOOT); } break; case PSN_QUERYCANCEL: // Cancel is meaningless and potentially harmful here (the install work // is not yet complete). If the user finds a way of cancelling, e.g. by // clicking the X button on the window, send the FINISH message. // Assume at least that they didn't want the app to run right away. gbIgnoreRunAppX = FALSE; // Send the PSN_WIZFINISH so we can clean up properly. notifyMessage->code = PSN_WIZFINISH; SendMessage(hDlg, WM_NOTIFY, wParam, (LPARAM)notifyMessage); // Tell the Wizard97 framework that we don't want to hard-quit. Processing // of the PSN_WIZFINISH will cause the app to shut down. SetWindowLong(hDlg, DWL_MSGRESULT, FALSE); return TRUE; } break; } return 0; } /////////////////////////////////////////////////////////////////////////////// // DIALOG: MESSAGE (A small utility message window) // LRESULT CALLBACK DlgProcMessage(HWND hDlg, UINT msg, WPARAM wParam, LONG lParam) { RECT rDlg; HWND hSTMessage = GetDlgItem(hDlg, IDC_MESSAGE); /* handle to the Static Text message window */ HDC hdcSTMessage; SIZE sizeString; LOGFONT logFont; HFONT hfontTmp; HFONT hfontOld; char szBuf[MAX_BUF]; char szBuf2[MAX_BUF]; ZeroMemory(szBuf, sizeof(szBuf)); ZeroMemory(szBuf2, sizeof(szBuf2)); switch(msg) { case WM_INITDIALOG: if(GetPrivateProfileString("Messages", "STR_MESSAGEBOX_TITLE", "", szBuf2, sizeof(szBuf2), szFileIniInstall)) { if((sgProduct.szProductName != NULL) && (*sgProduct.szProductName != '\0')) wsprintf(szBuf, szBuf2, sgProduct.szProductName); else wsprintf(szBuf, szBuf2, ""); } else if((sgProduct.szProductName != NULL) && (*sgProduct.szProductName != '\0')) lstrcpy(szBuf, sgProduct.szProductName); SetWindowText(hDlg, szBuf); SendDlgItemMessage(hDlg, IDC_MESSAGE, WM_SETFONT, (WPARAM)sgInstallGui.definedFont, 0L); break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_MESSAGE: hdcSTMessage = GetWindowDC(hSTMessage); SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), (PVOID)&logFont, 0); hfontTmp = CreateFontIndirect(&logFont); if(hfontTmp) hfontOld = SelectObject(hdcSTMessage, hfontTmp); GetTextExtentPoint32(hdcSTMessage, (LPSTR)lParam, lstrlen((LPSTR)lParam), &sizeString); SelectObject(hdcSTMessage, hfontOld); DeleteObject(hfontTmp); ReleaseDC(hSTMessage, hdcSTMessage); SetWindowPos(hDlg, NULL, (gSystemInfo.lastWindowPosCenterX)-((sizeString.cx + 55)/2), (gSystemInfo.lastWindowPosCenterY)-((sizeString.cy + 50)/2), sizeString.cx + 55, sizeString.cy + 50, SWP_SHOWWINDOW|SWP_NOZORDER); if(GetClientRect(hDlg, &rDlg)) SetWindowPos(hSTMessage, HWND_TOP, rDlg.left, rDlg.top, rDlg.right, rDlg.bottom, SWP_SHOWWINDOW|SWP_NOZORDER); SetDlgItemText(hDlg, IDC_MESSAGE, (LPSTR)lParam); break; } break; } return(0); } void ShowMessage(LPSTR szMessage, BOOL bShow) { if(sgProduct.mode != SILENT) { if(bShow && szMessage) { char szBuf[MAX_BUF]; ZeroMemory(szBuf, sizeof(szBuf)); GetPrivateProfileString("Messages", "MB_MESSAGE_STR", "", szBuf, sizeof(szBuf), szFileIniInstall); hDlgMessage = InstantiateDialog(hWndMain, DLG_MESSAGE, szBuf, DlgProcMessage); SendMessage(hDlgMessage, WM_COMMAND, IDC_MESSAGE, (LPARAM)szMessage); } else { DestroyWindow(hDlgMessage); hDlgMessage = NULL; } } } /////////////////////////////////////////////////////////////////////////////// // UTILITY FUNCTIONS void ProcessWindowsMessages() { MSG msg; while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } HWND InstantiateDialog(HWND hParent, DWORD dwDlgID, LPSTR szTitle, WNDPROC wpDlgProc) { char szBuf[MAX_BUF]; HWND hDlg = NULL; if((hDlg = CreateDialog(hSetupRscInst, MAKEINTRESOURCE(dwDlgID), hParent, wpDlgProc)) == NULL) { char szEDialogCreate[MAX_BUF]; if(GetPrivateProfileString("Messages", "ERROR_DIALOG_CREATE", "", szEDialogCreate, sizeof(szEDialogCreate), szFileIniInstall)) { wsprintf(szBuf, szEDialogCreate, szTitle); PrintError(szBuf, ERROR_CODE_SHOW); } PostQuitMessage(1); } return(hDlg); } void TruncateString(HWND hWnd, LPSTR szInURL, LPSTR szOutString, DWORD dwOutStringBufSize) { HDC hdcWnd; LOGFONT logFont; HFONT hfontNew; HFONT hfontOld; RECT rWndRect; SIZE sizeString; char *ptr = NULL; int iHalfLen; int iOutStringLen; if((DWORD)lstrlen(szInURL) > dwOutStringBufSize) return; ZeroMemory(szOutString, dwOutStringBufSize); lstrcpy(szOutString, szInURL); iOutStringLen = lstrlen(szOutString); hdcWnd = GetWindowDC(hWnd); GetClientRect(hWnd, &rWndRect); SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), (PVOID)&logFont, 0); hfontNew = CreateFontIndirect(&logFont); if(hfontNew) { hfontOld = (HFONT)SelectObject(hdcWnd, hfontNew); GetTextExtentPoint32(hdcWnd, szOutString, iOutStringLen, &sizeString); while(sizeString.cx > rWndRect.right) { iHalfLen = iOutStringLen / 2; if(iHalfLen == 2) break; ptr = szOutString + iHalfLen; memmove(ptr - 1, ptr, lstrlen(ptr) + 1); szOutString[iHalfLen - 2] = '.'; szOutString[iHalfLen - 1] = '.'; szOutString[iHalfLen] = '.'; iOutStringLen = lstrlen(szOutString); GetTextExtentPoint32(hdcWnd, szOutString, iOutStringLen, &sizeString); } } SelectObject(hdcWnd, hfontOld); DeleteObject(hfontNew); ReleaseDC(hWnd, hdcWnd); } void InitPathDisplay (HWND aWindow, char* aPath, int aFolderIcon, int aFolderField) { HICON largeIcon, smallIcon; char buf[MAX_BUF]; // Folder Icon ExtractIconEx("shell32.dll", 3, &largeIcon, &smallIcon, 1); SendMessage(GetDlgItem(aWindow, aFolderIcon), STM_SETICON, (LPARAM)smallIcon, 0); TruncateString(GetDlgItem(aWindow, aFolderField), aPath, buf, sizeof(buf)); SetDlgItemText(aWindow, aFolderField, buf); }