#include #include // use the standard namespace #if !defined (GSDL_NAMESPACE_BROKEN) #if defined(GSDL_USE_OBJECTSPACE) using namespace ospace::std; #else using namespace std; #endif #endif #include #include #include #include #include "dirSelector.h" #include "common.h" #include "configFile.h" #include "File.h" #include "FilePath.h" #include "FileCopier.h" #include "launchApp.h" #include "unInstall.h" #include "gsRegistry.h" #include "gsPlatform.h" #include "gsProgman.h" #include "gsProfile.h" #include "gsManifest.h" char *app_cmdLine; static char app_name[] = "Greenstone Installer"; HINSTANCE app_instance; HWND app_window; bool config_complete = false; dirSelector *rootSelector = NULL; typedef vector dirSelVector; class GSInstall : public installManager { private: configureFile *configFile; // the installation configure file FilePath *collectPath; // where the collection is currently installed FilePath *installToPath; // the first cut at a destination folder FilePath *sourcePath; // the root source folder FilePath *gsdlSourcePath; // the gsdl folder in the source area FilePath *destinationPath; // where the executables will be installed to FilePath *dataDestPath; // where the collection data files will go bool installVolume; // whether to install collection data bool installFullVolume; // whether to install all collection data dirSelVector selectedDirs; // configuration objects gsPlatform platform; // platform information gsRegistry *gsRegister; // registry gsManifest *manifest; // manifest of files gsProgramManager *progman; // program manager connection string setupExe; // form to use for gs(s)setup.exe void getSourcePath(); void getExistingInstall(); public: bool installExe; bool offerNetscape; GSInstall(bool uninstall); FilePath *collectionPath(); FilePath *installPath(); FilePath *installSourcePath() { return this->sourcePath; } string setupExeLeaf() { return this->setupExe; } bool copyFiles(); bool updateRegistry(); bool updateProfiles(); bool updateProgman(); bool updateSetupExe(); bool installNetscape(); bool removeFailed(string file) { return this->manifest->undoFailed(file); } void setDestination(); bool setUninstall(); void uninstall(); void setManifest(); void addSelectedDir(dirSelector *selector); }; static string gsdl_DBHOME = "gdbmhome"; static string gsdl_VLHOME = "gsdlhome"; static string gsdl_STATIC = "staticpath"; static string gsdl_COLLIST= "collections"; void gsInstall_getDesktopExt(int *sx, int *sy) { HDC dc = GetDC(GetDesktopWindow()); *sx = GetDeviceCaps(dc, HORZRES); *sy = GetDeviceCaps(dc, VERTRES); ReleaseDC(GetDesktopWindow(), dc); } /** * Get various and nefarious details before we start trying an installation. * The installation configuration file is read, we seek for an existing * installation and reconfigure the default install settings appropriately. * THe source path is also discovered. */ GSInstall::GSInstall(bool uninstall) : installManager() { // get the installation configuration file this->configFile = new configureFile("install.cfg"); // set up "default" installation bits this->installToPath = new FilePath("C:\\GSDL"); this->collectPath = NULL; this->installExe = true; // we must install the exe files this->offerNetscape = (this->configFile->getString("OfferNetscape") == "1"); // don't attempt this with windows 3.1 if (!this->platform.isWindows32s()) { // get the registry this->gsRegister = new gsRegistry(*this, *this->configFile); this->setupExe = "gssetup.exe"; } else { // TODO: in windows 3.1 we can't use the register as it isn't fully/properly // implemented; we must get the existing path information from elsewhere this->gsRegister = new gsRegistry(*this, *this->configFile); this->setupExe = "gsetup.exe"; } // assume for now we will install the full volume and the database this->installVolume = true; this->installFullVolume = true; // detect any existing installation; unnecessary in uninstall (it's the // "source" directory - see later if (uninstall == false) { this->getExistingInstall(); } // get where we are installing from this->getSourcePath(); // if doing an uninstall we now know where the "uninstall" is if (uninstall == true) { this->collectPath = this->sourcePath; } // get the manifest and program manager objects if (uninstall) { this->manifest = new gsManifest(*this); } else { this->manifest = new gsManifest(*this, *this->sourcePath); } this->progman = new gsProgramManager(*this); // tell manifest the number of bits in the raw windows environment; this may // be required for loading certain modules such as winsock; the number of // macros is over-the-top, but is more robust to unforeseen future requirements /* if (platform.isWindows32s()) { this->manifest->expandMacro("WINBITS", "16"); this->manifest->expandMacro("WIN16", "16"); this->manifest->expandMacro("WIN32", "32"); } else { this->manifest->expandMacro("WINBITS", "32"); this->manifest->expandMacro("WIN16", ""); this->manifest->expandMacro("WIN32", "32"); } */ // inform manifest of collection directory name string colDir; colDir = this->configFile->getString("CollectionDirName"); if (colDir != "") { this->manifest->expandMacro("COLDIRNAME", colDir); } } /** * Detect the presence of an existing installation */ void GSInstall::getExistingInstall() { if (!this->platform.isWindows32s()) { if (gsRegister->collectionInstalled()) { // TODO: check if receptionist etc should be replaced or not // TODO: check build version of the volume // Get location of the library executable from the registry; this // is thence used to get the location of llssite.cfg etc. this->collectPath = this->gsRegister->collectionPath(); if (this->collectPath->pathString() != "") { this->installToPath = this->collectPath; // we don't need to install the exe files this->installExe = true; // we do now (was false before), else it doesn't allow a proper // delete-and-reinstall cycle (doesn't install server.exe on subsequent installs then) } } } } /** * get the source path for this install; we derive this from the path of this * executable (the installer) */ void GSInstall::getSourcePath() { static char filename[512]; FilePath *exePath; // get the filepath of this executable GetModuleFileName(0, filename, 512); exePath = new FilePath(filename); // get the parent (i.e. the folder containing this executable) for the source // folder this->sourcePath = exePath->parent(); // get the gsdl source path this->gsdlSourcePath = new FilePath(this->sourcePath->pathString(), "gsdl"); delete exePath; } /** * Controls the actual copying of the files; manifests of what to install * are read in from a configuration on the hard drive - this should be basically * greenstone dependent, and void of any collection-specific rubbish! */ bool GSInstall::copyFiles() { // ensure that we have got the required destination and that we can write there if (this->installExe) { // this->destinationPath->ensureWriteablePath(); } // ensure that the destination path for the collection itself is available if (this->installVolume) { // this->dataDestPath->ensureWriteablePath(); } // do the copy return this->manifest->copy(this->gsdlSourcePath); } /** * Fulfill registry update requirements; first the keys are set up, then they * are filled with key item/value pairs. */ bool GSInstall::updateRegistry() { // don't do registry stuff under windows 32s // TODO: actually reinstate what is required if (this->platform.isWindows32s()) { return true; } // ensure all pertinent keys already exist for this volume/collection this->gsRegister->ensureKeysExist(); // now move on to add key items if (this->installExe) { // FilePath *serverPath = new FilePath(this->destinationPath->pathString(), "server.exe"); FilePath *serverPath = new FilePath(this->destinationPath->pathString(), "server.exe"); FilePath *setupPath = new FilePath(this->destinationPath->pathString(), this->setupExe); FilePath *logPath = new FilePath(this->destinationPath->pathString(), "install.log"); string exeKeyPath, uninstallCmd, uninstallKeyPath; gsPlatform platform; // store the normal collection key information this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, this->gsRegister->collectKeyId(), "library", serverPath->pathString()); // This test is in fact for 9x or NT 4+; we're worried about the registry // format, not about the shell as such if (platform.isExplorerShell()) { // get special app path key for windows 9x exeKeyPath = this->gsRegister->exeKeyId("server.exe"); // ensure that the exe key exists this->gsRegister->ensureKeyExists(HKEY_LOCAL_MACHINE, exeKeyPath); // store default key for this application this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, exeKeyPath, "", serverPath->pathString()); // store path for this application this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, exeKeyPath, "path", this->destinationPath->pathString()); // create uninstall command line uninstallCmd = setupPath->pathString() + " -u " + logPath->pathString(); uninstallKeyPath = this->gsRegister->uninstallKeyId(this->configFile->getString("CollectionName")); // ensure uninstall key exists this->gsRegister->ensureKeyExists(HKEY_LOCAL_MACHINE, uninstallKeyPath); this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, uninstallKeyPath, "DisplayName", this->configFile->getString("CollectionName")); this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, uninstallKeyPath, "UninstallString", uninstallCmd); } delete setupPath; delete serverPath; delete logPath; } if (this->installVolume || this->installFullVolume) { // no actual key items are held in the volume key; for future use } return true; } /** * Set the destination directory details */ void GSInstall::setDestination() { // get configuration from the install wizard pages this->destinationPath = new FilePath(this->selectedDirs[0]->selectedPath()); this->installFullVolume = this->selectedDirs[1]->getOption(); if (this->installFullVolume || true) // NB: always take path from 2nd dialog { this->dataDestPath = new FilePath(this->selectedDirs[1]->selectedPath()); } else { this->dataDestPath = this->destinationPath; } // set the log for writing FilePath *logPath = new FilePath(this->destinationPath->pathString(), "install.log"); this->setLogFile(logPath->pathString()); this->readLog(); delete logPath; } bool GSInstall::setUninstall() { char tempPathStr[MAX_PATH]; // if we failed to get the Windows temporary directory, abort if (GetTempPath(MAX_PATH, tempPathStr) == 0) { // TODO: abort! return false; } FilePath tempPath(tempPathStr); // if we are not running in the Windows temporary directory, copy this exe // and the installation log to the temporary directory and run them there if (*this->sourcePath != tempPath) { // copy this and install.log to temporary directory and restart FilePath exePath(*this->sourcePath, this->setupExe); FilePath logPath(*this->sourcePath, "install.log"); FilePath exeDest(tempPath, this->setupExe); FilePath logDest(tempPath, "install.log"); CopyFile(exePath.cString(), exeDest.cString(), false); CopyFile(logPath.cString(), logDest.cString(), false); // now run the gssetup in the temporary directory launchApp launchUninstall(exeDest); launchUninstall.setCommandLine(" -u " + logPath.pathString()); launchUninstall.run(false, 0, "", "", false); return false; } // open the log for reading from the directory this exe is now in (which // will in fact be the temporary directory as outlined above) FilePath *logPath = new FilePath(this->sourcePath->pathString(), "install.log"); this->setLogFile(logPath->pathString()); this->readLog(); delete logPath; return true; } void GSInstall::uninstall() { FilePath *iniPath; string command; stringArray params; this->manifest = new gsManifest(*this); // get a manifest manager iniPath = new FilePath(this->installRoot(), "llssite.cfg"); gsProfile gsdlProfile(*this, iniPath->pathString()); while ((command = this->popCommand(params)) != "") { if (!this->manifest->undoAction(command, params)) { if (!gsdlProfile.undoAction(command, params)) { if (!this->gsRegister->undoAction(command, params)) { if (!this->progman->undoAction(command, params)) { } else { } } } } } } /** * Collate the manifest for installation */ void GSInstall::setManifest() { if (this->installExe) { this->manifest->selectGroup("library", *this->destinationPath); } if (this->installFullVolume) { this->manifest->selectGroup("supporting", *this->dataDestPath); this->manifest->selectGroup("collection", *this->dataDestPath); } else { this->manifest->selectGroup("database", *this->dataDestPath); } } /** * Update the program manager/explorer shell with icons, groups etc for this * collection/application */ bool GSInstall::updateProgman() { string groupName; string collectionName; // if we managed to get a connection to the program manager (or explorer // shell) then do the requisite updates if (this->progman->connect()) { // get group name from folders groupName = this->configFile->getString("ProgramGroupName"); if (groupName == "") { // TODO: error handling this->progman->disconnect(); return false; } collectionName = this->configFile->getString("CollectionName"); if (collectionName == "") { // TODO: error handling this->progman->disconnect(); return false; } // add the group if (!this->progman->addProgramGroup(groupName)) { this->progman->disconnect(); return false; } // add a "server" icon FilePath libraryPath(this->destinationPath->pathString(), "server.exe"); if (!this->progman->addIcon(groupName, collectionName, libraryPath.pathString(), "", "")) { } FilePath readMePath(this->destinationPath->pathString(), "readme.txt"); if (!this->progman->addIcon(groupName, "ReadMe", readMePath.pathString(), "", "")) { } FilePath supportPath(this->destinationPath->pathString(), "Support.htm"); if (!this->progman->addIcon(groupName, "Technical Support", supportPath.pathString(), "", "")) { } FilePath uninstallPath(this->destinationPath->pathString(), this->setupExe); FilePath logPath(this->destinationPath->pathString(), "install.log"); if (this->platform.isWindows32s() == false) // NB: don't add this shortcut under // Windows32s as it causes a crash // // TODO: reinstate this with Win3.1 // happy code { if (!this->progman->addIcon(groupName, "Uninstall", uninstallPath.pathString(), " -u " + logPath.pathString(), "Remove this Greenstone collection")) { } } else { if (!this->progman->addIcon(groupName, "Uninstall", uninstallPath.pathString() + " -u " + logPath.pathString(), "", "Remove this Greenstone collection")) { } } // disconnect from program manager this->progman->disconnect(); } return true; } /** * Update the profile (ini) files associated with the program; these changes * must be made after copying to files in the destination/executable folders * as we can't write to CD-ROM (or at least we shouldn't - the install would * become tainted). */ bool GSInstall::updateProfiles() { FilePath *exePath; FilePath *dataPath; FilePath *iniPath; // if we're installing the exe, then the exe path leads to the destination // folder of this installation sequence; if not, then we pick it up from // the existing location of that folder if (this->installExe) { exePath = this->destinationPath; } else { exePath = this->collectPath; } iniPath = new FilePath(exePath->pathString(), "llssite.cfg"); // TODO: check if this 'if' structure is correct; suspect that it isn't quite // as we may not be installing the volume, but exe etc individually; // may be okay now but not future proof; also the destination directory // may or may not be tied to the exe directory if that existed already. // This all needs investigating if (this->installVolume) { // Manufacture the appropriate section name now; an equivalent string // is also constructed string volumeSectionString = this->configFile->getString("CollectionName") + "#" + this->configFile->getString("CollectionVolume"); // if we're installing the full data for the collection, then take the // data path to be at the selected destination directory for the collection // files; otherwise take the data path to be on the CD/distribution media if (this->installFullVolume) { dataPath = this->dataDestPath; } else { dataPath = this->gsdlSourcePath; } // create a profile object to write to the llssite.cfg file gsProfile gsdlProfile(*this, iniPath->pathString()); // if installing the executable, add the database and greenstone home // directories if (this->installExe) { // set the correct exe entries in llssite.cfg (in the gsdl section) gsdlProfile.writeString("gsdl", "gsdlhome", dataPath->pathString()); gsdlProfile.writeString("gsdl", "gdbmhome", this->dataDestPath->pathString()); } // set the correct collection volume entries in llssite.cfg if (this->installVolume) { // note the collection in the general gsdl section; and add the undo item too gsdlProfile.ensureListMember("gsdl", gsdl_COLLIST, volumeSectionString); // note the volume data in its own section gsdlProfile.writeString(volumeSectionString, "gsdlhome", dataPath->pathString()); gsdlProfile.writeString(volumeSectionString, "gdbmhome", this->dataDestPath->pathString()); gsdlProfile.writeString(volumeSectionString, "staticpath", dataPath->pathString()); } } // clean up delete iniPath; return true; } /** * Ensure that we've installed the very latest setup executable @ the destination/ * greenstone folder */ bool GSInstall::updateSetupExe() { FilePath *destExePath; FilePath srcExeFile(*this->sourcePath, "gssetup.exe"); if (this->installExe) { destExePath = this->destinationPath; } else { destExePath = this->collectPath; } FilePath destExeFile(*destExePath, this->setupExe); if (this->platform.isWindows32s() == false) // NB: Don't copy the setup executable // to Windows32s as it causes a hang! { if (!CopyFile(srcExeFile.cString(), destExeFile.cString(), false)) { return false; } } else { // Windows 3.1 has a peculiar behaviour on calling CopyFile on an .exe; // it doesn't. (Copy the file); thus we copy to an non-exe file and then // rename it into an exe file; this works. FilePath intExeFile(*destExePath, "gsetup.ex"); if (!CopyFile(srcExeFile.cString(), intExeFile.cString(), false)) { return false; } MoveFile(intExeFile.cString(), destExeFile.cString()); } return true; } bool GSInstall::installNetscape() { FilePath netscape32Path(this->sourcePath->pathString(), "netscape\\n32e405.exe"); FilePath netscape16Path(this->sourcePath->pathString(), "netscape\\n16e405.exe"); launchApp launchNetscape(netscape32Path); launchNetscape.platformApp(gsPlatform_WINDOWS32S, netscape16Path); launchNetscape.platformApp(gsPlatform_WINDOWS, netscape16Path); if (launchNetscape.run(true, 1, "This library is displayed using a web browser. If you don't " "currently have a web browser installed on your machine you may " "install the Netscape 4.05 browser now.\n\n" "Note that if your current browser was provided by your internet " "service provider, you should install Netscape in a different " "directory.\n\n" "Would you like to install the Netscape 4.05 browser now?", "Greenstone Installer", false) < 0) { // MessageBox(0, "Error", app_name, MB_OK); return false; } return true; } FilePath *GSInstall::collectionPath() { return this->collectPath; } FilePath *GSInstall::installPath() { return this->installToPath; } void GSInstall::addSelectedDir(dirSelector *selector) { this->selectedDirs.push_back(selector); } typedef struct { dirSelector * dirSelect; } GSInstall_dirPathData; HGLOBAL loadDirBrowser() { HRSRC resHdl; resHdl = FindResource(app_instance, "MySaveAsDlg", RT_DIALOG); return LoadResource(app_instance, resHdl); } void gsInstall_wizard_centre(HWND dialog) { RECT rect; int sx, sy; int dx, dy; gsInstall_getDesktopExt(&sx, &sy); GetWindowRect(dialog, &rect); dx = (sx - rect.right + rect.left) >> 1; dy = (sy - rect.bottom + rect.top) >> 1; SetWindowPos(dialog, 0, dx, dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } BOOL FAR PASCAL GSInstall_dlgproc(HWND Dialog, UINT Message, WPARAM wParam, LPARAM lParam) { static bool first = true; // static variable to hack the position of the // whole wizard; note doing this in the wizard // property sheet initialisation DOES NOT WORK switch (Message) { case WM_INITDIALOG: { dirSelector *selector = (dirSelector *) ((PROPSHEETPAGE *) lParam)->lParam; SetDlgItemText(Dialog, dirpath_PROMPT, selector->prompt); if (selector->optPrompt != NULL) { SetDlgItemText(Dialog, dirpath_OPTION, selector->optPrompt); EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), true); // was false EnableWindow(GetDlgItem(Dialog, dirpath_PATH), true); // was false } else { ShowWindow(GetDlgItem(Dialog, dirpath_OPTION), SW_HIDE); } SetWindowLong(Dialog, GWL_USERDATA, ((PROPSHEETPAGE *) lParam)->lParam); SetDlgItemText(Dialog, dirpath_PATH, selector->selectedPath()); // if this is the first time this function is called, then centre the // wizard into the centre of our screen. if (first) { gsInstall_wizard_centre(GetParent(Dialog)); first = false; } } return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case dirpath_BROWSE: ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->requestPath(Dialog, "Select Directory"); SetDlgItemText(Dialog, dirpath_PATH, ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->selectedPath()); break; case dirpath_OPTION: ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->setOption(IsDlgButtonChecked(Dialog, dirpath_OPTION) == BST_CHECKED); if (HIWORD(wParam) == BN_CLICKED && false) // don't do the enable/disable these days { EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), IsDlgButtonChecked(Dialog, dirpath_OPTION)); EnableWindow(GetDlgItem(Dialog, dirpath_PATH), IsDlgButtonChecked(Dialog, dirpath_OPTION)); } break; } break; case WM_NOTIFY: switch (((LPNMHDR) lParam)->code) { case PSN_SETACTIVE: { dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA)); // bodge to set the dialogue path to the correct value if (selector != rootSelector) { selector->setPath(rootSelector->selectedPath()); SetDlgItemText(Dialog, dirpath_PATH, selector->selectedPath()); } PropSheet_SetWizButtons(GetParent(Dialog), (selector->isFirst() ? 0 : PSWIZB_BACK) | (selector->isFinal() ? PSWIZB_FINISH : PSWIZB_NEXT)); } break; case PSN_KILLACTIVE: break; case PSN_WIZNEXT: { // note the path from the dialog dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA)); selector->setPathFromEdit(GetDlgItem(Dialog, dirpath_PATH)); // create a new FilePath object to check on the proposed destination FilePath *path = new FilePath(selector->selectedPath()); // if the proposed destination doesn't exist, ask the user whether to // create it now. TODO: actually create it if asked! if (path->exists() == false) { char buffer[128]; sprintf(buffer, "Directory %s does not exist - create it?", selector->selectedPath()); // if the user cancelled that, then don't permit them to go to the next // page of the wizard if (MessageBox(0, buffer, app_name, MB_YESNO | MB_TOPMOST) == IDNO) { delete path; SetWindowLong(Dialog, DWL_MSGRESULT, TRUE); return TRUE; } } delete path; } break; case PSN_WIZFINISH: { // Finish the activity now config_complete = true; } break; } break; } return FALSE; } void GSInstall_init_propertySheet(PROPSHEETPAGE &ppage, char *prompt, char *optPrompt, char *title, GSInstall &installer, bool isFirst, bool isFinal) { GSInstall_dirPathData *data = new GSInstall_dirPathData; // create the directory Selector data->dirSelect = new dirSelector(prompt, optPrompt, title, installer.installPath()); data->dirSelect->setFirst(isFirst); data->dirSelect->setFinal(isFinal); // if there is no extant root selector, make this it if (rootSelector == NULL) { rootSelector = data->dirSelect; } // add this directory selector to the installer installer.addSelectedDir(data->dirSelect); // set up the rest of the page ppage.dwSize = sizeof(PROPSHEETPAGE); ppage.dwFlags = PSP_USETITLE; ppage.hInstance = app_instance; ppage.pszTemplate = "getDirPath"; ppage.pszIcon = 0; ppage.pszTitle = app_name; ppage.pfnDlgProc = (DLGPROC) GSInstall_dlgproc; ppage.lParam = (LPARAM) data->dirSelect; ppage.pfnCallback = NULL; } int CALLBACK GSInstall_wizardProc(HWND dialog, UINT Message, LPARAM lParameter) { switch (Message) { case PSCB_INITIALIZED : // Process PSCB_INITIALIZED gsInstall_wizard_centre(dialog); break ; case PSCB_PRECREATE : // Process PSCB_PRECREATE break ; default : // Unknown message break ; } return 0; } bool GSInstall_init_wizard(GSInstall &install) { PROPSHEETHEADER pshead; PROPSHEETPAGE ppage[2]; bool reply; ZeroMemory(&pshead, sizeof(PROPSHEETHEADER)); pshead.dwSize = sizeof(PROPSHEETHEADER); pshead.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK | PSH_USEHICON | PSH_WIZARD; pshead.hwndParent = app_window; pshead.hInstance = app_instance; pshead.hIcon = NULL; pshead.pszCaption = "Greenstone Installer"; pshead.nPages = 2; pshead.nStartPage = 0; if (install.installExe == true) { pshead.ppsp = ppage; } else // cheat as the executable etc. is already installed { pshead.ppsp = &ppage[1]; } pshead.pfnCallback = GSInstall_wizardProc; GSInstall_init_propertySheet( ppage[0], "Choose a directory to install your " "Greenstone software to.", NULL, "Select", install, true, false); GSInstall_init_propertySheet(ppage[1], "Choose a directory to install the collection " "files to.\n\n" "You can also choose to install all the collection " "files onto your computer hard drive.\n\n" "If you do this, you will not have to load the " "CD-ROM each time you use your Greenstone software " "but more of your hard disk will be used.\n\n" "Some collection files must be installed on your " "computer.\n\n", "Install all collection files", "Select", install, false, true); reply = (PropertySheet (&pshead) >= 0); return reply; } long FAR PASCAL GSInstallWindProc(HWND Window, WORD Message, WPARAM wParameter, LPARAM lParameter) { long reply = 0; switch(Message) { case WM_CREATE: { ShowWindow(Window, SW_MAXIMIZE); } break; case WM_COMMAND: break; case WM_USER: { if (strstr(app_cmdLine, "-u") != NULL) { // uninstall action // skip past the -u option itself char *at = strstr(app_cmdLine, "-u"); at += strlen("-u"); // extract the log file path from the command line while (*at == ' ') { at ++; } string logPathString(at); FilePath logPath(logPathString); GSInstall install(true); // if we're running in the temporary directory, do the uninstall if (install.setUninstall()) { install.uninstall(); // close the log to write back all changes to the log; if the file // will be deleted, it must be closed; copying may also fail, so it's // safer to close it before doing either. install.recordLog(); // if the install is empty, terminate all final items (currently the // log and setup executables, if (install.isEmpty()) { // delete the log file DeleteFile(logPath.cString()); // get it's parent to find where the gssetup executable will be FilePath *logParent = logPath.parent(); FilePath uninstallPath(*logParent, install.setupExeLeaf()); // delete the gssetup executable DeleteFile(uninstallPath.cString()); // kill the original log parent directory if it should have died if (install.removeFailed(logParent->pathString())) { RemoveDirectory(logParent->cString()); } // dispose of the parent directory information delete logParent; } // if not, then overwrite the original log with the modified one else { // do nothing - should be changed already! } } } // install wizard else { GSInstall install(false); GSInstall_init_wizard(install); if (config_complete == false) { MessageBox(0, "Install cancelled", app_name, MB_OK); } else { // configure the installation install.setDestination(); install.setManifest(); if (!install.copyFiles()) // caused page fault; Windows 3.1 { MessageBox(0, "Not enough space to install required files", "Greenstone Installer", MB_OK); install.abortLog(); DestroyWindow(Window); return false; } install.updateProgman(); // caused divide overflow; Windows 3.1 install.updateRegistry(); install.updateProfiles(); install.updateSetupExe(); // caused bomb-out of Windows; 3.1 // close log install.recordLog(); // do further actions if (install.offerNetscape == true) { install.installNetscape(); } MessageBox(0, "Installation complete.", "Greenstone Installer", MB_OK); } } DestroyWindow(Window); } break; case WM_USER + 1: break; case WM_CLOSE: /*if (!file_ischanged || IDCANCEL != file_query(Window, file_name))*/ DestroyWindow(Window); return 0L; case WM_DESTROY: { PostQuitMessage(0); } break; default: return(DefWindowProc(Window, Message, wParameter, lParameter)); } return reply; } void GSInstall_init(HINSTANCE instance, int Show) { int sx, sy; gsInstall_getDesktopExt(&sx, &sy); app_window = CreateWindow("GSInstall:Main", "Greenstone Installer", WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | CS_DBLCLKS, 0, 0, sx, sy, NULL, NULL, app_instance, NULL); ShowWindow(app_window, Show); PostMessage(app_window, WM_USER, 0, 0L); } void WinClassInit(void) { WNDCLASS Class; Class.lpszClassName = "GSInstall:Main"; Class.hInstance = app_instance; Class.lpfnWndProc = (WNDPROC) GSInstallWindProc; Class.hCursor = LoadCursor(NULL, IDC_ARROW); Class.hIcon = NULL; //LoadIcon(app_instance, "GSInstall"); Class.lpszMenuName = NULL; Class.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE+1); Class.style = 0; Class.cbClsExtra = 0; Class.cbWndExtra = 0; RegisterClass(&Class); } int PASCAL WinMain(HINSTANCE Current, HINSTANCE Previous, LPSTR CmdLine, int CmdShow) { MSG msg; gsPlatform p; if (p.isWindows32s()) { char filename[512]; FilePath *exePath; FilePath *dirPath; // get the filepath of this executable GetModuleFileName(0, filename, 512); exePath = new FilePath(filename); // get the parent (i.e. the folder containing this executable) for the source // folder dirPath = exePath->parent(); delete exePath; exePath = new FilePath(dirPath->cString(), "install.log"); if (exePath->exists()) { app_cmdLine = (char *) malloc(256); lstrcpy(app_cmdLine, "gsetup.exe -u "); lstrcat(app_cmdLine, exePath->cString()); } else { app_cmdLine = (char *) malloc(1); app_cmdLine[0] = '\0'; } delete exePath; delete dirPath; } else { app_cmdLine = (char *) malloc(lstrlen(CmdLine) + 1); lstrcpy(app_cmdLine, CmdLine); } app_instance = Current; /* -- init application */ if (!Previous) { WinClassInit(); InitCommonControls(); } /* -- init instance */ GSInstall_init(Current, CmdShow); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; }