source: trunk/gsinstaller/gsinstall.cpp@ 1584

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

Removed messages and worked around the failure of windows 32s detection
which was resulting in the incorrect execution of the netscape installation.

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