source: trunk/gsinstaller/gsinstall.cpp@ 1537

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

Changes to get compiling on VC++ and gcc

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