Index: /trunk/gsinstaller/FilePath.cpp
===================================================================
--- /trunk/gsinstaller/FilePath.cpp	(revision 1497)
+++ /trunk/gsinstaller/FilePath.cpp	(revision 1498)
@@ -96,8 +96,5 @@
 }
 
-/**
- * Construct a Filepath from a directory and a sub-directory path
- */
-FilePath::FilePath(string filePath, string subPath)
+void FilePath::_init(string filePath, string subPath)
 { // copy the directory path
   this->path = filePath;
@@ -123,4 +120,15 @@
 }
 
+/**
+ * Construct a Filepath from a directory and a sub-directory path
+ */
+FilePath::FilePath(string filePath, string subPath)
+{ this->_init(filePath, subPath);
+}
+
+FilePath::FilePath(FilePath &path, string subPath)
+{ this->_init(path.pathString(), subPath);
+}
+
 FilePath::FilePath(string filePath)
 { if (filePath.length() < 3)
@@ -130,4 +138,9 @@
   else
   { this->path	= filePath;
+
+  	// trim trailing directory separators
+  	if (this->path[this->path.length() - 1] == '\\')
+  	{	this->path = this->path.substr(0, this->path.length() - 1);
+    }
   }
 
Index: /trunk/gsinstaller/FilePath.h
===================================================================
--- /trunk/gsinstaller/FilePath.h	(revision 1497)
+++ /trunk/gsinstaller/FilePath.h	(revision 1498)
@@ -8,4 +8,5 @@
 		string path;			// full path of this item
     bool	 is_aRoot;	// indicates whether this directory/file is a file root
+    void   _init(string path, string subPath);
 	public:
   	FilePath();
@@ -13,4 +14,5 @@
     FilePath(string filePath, string filePath2);
     FilePath(int nPaths, ...);
+    FilePath(FilePath &path, string subPath);
     bool      equals(FilePath &path);
     bool      equals(const char *path);
@@ -27,4 +29,5 @@
     string      pathString();
     bool operator==(const FilePath &b) { return this->path == b.path; }
+    bool operator!=(const FilePath &b) { return this->path != b.path; }
     bool operator<(const FilePath &b) { return this->path < b.path; }
 };
Index: /trunk/gsinstaller/fileCopier.cpp
===================================================================
--- /trunk/gsinstaller/fileCopier.cpp	(revision 1497)
+++ /trunk/gsinstaller/fileCopier.cpp	(revision 1498)
@@ -116,4 +116,9 @@
   	// this->copied += file->getRawFileSize();
 
+    // note for uninstall the action done
+	  if (monitor != NULL)
+  	{	monitor->copied(file->getFileName(), thisDestDir, true);
+  	}
+
   	// copy children
     vector<File>::iterator here	= file->childBegin();
@@ -123,8 +128,4 @@
     	here ++;
     }
-
-	  if (monitor != NULL)
-  	{	monitor->copied(file->getFileName(), thisDestDir, true);
-  	}
 
     // delete constructed destination name
Index: /trunk/gsinstaller/gsManifest.cpp
===================================================================
--- /trunk/gsinstaller/gsManifest.cpp	(revision 1497)
+++ /trunk/gsinstaller/gsManifest.cpp	(revision 1498)
@@ -248,17 +248,14 @@
 
 void gsManifest::logAction(string actionName, string file)
