source: trunk/gsinstaller/gsinstall.cpp@ 1765

Last change on this file since 1765 was 1765, checked in by cs025, 23 years ago

Fixes for Windows 3.1; avoids crashes at the expense of functionality (to be
reinstated).

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