source: trunk/gsinstaller/gsinstall.cpp@ 1539

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

Got compiling on VC++ 4.2

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