-{	manager->writeString(actionName);
-	manager->writeSeparator();
-  manager->writeString(file);
-  manager->writeString("\n");
+{ unInstallCommand command(actionName);
+	command.addParameter(file);
+  manager->storeCommand(command);
 }
 
 void gsManifest::logAction(string actionName, string source, string dest)
-{	manager->writeString(actionName);
-	manager->writeSeparator();
-  manager->writeString(source);
-	manager->writeSeparator();
-  manager->writeString(dest);
-  manager->writeString("\n");
+{	unInstallCommand command(actionName);
+	command.addParameter(source);
+  command.addParameter(dest);
+  manager->storeCommand(command);
 }
 
Index: /trunk/gsinstaller/gsProfile.cpp
===================================================================
--- /trunk/gsinstaller/gsProfile.cpp	(revision 1497)
+++ /trunk/gsinstaller/gsProfile.cpp	(revision 1498)
@@ -10,14 +10,10 @@
 void gsProfile::logAction(string action, string sectionName, string item,
 													string value)
-{ manager->writeString(action);
-	manager->writeSeparator();
-  manager->writeString(this->fileName);
-  manager->writeSeparator();
-  manager->writeString(sectionName);
-  manager->writeSeparator();
-  manager->writeString(item);
-  manager->writeSeparator();
-  manager->writeString(value);
-  manager->writeString("\n");
+{ unInstallCommand command(action);
+	command.addParameter(this->fileName);
+  command.addParameter(sectionName);
+  command.addParameter(item);
+  command.addParameter(value);
+  manager->storeCommand(command);
 }
 
Index: /trunk/gsinstaller/gsProgman.cpp
===================================================================
--- /trunk/gsinstaller/gsProgman.cpp	(revision 1497)
+++ /trunk/gsinstaller/gsProgman.cpp	(revision 1498)
@@ -87,19 +87,15 @@
 
 void gsProgramManager::logAction(string actionName, string group)
-{	manager->writeString(actionName);
-	manager->writeSeparator();
-  manager->writeString(group);
-	manager->writeString("\n");
+{ unInstallCommand command(actionName);
+	command.addParameter(group);
+	manager->storeCommand(command);
 }
 
 void gsProgramManager::logAction(string actionName, string group, string item, string parameter)
-{	manager->writeString(actionName);
-	manager->writeSeparator();
-  manager->writeString(group);
-	manager->writeSeparator();
-  manager->writeString(item);
-	manager->writeSeparator();
-  manager->writeString(parameter);
-	manager->writeString("\n");
+{ unInstallCommand command(actionName);
+  command.addParameter(group);
+ 	command.addParameter(item);
+  command.addParameter(parameter);
+  manager->storeCommand(command);
 }
 
@@ -109,5 +105,5 @@
   	return true;
   }
-  else if (actionName == "ProgManAddIcon")
+  else if (actionName == "ProgManAddItem")
   {	this->removeIcon(params[0], params[1]);
   	return true;
@@ -211,4 +207,10 @@
 		fullPath	= new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), ".lnk");
 
+    // check if the shortcut already exists then don't create this again
+    if (fullPath->exists())
+    { delete fullPath;
+    	return true;
+    }
+
 		// Get a pointer to the IShellLink interface.
   	hres = CoCreateInstance(CLSID_ShellLink, NULL,
@@ -241,4 +243,5 @@
   	  psl->Release();
 	  }
+    delete fullPath;
   }
   else
@@ -317,8 +320,13 @@
 	  }
 
+    // get path of folder from shell
 		SHGetPathFromIDList(pidl, buffer);
-		fullPath	= new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk");
-
-    // TODO: delete file
+
+    // delete file
+    fullPath	= new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk");
+		if (!DeleteFile(fullPath->cString()))
+    { reply = false;
+    }
+    delete fullPath;
   }
   else
Index: /trunk/gsinstaller/gsRegistry.cpp
===================================================================
--- /trunk/gsinstaller/gsRegistry.cpp	(revision 1497)
+++ /trunk/gsinstaller/gsRegistry.cpp	(revision 1498)
@@ -3,7 +3,5 @@
 gsRegistry::gsRegistry(installManager &manager, configureFile &configFile)
   : installAgent(manager)
