// (c) 2005 Electronic Arts Inc.
//

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.ServiceProcess;
using System.Windows.Forms;
using System.Collections.Generic;

using Microsoft.Win32;

using EA.GameTalkMessages;

namespace EA.GameTalk
{
	/// <summary>
	/// Summary description for Installer.
	/// </summary>
	public sealed class Installer
	{
		private const string mGameTalkServerServiceRegEntry = @"SYSTEM\CurrentControlSet\Services\GameServer";
		private string mInstallationDirectory = Application.CommonAppDataPath;
		private string mGameTalkVersion;

		private Installer()
		{
			Assembly asm = Assembly.GetExecutingAssembly();
			// The following is GameTalk's version (NOT the tool that happens to be running GameTalk)
			mGameTalkVersion = asm.GetName().Version.ToString();

			// Instead of using Application.LocalUserAppDataPath - we will try to set mInstallationDirectory
			// to a path that closely resembles Application.CommonAppDataPath (shared between users)
			string rootPathForCommonAppDataPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData);
			object[] objArray = asm.GetCustomAttributes(false);
			// Windows can handle a directory with two consecutive backslashes - so empty string will work
			string companyName = string.Empty;
			// Windows can handle a directory with two consecutive backslashes - so empty string will work
			string titleName = string.Empty;
			foreach (object obj in objArray)
			{
				AssemblyCompanyAttribute company = obj as AssemblyCompanyAttribute;
				if (company != null)
					companyName = company.Company;

				AssemblyTitleAttribute title = obj as AssemblyTitleAttribute;
				if (title != null)
					titleName = title.Title;
			}
			// For some reason by default Microsoft removes "." from the company string it returns the string
			// from Application.CommonAppDataPath - so we'll imitate that
			mInstallationDirectory = rootPathForCommonAppDataPath + "\\" + companyName.Replace(".", "") + "\\" + titleName + "\\" + mGameTalkVersion;
		}

		#region Singleton Code
		class Nested
		{
			// Explicit static constructor to tell C# compiler
			// not to mark type as beforefieldinit
			static Nested()
			{
			}

			internal static readonly Installer instance = new Installer();
		}

		/// <summary>
		/// Singleton
		/// </summary>
		public static Installer Instance
		{
			get
			{
				return Nested.instance;
			}
		}
		#endregion

		/// <summary>
		/// Create a file from the resource specified
		/// </summary>
		/// <param name="resourceName">The resource name to use</param>
		/// <param name="fileName">The file name to write the resource to file</param>
		/// <param name="asm"></param>
		public static void CreateFileFromResource(string resourceName, string fileName, Assembly asm)
		{
			// Create path if it doesn't exists
			string path = Path.GetDirectoryName(fileName);
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}

