source: trunk/gsinstaller/gsinstall.cpp@ 1543

Last change on this file since 1543 was 1543, checked in by sjboddie, 24 years ago

* empty log message *

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