source: trunk/gsinstaller/gsinstall.cpp@ 1541

Last change on this file since 1541 was 1541, checked in by cs025, 24 years ago

Fixes for WindowsNT. Also made File class subclass of FilePath class.

  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 KB
Line 
1#include <vector>
2#include <string>
3
4// use the standard namespace
5#if !defined (GSDL_NAMESPACE_BROKEN)
6#if defined(GSDL_USE_OBJECTSPACE)
7using namespace ospace::std;
8#else
9using namespace std;
10#endif
11#endif
12
13#include <stdlib.h>
14#include <stdio.h>
15#include <windows.h>
16#include <commctrl.h>
17
18#include "dirSelector.h"
19#include "common.h"
20#include "configFile.h"
21#include "File.h"
22#include "FilePath.h"
23#include "FileCopier.h"
24#include "launchApp.h"
25#include "unInstall.h"
26
27#include "gsRegistry.h"
28#include "gsPlatform.h"
29#include "gsProgman.h"
30#include "gsProfile.h"
31#include "gsManifest.h"
32
33char *app_cmdLine;
34static char app_name[] = "Greenstone Installer";
35HINSTANCE app_instance;
36HWND app_window;
37
38bool config_complete = false;
39
40dirSelector *rootSelector = NULL;
41
42typedef vector<dirSelector *> dirSelVector;
43
44class GSInstall : public installManager
45{
46private:
47 configureFile *configFile; // the installation configure file
48
49 FilePath *collectPath; // where the collection is currently installed
50 FilePath *installToPath; // the first cut at a destination folder
51 FilePath *sourcePath; // the root source folder
52 FilePath *gsdlSourcePath; // the gsdl folder in the source area
53 FilePath *destinationPath; // where the executables will be installed to
54 FilePath *dataDestPath; // where the collection data files will go
55
56 bool installVolume; // whether to install collection data
57 bool installFullVolume; // whether to install all collection data
58
59 dirSelVector selectedDirs; // configuration objects
60
61 gsPlatform platform; // platform information
62 gsRegistry *gsRegister; // registry
63 gsManifest *manifest; // manifest of files
64 gsProgramManager *progman; // program manager connection
65
66 void getSourcePath();
67 void getExistingInstall();
68public:
69 bool installExe;
70
71 GSInstall(bool uninstall);
72 FilePath *collectionPath();
73 FilePath *installPath();
74 bool copyFiles();
75 bool updateRegistry();
76 bool updateProfiles();
77 bool updateProgman();
78 bool updateSetupExe();
79 bool installNetscape();
80 void setDestination();
81 bool setUninstall();
82 void uninstall();
83 void setManifest();
84 void addSelectedDir(dirSelector *selector);
85};
86
87static string gsdl_DBHOME = "gdbmhome";
88static string gsdl_VLHOME = "gsdlhome";
89static string gsdl_STATIC = "staticpath";
90static string gsdl_COLLIST= "collections";
91
92void gsInstall_getDesktopExt(int *sx, int *sy)
93{
94 HDC dc = GetDC(GetDesktopWindow());
95 *sx = GetDeviceCaps(dc, HORZRES);
96 *sy = GetDeviceCaps(dc, VERTRES);
97 ReleaseDC(GetDesktopWindow(), dc);
98}
99
100/**
101 * Get various and nefarious details before we start trying an installation.
102 * The installation configuration file is read, we seek for an existing
103 * installation and reconfigure the default install settings appropriately.
104 * THe source path is also discovered.
105 */
106GSInstall::GSInstall(bool uninstall)
107 : installManager()
108{
109 // get the installation configuration file
110 this->configFile = new configureFile("install.cfg");
111
112 // set up "default" installation bits
113 this->installToPath = new FilePath("C:\\GSDL");
114 this->collectPath = NULL;
115 this->installExe = true; // we must install the exe files
116
117 // don't attempt this with windows 3.1
118 if (!this->platform.isWindows32s())
119 {
120 // get the registry
121 this->gsRegister = new gsRegistry(*this, *this->configFile);
122 }
123 else
124 {
125 // TODO: in windows 3.1 we can't use the register as it isn't fully/properly
126 // implemented; we must get the existing path information from elsewhere
127 this->gsRegister = new gsRegistry(*this, *this->configFile);
128 }
129
130 // assume for now we will install the full volume and the database
131 this->installVolume = true;
132 this->installFullVolume = true;
133
134 // detect any existing installation; unnecessary in uninstall (it's the
135 // "source" directory - see later
136 if (uninstall == false)
137 {
138 this->getExistingInstall();
139 }
140
141 // get where we are installing from
142 this->getSourcePath();
143
144 // if doing an uninstall we now know where the "uninstall" is
145 if (uninstall == true)
146 {
147 this->collectPath = this->sourcePath;
148 }
149
150 // get the manifest and program manager objects
151 if (uninstall)
152 {
153 this->manifest = new gsManifest(*this);
154 }
155 else
156 {
157 this->manifest = new gsManifest(*this, *this->sourcePath);
158 }
159 this->progman = new gsProgramManager(*this);
160
161 // tell manifest the number of bits in the raw windows environment; this may
162 // be required for loading certain modules such as winsock; the number of
163 // macros is over-the-top, but is more robust to unforeseen future requirements
164 /* if (platform.isWindows32s())
165 { this->manifest->expandMacro("WINBITS", "16");
166 this->manifest->expandMacro("WIN16", "16");
167 this->manifest->expandMacro("WIN32", "32");
168 }
169 else
170 { this->manifest->expandMacro("WINBITS", "32");
171 this->manifest->expandMacro("WIN16", "");
172 this->manifest->expandMacro("WIN32", "32");
173 }
174 */
175 // inform manifest of collection directory name
176 string colDir;
177 colDir = this->configFile->getString("CollectionDirName");
178 if (colDir != "")
179 {
180 this->manifest->expandMacro("COLDIRNAME", colDir);
181 }
182}
183
184/**
185 * Detect the presence of an existing installation
186 */
187void GSInstall::getExistingInstall()
188{
189 if (!this->platform.isWindows32s())
190 {
191 if (gsRegister->collectionInstalled())
192 {
193 // TODO: check if receptionist etc should be replaced or not
194
195 // TODO: check build version of the volume
196
197 // Get location of the library executable from the registry; this
198 // is thence used to get the location of gsdl.ini etc.
199 this->collectPath = this->gsRegister->collectionPath();
200 if (this->collectPath->pathString() != "")
201 {
202 this->installToPath = this->collectPath;
203 // we don't need to install the exe files
204 this->installExe = false;
205 }
206 }
207 }
208}
209
210/**
211 * get the source path for this install; we derive this from the path of this
212 * executable (the installer)
213 */
214void GSInstall::getSourcePath()
215{ static char filename[512];
216 FilePath *exePath;
217
218 // get the filepath of this executable
219 GetModuleFileName(0, filename, 512);
220 exePath = new FilePath(filename);
221
222 // get the parent (i.e. the folder containing this executable) for the source
223 // folder
224 this->sourcePath = exePath->parent();
225
226 // get the gsdl source path
227 this->gsdlSourcePath = new FilePath(this->sourcePath->pathString(), "gsdl");
228 delete exePath;
229}
230
231/**
232 * Controls the actual copying of the files; manifests of what to install
233 * are read in from a configuration on the hard drive - this should be basically
234 * greenstone dependent, and void of any collection-specific rubbish!
235 */
236bool GSInstall::copyFiles()
237{ // ensure that we have got the required destination and that we can write there
238 if (this->installExe)
239 { this->destinationPath->ensureWriteablePath();
240 }
241
242 // ensure that the destination path for the collection itself is available
243 if (this->installVolume)
244 { this->dataDestPath->ensureWriteablePath();
245 }
246
247 // do the copy
248 this->manifest->copy(this->gsdlSourcePath);
249
250 return true;
251}
252
253/**
254 * Fulfill registry update requirements; first the keys are set up, then they
255 * are filled with key item/value pairs.
256 */
257bool GSInstall::updateRegistry()
258{ // don't do registry stuff under windows 32s
259 if (this->platform.isWindows32s() && FALSE)
260 { return true;
261 }
262
263 // ensure all pertinent keys already exist for this volume/collection
264 this->gsRegister->ensureKeysExist();
265
266 // now move on to add key items
267 if (this->installExe)
268 { FilePath *serverPath = new FilePath(this->destinationPath->pathString(), "server.exe");
269 FilePath *setupPath = new FilePath(this->destinationPath->pathString(), "gssetup.exe");
270 FilePath *logPath = new FilePath(this->destinationPath->pathString(), "install.log");
271 string exeKeyPath, uninstallCmd, uninstallKeyPath;
272 gsPlatform platform;
273
274 // store the normal collection key information
275 this->gsRegister->storeKeyString( HKEY_LOCAL_MACHINE,
276 this->gsRegister->collectKeyId(),
277 "library",
278 serverPath->pathString());
279
280 // This test is in fact for 9x or NT 4+; we're worried about the registry
281 // format, not about the shell as such
282 if (platform.isExplorerShell())
283 { // get special app path key for windows 9x
284 exeKeyPath = this->gsRegister->exeKeyId("library.exe");
285
286 // ensure that the exe key exists
287 this->gsRegister->ensureKeyExists(HKEY_LOCAL_MACHINE, exeKeyPath);
288
289 // store default key for this application
290 this->gsRegister->storeKeyString( HKEY_LOCAL_MACHINE,
291 exeKeyPath,
292 "",
293 serverPath->pathString());
294
295 // store path for this application
296 this->gsRegister->storeKeyString( HKEY_LOCAL_MACHINE,
297 exeKeyPath,
298 "path",
299 this->destinationPath->pathString());
300
301 // create uninstall command line
302 uninstallCmd = setupPath->pathString() + " -u " + logPath->pathString();
303 uninstallKeyPath = this->gsRegister->uninstallKeyId(this->configFile->getString("CollectionName"));
304
305 // ensure uninstall key exists
306 this->gsRegister->ensureKeyExists(HKEY_LOCAL_MACHINE, uninstallKeyPath);
307
308 this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, uninstallKeyPath,
309 "DisplayName",
310 this->configFile->getString("CollectionName"));
311 this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, uninstallKeyPath,
312 "UninstallString", uninstallCmd);
313 }
314 delete setupPath;
315 delete serverPath;
316 delete logPath;
317 }
318
319 if (this->installVolume || this->installFullVolume)
320 { // no actual key items are held in the volume key; for future use
321 }
322 return true;
323}
324
325/**
326 * Set the destination directory details
327 */
328void GSInstall::setDestination()
329{ // get configuration from the install wizard pages
330 this->destinationPath = new FilePath(this->selectedDirs[0]->selectedPath());
331 this->installFullVolume = this->selectedDirs[1]->getOption();
332 if (this->installFullVolume || true) // NB: always take path from 2nd dialog
333 { this->dataDestPath = new FilePath(this->selectedDirs[1]->selectedPath());
334 }
335 else
336 { this->dataDestPath = this->destinationPath;
337 }
338
339 // open the log for writing
340 FilePath *logPath = new FilePath(this->destinationPath->pathString(), "install.log");
341 this->openLog(logPath->pathString(), true);
342 delete logPath;
343}
344
345bool GSInstall::setUninstall()
346{ char tempPathStr[MAX_PATH];
347
348 // if we failed to get the Windows temporary directory, abort
349 if (GetTempPath(MAX_PATH, tempPathStr) == 0)
350 { // TODO: abort!
351 return false;
352 }
353
354 FilePath tempPath(tempPathStr);
355
356 // if we are not running in the Windows temporary directory, copy this exe
357 // and the installation log to the temporary directory and run them there
358 if (*this->sourcePath != tempPath)
359 { // copy this and install.log to temporary directory and restart
360 FilePath exePath(*this->sourcePath, "gssetup.exe");
361 FilePath logPath(*this->sourcePath, "install.log");
362
363 FilePath exeDest(tempPath, "gssetup.exe");
364 FilePath logDest(tempPath, "install.log");
365
366 CopyFile(exePath.cString(), exeDest.cString(), false);
367 CopyFile(logPath.cString(), logDest.cString(), false);
368
369 // now run the gssetup in the temporary directory
370 launchApp launchUninstall(exeDest);
371 launchUninstall.setCommandLine(" -u " + logPath.pathString());
372 launchUninstall.run(false, 0, "", "", false);
373
374 return false;
375 }
376
377 // open the log for reading from the directory this exe is now in (which
378 // will in fact be the temporary directory as outlined above)
379 FilePath *logPath = new FilePath(this->sourcePath->pathString(), "install.log");
380 this->openLog(logPath->pathString(), false);
381 delete logPath;
382
383 return true;
384}
385
386void GSInstall::uninstall()
387{ FilePath *iniPath;
388 string command;
389 stringArray params;
390
391 this->manifest = new gsManifest(*this); // get a manifest manager
392
393 iniPath = new FilePath(this->collectPath->pathString(), "gsdl.ini");
394 gsProfile gsdlProfile(*this, iniPath->pathString());
395
396 while ((command = this->popCommand(params)) != "")
397 { if (!this->manifest->undoAction(command, params))
398 { if (!gsdlProfile.undoAction(command, params))
399 { if (!this->gsRegister->undoAction(command, params))
400 { if (!this->progman->undoAction(command, params))
401 {
402 }
403 }
404 }
405 }
406 }
407}
408
409/**
410 * Collate the manifest for installation
411 */
412void GSInstall::setManifest()
413{ if (this->installExe)
414 { this->manifest->selectGroup("library", *this->destinationPath);
415 }
416 if (this->installFullVolume)
417 { this->manifest->selectGroup("collection", *this->dataDestPath);
418 }
419 else
420 { this->manifest->selectGroup("database", *this->dataDestPath);
421 }
422}
423
424/**
425 * Update the program manager/explorer shell with icons, groups etc for this
426 * collection/application
427 */
428bool GSInstall::updateProgman()
429{ string groupName;
430
431 // if we managed to get a connection to the program manager (or explorer
432 // shell) then do the requisite updates
433 if (this->progman->connect())
434 { // get group name from folders
435 groupName = this->configFile->getString("ProgramGroupName");
436 if (groupName == "")
437 { // TODO: error handling
438 this->progman->disconnect();
439 return false;
440 }
441
442 // add the group
443 if (!this->progman->addProgramGroup(groupName))
444 { this->progman->disconnect();
445 return false;
446 }
447
448 // add a "server" icon
449 FilePath libraryPath(this->destinationPath->pathString(), "library.exe");
450 if (!this->progman->addIcon(groupName, "Library (without nextwork support)", libraryPath.pathString(), ""))
451 { // assume that it may be there already
452 }
453
454 // check for server existence
455 FilePath serverPath(this->destinationPath->pathString(), "server.exe");
456 if (serverPath.exists())
457 { if (!this->progman->addIcon(groupName, "Server", serverPath.pathString(), ""))
458 { // assume that it may be there already
459 }
460 }
461
462 FilePath readMePath(this->destinationPath->pathString(), "readme.txt");
463 if (!this->progman->addIcon(groupName, "ReadMe", readMePath.pathString(), ""))
464 {
465 }
466
467 FilePath supportPath(this->destinationPath->pathString(), "support.html");
468 if (!this->progman->addIcon(groupName, "Technical Support", supportPath.pathString(), ""))
469 {
470 }
471
472 // TODO: uninstall icon
473 // FilePath uninstallPath(this->destinationPath->pathString(), "gssetup.exe");
474
475 // disconnect from program manager
476 this->progman->disconnect();
477 }
478 return true;
479}
480
481/**
482 * Update the profile (ini) files associated with the program; these changes
483 * must be made after copying to files in the destination/executable folders
484 * as we can't write to CD-ROM (or at least we shouldn't - the install would
485 * become tainted).
486 */
487bool GSInstall::updateProfiles()
488{ FilePath *exePath;
489 FilePath *dataPath;
490 FilePath *iniPath;
491
492 // if we're installing the exe, then the exe path leads to the destination
493 // folder of this installation sequence; if not, then we pick it up from
494 // the existing location of that folder
495 if (this->installExe)
496 { exePath = this->destinationPath;
497 }
498 else
499 { exePath = this->collectPath;
500 }
501 iniPath = new FilePath(exePath->pathString(), "gsdl.ini");
502
503 // TODO: check if this 'if' structure is correct; suspect that it isn't quite
504 // as we may not be installing the volume, but exe etc individually;
505 // may be okay now but not future proof; also the destination directory
506 // may or may not be tied to the exe directory if that existed already.
507 // This all needs investigating
508 if (this->installVolume)
509 { // Manufacture the appropriate section name now; an equivalent string
510 // is also constructed
511 string volumeSectionString = this->configFile->getString("CollectionName") +
512 "#" + this->configFile->getString("CollectionVolume");
513
514 // if we're installing the full data for the collection, then take the
515 // data path to be at the selected destination directory for the collection
516 // files; otherwise take the data path to be on the CD/distribution media
517 if (this->installFullVolume)
518 { dataPath = this->dataDestPath;
519 }
520 else
521 { dataPath = this->gsdlSourcePath;
522 }
523
524 // create a profile object to write to the gsdl.ini file
525 gsProfile gsdlProfile(*this, iniPath->pathString());
526
527 // if installing the executable, add the database and greenstone home
528 // directories
529 if (this->installExe)
530 { // set the correct exe entries in gsdl.ini (in the gsdl section)
531 gsdlProfile.writeString("gsdl", "gsdlhome", dataPath->pathString());
532 gsdlProfile.writeString("gsdl", "gdbmhome", this->dataDestPath->pathString());
533 }
534
535 // set the correct collection volume entries in gsdl.ini
536 if (this->installVolume)
537 { // note the collection in the general gsdl section; and add the undo item too
538 gsdlProfile.ensureListMember("gsdl", gsdl_COLLIST, volumeSectionString);
539
540 // note the volume data in its own section
541 gsdlProfile.writeString(volumeSectionString, "gsdlhome", dataPath->pathString());
542 gsdlProfile.writeString(volumeSectionString, "gdbmhome", this->dataDestPath->pathString());
543 gsdlProfile.writeString(volumeSectionString, "staticpath", dataPath->pathString());
544 }
545 }
546
547 // clean up
548 delete iniPath;
549
550 return true;
551}
552
553/**
554 * Ensure that we've installed the very latest setup executable @ the destination/
555 * greenstone folder
556 */
557bool GSInstall::updateSetupExe()
558{ FilePath *destExePath;
559 FilePath srcExeFile(*this->sourcePath, "gssetup.exe");
560
561 if (this->installExe)
562 { destExePath = this->destinationPath;
563 }
564 else
565 { destExePath = this->collectPath;
566 }
567 FilePath destExeFile(*destExePath, "gssetup.exe");
568
569 if (!CopyFile(srcExeFile.cString(), destExeFile.cString(), false))
570 { return false;
571 }
572 return true;
573}
574
575bool GSInstall::installNetscape()
576{ FilePath netscape32Path(this->sourcePath->pathString(), "netscape\\n32e405.exe");
577 FilePath netscape16Path(this->sourcePath->pathString(), "netscape\\n16e405.exe");
578
579 launchApp launchNetscape(netscape32Path);
580 launchNetscape.platformApp(gsPlatform_WINDOWS32S, netscape16Path);
581 if (launchNetscape.run(true, 1,
582 "This library is displayed using a web browser. If you don't "
583 "currently have a web browser installed on your machine you may "
584 "install the Netscape 4.05 browser now.\n\n"
585 "Note that if your current browser was provided by your internet "
586 "service provider, you should install Netscape in a different "
587 "directory.\n\n"
588 "Would you like to install the Netscape 4.05 browser now?",
589 "Greenstone Installer", false) < 0)
590 { MessageBox(0, "Error", app_name, MB_OK);
591 return false;
592 }
593 return true;
594}
595
596FilePath *GSInstall::collectionPath()
597{ return this->collectPath;
598}
599
600FilePath *GSInstall::installPath()
601{ return this->installToPath;
602}
603
604void GSInstall::addSelectedDir(dirSelector *selector)
605{ this->selectedDirs.push_back(selector);
606}
607
608typedef struct
609{ dirSelector * dirSelect;
610} GSInstall_dirPathData;
611
612HGLOBAL loadDirBrowser()
613{ HRSRC resHdl;
614
615 resHdl = FindResource(app_instance, "MySaveAsDlg", RT_DIALOG);
616 return LoadResource(app_instance, resHdl);
617}
618
619void gsInstall_wizard_centre(HWND dialog)
620{
621 RECT rect;
622 int sx, sy;
623 int dx, dy;
624
625 gsInstall_getDesktopExt(&sx, &sy);
626 GetWindowRect(dialog, &rect);
627
628 dx = (sx - rect.right + rect.left) >> 1;
629 dy = (sy - rect.bottom + rect.top) >> 1;
630 SetWindowPos(dialog, 0, dx, dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
631}
632
633BOOL FAR PASCAL GSInstall_dlgproc(HWND Dialog, UINT Message, WPARAM wParam, LPARAM lParam)
634{ static bool first = true; // static variable to hack the position of the
635 // whole wizard; note doing this in the wizard
636 // property sheet initialisation DOES NOT WORK
637
638 switch (Message)
639 { case WM_INITDIALOG:
640 { dirSelector *selector = (dirSelector *) ((PROPSHEETPAGE *) lParam)->lParam;
641
642 SetDlgItemText(Dialog, dirpath_PROMPT, selector->prompt);
643 if (selector->optPrompt != NULL)
644 { SetDlgItemText(Dialog, dirpath_OPTION, selector->optPrompt);
645 EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), true); // was false
646 EnableWindow(GetDlgItem(Dialog, dirpath_PATH), true); // was false
647 }
648 else
649 { ShowWindow(GetDlgItem(Dialog, dirpath_OPTION), SW_HIDE);
650 }
651 SetWindowLong(Dialog, GWL_USERDATA, ((PROPSHEETPAGE *) lParam)->lParam);
652 SetDlgItemText(Dialog, dirpath_PATH, selector->selectedPath());
653
654 // if this is the first time this function is called, then centre the
655 // wizard into the centre of our screen.
656 if (first)
657 { gsInstall_wizard_centre(GetParent(Dialog));
658 first = false;
659 }
660 }
661 return TRUE;
662
663 case WM_COMMAND:
664 switch (LOWORD(wParam))
665 { case dirpath_BROWSE:
666 ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->requestPath(Dialog, "Select Directory");
667 SetDlgItemText(Dialog, dirpath_PATH, ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->selectedPath());
668 break;
669
670 case dirpath_OPTION:
671 ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->setOption(IsDlgButtonChecked(Dialog, dirpath_OPTION));
672 if (HIWORD(wParam) == BN_CLICKED && false) // don't do the enable/disable these days
673 { EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), IsDlgButtonChecked(Dialog, dirpath_OPTION));
674 EnableWindow(GetDlgItem(Dialog, dirpath_PATH), IsDlgButtonChecked(Dialog, dirpath_OPTION));
675 }
676 break;
677 }
678 break;
679
680 case WM_NOTIFY:
681 switch (((LPNMHDR) lParam)->code)
682 { case PSN_SETACTIVE:
683 { dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA));
684
685 // bodge to set the dialogue path to the correct value
686 if (selector != rootSelector)
687 { selector->setPath(rootSelector->selectedPath());
688 SetDlgItemText(Dialog, dirpath_PATH, selector->selectedPath());
689 }
690
691 if (selector->isFinal())
692 { PropSheet_SetWizButtons(GetParent(Dialog), PSWIZB_BACK | PSWIZB_FINISH);
693 }
694 else
695 { PropSheet_SetWizButtons(GetParent(Dialog), PSWIZB_BACK | PSWIZB_NEXT);
696 }
697 }
698 break;
699
700 case PSN_KILLACTIVE:
701 break;
702
703 case PSN_WIZNEXT:
704 { // note the path from the dialog
705 dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA));
706 selector->setPathFromEdit(GetDlgItem(Dialog, dirpath_PATH));
707
708 // create a new FilePath object to check on the proposed destination
709 FilePath *path = new FilePath(selector->selectedPath());
710
711 // if the proposed destination doesn't exist, ask the user whether to
712 // create it now. TODO: actually create it if asked!
713 if (path->exists() == false)
714 { char buffer[128];
715
716 sprintf(buffer, "Directory %s does not exist - create it?", selector->selectedPath());
717
718 // if the user cancelled that, then don't permit them to go to the next
719 // page of the wizard
720 if (MessageBox(0, buffer, app_name, MB_YESNO | MB_TOPMOST) == IDNO)
721 { delete path;
722 SetWindowLong(Dialog, DWL_MSGRESULT, TRUE);
723 return TRUE;
724 }
725 }
726 delete path;
727 }
728 break;
729
730 case PSN_WIZFINISH:
731 { // Finish the activity now
732 config_complete = true;
733 }
734 break;
735 }
736 break;
737 }
738 return FALSE;
739}
740
741void GSInstall_init_propertySheet(PROPSHEETPAGE &ppage, char *prompt, char *optPrompt,
742 char *title, GSInstall &installer, bool isFinal)
743{ GSInstall_dirPathData *data = new GSInstall_dirPathData;
744
745 // create the directory Selector
746 data->dirSelect = new dirSelector(prompt, optPrompt, title, installer.installPath());
747 data->dirSelect->setFinal(isFinal);
748
749 // if there is no extant root selector, make this it
750 if (rootSelector == NULL)
751 { rootSelector = data->dirSelect;
752 }
753
754 // add this directory selector to the installer
755 installer.addSelectedDir(data->dirSelect);
756
757 // set up the rest of the page
758 ppage.dwSize = sizeof(PROPSHEETPAGE);
759 ppage.dwFlags = PSP_USETITLE;
760 ppage.hInstance = app_instance;
761 ppage.pszTemplate = "getDirPath";
762 ppage.pszIcon = 0;
763 ppage.pszTitle = app_name;
764 ppage.pfnDlgProc = (DLGPROC) GSInstall_dlgproc;
765 ppage.lParam = (LPARAM) data->dirSelect;
766 ppage.pfnCallback = NULL;
767}
768
769int CALLBACK GSInstall_wizardProc(HWND dialog, UINT Message, LPARAM lParameter)
770{ switch (Message)
771 { case PSCB_INITIALIZED :
772 // Process PSCB_INITIALIZED
773 gsInstall_wizard_centre(dialog);
774 break ;
775
776 case PSCB_PRECREATE :
777 // Process PSCB_PRECREATE
778 break ;
779
780 default :
781 // Unknown message
782 break ;
783 }
784 return 0;
785}
786
787bool GSInstall_init_wizard(GSInstall &install)
788{
789 PROPSHEETHEADER pshead;
790 PROPSHEETPAGE ppage[2];
791 bool reply;
792
793 ZeroMemory(&pshead, sizeof(PROPSHEETHEADER));
794 pshead.dwSize = sizeof(PROPSHEETHEADER);
795 pshead.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK | PSH_USEHICON | PSH_WIZARD;
796 pshead.hwndParent = app_window;
797 pshead.hInstance = app_instance;
798 pshead.hIcon = NULL;
799 pshead.pszCaption = "Greenstone Installer";
800 pshead.nPages = 2;
801 pshead.nStartPage = 0;
802 if (install.installExe == true)
803 {
804 pshead.ppsp = ppage;
805 }
806 else // cheat as the executable etc. is already installed
807 {
808 pshead.ppsp = &ppage[1];
809 }
810 pshead.pfnCallback = GSInstall_wizardProc;
811
812 GSInstall_init_propertySheet( ppage[0],
813 "Choose a directory to install your "
814 "GreenStone software to.", NULL,
815 "Select", install, false);
816 GSInstall_init_propertySheet(ppage[1],
817 "Choose a directory to install the collection "
818 "files to.\n\n"
819 "You can also choose to install all the collection "
820 "files onto your computer hard drive.\n\n"
821 "If you do this, you will not have to load the "
822 "CD-ROM each time you use your Greenstone software "
823 "but more of your hard disk will be used.\n\n"
824 "Some collection files must be installed on your "
825 "computer.\n\n",
826 "Install all collection files",
827 "Select", install, true);
828
829 reply = (PropertySheet (&pshead) >= 0);
830 return reply;
831}
832
833long FAR PASCAL GSInstallWindProc(HWND Window, WORD Message, WPARAM wParameter, LPARAM lParameter)
834{
835 long reply = 0;
836
837 switch(Message)
838 {
839 case WM_CREATE:
840 {
841 ShowWindow(Window, SW_MAXIMIZE);
842 }
843 break;
844
845 case WM_COMMAND:
846 break;
847
848 case WM_USER:
849 {
850 // uninstall action
851 if (strstr(app_cmdLine, "-u") != NULL)
852 {
853 // skip past the -u option itself
854 char *at = strstr(app_cmdLine, "-u");
855 at += strlen("-u");
856
857 // extract the log file path from the command line
858 while (*at == ' ')
859 {
860 at ++;
861 }
862 string logPathString(at);
863 FilePath logPath(logPathString);
864
865 GSInstall install(true);
866 // if we're running in the temporary directory, do the uninstall
867 if (install.setUninstall())
868 {
869 install.uninstall();
870
871 // close the log to write back all changes to the log; if the file
872 // will be deleted, it must be closed; copying may also fail, so it's
873 // safer to close it before doing either.
874 install.closeLog();
875
876 // if the install is empty, terminate all final items (currently the
877 // log and setup executables,
878 if (install.isEmpty())
879 {
880 // delete the log file
881 DeleteFile(logPath.cString());
882
883 // get it's parent to find where the gssetup executable will be
884 FilePath *logParent = logPath.parent();
885 FilePath uninstallPath(*logParent, "gssetup.exe");
886
887 // delete the gssetup executable
888 DeleteFile(uninstallPath.cString());
889
890 // dispose of the parent directory information
891 delete logParent;
892 }
893 // if not, then overwrite the original log with the modified one
894 else
895 {
896 // do nothing - should be changed already!
897 }
898 }
899 }
900 // install wizard
901 else
902 {
903 GSInstall install(false);
904 GSInstall_init_wizard(install);
905 if (config_complete == false)
906 {
907 MessageBox(0, "Install cancelled", app_name, MB_OK);
908 }
909 else
910 {
911 // configure the installation
912 install.setDestination();
913 install.setManifest();
914
915 // perform installation
916 install.copyFiles();
917 install.updateProgman();
918 install.updateRegistry();
919 install.updateProfiles();
920 install.updateSetupExe();
921
922 // the log will need reopening (probably failed initially)
923 install.reopenLog();
924
925 // close log
926 install.closeLog();
927
928 // do further actions
929 install.installNetscape();
930 }
931 }
932 DestroyWindow(Window);
933 }
934 break;
935
936 case WM_CLOSE:
937 /*if (!file_ischanged || IDCANCEL != file_query(Window, file_name))*/
938 DestroyWindow(Window);
939 return 0L;
940
941 case WM_DESTROY:
942 {
943 PostQuitMessage(0);
944 }
945 break;
946
947 default:
948 return(DefWindowProc(Window, Message, wParameter, lParameter));
949 }
950 return reply;
951}
952
953void GSInstall_init(HINSTANCE instance, int Show)
954{ int sx, sy;
955
956 gsInstall_getDesktopExt(&sx, &sy);
957
958 app_window = CreateWindow("GSInstall:Main", "GreenStone Installer",
959 WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | CS_DBLCLKS,
960 0, 0,
961 sx, sy,
962 NULL,
963 NULL,
964 app_instance,
965 NULL);
966
967 ShowWindow(app_window, Show);
968
969 PostMessage(app_window, WM_USER, 0, 0L);
970}
971
972void WinClassInit(void)
973{
974 WNDCLASS Class;
975
976 Class.lpszClassName = "GSInstall:Main";
977 Class.hInstance = app_instance;
978 Class.lpfnWndProc = (WNDPROC) GSInstallWindProc;
979 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
980 Class.hIcon = NULL; //LoadIcon(app_instance, "GSInstall");
981 Class.lpszMenuName = NULL;
982 Class.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE+1);
983 //Class.style = NULL;
984 Class.style = 0;
985 Class.cbClsExtra = 0;
986 Class.cbWndExtra = 0;
987 RegisterClass(&Class);
988 /*
989 Class.lpszClassName = "GSInstall:Splash";
990 Class.hInstance = app_instance;
991 Class.lpfnWndProc = (WNDPROC) splash_windproc;
992 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
993 Class.hIcon = NULL;
994 Class.lpszMenuName = NULL;
995 Class.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
996 Class.style = NULL;
997 Class.cbClsExtra = 0;
998 Class.cbWndExtra = 0;
999 RegisterClass(&Class);*/
1000}
1001
1002int PASCAL WinMain(HINSTANCE Current,
1003 HINSTANCE Previous,
1004 LPSTR CmdLine,
1005 int CmdShow)
1006{
1007 MSG msg;
1008 // HACCEL accel;
1009
1010 app_cmdLine = (char *) malloc(lstrlen(CmdLine) + 1);
1011 lstrcpy(app_cmdLine, CmdLine);
1012
1013 app_instance = Current;
1014 /* -- init application */
1015 if (!Previous)
1016 {
1017 WinClassInit();
1018 InitCommonControls();
1019 // grbStatic_registerClass(Current);
1020 }
1021
1022 /* -- init instance */
1023 GSInstall_init(Current, CmdShow);
1024
1025 // config_init("ReTreeval");
1026
1027 // accel = LoadAccelerators(Current, "ReTreevalMenu");
1028
1029 while (GetMessage(&msg, NULL, 0, 0))
1030 {
1031 /*if (!TranslateAccelerator(app_window, accel, &msg))
1032 { */
1033 TranslateMessage(&msg);
1034 DispatchMessage(&msg);
1035 /*}*/
1036 }
1037 return (int) msg.wParam;
1038}
Note: See TracBrowser for help on using the repository browser.