			Stream stream = asm.GetManifestResourceStream(resourceName);
			BinaryReader reader = new BinaryReader(stream);
			FileStream fileStream = null;
			bool success = false;
			// Sometimes we get blocked from creating a file - but often a slight pause can make all the difference
			for (int i = 0; (i < 50) && (!success); i++)
			{
				try
				{
					fileStream = File.Open(fileName, FileMode.Create, FileAccess.Write);
					BinaryWriter writer = new BinaryWriter(fileStream);

					for (; (i < 50) && (!success); i++)
					{
						try
						{
							writer.Write(reader.ReadBytes((int)stream.Length));
							writer.Flush();
							success = true;
						}
						catch (Exception e)
						{
							Trace.WriteLine(e.Message);
							System.Threading.Thread.Sleep(15);
						}
					}
				}
				catch (Exception e)
				{
					Trace.WriteLine(e.Message);
					System.Threading.Thread.Sleep(15);
				}
				finally
				{
					if (fileStream != null)
					{
						fileStream.Close();
					}
				}
			}
		}

		/// <summary>
		/// Whether a new version needs to be installed based on the version number stored in the registry and this assembly's version number
		/// </summary>
		/// <param name="installedVersion"></param>
		/// <param name="currentVersionStr"></param>
		/// <returns></returns>
		public static bool ShouldNewVersionBeInstalled(string installedVersion, string currentVersionStr)
		{
			bool installNewVersion = false;
			if (installedVersion != null)
			{
				try
				{
					string[] currentVersion = currentVersionStr.Split('.');
					string[] registryVersion = installedVersion.Split('.');
					int currentMajor = int.Parse(currentVersion[0]);
					int registryMajor = int.Parse(registryVersion[0]);
					int currentMinor = int.Parse(currentVersion[1]);
					int registryMinor = int.Parse(registryVersion[1]);

					int currentRevision = int.Parse(currentVersion[2]);
					int registryRevision = int.Parse(registryVersion[2]);
					// In case we want to make install decisions based on build
					/*int currentBuild = int.Parse(currentVersion[3]);
					int registryBuild = int.Parse(registryVersion[3]);
					installNewVersion = (currentMajor >= registryMajor) && (currentMinor >= registryMinor)
						|| (currentRevision >= registryRevision) || (currentBuild > registryBuild);*/
					if (!installNewVersion)
						installNewVersion = (currentMajor >= registryMajor) && (currentMinor >= registryMinor)
							&& (currentRevision > registryRevision);

					if (!installNewVersion)
						installNewVersion = (currentMajor >= registryMajor) && (currentMinor > registryMinor);

					if (!installNewVersion)
						installNewVersion = (currentMajor > registryMajor);
				}
				catch { }
			}
			else
				installNewVersion = true;

			return installNewVersion;
		}

		private bool ShouldNewVersionBeInstalled(string installedVersion)
		{
			return ShouldNewVersionBeInstalled(installedVersion, mGameTalkVersion);
		}

		/// <summary>
		/// Work-around for a microsoft bug
		/// </summary>
		/// <param name="gameTalkServerServiceRegEntry"></param>
		public static void PatchRegistry(string gameTalkServerServiceRegEntry)
		{
			try
			{
				RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(gameTalkServerServiceRegEntry, true);
				if (rk == null)
					return;

				string imagePathValue = (string)rk.GetValue("ImagePath");
				if ((imagePathValue != null) && (imagePathValue.IndexOf("\"") == -1))
					rk.SetValue("ImagePath", "\"" + imagePathValue + "\"");
			}
			catch (Exception)
			{
				//Trace.WriteLine(e.Message + Environment.NewLine+ e.StackTrace);
			}
		}

		private void UpdateServerUsbAssembliesOnDisk(bool overwriteFiles = false, bool deleteFiles = false)
		{
			const string usbServiceResourcePrefix = "ea.gametalk.usbservice.";
			System.Reflection.Assembly executingAssembly = Assembly.GetExecutingAssembly();
			foreach (string manifestResourceName in executingAssembly.GetManifestResourceNames())
			{
				if (manifestResourceName.ToLower().Contains(usbServiceResourcePrefix))
				{
					string fileName = manifestResourceName.Substring(usbServiceResourcePrefix.Length);
					string fullFilePath = System.IO.Path.Combine(mInstallationDirectory, "plugins", fileName);
					if (deleteFiles)
					{
						try
						{
							if (File.Exists(fullFilePath))
								File.Delete(fullFilePath);
						}
						catch {	}
					}
					else
					{
						if ((!File.Exists(fullFilePath)) || overwriteFiles)
							CreateFileFromResource(manifestResourceName, fullFilePath, executingAssembly);
					}
				}
			}
		}

		private void WriteServerAssembliesToDisk(bool overwriteFiles = false)
		{
			const string gameServerResourcePrefix = "ea.gametalk.gameserver.";
			System.Reflection.Assembly executingAssembly = Assembly.GetExecutingAssembly();
			foreach (string manifestResourceName in executingAssembly.GetManifestResourceNames())
			{
				if (manifestResourceName.ToLower().Contains(gameServerResourcePrefix))
				{
					// If users get upset about us deploying pdb's - we can uncomment the following:
/*#if !DEBUG
					if (manifestResourceName.EndsWith(".pdb")
						continue;
#endif*/
					// Can't believe we can't get the file name doing the following - don't understand why
					/*ManifestResourceInfo manifestResource = executingAssembly.GetManifestResourceInfo(manifestResourceName);
					string fileName = manifestResource.FileName;*/
					string fileName = manifestResourceName.Substring(gameServerResourcePrefix.Length);
					string fullFilePath = System.IO.Path.Combine(mInstallationDirectory, fileName);
					if ((!File.Exists(fullFilePath)) || overwriteFiles)
						CreateFileFromResource(manifestResourceName, fullFilePath, executingAssembly);
				}
			}
		}

		private ServiceController GetGameTalkServerService()
		{
			ServiceController[] services = ServiceController.GetServices();
			foreach (ServiceController service in services)
			{
				if (service.ServiceName.Equals("GameServer"))
					return service;
			}

			return null;
		}

		/// <summary>
		/// This will stop the existing GameTalkServer and install and start a new one
		/// </summary>
		/// <returns></returns>
		public bool InstallServer(bool startServerAsApp, bool installUsbPlugin = false)
		{
			string gameTalkServerFilename = "GameTalkServer.exe";
			if (Configuration.Instance.Use32BitGameTalkServer)
				gameTalkServerFilename = "GameTalkServer-32bit.exe";
			string installUtilFullFilename = mInstallationDirectory + @"\" + "InstallUtil.exe";

			bool installedNewVersion = false;
			// This indicates either the service wasn't found or we're not trying to install the server as a service (i.e. if the user wants to start it as an application)
			bool serverFound = false;
			ServiceController gameTalkServerService = GetGameTalkServerService();
			Process gameTalkServerProcess = Configuration.Instance.GameTalkServerRunningAsApplication();
			if (startServerAsApp)
			{
				if ((gameTalkServerService == null) && (gameTalkServerProcess != null)) // Basically we're saying - if the service is installed - then we'll assume the process running is the service (not necessarily true - but shouldn't be too harmful)
					serverFound = true;
			}
			else if (gameTalkServerService != null)
				serverFound = true;

			string latestInstalledVersion = Configuration.Instance.GetInstalledGameTalkVersion();
			bool installNewVersion = ShouldNewVersionBeInstalled(latestInstalledVersion);
			// The above checks the version of the last GameTalk that was installed
			// That doesn't mean that that version is currently running (because there are old versions of GameTalk that don't update that key)
			// So we check on the GameTalkServer's "path to executable" registry key
			// to make sure that is the same file path as the current version and if not - reinstall/start
			if (!installNewVersion)
			{
				RegistryKey gameTalkServiceExecPathKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(mGameTalkServerServiceRegEntry);
				if (gameTalkServiceExecPathKey != null)
				{
					string gameTalkServiceExecPath = (string)gameTalkServiceExecPathKey.GetValue("ImagePath");
					if (gameTalkServiceExecPath != null)
					{
						string gameTalkStr = "\\gametalk\\";
						int startOfGameTalkStr = gameTalkServiceExecPath.IndexOf(gameTalkStr);
						int startOfGameTalkExecStr = gameTalkServiceExecPath.IndexOf("\\gametalkserver.exe");
						if ((startOfGameTalkStr != -1) && (startOfGameTalkExecStr != -1))
						{
							int endOfGameTalkStr = startOfGameTalkStr + gameTalkStr.Length;
							if (endOfGameTalkStr < startOfGameTalkExecStr)
							{
								string currentlyRunningVersion = gameTalkServiceExecPath.Substring(endOfGameTalkStr, startOfGameTalkExecStr - endOfGameTalkStr);
								installNewVersion = ShouldNewVersionBeInstalled(currentlyRunningVersion);
							}
						}
					}

					gameTalkServiceExecPathKey.Close();
				}
			}

			if ((!serverFound) || (installNewVersion))
			{
				// Good idea to stop the GameTalkMonitor before we delete or overwrite files - its version of GameTalkMessages.dll is contained in it - but that may not always be the case
				StopGameTalkMonitor();
				// This writes the GameTalkMessages.dll, FileTalkServer.dll, etc to disk
				// We need to create the GameTalkServer and InstallUtil files to uninstall GameTalkServer
				WriteServerAssembliesToDisk();
				// Stop and delete service
				try
				{
					if ((gameTalkServerService != null) && (gameTalkServerService.Status != ServiceControllerStatus.Stopped))
						gameTalkServerService.Stop();
				}
				catch { }
				try
				{
					if ((gameTalkServerProcess != null) && (!gameTalkServerProcess.HasExited))
						gameTalkServerProcess.Kill();
				}
				catch {	}

				// After the above conditional file creations - there may still be old versions of the above files
				ProcessStartInfo info = null;
				Process p = null;
				info = new ProcessStartInfo();
				info.FileName = installUtilFullFilename;
				info.Arguments = "/u " + gameTalkServerFilename;
				info.WorkingDirectory = mInstallationDirectory;
				info.WindowStyle = ProcessWindowStyle.Hidden;
				// Next two statements are for debug only
				//info.RedirectStandardOutput = true;
				//info.UseShellExecute = false;
				p = Process.Start(info);
				// Next two statements are for debug only
				//string output = p.StandardOutput.ReadToEnd();
				//Trace.WriteLine("output: " + output);
				p.WaitForExit();

				// Create the necessary files - this may overwrite old versions of these files - that's a good thing
				// The reason we have two sections in which we create these files is in case the GameTalkServer 
				// process was using the GameTalkServer.exe file, we will write, prior to us shutting it down
				WriteServerAssembliesToDisk(true);

				if (installUsbPlugin)
					UpdateServerUsbAssembliesOnDisk(true);
				else
					UpdateServerUsbAssembliesOnDisk(false, true);

				if (!startServerAsApp)
				{
					// Install service
					info = new ProcessStartInfo();
					info.FileName = installUtilFullFilename;
					info.Arguments = gameTalkServerFilename;
					info.WorkingDirectory = mInstallationDirectory;
					info.WindowStyle = ProcessWindowStyle.Hidden;
					// The four commented out lines are useful for debugging
                    // DON'T FORGET TO COMMENT OUT THE FOLLOWING TWO LINES IN RELEASE
					//info.RedirectStandardOutput = true;
					//info.UseShellExecute = false;
					p = Process.Start(info);
                    // DON'T FORGET TO COMMENT OUT THE FOLLOWING TWO LINES IN RELEASE
					//string output2 = p.StandardOutput.ReadToEnd();
					//Trace.WriteLine("output2: " + output2);
					p.WaitForExit();

					// The registry may have gotten corrupted by the InstallUtil - Microsoft bug
					PatchRegistry(mGameTalkServerServiceRegEntry);

					// Start service after install
					info = new ProcessStartInfo();
					info.FileName = "sc.exe";
					info.Arguments = "start GameServer";
					info.WorkingDirectory = mInstallationDirectory;
					info.WindowStyle = ProcessWindowStyle.Hidden;
					// Two following lines are for debugging
					/*info.RedirectStandardOutput = true;
					info.UseShellExecute = false;*/
					p = Process.Start(info);
					// Two following lines are for debugging
					/*string output3 = p.StandardOutput.ReadToEnd();
					Trace.WriteLine("output3: "+output3);*/
				}
				else // If we're starting the GameTalkServer as an application (instead of as a service)
				{
					if ((gameTalkServerProcess == null) || (installNewVersion))
					{
						info = new ProcessStartInfo();
						info.FileName = gameTalkServerFilename;
						// This argument can be anything - since if the GameTalkServer is passed anything (for a command line parameter) - it will start as an application
						info.Arguments = EA.GameTalkMessages.Configuration.RunServerAsAppCommandLineArgs;
						info.WorkingDirectory = mInstallationDirectory;
						info.WindowStyle = ProcessWindowStyle.Hidden;
						// The four commented out lines are useful for debugging
						/*info.RedirectStandardOutput = true;
						info.UseShellExecute = false;*/
						p = Process.Start(info);
						/*string output2 = p.StandardOutput.ReadToEnd();
						Trace.WriteLine("output2: " + output2);*/
						//p.WaitForExit();
					}
				}
				Configuration.Instance.SetInstalledGameTalkVersion(mGameTalkVersion, startServerAsApp);

				installedNewVersion = true;
			}
			else if (!startServerAsApp) // make sure service is running
			{
				if (gameTalkServerService != null)
				{
					if (gameTalkServerService.Status != ServiceControllerStatus.Running)
						gameTalkServerService.Start();
				}
				else 
					throw new Exception("GameTalkServer was apparently found - but we don't have a reference to it!  How is this possible!?!");
			}

			return installedNewVersion;
		}

		/// <summary>
		/// Stop the GameTalkMonitor from running
		/// </summary>
		public void StopGameTalkMonitor()
		{
			// Kill them all so that we use the latest
			Process[] activeProcesses = Process.GetProcessesByName("GameTalkViewer");
			try
			{
				foreach (Process p in activeProcesses)
				{
					// Process.Close() should allow the GameTalkViewer to close gracefully 
					// and thereby remove the NotifyIcon (set Icon to Visible = false) from the system tray
					p.Close();
					// It is possible to lose the association between the GameTalkViewer app. and this process object
					// If this occurs - an exception is raised - "No process is associated with this object error"
					p.WaitForExit();
				}
			}
			catch (Exception exception)
			{
				try
				{
					Trace.WriteLine(exception.Message);
					// Whatever didn't work - lets grab the list of processes and try killing them/it (instead of closing them gracefully)
					Process[] activeProcesses2 = Process.GetProcessesByName("GameTalkViewer");
					foreach (Process p in activeProcesses2)
					{
						try
						{
							p.Kill();
							p.WaitForExit();
						}
						catch { }
					}
				}
				catch { }
			}
		}

		private bool GameTalkMonitorRunning()
		{
			Process[] activeProcesses = Process.GetProcessesByName("GameTalkViewer");
			if (activeProcesses.Length == 0)
				return false;
			/*else
				Debug.WriteLine("activeProcess: " + activeProcesses[0].ProcessName);*/
			return true;
		}

		/// <summary>
		/// Nesting all references to the IWshRuntimeLibrary into methods with a try/catch around the whole method to insulate ourselves from a "could not load assembly" exception
		/// </summary>
		/// <param name="installedServer"></param>
		/// <param name="viewerExecutableFilePath"></param>
		private void InstallGameTalkMonitorShortCutToStartup(bool installedServer, string viewerExecutableFilePath)
		{
			try
			{
				if (installedServer) // If the GameTalkServer was installed - then we may want to update/create the GameTalkMonitor short-cut in the user's start-up folder
				{
					// Note: Even if GameTalkViewer.lnk already exists - we may still overwrite it - because it could be pointing at an old version of the GameTalkViewer.exe
					string shortCutPathInStartUp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "GameTalkViewer.lnk");
					if (File.Exists(viewerExecutableFilePath)) // || (!File.Exists(shortCutPathInStartUp))) // The GameTalkMonitor executable DOES exist - so ensure the short-cut points to it - not much point in creating the short-cut (if the executable we want to point to - doesn't exist)
					{
						// Install start-up short-cut to the GameTalkMonitor - so the user doesn't have to run a GameTalk application to get the GameTalkMonitor to start
						try
						{
							IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
							IWshRuntimeLibrary.IWshShortcut link = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(shortCutPathInStartUp);
							link.TargetPath = viewerExecutableFilePath;
							// This Save function supports overwriting - so no need to check if the short-cut file already exists
							link.Save();
						}
						catch (Exception exception)
						{
							Trace.WriteLine("Had a problem creating a short-cut to the GameTalkMonitor executable in your start-up directory" + Environment.NewLine + exception.Message + Environment.NewLine + exception.StackTrace);
						}
					}
					else
						Trace.WriteLine("The GameTalkMonitor executable was not created!  Is it possible the assembly (GameTalkViewer.exe) just hadn't finished writing to disc by the time we got here?");
				}
			}
			catch (System.Exception ex)
			{
				Trace.WriteLine("failed to install GameTalkMonitor shortcut into user's startup folder: " + ex.Message + Environment.NewLine + ex.StackTrace);
			}
		}

		/// <summary>
		/// Nesting all references to the IWshRuntimeLibrary into methods with a try/catch around the whole method to insulate ourselves from a "could not load assembly" exception
		/// </summary>
		/// <returns></returns>
		private bool AbleToLoadWshRuntimeLib()
		{
			try
			{
				// Either Assembly.GetExecutingAssembly() or Assembly.GetCallingAssembly() will be the GameTalk.dll - so use that location to find the interop assembly
				string gameTalkDllPath = Assembly.GetExecutingAssembly().Location;
				FileInfo gameTalkDllFileInfo = new FileInfo(gameTalkDllPath);
				//string gameTalkDllFileInfoDirPath = gameTalkDllFileInfo.DirectoryName;
				FileInfo iWshRuntimeLibraryFileInfo = null;
				foreach (FileInfo fileInfo in gameTalkDllFileInfo.Directory.EnumerateFiles())
				{
					if (fileInfo.Name.ToLower().Contains("iwshruntimelibrary"))
					{
						iWshRuntimeLibraryFileInfo = fileInfo;
						break;
					}
				}
				if (iWshRuntimeLibraryFileInfo != null) // we found the dll - now try loading it
				{
					Assembly iWshRuntimeLibraryAssembly = Assembly.LoadFrom(iWshRuntimeLibraryFileInfo.FullName);
					if (iWshRuntimeLibraryAssembly != null)
						return true;
				}
			}
			catch (System.Exception ex)
			{
				Trace.WriteLine("failed to load the iWshRuntimeLibrary Assembly: " + ex.Message + Environment.NewLine + ex.StackTrace);				
			}
			return false;
		}

		/// <summary>
		/// This will stop the currently running GameTalkMonitor and install and start
		/// a new one based on whether a new GameTalkServer was installed
		/// </summary>
		/// <param name="installedServer"></param>
		/// <param name="startServerAsApp"></param>
		public void InstallViewer(bool installedServer, bool startServerAsApp)
		{
			string viewerExecutableFilePath = mInstallationDirectory + @"\" + "GameTalkViewer.exe";
			string viewerPdbFilePath = mInstallationDirectory + @"\" + "GameTalkViewer.pdb";
			// Kill the process first, then create the file - in case the process has a lock on the file
			if (installedServer)
			{
				// This is a bit redundant - since this should've already happened
				StopGameTalkMonitor();
				// We could check the file exists before we write to it using
                // if (!File.Exists(viewerExecutableFilePath))
				// But I'm finding users increasingly mischevious in poking in the install directory - so we'll just overwrite it
				CreateFileFromResource("EA.GameTalk.GameTalkViewer.GameTalkViewer.exe", viewerExecutableFilePath, Assembly.GetExecutingAssembly());
				// For debugging
/*#if DEBUG
				CreateFileFromResource("EA.GameTalk.GameTalkViewer.GameTalkViewer.pdb", viewerPdbFilePath, Assembly.GetExecutingAssembly());
#endif*/
			}
            else if (!File.Exists(viewerExecutableFilePath)) // The server didn't need to be installed - so we may not need to "install and run" the GameTalkMonitor
			{
				try
				{
					// There doesn't seem to be any point in checking whether the process is already running - if the file doesn't exist - write it out
					/*activeProcesses = Process.GetProcessesByName("GameTalkViewer");
					if (activeProcesses.Length == 0)*/
					CreateFileFromResource("EA.GameTalk.GameTalkViewer.GameTalkViewer.exe", viewerExecutableFilePath, Assembly.GetExecutingAssembly());
					// For debugging
/*#if DEBUG
					CreateFileFromResource("EA.GameTalk.GameTalkViewer.GameTalkViewer.pdb", viewerPdbFilePath, Assembly.GetExecutingAssembly());
#endif*/
				}
				catch (Exception exception)
				{
					try
					{
						Trace.WriteLine(exception.Message);
					}
					catch { }
				}
			}

			// Start application if it isn't running
			bool gameTalkMonitorRunning = GameTalkMonitorRunning();
			//Debug.WriteLine("InstallViewer: gameTalkMonitorRunning: "+gameTalkMonitorRunning+ " installedServer" + installedServer + " startServerAsApp: " + startServerAsApp);
			if (!gameTalkMonitorRunning)
			{
				ProcessStartInfo info = new ProcessStartInfo();
				info.FileName = "GameTalkViewer.exe";
				if (startServerAsApp)
					info.Arguments = EA.GameTalkMessages.Configuration.RunServerAsAppCommandLineArgs;
				info.WorkingDirectory = mInstallationDirectory;
				info.UseShellExecute = true;
				Process gameTalkMonitorProcess = Process.Start(info);
/*#if DEBUG
				Debug.WriteLine("1. gameTalkMonitorProcess: exited: " + gameTalkMonitorProcess.HasExited + " responding: " + gameTalkMonitorProcess.Responding);
				System.Threading.Thread.Sleep(500);
				Debug.WriteLine("2. gameTalkMonitorProcess: exited: " + gameTalkMonitorProcess.HasExited + " responding: " + gameTalkMonitorProcess.Responding);
#endif*/
			}

			// Nesting all references to the IWshRuntimeLibrary into methods with a try/catch around the whole method to insulate ourselves from a "could not load assembly" exception
			if ((installedServer) && (AbleToLoadWshRuntimeLib())) // Even if the GameTalkServer was installed - if we can't load the IWshRuntimeLibrary assembly - then we can't create the short-cut - so don't bother trying
				InstallGameTalkMonitorShortCutToStartup(installedServer, viewerExecutableFilePath);
		}
	}
}
