source: trunk/gsinstaller/gsinstall.cpp@ 1545

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

Improved logging of manifest items, tidied the handling of items with extended
paths in the manifest (logging creation of directories on the path); finally
removed some old garbage from gsinstall.cpp.

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