-{ unsigned int space;
-
-	// Create string for volume key
+{ // Create string for volume key
 	volumeKey = "Software\\" + configFile.getString("CompanyName") + "\\" +
 							configFile.getString("CollectionName") + "\\" +
@@ -18,19 +16,16 @@
 
 bool gsRegistry::logAction(string action, HKEY base, string path, string item, string value)
-{	manager->writeString(action);
-	manager->writeSeparator();
-  manager->writeString(path);
+{ unInstallCommand command(action);
+	command.addParameter(path);
 	if (item != "" || value != "")
-  { manager->writeSeparator();
-  	if (item == "")
-    {	manager->writeString("{Default}");
+  {	if (item == "")
+    {	command.addParameter("{Default}");
     }
     else
-    {	manager->writeString(item);
+    {	command.addParameter(item);
     }
-		manager->writeSeparator();
-  	manager->writeString(value);
+    command.addParameter(value);
   }
-  manager->writeString("\n");
+  return manager->storeCommand(command);
 }
 
@@ -66,5 +61,5 @@
 
 bool gsRegistry::destroyKey(HKEY base, string key)
-{	registry_deletekey(base, key.c_str());
+{	return registry_deletekey(base, key.c_str());
 }
 
@@ -92,4 +87,5 @@
   registry_deleteitem(local, item.c_str());
   registry_closekey(local);
+  return true;
 }
 
Index: /trunk/gsinstaller/gsinstall.cpp
===================================================================
--- /trunk/gsinstaller/gsinstall.cpp	(revision 1497)
+++ /trunk/gsinstaller/gsinstall.cpp	(revision 1498)
@@ -67,5 +67,5 @@
     bool				installNetscape();
     void				setDestination();
-    void				setUninstall();
+    bool				setUninstall();
     void				uninstall();
     void				setManifest();
@@ -320,10 +320,43 @@
 }
 
-void GSInstall::setUninstall()
-{
-  // open the log for reading
-  FilePath *logPath = new FilePath(this->collectPath->pathString(), "install.log");
+bool GSInstall::setUninstall()
+{ char tempPathStr[MAX_PATH];
+
+  // if we failed to get the Windows temporary directory, abort
+  if (GetTempPath(MAX_PATH, tempPathStr) == 0)
+  { // TODO: abort!
+  	return false;
+  }
+
+  FilePath tempPath(tempPathStr);
+
+  // if we are not running in the Windows temporary directory, copy this exe
+  // and the installation log to the temporary directory and run them there
+  if (*this->sourcePath != tempPath)
+  { // copy this and install.log to temporary directory and restart
+  	FilePath exePath(*this->sourcePath, "gssetup.exe");
+    FilePath logPath(*this->sourcePath, "install.log");
+
+    FilePath exeDest(tempPath, "gssetup.exe");
+    FilePath logDest(tempPath, "install.log");
+
+  	CopyFile(exePath.cString(), exeDest.cString(), false);
+    CopyFile(logPath.cString(), logDest.cString(), false);
+
+    // now run the gssetup in the temporary directory
+    launchApp launchUninstall(exeDest);
+    launchUninstall.setCommandLine(" -u " + logPath.pathString());
+    launchUninstall.run(false, 0, "", "", false);
+
+    return false;
+  }
+
+  // open the log for reading from the directory this exe is now in (which
+  // will in fact be the temporary directory as outlined above)
+  FilePath *logPath = new FilePath(this->sourcePath->pathString(), "install.log");
   this->openLog(logPath->pathString(), false);
   delete logPath;
+
+  return true;
 }
 
@@ -338,5 +371,5 @@
 	gsProfile gsdlProfile(*this, iniPath->pathString());
 
-	while ((command = this->readCommand(params)) != "")
+	while ((command = this->popCommand(params)) != "")
   {	if (!this->manifest->undoAction(command, params))
     { if (!gsdlProfile.undoAction(command, params))
@@ -752,11 +785,47 @@
     case WM_USER:
     { // uninstall action
-    	if (strstr(app_cmdLine, "-u") != NULL || true)
-    	{ char *at = strstr(app_cmdLine, "-u");
-      	at += strlen("-u") + 1;
+    	if (strstr(app_cmdLine, "-u") != NULL)
+    	{ // skip past the -u option itself
+      	char *at = strstr(app_cmdLine, "-u");
+      	at += strlen("-u");
+
+        // extract the log file path from the command line
+        while (*at == ' ')
+        { at ++;
+        }
+        string logPathString(at);
+        FilePath logPath(logPathString);
 
  				GSInstall install(true);
-        install.setUninstall();
-        install.uninstall();
+        // if we're running in the temporary directory, do the uninstall
+        if (install.setUninstall())
+      	{	install.uninstall();
+
+        	// close the log to write back all changes to the log; if the file
+          // will be deleted, it must be closed; copying may also fail, so it's
+          // safer to close it before doing either.
+        	install.closeLog();
+
+          // if the install is empty, terminate all final items (currently the
+          // log and setup executables,
+          if (install.isEmpty())
+          { // delete the log file
+          	DeleteFile(logPath.cString());
+
+            // get it's parent to find where the gssetup executable will be
+          	FilePath *logParent = logPath.parent();
+						FilePath uninstallPath(*logParent, "gssetup.exe");
+
+            // delete the gssetup executable
+            DeleteFile(uninstallPath.cString());
+
+            // dispose of the parent directory information
+            delete logParent;
+          }
+          // if not, then overwrite the original log with the modified one
+          else
+          { // do nothing - should be changed already!
+          }
+        }
       }
       // install wizard
@@ -777,4 +846,10 @@
     		  install.updateRegistry();
         	install.updateProfiles();
+
+          // the log will need reopening (probably failed initially)
+				  install.reopenLog();
+
+          // close log
+          install.closeLog();
 
 	        // do further actions
Index: /trunk/gsinstaller/launchApp.cpp
===================================================================
--- /trunk/gsinstaller/launchApp.cpp	(revision 1497)
+++ /trunk/gsinstaller/launchApp.cpp	(revision 1498)
@@ -11,7 +11,12 @@
 }
 
+void launchApp::setCommandLine(string commandLine)
+{	this->commandline = commandLine;
+}
+
 int launchApp::run(bool test, int deftest, string prompt, string header, bool wait)
 { gsPlatform	platform;
 	FilePath		exePath;
+  string			runLine;
 
 	if (test)
@@ -43,6 +48,14 @@
   process.hProcess	=	0;
 
+  // build command line if required
+  if (this->commandline != "")
+  { runLine = exePath.pathString() + " " + this->commandline;
+  }
+
 	// execute the process
-  if (CreateProcess(exePath.cString(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &process) == 0)
+  if (CreateProcess((LPSTR) exePath.cString(),
+  									runLine != "" ? (LPSTR) runLine.c_str() : NULL,
+                    NULL, NULL, FALSE, 0, NULL, NULL,
+                    &startup, &process) == 0)
   {	DWORD	error	= GetLastError();
   	return -2;
Index: /trunk/gsinstaller/launchApp.h
===================================================================
--- /trunk/gsinstaller/launchApp.h	(revision 1497)
+++ /trunk/gsinstaller/launchApp.h	(revision 1498)
@@ -12,7 +12,9 @@
 {	private:
 		_exeMap	exeMap;
+    string  commandline;
 	public:
   	launchApp(FilePath &appsrc);
     void platformApp(string platform, FilePath &appsrc);
+    void setCommandLine(string commands);
     int run(bool test, int deftest, string prompt, string title, bool wait);
 };
Index: /trunk/gsinstaller/stringArray.cpp
===================================================================
--- /trunk/gsinstaller/stringArray.cpp	(revision 1497)
+++ /trunk/gsinstaller/stringArray.cpp	(revision 1498)
@@ -146,4 +146,18 @@
 }
 
+string stringArray::toString(string separator)
+{ string reply;
+
+	vector<string>::iterator here = this->array.begin();
+	vector<string>::iterator end  = this->array.end();
+  while (here != end)
+  {	if (here != this->array.begin())
+  	{ reply += separator;
+    }
+    reply += *here;
+  }
+  return reply;
+}
+
 stringArray stringArray::words(char *buffer)
 {	stringArray reply;
@@ -176,4 +190,5 @@
 void stringArray::clear()
 {	this->array.empty();
+	this->array.erase(this->array.begin(), this->array.end());
 }
 
Index: /trunk/gsinstaller/stringArray.h
===================================================================
--- /trunk/gsinstaller/stringArray.h	(revision 1497)
+++ /trunk/gsinstaller/stringArray.h	(revision 1498)
@@ -28,4 +28,5 @@
     int  indexOf(string member);
     int  writeToCString(char *buffer, char *divider, int bufflen);
+    string toString(string separator);
     string &operator[](const unsigned int);
 };
Index: /trunk/gsinstaller/unInstall.cpp
===================================================================
--- /trunk/gsinstaller/unInstall.cpp	(revision 1497)
+++ /trunk/gsinstaller/unInstall.cpp	(revision 1498)
@@ -6,8 +6,37 @@
 
 bool installManager::openLog(string filename, bool write)
-{	if (this->logfile.rdbuf()->is_open())
-	{	this->logfile.close();
-  }
-  this->logfile.open(filename.c_str(), (write ? ios::out : ios::in) | ios::app);
+{ string command;
+	stringArray params;
+
+	if (this->logfile.rdbuf()->is_open())
+	{	this->closeLog();
+  }
+  this->logfileName = filename;
+  this->logfile.open(filename.c_str(), ios::out | ios::in);
+  if (write == false)
+  { while ((command = this->readCommand(params)) != "")
+  	{ if (command[0] == '[' && command[command.length()-1] == ']')
+  		{ this->setModule(command.substr(1, command.length() - 2));
+    	}
+    	else
+    	{ unInstallCommand action(command, params);
+    		this->storeCommand(action);
+    	}
+    }
+  }
+  this->setModule("default");
+  return true;
+}
+
+bool installManager::reopenLog()
+{ if (this->logfile.rdbuf()->is_open())
+  { this->logfile.close();
+  }
+  else
+  { this->logfile.close();
+	}
+  
+  this->logfile.open(this->logfileName.c_str(), ios::out | ios::in);
+  return true;
 }
 
@@ -16,7 +45,30 @@
 }
 
+bool installManager::storeCommand(unInstallCommand &command)
+{ this->modules[this->currentModule].push_back(command);
+	return true;
+}
+
+bool installManager::writeCommand(unInstallCommand &command)
+{ if (!this->writeString(command.command))
+	{ return false;
+  }
+	for (unsigned int p = 0; p < command.parameters.size(); p ++)
+  {	if (!this->writeSeparator())
+  	{ return false;
+    }
+    if (!this->writeString(command.parameters[p]))
+    { return false;
+    }
+  }
+  if (!this->writeString("\n"))
+  { return false;
+  }
+  return true;
+}
+
 bool installManager::writeString(char *buffer)
 { string s(buffer);
-	this->writeString(s);
+	return this->writeString(s);
 }
 
@@ -43,11 +95,20 @@
 
 string installManager::readString()
-{	string reply;
+{	string reply = "";
 	char c;
 
+  if (this->logfile.eof())
+	{	return reply;
+  }
+
   this->logfile >> c;
-  while (c <= ' ')
+  while (c <= ' ' && !this->logfile.eof())
   {	this->logfile.get();
   }
+
+  if (this->logfile.eof())
+  { return reply;
+  }
+
   if (c == '\"')
   { do
@@ -57,13 +118,18 @@
       }
     }
-    while (c != '\"');
+    while (c != '\"' && !this->logfile.eof());
   }
   else
-  { /*while (c > ' ')
+  { while (c > ' ')
     { reply += c;
+    	if (this->logfile.eof())
+      {	break;
+      }
     	c = this->logfile.get();
-    }*/
-  	this->logfile.putback(c);
-    this->logfile >> reply;
+    }
+    if (!this->logfile.eof())
+    {	this->logfile.putback(c);
+    }
+    //this->logfile >> reply;
   }
   return reply;
@@ -71,22 +137,90 @@
 
 string installManager::readCommand(stringArray &array)
-{	string reply;
+{	string reply = "";
   char c;
 
   array.clear();
 
+  if (this->logfile.eof())
+  {	return reply;
+  }
+
 	reply = this->readString();
-  while((c = this->logfile.get()) != '\n')
+  if (reply == "")
+  { return reply;
+  }
+
+  while(!this->logfile.eof() &&
+  			(c = this->logfile.get()) != '\n')
   {	this->logfile.putback(c);
-  	array.add(this->readString());
-  }
-  this->logfile.putback(c);
+   	array.add(this->readString());
+  }
+  if (!this->logfile.eof())
+  { this->logfile.putback(c);
+  }
 
   return reply;
+}
+
+string installManager::popCommand(stringArray &array)
+{ string command;
+
+  if (this->modules[this->currentModule].size() == 0)
+  { command = "";
+  }
+  else
+  { unsigned int last;
+
+	  last = this->modules[this->currentModule].size() - 1;
+  	command = this->modules[this->currentModule][last].commandName();
+  	array		= this->modules[this->currentModule][last].parameterList();
+    this->modules[this->currentModule].erase(this->modules[this->currentModule].begin() + last);
+  }
+  return command;
+}
+
+bool installManager::closeLog()
+{ if (this->logfile.rdbuf()->is_open() == false)
+  { return false;
+  }
+
+	unInstallCommandMap::iterator here = this->modules.begin();
+	unInstallCommandMap::iterator end  = this->modules.end();
+
+  while (here != end)
+  {	this->writeString("[" + (*here).first + "]\n");
+
+  	unInstallCommandList::iterator	ahere = (*here).second.begin();
+    unInstallCommandList::iterator  aend  = (*here).second.end();
+    while (ahere != aend)
+		{ this->writeCommand(*ahere);
+    	ahere ++;
+    }
+  	here ++;
+  }
+	this->logfile.close();
+  return true;
+}
+
+bool installManager::isEmpty()
+{ unInstallCommandMap::iterator here = this->modules.begin();
+	unInstallCommandMap::iterator end  = this->modules.end();
+
+  while (here != end)
+  {	this->writeString("[" + (*here).first + "]\n");
+
+  	unInstallCommandList::iterator	ahere = (*here).second.begin();
+    unInstallCommandList::iterator  aend  = (*here).second.end();
+    if (ahere != aend)
+    {	return false;
+    }
+  	here ++;
+  }
+  return true;
 }
 
 installManager::~installManager()
 {	if (this->logfile.rdbuf()->is_open())
-	{	this->logfile.close();
+	{	this->closeLog();
   }
 }
Index: /trunk/gsinstaller/unInstall.h
===================================================================
--- /trunk/gsinstaller/unInstall.h	(revision 1497)
+++ /trunk/gsinstaller/unInstall.h	(revision 1498)
@@ -13,7 +13,18 @@
 static string uninstall_ALL = "all";
 
-typedef struct unInstallCommand
-{	string			command;
-	stringArray	parameters;
+typedef class unInstallCommand
+{ public:
+		string			command;
+		stringArray	parameters;
+
+    unInstallCommand() { };
+    unInstallCommand(string commandname) { this->command = commandname; };
+    unInstallCommand(string commandname, stringArray params)
+    { this->command = commandname;
+    	this->parameters = params;
+    };
+    void addParameter(string parameter) { this->parameters.add(parameter); };
+    string commandName() { return this->command; };
+    stringArray &parameterList() { return this->parameters; };
 } unInstallCommand;
 
@@ -24,15 +35,24 @@
 class installManager
 {	private:
-		fstream logfile;
-    string	currentModule;
-	public:
-  	installManager() { };
-    bool openLog(string filename, bool write);
-    void setModule(string moduleName);
+		fstream 							logfile;
+    string								logfileName;
+    string								currentModule;
+    unInstallCommandMap 	modules;
+
     bool writeString(string str);
     bool writeString(char *string);
     bool writeSeparator();
     string readString();
+    bool writeCommand(unInstallCommand &command);
     string readCommand(stringArray &params);
+	public:
+  	installManager() { };
+    bool openLog(string filename, bool write);
+    bool closeLog();
+    bool reopenLog();
+    void setModule(string moduleName);
+    bool storeCommand(unInstallCommand &command);
+    string popCommand(stringArray &params);
+    bool isEmpty();
     ~installManager();
 };
