source: trunk/gsinstaller/gsinstall.cpp@ 1657

Last change on this file since 1657 was 1657, checked in by sjboddie, 23 years ago

Fixed a couple of bugs that surfaced on windows 2000

  • Property svn:keywords set to Author Date Id Revision
File size: 30.2 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{
216 static char filename[512];
217 FilePath *exePath;
218
219 // get the filepath of this executable
220 GetModuleFileName(0, filename, 512);
221 exePath = new FilePath(filename);
222
223 // get the parent (i.e. the folder containing this executable) for the source
224 // folder
225 this->sourcePath = exePath->parent();
226
227 // get the gsdl source path
228 this->gsdlSourcePath = new FilePath(this->sourcePath->pathString(), "gsdl");
229 delete exePath;
230}
231
232/**
233 * Controls the actual copying of the files; manifests of what to install
234 * are read in from a configuration on the hard drive - this should be basically
235 * greenstone dependent, and void of any collection-specific rubbish!
236 */
237bool GSInstall::copyFiles()
238{
239 // ensure that we have got the required destination and that we can write there
240 if (this->installExe)
241 {
242// this->destinationPath->ensureWriteablePath();
243 }
244
245 // ensure that the destination path for the collection itself is available
246 if (this->installVolume)
247 {
248// this->dataDestPath->ensureWriteablePath();
249 }
250
251 // do the copy
252 this->manifest->copy(this->gsdlSourcePath);
253
254 return true;
255}
256
257/**
258 * Fulfill registry update requirements; first the keys are set up, then they
259 * are filled with key item/value pairs.
260 */
261bool GSInstall::updateRegistry()
262{
263 // don't do registry stuff under windows 32s
264 if (this->platform.isWindows32s() && FALSE)
265 {
266 return true;
267 }
268
269 // ensure all pertinent keys already exist for this volume/collection
270 this->gsRegister->ensureKeysExist();
271
272 // now move on to add key items
273 if (this->installExe)
274 {
275 // FilePath *serverPath = new FilePath(this->destinationPath->pathString(), "server.exe");
276 FilePath *serverPath = new FilePath(this->destinationPath->pathString(), "server.exe");
277 FilePath *setupPath = new FilePath(this->destinationPath->pathString(), "gssetup.exe");
278 FilePath *logPath = new FilePath(this->destinationPath->pathString(), "install.log");
279 string exeKeyPath, uninstallCmd, uninstallKeyPath;
280 gsPlatform platform;
281
282 // store the normal collection key information
283 this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE,
284 this->gsRegister->collectKeyId(),
285 "library",
286 serverPath->pathString());
287
288 // This test is in fact for 9x or NT 4+; we're worried about the registry
289 // format, not about the shell as such
290 if (platform.isExplorerShell())
291 {
292 // get special app path key for windows 9x
293 exeKeyPath = this->gsRegister->exeKeyId("server.exe");
294
295 // ensure that the exe key exists
296 this->gsRegister->ensureKeyExists(HKEY_LOCAL_MACHINE, exeKeyPath);
297
298 // store default key for this application
299 this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE,
300 exeKeyPath,
301 "",
302 serverPath->pathString());
303
304 // store path for this application
305 this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE,
306 exeKeyPath,
307 "path",
308 this->destinationPath->pathString());
309
310 // create uninstall command line
311 uninstallCmd = setupPath->pathString() + " -u " + logPath->pathString();
312 uninstallKeyPath = this->gsRegister->uninstallKeyId(this->configFile->getString("CollectionName"));
313
314 // ensure uninstall key exists
315 this->gsRegister->ensureKeyExists(HKEY_LOCAL_MACHINE, uninstallKeyPath);
316
317 this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, uninstallKeyPath,
318 "DisplayName",
319 this->configFile->getString("CollectionName"));
320 this->gsRegister->storeKeyString(HKEY_LOCAL_MACHINE, uninstallKeyPath,
321 "UninstallString", uninstallCmd);
322 }
323 delete setupPath;
324 delete serverPath;
325 delete logPath;
326 }
327
328 if (this->installVolume || this->installFullVolume)
329 {
330 // no actual key items are held in the volume key; for future use
331 }
332 return true;
333}
334
335/**
336 * Set the destination directory details
337 */
338void GSInstall::setDestination()
339{
340 // get configuration from the install wizard pages
341 this->destinationPath = new FilePath(this->selectedDirs[0]->selectedPath());
342 this->installFullVolume = this->selectedDirs[1]->getOption();
343 if (this->installFullVolume || true) // NB: always take path from 2nd dialog
344 {
345 this->dataDestPath = new FilePath(this->selectedDirs[1]->selectedPath());
346 }
347 else
348 {
349 this->dataDestPath = this->destinationPath;
350 }
351
352
353 // set the log for writing
354
355 FilePath *logPath = new FilePath(this->destinationPath->pathString(), "install.log");
356
357 this->setLogFile(logPath->pathString());
358
359 this->readLog();
360
361 delete logPath;
362
363}
364
365bool GSInstall::setUninstall()
366{
367 char tempPathStr[MAX_PATH];
368
369 // if we failed to get the Windows temporary directory, abort
370 if (GetTempPath(MAX_PATH, tempPathStr) == 0)
371 {
372 // TODO: abort!
373 return false;
374 }
375
376 FilePath tempPath(tempPathStr);
377
378 // if we are not running in the Windows temporary directory, copy this exe
379 // and the installation log to the temporary directory and run them there
380 if (*this->sourcePath != tempPath)
381 {
382 // copy this and install.log to temporary directory and restart
383 FilePath exePath(*this->sourcePath, "gssetup.exe");
384 FilePath logPath(*this->sourcePath, "install.log");
385
386 FilePath exeDest(tempPath, "gssetup.exe");
387 FilePath logDest(tempPath, "install.log");
388
389 CopyFile(exePath.cString(), exeDest.cString(), false);
390 CopyFile(logPath.cString(), logDest.cString(), false);
391
392 // now run the gssetup in the temporary directory
393 launchApp launchUninstall(exeDest);
394 launchUninstall.setCommandLine(" -u " + logPath.pathString());
395 launchUninstall.run(false, 0, "", "", false);
396
397 return false;
398 }
399
400 // open the log for reading from the directory this exe is now in (which
401 // will in fact be the temporary directory as outlined above)
402 FilePath *logPath = new FilePath(this->sourcePath->pathString(), "install.log");
403
404 this->setLogFile(logPath->pathString());
405 this->readLog();
406 delete logPath;
407
408 return true;
409}
410
411void GSInstall::uninstall()
412{
413 FilePath *iniPath;
414 string command;
415 stringArray params;
416
417 this->manifest = new gsManifest(*this); // get a manifest manager
418
419 iniPath = new FilePath(this->collectPath->pathString(), "gsdl.ini");
420 gsProfile gsdlProfile(*this, iniPath->pathString());
421
422 while ((command = this->popCommand(params)) != "")
423 {
424 if (!this->manifest->undoAction(command, params))
425 {
426 if (!gsdlProfile.undoAction(command, params))
427 {
428 if (!this->gsRegister->undoAction(command, params))
429 {
430 if (!this->progman->undoAction(command, params))
431 {
432 }
433 }
434 }
435 }
436 }
437}
438
439/**
440 * Collate the manifest for installation
441 */
442void GSInstall::setManifest()
443{
444 if (this->installExe)
445 {
446 this->manifest->selectGroup("library", *this->destinationPath);
447 }
448 if (this->installFullVolume)
449 {
450 this->manifest->selectGroup("collection", *this->dataDestPath);
451 }
452 else
453 {
454 this->manifest->selectGroup("database", *this->dataDestPath);
455 }
456}
457
458/**
459 * Update the program manager/explorer shell with icons, groups etc for this
460 * collection/application
461 */
462bool GSInstall::updateProgman()
463{
464 string groupName;
465 string collectionName;
466
467 // if we managed to get a connection to the program manager (or explorer
468 // shell) then do the requisite updates
469 if (this->progman->connect())
470 {
471 // get group name from folders
472 groupName = this->configFile->getString("ProgramGroupName");
473 if (groupName == "")
474 {
475 // TODO: error handling
476 this->progman->disconnect();
477 return false;
478 }
479 collectionName = this->configFile->getString("CollectionName");
480 if (collectionName == "")
481 {
482 // TODO: error handling
483 this->progman->disconnect();
484 return false;
485 }
486
487 // add the group
488 if (!this->progman->addProgramGroup(groupName))
489 {
490 this->progman->disconnect();
491 return false;
492 }
493
494 // add a "server" icon
495 FilePath libraryPath(this->destinationPath->pathString(), "server.exe");
496 if (!this->progman->addIcon(groupName, collectionName, libraryPath.pathString(), "", ""))
497 {
498 }
499
500 FilePath readMePath(this->destinationPath->pathString(), "readme.txt");
501 if (!this->progman->addIcon(groupName, "ReadMe", readMePath.pathString(), "", ""))
502 {
503 }
504
505 FilePath supportPath(this->destinationPath->pathString(), "Support.htm");
506 if (!this->progman->addIcon(groupName, "Technical Support", supportPath.pathString(), "", ""))
507 {
508 }
509
510
511 FilePath uninstallPath(this->destinationPath->pathString(), "gssetup.exe");
512 FilePath logPath(this->destinationPath->pathString(), "install.log");
513 if (!this->progman->addIcon(groupName, "Uninstall", uninstallPath.pathString(), " -u " + logPath.pathString(),
514 "Remove this Greenstone collection"))
515 {
516 }
517
518 // disconnect from program manager
519 this->progman->disconnect();
520 }
521 return true;
522}
523
524/**
525 * Update the profile (ini) files associated with the program; these changes
526 * must be made after copying to files in the destination/executable folders
527 * as we can't write to CD-ROM (or at least we shouldn't - the install would
528 * become tainted).
529 */
530bool GSInstall::updateProfiles()
531{
532 FilePath *exePath;
533 FilePath *dataPath;
534 FilePath *iniPath;
535
536 // if we're installing the exe, then the exe path leads to the destination
537 // folder of this installation sequence; if not, then we pick it up from
538 // the existing location of that folder
539 if (this->installExe)
540 {
541 exePath = this->destinationPath;
542 }
543 else
544 {
545 exePath = this->collectPath;
546 }
547 iniPath = new FilePath(exePath->pathString(), "gsdl.ini");
548
549 // TODO: check if this 'if' structure is correct; suspect that it isn't quite
550 // as we may not be installing the volume, but exe etc individually;
551 // may be okay now but not future proof; also the destination directory
552 // may or may not be tied to the exe directory if that existed already.
553 // This all needs investigating
554 if (this->installVolume)
555 {
556 // Manufacture the appropriate section name now; an equivalent string
557 // is also constructed
558 string volumeSectionString = this->configFile->getString("CollectionName") +
559 "#" + this->configFile->getString("CollectionVolume");
560
561 // if we're installing the full data for the collection, then take the
562 // data path to be at the selected destination directory for the collection
563 // files; otherwise take the data path to be on the CD/distribution media
564 if (this->installFullVolume)
565 {
566 dataPath = this->dataDestPath;
567 }
568 else
569 {
570 dataPath = this->gsdlSourcePath;
571 }
572
573 // create a profile object to write to the gsdl.ini file
574 gsProfile gsdlProfile(*this, iniPath->pathString());
575
576 // if installing the executable, add the database and greenstone home
577 // directories
578 if (this->installExe)
579 {
580 // set the correct exe entries in gsdl.ini (in the gsdl section)
581 gsdlProfile.writeString("gsdl", "gsdlhome", dataPath->pathString());
582 gsdlProfile.writeString("gsdl", "gdbmhome", this->dataDestPath->pathString());
583 }
584
585 // set the correct collection volume entries in gsdl.ini
586 if (this->installVolume)
587 {
588 // note the collection in the general gsdl section; and add the undo item too
589 gsdlProfile.ensureListMember("gsdl", gsdl_COLLIST, volumeSectionString);
590
591 // note the volume data in its own section
592 gsdlProfile.writeString(volumeSectionString, "gsdlhome", dataPath->pathString());
593 gsdlProfile.writeString(volumeSectionString, "gdbmhome", this->dataDestPath->pathString());
594 gsdlProfile.writeString(volumeSectionString, "staticpath", dataPath->pathString());
595 }
596 }
597
598 // clean up
599 delete iniPath;
600
601 return true;
602}
603
604/**
605 * Ensure that we've installed the very latest setup executable @ the destination/
606 * greenstone folder
607 */
608bool GSInstall::updateSetupExe()
609{
610 FilePath *destExePath;
611 FilePath srcExeFile(*this->sourcePath, "gssetup.exe");
612
613 if (this->installExe)
614 {
615 destExePath = this->destinationPath;
616 }
617 else
618 {
619 destExePath = this->collectPath;
620 }
621 FilePath destExeFile(*destExePath, "gssetup.exe");
622
623 if (!CopyFile(srcExeFile.cString(), destExeFile.cString(), false))
624 {
625 return false;
626 }
627 return true;
628}
629
630bool GSInstall::installNetscape()
631{
632 FilePath netscape32Path(this->sourcePath->pathString(), "netscape\\n32e405.exe");
633 FilePath netscape16Path(this->sourcePath->pathString(), "netscape\\n16e405.exe");
634
635 launchApp launchNetscape(netscape32Path);
636 launchNetscape.platformApp(gsPlatform_WINDOWS32S, netscape16Path);
637 launchNetscape.platformApp(gsPlatform_WINDOWS, netscape16Path);
638 if (launchNetscape.run(true, 1,
639 "This library is displayed using a web browser. If you don't "
640 "currently have a web browser installed on your machine you may "
641 "install the Netscape 4.05 browser now.\n\n"
642 "Note that if your current browser was provided by your internet "
643 "service provider, you should install Netscape in a different "
644 "directory.\n\n"
645 "Would you like to install the Netscape 4.05 browser now?",
646 "Greenstone Installer", false) < 0)
647 {
648 // MessageBox(0, "Error", app_name, MB_OK);
649 return false;
650 }
651 return true;
652}
653
654FilePath *GSInstall::collectionPath()
655{
656 return this->collectPath;
657}
658
659FilePath *GSInstall::installPath()
660{
661 return this->installToPath;
662}
663
664void GSInstall::addSelectedDir(dirSelector *selector)
665{
666 this->selectedDirs.push_back(selector);
667}
668
669typedef struct
670{
671 dirSelector * dirSelect;
672} GSInstall_dirPathData;
673
674HGLOBAL loadDirBrowser()
675{
676 HRSRC resHdl;
677
678 resHdl = FindResource(app_instance, "MySaveAsDlg", RT_DIALOG);
679 return LoadResource(app_instance, resHdl);
680}
681
682void gsInstall_wizard_centre(HWND dialog)
683{
684 RECT rect;
685 int sx, sy;
686 int dx, dy;
687
688 gsInstall_getDesktopExt(&sx, &sy);
689 GetWindowRect(dialog, &rect);
690
691 dx = (sx - rect.right + rect.left) >> 1;
692 dy = (sy - rect.bottom + rect.top) >> 1;
693 SetWindowPos(dialog, 0, dx, dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
694}
695
696BOOL FAR PASCAL GSInstall_dlgproc(HWND Dialog, UINT Message, WPARAM wParam, LPARAM lParam)
697{
698 static bool first = true; // static variable to hack the position of the
699 // whole wizard; note doing this in the wizard
700 // property sheet initialisation DOES NOT WORK
701
702 switch (Message)
703 {
704 case WM_INITDIALOG:
705 {
706 dirSelector *selector = (dirSelector *) ((PROPSHEETPAGE *) lParam)->lParam;
707
708 SetDlgItemText(Dialog, dirpath_PROMPT, selector->prompt);
709 if (selector->optPrompt != NULL)
710 {
711 SetDlgItemText(Dialog, dirpath_OPTION, selector->optPrompt);
712 EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), true); // was false
713 EnableWindow(GetDlgItem(Dialog, dirpath_PATH), true); // was false
714 }
715 else
716 {
717 ShowWindow(GetDlgItem(Dialog, dirpath_OPTION), SW_HIDE);
718 }
719 SetWindowLong(Dialog, GWL_USERDATA, ((PROPSHEETPAGE *) lParam)->lParam);
720 SetDlgItemText(Dialog, dirpath_PATH, selector->selectedPath());
721
722 // if this is the first time this function is called, then centre the
723 // wizard into the centre of our screen.
724 if (first)
725 {
726 gsInstall_wizard_centre(GetParent(Dialog));
727 first = false;
728 }
729 }
730 return TRUE;
731
732 case WM_COMMAND:
733 switch (LOWORD(wParam))
734 {
735 case dirpath_BROWSE:
736 ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->requestPath(Dialog, "Select Directory");
737 SetDlgItemText(Dialog, dirpath_PATH, ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->selectedPath());
738 break;
739
740 case dirpath_OPTION:
741 ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA))->setOption(IsDlgButtonChecked(Dialog, dirpath_OPTION));
742 if (HIWORD(wParam) == BN_CLICKED && false)
743 // don't do the enable/disable these days
744 {
745 EnableWindow(GetDlgItem(Dialog, dirpath_BROWSE), IsDlgButtonChecked(Dialog, dirpath_OPTION));
746 EnableWindow(GetDlgItem(Dialog, dirpath_PATH), IsDlgButtonChecked(Dialog, dirpath_OPTION));
747 }
748 break;
749 }
750 break;
751
752 case WM_NOTIFY:
753 switch (((LPNMHDR) lParam)->code)
754 {
755 case PSN_SETACTIVE:
756 {
757 dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA));
758
759 // bodge to set the dialogue path to the correct value
760 if (selector != rootSelector)
761 {
762 selector->setPath(rootSelector->selectedPath());
763 SetDlgItemText(Dialog, dirpath_PATH, selector->selectedPath());
764 }
765
766 if (selector->isFinal())
767 {
768 PropSheet_SetWizButtons(GetParent(Dialog), PSWIZB_BACK | PSWIZB_FINISH);
769 }
770 else
771 {
772 PropSheet_SetWizButtons(GetParent(Dialog), PSWIZB_BACK | PSWIZB_NEXT);
773 }
774 }
775 break;
776
777 case PSN_KILLACTIVE:
778 break;
779
780 case PSN_WIZNEXT:
781 {
782 // note the path from the dialog
783 dirSelector *selector = ((dirSelector *) GetWindowLong(Dialog, GWL_USERDATA));
784 selector->setPathFromEdit(GetDlgItem(Dialog, dirpath_PATH));
785
786 // create a new FilePath object to check on the proposed destination
787 FilePath *path = new FilePath(selector->selectedPath());
788
789 // if the proposed destination doesn't exist, ask the user whether to
790 // create it now. TODO: actually create it if asked!
791 if (path->exists() == false)
792 {
793 char buffer[128];
794
795 sprintf(buffer, "Directory %s does not exist - create it?", selector->selectedPath());
796
797 // if the user cancelled that, then don't permit them to go to the next
798 // page of the wizard
799 if (MessageBox(0, buffer, app_name, MB_YESNO | MB_TOPMOST) == IDNO)
800 {
801 delete path;
802 SetWindowLong(Dialog, DWL_MSGRESULT, TRUE);
803 return TRUE;
804 }
805 }
806 delete path;
807 }
808 break;
809
810 case PSN_WIZFINISH:
811 {
812 // Finish the activity now
813 config_complete = true;
814 }
815 break;
816 }
817 break;
818 }
819 return FALSE;
820}
821
822void GSInstall_init_propertySheet(PROPSHEETPAGE &ppage, char *prompt, char *optPrompt,
823 char *title, GSInstall &installer, bool isFinal)
824{
825 GSInstall_dirPathData *data = new GSInstall_dirPathData;
826
827 // create the directory Selector
828 data->dirSelect = new dirSelector(prompt, optPrompt, title, installer.installPath());
829 data->dirSelect->setFinal(isFinal);
830
831 // if there is no extant root selector, make this it
832 if (rootSelector == NULL)
833 {
834 rootSelector = data->dirSelect;
835 }
836
837 // add this directory selector to the installer
838 installer.addSelectedDir(data->dirSelect);
839
840 // set up the rest of the page
841 ppage.dwSize = sizeof(PROPSHEETPAGE);
842 ppage.dwFlags = PSP_USETITLE;
843 ppage.hInstance = app_instance;
844 ppage.pszTemplate = "getDirPath";
845 ppage.pszIcon = 0;
846 ppage.pszTitle = app_name;
847 ppage.pfnDlgProc = (DLGPROC) GSInstall_dlgproc;
848 ppage.lParam = (LPARAM) data->dirSelect;
849 ppage.pfnCallback = NULL;
850}
851
852int CALLBACK GSInstall_wizardProc(HWND dialog, UINT Message, LPARAM lParameter)
853{
854 switch (Message)
855 {
856 case PSCB_INITIALIZED :
857 // Process PSCB_INITIALIZED
858 gsInstall_wizard_centre(dialog);
859 break ;
860
861 case PSCB_PRECREATE :
862 // Process PSCB_PRECREATE
863 break ;
864
865 default :
866 // Unknown message
867 break ;
868 }
869 return 0;
870}
871
872bool GSInstall_init_wizard(GSInstall &install)
873{
874 PROPSHEETHEADER pshead;
875 PROPSHEETPAGE ppage[2];
876 bool reply;
877
878 ZeroMemory(&pshead, sizeof(PROPSHEETHEADER));
879 pshead.dwSize = sizeof(PROPSHEETHEADER);
880 pshead.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK | PSH_USEHICON | PSH_WIZARD;
881 pshead.hwndParent = app_window;
882 pshead.hInstance = app_instance;
883 pshead.hIcon = NULL;
884 pshead.pszCaption = "Greenstone Installer";
885 pshead.nPages = 2;
886 pshead.nStartPage = 0;
887 if (install.installExe == true)
888 {
889 pshead.ppsp = ppage;
890 }
891 else // cheat as the executable etc. is already installed
892 {
893 pshead.ppsp = &ppage[1];
894 }
895 pshead.pfnCallback = GSInstall_wizardProc;
896
897 GSInstall_init_propertySheet( ppage[0],
898 "Choose a directory to install your "
899 "GreenStone software to.", NULL,
900 "Select", install, false);
901 GSInstall_init_propertySheet(ppage[1],
902 "Choose a directory to install the collection "
903 "files to.\n\n"
904 "You can also choose to install all the collection "
905 "files onto your computer hard drive.\n\n"
906 "If you do this, you will not have to load the "
907 "CD-ROM each time you use your Greenstone software "
908 "but more of your hard disk will be used.\n\n"
909 "Some collection files must be installed on your "
910 "computer.\n\n",
911 "Install all collection files",
912 "Select", install, true);
913
914 reply = (PropertySheet (&pshead) >= 0);
915 return reply;
916}
917
918long FAR PASCAL GSInstallWindProc(HWND Window, WORD Message, WPARAM wParameter, LPARAM lParameter)
919{
920 long reply = 0;
921
922 switch(Message)
923 {
924 case WM_CREATE:
925 {
926 ShowWindow(Window, SW_MAXIMIZE);
927 }
928 break;
929
930 case WM_COMMAND:
931 break;
932
933 case WM_USER:
934 {
935 if (strstr(app_cmdLine, "-u") != NULL)
936 {
937 // uninstall action
938
939 // skip past the -u option itself
940 char *at = strstr(app_cmdLine, "-u");
941 at += strlen("-u");
942
943 // extract the log file path from the command line
944 while (*at == ' ')
945 {
946 at ++;
947 }
948 string logPathString(at);
949 FilePath logPath(logPathString);
950
951 GSInstall install(true);
952 // if we're running in the temporary directory, do the uninstall
953 if (install.setUninstall())
954 {
955 install.uninstall();
956
957 // close the log to write back all changes to the log; if the file
958 // will be deleted, it must be closed; copying may also fail, so it's
959 // safer to close it before doing either.
960 install.recordLog();
961
962 // if the install is empty, terminate all final items (currently the
963 // log and setup executables,
964 if (install.isEmpty())
965 {
966 // delete the log file
967 DeleteFile(logPath.cString());
968
969 // get it's parent to find where the gssetup executable will be
970 FilePath *logParent = logPath.parent();
971 FilePath uninstallPath(*logParent, "gssetup.exe");
972
973 // delete the gssetup executable
974 DeleteFile(uninstallPath.cString());
975
976 // dispose of the parent directory information
977 delete logParent;
978 }
979 // if not, then overwrite the original log with the modified one
980 else
981 {
982 // do nothing - should be changed already!
983 }
984 }
985 }
986 // install wizard
987 else
988 {
989 GSInstall install(false);
990 GSInstall_init_wizard(install);
991 if (config_complete == false)
992 {
993 MessageBox(0, "Install cancelled", app_name, MB_OK);
994 }
995 else
996 {
997 // configure the installation
998 install.setDestination();
999 install.setManifest();
1000
1001 // perform installation
1002 install.copyFiles();
1003 install.updateProgman();
1004 install.updateRegistry();
1005 install.updateProfiles();
1006 install.updateSetupExe();
1007
1008 // close log
1009 install.recordLog();
1010
1011 // do further actions
1012 install.installNetscape();
1013 }
1014 }
1015 DestroyWindow(Window);
1016 }
1017 break;
1018
1019 case WM_USER + 1:
1020 break;
1021
1022 case WM_CLOSE:
1023 /*if (!file_ischanged || IDCANCEL != file_query(Window, file_name))*/
1024 DestroyWindow(Window);
1025 return 0L;
1026
1027 case WM_DESTROY:
1028 {
1029 PostQuitMessage(0);
1030 }
1031 break;
1032
1033 default:
1034 return(DefWindowProc(Window, Message, wParameter, lParameter));
1035 }
1036 return reply;
1037}
1038
1039void GSInstall_init(HINSTANCE instance, int Show)
1040{
1041 int sx, sy;
1042
1043 gsInstall_getDesktopExt(&sx, &sy);
1044
1045 app_window = CreateWindow("GSInstall:Main", "GreenStone Installer",
1046 WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | CS_DBLCLKS,
1047 0, 0,
1048 sx, sy,
1049 NULL,
1050 NULL,
1051 app_instance,
1052 NULL);
1053
1054 ShowWindow(app_window, Show);
1055
1056 PostMessage(app_window, WM_USER, 0, 0L);
1057}
1058
1059void WinClassInit(void)
1060{
1061 WNDCLASS Class;
1062
1063 Class.lpszClassName = "GSInstall:Main";
1064 Class.hInstance = app_instance;
1065 Class.lpfnWndProc = (WNDPROC) GSInstallWindProc;
1066 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
1067 Class.hIcon = NULL; //LoadIcon(app_instance, "GSInstall");
1068 Class.lpszMenuName = NULL;
1069 Class.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE+1);
1070 Class.style = 0;
1071 Class.cbClsExtra = 0;
1072 Class.cbWndExtra = 0;
1073 RegisterClass(&Class);
1074}
1075
1076int PASCAL WinMain(HINSTANCE Current,
1077 HINSTANCE Previous,
1078 LPSTR CmdLine,
1079 int CmdShow)
1080{
1081 MSG msg;
1082
1083 app_cmdLine = (char *) malloc(lstrlen(CmdLine) + 1);
1084 lstrcpy(app_cmdLine, CmdLine);
1085
1086 app_instance = Current;
1087 /* -- init application */
1088 if (!Previous)
1089 {
1090 WinClassInit();
1091 InitCommonControls();
1092 }
1093
1094 /* -- init instance */
1095 GSInstall_init(Current, CmdShow);
1096
1097 while (GetMessage(&msg, NULL, 0, 0))
1098 {
1099 TranslateMessage(&msg);
1100 DispatchMessage(&msg);
1101 }
1102 return (int) msg.wParam;
1103}
Note: See TracBrowser for help on using the repository browser.