source: trunk/gsinstaller/gsinstall.cpp@ 2073

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

minor mods. changed some occurances of bool, true, and false to BOOL, TRUE
and FALSE in copyProgress.cpp (for VC++4.2) and changed all references to
gsdl.ini to instead point at gsdlsite.cfg.

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