Describes a message to be displayed to the user.
		/// <summary>
		/// This initializes the services required to run the client.
		/// </summary>
		/// <param name="p_gmdGameMode">The game mode for which mods are being managed.</param>
		/// <param name="p_mrpModRepository">The mod repository to use to retrieve mods and mod metadata.</param>
		/// <param name="p_nfuFileUtility">The file utility class.</param>
		/// <param name="p_scxUIContext">The <see cref="SynchronizationContext"/> to use to marshall UI interactions to the UI thread.</param>
		/// <param name="p_vwmErrorMessage">The error message if the UAC check failed.</param>
		/// <returns>A <see cref="ServiceManager"/> containing the initialized services, or <c>null</c> if the
		/// services didn't initialize properly.</returns>
		protected ServiceManager InitializeServices(IGameMode p_gmdGameMode, IModRepository p_mrpModRepository, NexusFileUtil p_nfuFileUtility, SynchronizationContext p_scxUIContext, out ViewMessage p_vwmErrorMessage)
		{
			IModCacheManager mcmModCacheManager = new NexusModCacheManager(p_gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory, p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory, p_nfuFileUtility);

			Trace.TraceInformation("Registering supported Script Types...");
			Trace.Indent();
			IScriptTypeRegistry stgScriptTypeRegistry = ScriptTypeRegistry.DiscoverScriptTypes(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "ScriptTypes"), p_gmdGameMode);
			if (stgScriptTypeRegistry.Types.Count == 0)
			{
				p_vwmErrorMessage = new ViewMessage("No script types were found.", null, "No Script Types", MessageBoxIcon.Error);
				return null;
			}
			Trace.TraceInformation("Found {0} script types.", stgScriptTypeRegistry.Types.Count);
			Trace.Unindent();

			Trace.TraceInformation("Registering supported mod formats...");
			Trace.Indent();
			IModFormatRegistry mfrModFormatRegistry = ModFormatRegistry.DiscoverFormats(mcmModCacheManager, stgScriptTypeRegistry, Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "ModFormats"));
			if (mfrModFormatRegistry.Formats.Count == 0)
			{
				p_vwmErrorMessage = new ViewMessage("No mod formats were found.", null, "No Mod Formats", MessageBoxIcon.Error);
				return null;
			}
			Trace.TraceInformation("Found {0} formats.", mfrModFormatRegistry.Formats.Count);
			Trace.Unindent();

			Trace.TraceInformation("Finding managed mods...");
			Trace.Indent();

			ModRegistry mrgModRegistry = null;
			try
			{
				mrgModRegistry = ModRegistry.DiscoverManagedMods(mfrModFormatRegistry, mcmModCacheManager, p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory, EnvironmentInfo.Settings.ScanSubfoldersForMods, p_gmdGameMode, p_gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory, p_gmdGameMode.GameModeEnvironmentInfo.ModDownloadCacheDirectory, p_gmdGameMode.GameModeEnvironmentInfo.ModReadMeDirectory, p_gmdGameMode.GameModeEnvironmentInfo.CategoryDirectory);
			}
			catch (UnauthorizedAccessException ex)
			{
				p_vwmErrorMessage = new ViewMessage(String.Format("An error occured while retrieving managed mods: \n\n{0}", ex.Message), null, "Install Log", MessageBoxIcon.Error);
				return null;
			}

			Trace.TraceInformation("Found {0} managed mods.", mrgModRegistry.RegisteredMods.Count);
			Trace.Unindent();

			Trace.TraceInformation("Initializing Install Log...");
			Trace.Indent();
			Trace.TraceInformation("Checking if upgrade is required...");
			InstallLogUpgrader iluUgrader = new InstallLogUpgrader();

			string strLogPath = string.Empty;

			try
			{
				strLogPath = Path.Combine(p_gmdGameMode.GameModeEnvironmentInfo.InstallInfoDirectory, "InstallLog.xml");
			}
			catch (ArgumentNullException)
			{
				p_vwmErrorMessage = new ViewMessage("Unable to retrieve critical paths from the config file." + Environment.NewLine + "Select this game again to fix the folders setup.", null, "Config error", MessageBoxIcon.Warning);
				return null;
			}

			if (!InstallLog.IsLogValid(strLogPath))
				InstallLog.Restore(strLogPath);
			if (iluUgrader.NeedsUpgrade(strLogPath))
			{
				if (!iluUgrader.CanUpgrade(strLogPath))
				{
					p_vwmErrorMessage = new ViewMessage(String.Format("{0} does not support version {1} of the Install Log.", EnvironmentInfo.Settings.ModManagerName, InstallLog.ReadVersion(strLogPath)), null, "Install Log", MessageBoxIcon.Error);
					return null;
				}
				IBackgroundTask tskUpgrader = iluUgrader.UpgradeInstallLog(strLogPath, p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory, mrgModRegistry);
				m_areTaskWait.Reset();
				tskUpgrader.TaskEnded += new EventHandler<TaskEndedEventArgs>(Task_TaskEnded);
				OnTaskStarted(tskUpgrader);
				if (tskUpgrader.IsActive)
					m_areTaskWait.WaitOne();
				tskUpgrader.TaskEnded -= new EventHandler<TaskEndedEventArgs>(Task_TaskEnded);
				if (tskUpgrader.Status != TaskStatus.Complete)
				{
					string strDetails = (string)(tskUpgrader.ReturnValue ?? null);
					p_vwmErrorMessage = new ViewMessage("Install Log was not upgraded.", strDetails, "Install Log", MessageBoxIcon.Error);
					return null;
				}
			}
			IInstallLog ilgInstallLog = InstallLog.Initialize(mrgModRegistry, p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory, strLogPath);
			Trace.Unindent();

			Trace.TraceInformation("Initializing Plugin Management Services...");
			Trace.Indent();
			PluginRegistry prgPluginRegistry = null;
			IPluginOrderLog polPluginOrderLog = null;
			ActivePluginLog aplPluginLog = null;
			IPluginManager pmgPluginManager = null;
			if (!p_gmdGameMode.UsesPlugins)
				Trace.TraceInformation("Not required.");
			else
			{
				Trace.TraceInformation("Initializing Plugin Registry...");
				Trace.Indent();
				prgPluginRegistry = PluginRegistry.DiscoverManagedPlugins(p_gmdGameMode.GetPluginFactory(), p_gmdGameMode.GetPluginDiscoverer());
				Trace.TraceInformation("Found {0} managed plugins.", prgPluginRegistry.RegisteredPlugins.Count);
				Trace.Unindent();

				Trace.TraceInformation("Initializing Plugin Order Log...");
				Trace.Indent();
				polPluginOrderLog = PluginOrderLog.Initialize(prgPluginRegistry, p_gmdGameMode.GetPluginOrderLogSerializer(), p_gmdGameMode.GetPluginOrderValidator());
				Trace.Unindent();

				Trace.TraceInformation("Initializing Active Plugin Log...");
				Trace.Indent();
				aplPluginLog = ActivePluginLog.Initialize(prgPluginRegistry, p_gmdGameMode.GetActivePluginLogSerializer(polPluginOrderLog));
				Trace.Unindent();

				Trace.TraceInformation("Initializing Plugin Manager...");
				Trace.Indent();
				pmgPluginManager = PluginManager.Initialize(p_gmdGameMode, prgPluginRegistry, aplPluginLog, polPluginOrderLog, p_gmdGameMode.GetPluginOrderValidator());
				Trace.Unindent();
			}
			Trace.Unindent();

			Trace.TraceInformation("Initializing Activity Monitor...");
			Trace.Indent();
			DownloadMonitor dmtMonitor = new DownloadMonitor();
			Trace.Unindent();

            Trace.TraceInformation("Initializing Activate Mods Monitor...");
			Trace.Indent();
			ActivateModsMonitor ammMonitor = new ActivateModsMonitor();
			Trace.Unindent();

			Trace.TraceInformation("Initializing Mod Manager...");
			Trace.Indent();
            ModManager mmgModManager = ModManager.Initialize(p_gmdGameMode, EnvironmentInfo, p_mrpModRepository, dmtMonitor, ammMonitor, mfrModFormatRegistry, mrgModRegistry, p_nfuFileUtility, p_scxUIContext, ilgInstallLog, pmgPluginManager);
			Trace.Unindent();

			Trace.TraceInformation("Initializing Update Manager...");
			Trace.Indent();
			UpdateManager umgUpdateManager = new UpdateManager(p_gmdGameMode, EnvironmentInfo);
			Trace.Unindent();

			p_vwmErrorMessage = null;
            return new ServiceManager(ilgInstallLog, aplPluginLog, polPluginOrderLog, p_mrpModRepository, mmgModManager, pmgPluginManager, dmtMonitor, ammMonitor, umgUpdateManager);
		}
		/// <summary>
		/// Builds the game mode.
		/// </summary>
		/// <param name="p_futFileUtility">The file utility class to be used by the game mode.</param>
		/// <param name="p_imsWarning">The resultant warning resultant from the creation of the game mode.
		/// <c>null</c> if there are no warnings.</param>
		/// <returns>The game mode.</returns>
		public IGameMode BuildGameMode(FileUtil p_futFileUtility, out ViewMessage p_imsWarning)
		{
			if (EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId] == null)
				EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId] = new PerGameModeSettings<object>();
			if (!EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId].ContainsKey("AskAboutReadOnlySettingsFiles"))
			{
				EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId]["AskAboutReadOnlySettingsFiles"] = true;
				EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId]["UnReadOnlySettingsFiles"] = true;
				EnvironmentInfo.Settings.Save();
			}

			GrimrockGameMode gmdGameMode = InstantiateGameMode(p_futFileUtility);
			p_imsWarning = null;

			return gmdGameMode;
		}
		/// <summary>
		/// Ensures that the game mode environment's paths exist.
		/// </summary>
		/// <param name="p_gmdGameMode">The game mode whose paths are to be created.</param>
		/// <param name="p_vwmErrorMessage">The error message if the creation fails.</param>
		/// <returns><c>true</c> if the creation passed;
		/// <c>false</c> otherwise.</returns>
		protected bool CreateEnvironmentPaths(IGameMode p_gmdGameMode, out ViewMessage p_vwmErrorMessage)
		{
			string[] strPaths = new string[] { p_gmdGameMode.GameModeEnvironmentInfo.CategoryDirectory,
												p_gmdGameMode.GameModeEnvironmentInfo.InstallInfoDirectory,
												p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory,
												p_gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory,
												p_gmdGameMode.GameModeEnvironmentInfo.ModDownloadCacheDirectory,
												p_gmdGameMode.GameModeEnvironmentInfo.OverwriteDirectory};
			foreach (string strPath in strPaths)
				if (!String.IsNullOrEmpty(strPath))
					if (!Directory.Exists(strPath))
						Directory.CreateDirectory(strPath);
			p_vwmErrorMessage = null;
			return true;
		}
		/// <summary>
		/// Checks to see if UAC is interfering with file installation.
		/// </summary>
		/// <param name="p_gmdGameMode">The game mode whose paths are to be checked.</param>
		/// <param name="p_vwmErrorMessage">The error message if the initialization failed.</param>
		/// <returns><c>true</c> if the check passed;
		/// <c>false</c> otherwise.</returns>
		protected bool UacCheckEnvironment(IGameMode p_gmdGameMode, out ViewMessage p_vwmErrorMessage)
		{
			Dictionary<string, string> dicPaths = new Dictionary<string, string>();
			if (!String.IsNullOrEmpty(p_gmdGameMode.GameModeEnvironmentInfo.InstallInfoDirectory) && (!dicPaths.ContainsKey(p_gmdGameMode.GameModeEnvironmentInfo.InstallInfoDirectory)))
				dicPaths[p_gmdGameMode.GameModeEnvironmentInfo.InstallInfoDirectory] = "Install Info";
			if (!String.IsNullOrEmpty(p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory) && (!dicPaths.ContainsKey(p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory)))
				dicPaths[p_gmdGameMode.GameModeEnvironmentInfo.ModDirectory] = "Mods";
			if (!String.IsNullOrEmpty(p_gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory) && (!dicPaths.ContainsKey(p_gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory)))
				dicPaths[p_gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory] = "Mods";
			if (!String.IsNullOrEmpty(p_gmdGameMode.GameModeEnvironmentInfo.ModDownloadCacheDirectory) && (!dicPaths.ContainsKey(p_gmdGameMode.GameModeEnvironmentInfo.ModDownloadCacheDirectory)))
				dicPaths[p_gmdGameMode.GameModeEnvironmentInfo.ModDownloadCacheDirectory] = "Mods";
			if (!String.IsNullOrEmpty(p_gmdGameMode.GameModeEnvironmentInfo.OverwriteDirectory) && (!dicPaths.ContainsKey(p_gmdGameMode.GameModeEnvironmentInfo.OverwriteDirectory)))
				dicPaths[p_gmdGameMode.GameModeEnvironmentInfo.OverwriteDirectory] = "Install Info";
			if (!String.IsNullOrEmpty(p_gmdGameMode.GameModeEnvironmentInfo.CategoryDirectory) && (!dicPaths.ContainsKey(p_gmdGameMode.GameModeEnvironmentInfo.CategoryDirectory)))
				dicPaths[p_gmdGameMode.GameModeEnvironmentInfo.CategoryDirectory] = "Mods";
			if (!String.IsNullOrEmpty(p_gmdGameMode.GameModeEnvironmentInfo.InstallationPath) && (!dicPaths.ContainsKey(p_gmdGameMode.GameModeEnvironmentInfo.InstallationPath)))
				dicPaths[p_gmdGameMode.GameModeEnvironmentInfo.InstallationPath] = "Install Path";

			foreach (KeyValuePair<string, string> kvpUacCheckPath in dicPaths)
			{
				try
				{
					Path.GetDirectoryName(kvpUacCheckPath.Key);
				}
				catch (Exception ex)
				{
					Trace.TraceError(String.Format("The path: " + Environment.NewLine + "{0}" + Environment.NewLine + "has returned an error.", kvpUacCheckPath.Key));
					string strPathMessage = (String.Format("The path: " + Environment.NewLine + "{0}" + Environment.NewLine + "has returned an error.", kvpUacCheckPath.Key));
					string strPathDetails = String.Format("Error details: " + Environment.NewLine + "{0} ", ex.Message);
					p_vwmErrorMessage = new ViewMessage(strPathMessage, strPathDetails, "Error", MessageBoxIcon.Error);
					return false;
				}

				if (!UacCheck(kvpUacCheckPath.Key))
				{
					if (!Directory.Exists(Path.GetPathRoot(kvpUacCheckPath.Key)))
					{
						Trace.TraceError("Unable to access: " + kvpUacCheckPath.Key);
						string strHDMessage = "Unable to access:" + Environment.NewLine + kvpUacCheckPath.Key;
						string strHDDetails = String.Format("This error usually happens when you set one of the {0} folders on a hard drive that is no longer in your system:" +
											 Environment.NewLine + Environment.NewLine + "Select this game mode again to go back to the folder setup screen and make sure the {1} path is correct.",
											EnvironmentInfo.Settings.ModManagerName, kvpUacCheckPath.Value);
						p_vwmErrorMessage = new ViewMessage(strHDMessage, strHDDetails, "Warning", MessageBoxIcon.Warning);
						EnvironmentInfo.Settings.CompletedSetup[p_gmdGameMode.ModeId] = false;
						EnvironmentInfo.Settings.Save();
						return false;
					}

					Trace.TraceError("Unable to get write permissions for: " + kvpUacCheckPath.Key);
					string strMessage = "Unable to get write permissions for:" + Environment.NewLine + kvpUacCheckPath.Key;
					string strDetails = String.Format("This error happens when you are running Windows Vista or later, and have put {0}'s <b>{1}</b> folder in the <b>Program Files</b> folder. You need to do one of the following:<ol>" +
										"<li>Disable UAC (<i>not recommended</i>).</li>" +
										@"<li>Move {0}'s <b>{1}</b> folder outside of the <b>Program Files</b> folder (for example, to <b>C:\Games\ModManagerInfo\{1}</b>).</li>" +
										"<li>Run <b>{0}</b> as administrator. You can try this by right-clicking on <b>{0}</b>'s shortcut and selecting <i>Run as administrator</i>. Alternatively, right-click on the shortcut, select <i>Properties->Compatibility</i> and check <i>Run this program as an administrator</i>." +
										"</ol>" +
										"The best thing to do in order to avoid other problems, and the generally recommended solution, is to Move {0}'s <b>{1}</b> folder outside of the <b>Program Files</b> folder.",
										EnvironmentInfo.Settings.ModManagerName, kvpUacCheckPath.Value);
					p_vwmErrorMessage = new ViewMessage(strMessage, strDetails, "Error", MessageBoxIcon.Error);
					return false;
				}
			}
			p_vwmErrorMessage = null;
			return true;
		}
		/// <summary>
		/// Applies the specified setting that was deferred to the next application startup. 
		/// </summary>
		/// <param name="p_strKey">The key of the setting to apply.</param>
		/// <param name="p_strValue">The value of the setting to apply.</param>
		/// <param name="p_vwmErrorMessage">The error message if the application of the setting fails.</param>
		/// <returns><c>true</c> if the setting was applied successfully;
		/// <c>false</c> otherwise.</returns>
		protected bool ApplyDelayedSetting(string p_strKey, string p_strValue, out ViewMessage p_vwmErrorMessage)
		{
			string[] strPropertyIndexers = p_strKey.Split(new char[] { '~' }, StringSplitOptions.RemoveEmptyEntries);
			if (strPropertyIndexers.Length == 0)
			{
				p_vwmErrorMessage = new ViewMessage("Missing Setting name.", "Missing Setting Name");
				return false;
			}

			PropertyInfo pifSetting = null;
			try
			{
				pifSetting = EnvironmentInfo.GetType().GetProperty("Settings");
			}
			catch (AmbiguousMatchException)
			{
				Trace.TraceInformation("Ambiguous Match while getting {0}.", "Settings");
				Trace.Indent();
				Trace.TraceInformation("Delayed Setting: {0}", p_strKey);
				Trace.TraceInformation("Type: {0}", EnvironmentInfo.GetType().FullName);
				Trace.TraceInformation("All Properties:");
				Trace.Indent();
				foreach (PropertyInfo pifProperty in EnvironmentInfo.GetType().GetProperties())
					Trace.TraceInformation("{0}, declared in {1}", pifProperty.Name, pifProperty.DeclaringType.FullName);
				Trace.Unindent();
				Trace.Unindent();
				throw;
			}
			object objSetting = EnvironmentInfo;
			Type tpeSettings = null;
			for (Int32 i = 0; i < strPropertyIndexers.Length; i++)
			{
				if (pifSetting.GetIndexParameters().Length == 1)
					objSetting = pifSetting.GetValue(objSetting, new object[] { strPropertyIndexers[i] });
				else if (pifSetting.GetIndexParameters().Length == 0)
					objSetting = pifSetting.GetValue(objSetting, null);
				else
				{
					p_vwmErrorMessage = new ViewMessage(String.Format("Cannot set value for setting: '{0}'. Index Parameter Count is greater than 1.", p_strKey), "Invalid Setting");
					return false;
				}
				tpeSettings = objSetting.GetType();
				try
				{
					pifSetting = tpeSettings.GetProperty(strPropertyIndexers[i]);
				}
				catch (AmbiguousMatchException)
				{
					Trace.TraceInformation("Ambiguous Match while getting {0}.", strPropertyIndexers[i]);
					Trace.Indent();
					Trace.TraceInformation("Delayed Setting: {0}", p_strKey);
					Trace.TraceInformation("Type: {0}", tpeSettings.FullName);
					Trace.TraceInformation("All Properties:");
					Trace.Indent();
					foreach (PropertyInfo pifProperty in tpeSettings.GetProperties())
						Trace.TraceInformation("{0}, declared in {1}", pifProperty.Name, pifProperty.DeclaringType.FullName);
					Trace.Unindent();
					Trace.Unindent();
					throw;
				}
				try
				{
					if (pifSetting == null)
						for (Type tpeBase = tpeSettings; (pifSetting == null) && (tpeBase != null); tpeBase = tpeBase.BaseType)
							pifSetting = tpeBase.GetProperty("Item", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
				}
				catch (AmbiguousMatchException)
				{
					Trace.TraceInformation("Ambiguous Match while getting {0}.", "Item");
					Trace.Indent();
					Trace.TraceInformation("Delayed Setting: {0}", p_strKey);
					Trace.TraceInformation("Type: {0}", tpeSettings.FullName);
					Trace.TraceInformation("All Properties:");
					Trace.Indent();
					foreach (PropertyInfo pifProperty in tpeSettings.GetProperties())
						Trace.TraceInformation("{0}, declared in {1}", pifProperty.Name, pifProperty.DeclaringType.FullName);
					Trace.Unindent();
					Trace.Unindent();
					throw;
				}
				if (pifSetting == null)
				{
					p_vwmErrorMessage = new ViewMessage(String.Format("Cannot set value for setting: '{0}'. Setting does not exist.", p_strKey), "Invalid Setting");
					return false;
				}
			}
			if (pifSetting.GetIndexParameters().Length == 1)
				pifSetting.SetValue(objSetting, p_strValue, new object[] { strPropertyIndexers[strPropertyIndexers.Length - 1] });
			else if (pifSetting.GetIndexParameters().Length == 0)
				pifSetting.SetValue(objSetting, p_strValue, null);
			else
			{
				p_vwmErrorMessage = new ViewMessage(String.Format("Cannot set value for setting: '{0}'. Index Parameter Count is greater than 1.", p_strKey), "Invalid Setting");
				return false;
			}
			p_vwmErrorMessage = null;
			return true;
		}
		/// <summary>
		/// Applies any settings that were deferred to the next application startup.
		/// </summary>
		/// <param name="p_strGameModeId">The id of the current game mode.</param>
		/// <param name="p_vwmErrorMessage">The error message if the application of settings fails.</param>
		/// <returns><c>true</c> if the settings were applied successfully;
		/// <c>false</c> otherwise.</returns>
		protected bool ApplyDelayedSettings(string p_strGameModeId, out ViewMessage p_vwmErrorMessage)
		{
			if ((EnvironmentInfo.Settings.DelayedSettings[p_strGameModeId] == null) || (EnvironmentInfo.Settings.DelayedSettings["ALL"] == null))
			{
				p_vwmErrorMessage = null;
				return true;
			}
			foreach (KeyValuePair<string, string> kvpSetting in EnvironmentInfo.Settings.DelayedSettings["ALL"])
				if (!ApplyDelayedSetting(kvpSetting.Key, kvpSetting.Value, out p_vwmErrorMessage))
					return false;
			EnvironmentInfo.Settings.DelayedSettings["ALL"].Clear();
			foreach (KeyValuePair<string, string> kvpSetting in EnvironmentInfo.Settings.DelayedSettings[p_strGameModeId])
				if (!ApplyDelayedSetting(kvpSetting.Key, kvpSetting.Value, out p_vwmErrorMessage))
					return false;
			EnvironmentInfo.Settings.DelayedSettings[p_strGameModeId].Clear();
			p_vwmErrorMessage = null;
			return true;
		}
		/// <summary>
		/// Performs the applicatio initialization.
		/// </summary>
		/// <param name="p_gmfGameModeFactory">The factory to use to create the game mode for which we will be managing mods.</param>
		/// <param name="p_scxUIContext">The <see cref="SynchronizationContext"/> to use to marshall UI interactions to the UI thread.</param>
		/// <param name="p_vwmErrorMessage">The error message if the initialization failed.</param>
		/// <returns><c>true</c> if the initialization was successful;
		/// <c>false</c> otherwise.</returns>
		protected bool DoApplicationInitialize(IGameModeFactory p_gmfGameModeFactory, SynchronizationContext p_scxUIContext, out ViewMessage p_vwmErrorMessage)
		{
			if (EnvironmentInfo.Settings.CustomGameModeSettings[p_gmfGameModeFactory.GameModeDescriptor.ModeId] == null)
				EnvironmentInfo.Settings.CustomGameModeSettings[p_gmfGameModeFactory.GameModeDescriptor.ModeId] = new PerGameModeSettings<object>();
			if (EnvironmentInfo.Settings.DelayedSettings[p_gmfGameModeFactory.GameModeDescriptor.ModeId] == null)
				EnvironmentInfo.Settings.DelayedSettings[p_gmfGameModeFactory.GameModeDescriptor.ModeId] = new KeyedSettings<string>();
			if (EnvironmentInfo.Settings.DelayedSettings["ALL"] == null)
				EnvironmentInfo.Settings.DelayedSettings["ALL"] = new KeyedSettings<string>();
			StepOverallProgress();

			if (!ApplyDelayedSettings(p_gmfGameModeFactory.GameModeDescriptor.ModeId, out p_vwmErrorMessage))
			{
				EnvironmentInfo.Settings.Reload();
				return false;
			}
			EnvironmentInfo.Settings.Save();
			StepOverallProgress();

			string strUacCheckPath = EnvironmentInfo.Settings.InstallationPaths[p_gmfGameModeFactory.GameModeDescriptor.ModeId];
			if (String.IsNullOrEmpty(strUacCheckPath) || (!String.IsNullOrEmpty(p_gmfGameModeFactory.GameModeDescriptor.InstallationPath)))
				strUacCheckPath = p_gmfGameModeFactory.GameModeDescriptor.InstallationPath;
			if (!String.IsNullOrEmpty(strUacCheckPath))
			{
				try
				{
					Path.GetDirectoryName(strUacCheckPath);
				}
				catch (Exception ex)
				{
					Trace.TraceError(String.Format("The path: " + Environment.NewLine + "{0}" + Environment.NewLine + "has returned an error.", strUacCheckPath));
					string strPathMessage = (String.Format("The path: " + Environment.NewLine + "{0}" + Environment.NewLine + "has returned an error.", strUacCheckPath));
					string strPathDetails = String.Format("Error details: " + Environment.NewLine + "{0} ", ex.Message);
					p_vwmErrorMessage = new ViewMessage(strPathMessage, strPathDetails, "Error", MessageBoxIcon.Error);
					return false;
				}

				if (!UacCheck(strUacCheckPath))
				{
					Trace.TraceError("Unable to get write permissions for: " + strUacCheckPath);
					string strMessage = "Unable to get write permissions for:" + Environment.NewLine + strUacCheckPath;
					string strDetails = String.Format("This error happens when you are running Windows Vista or later,  and have installed <b>{0}</b> in the <b>Program Files</b> folder. You need to do one of the following:<ol>" +
										"<li>Disable UAC (<i>not recommended</i>).</li>" +
										@"<li>Move <b>{0}</b> outside of the <b>Program Files</b> folder (for example, to <b>C:\Games\{0}</b>). This may require a reinstall.<br>With Oblivion you could just copy the game folder to a new location, run the game, and all would be well. This may not work with other games.</li>" +
										"<li>Run <b>{1}</b> as administrator. You can try this by right-clicking on <b>{1}</b> shortcut and selecting <i>Run as administrator</i>. Alternatively, right-click on the shortcut, select <i>Properties->Compatibility</i> and check <i>Run this program as an administrator</i>." +
										"</ol>" +
										"The best thing to do in order to avoid other problems, and the generally recommended solution, is to install <b>{0}</b> outside of the <b>Program Files</b> folder.",
										p_gmfGameModeFactory.GameModeDescriptor.Name, EnvironmentInfo.Settings.ModManagerName);
					p_vwmErrorMessage = new ViewMessage(strMessage, strDetails, "Error", MessageBoxIcon.Error);
					return false;
				}
			}
			else
			{
				EnvironmentInfo.Settings.CompletedSetup[p_gmfGameModeFactory.GameModeDescriptor.ModeId] = false;
				EnvironmentInfo.Settings.Save();
			}
			StepOverallProgress();

			if (!EnvironmentInfo.Settings.CompletedSetup.ContainsKey(p_gmfGameModeFactory.GameModeDescriptor.ModeId) || !EnvironmentInfo.Settings.CompletedSetup[p_gmfGameModeFactory.GameModeDescriptor.ModeId])
			{
				if (!p_gmfGameModeFactory.PerformInitialSetup(ShowView, ShowMessage))
				{
					p_vwmErrorMessage = null;
					return false;
				}
				EnvironmentInfo.Settings.CompletedSetup[p_gmfGameModeFactory.GameModeDescriptor.ModeId] = true;
				EnvironmentInfo.Settings.Save();
			}
			StepOverallProgress();

			if (p_gmfGameModeFactory.GameModeDescriptor.OrderedCriticalPluginNames != null)
				foreach (string strPlugin in p_gmfGameModeFactory.GameModeDescriptor.OrderedCriticalPluginNames)
					if (!File.Exists(strPlugin))
					{
						StringBuilder stbMessage = new StringBuilder();
						stbMessage.AppendFormat("You are missing {0}.", strPlugin);
						if (String.IsNullOrEmpty(p_gmfGameModeFactory.GameModeDescriptor.CriticalFilesErrorMessage))
							stbMessage.AppendFormat("Please verify your game install and ensure {0} is present.", strPlugin);
						else
							stbMessage.AppendLine(Environment.NewLine + p_gmfGameModeFactory.GameModeDescriptor.CriticalFilesErrorMessage);
						p_vwmErrorMessage = new ViewMessage(stbMessage.ToString(), null, "Missing File", MessageBoxIcon.Warning);
						return false;
					}

			StepOverallProgress();

			if (!p_gmfGameModeFactory.PerformInitialization(ShowView, ShowMessage))
			{
				p_vwmErrorMessage = null;
				return false;
			}
			StepOverallProgress();

			NexusFileUtil nfuFileUtility = new NexusFileUtil(EnvironmentInfo);

			ViewMessage vwmWarning = null;
			IGameMode gmdGameMode = p_gmfGameModeFactory.BuildGameMode(nfuFileUtility, out vwmWarning);
			if (gmdGameMode == null)
			{
				p_vwmErrorMessage = vwmWarning ?? new ViewMessage(String.Format("Could not initialize {0} Game Mode.", p_gmfGameModeFactory.GameModeDescriptor.Name), null, "Error", MessageBoxIcon.Error);
				return false;
			}
			if (vwmWarning != null)
				ShowMessage(vwmWarning);
			//Now we have a game mode use it's theme.
			FontSetResolver.AddFontSets(gmdGameMode.ModeTheme.FontSets);
			StepOverallProgress();

			if (!UacCheckEnvironment(gmdGameMode, out p_vwmErrorMessage))
			{
				//TODO it would be really nice of us if we, instead of closing,
				// force the game mode to reinitialize, and select new paths
				return false;
			}
			StepOverallProgress();

			if (!CreateEnvironmentPaths(gmdGameMode, out p_vwmErrorMessage))
				return false;
			StepOverallProgress();

			Trace.TraceInformation(String.Format("Game Mode Built: {0} ({1})", gmdGameMode.Name, gmdGameMode.ModeId));
			Trace.Indent();
			Trace.TraceInformation(String.Format("Installation Path: {0}", gmdGameMode.GameModeEnvironmentInfo.InstallationPath));
			Trace.TraceInformation(String.Format("Install Info Path: {0}", gmdGameMode.GameModeEnvironmentInfo.InstallInfoDirectory));
			Trace.TraceInformation(String.Format("Mod Path: {0}", gmdGameMode.GameModeEnvironmentInfo.ModDirectory));
			Trace.TraceInformation(String.Format("Mod Cache Path: {0}", gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory));
			Trace.TraceInformation(String.Format("Mod Download Cache: {0}", gmdGameMode.GameModeEnvironmentInfo.ModDownloadCacheDirectory));
			Trace.TraceInformation(String.Format("Overwrite Path: {0}", gmdGameMode.GameModeEnvironmentInfo.OverwriteDirectory));
			Trace.Unindent();

			ScanForReadonlyFiles(gmdGameMode);
			StepOverallProgress();

			Trace.TraceInformation("Initializing Mod Repository...");
			Trace.Indent();
			IModRepository mrpModRepository = NexusModRepository.GetRepository(gmdGameMode);
			Trace.Unindent();
			StepOverallProgress();

			StepOverallProgress();

			if ((gmdGameMode.GameModeEnvironmentInfo.ModCacheDirectory == null) || (gmdGameMode.GameModeEnvironmentInfo.ModDirectory == null))
			{
				ShowMessage(new ViewMessage("Unable to retrieve critical paths from the config file." + Environment.NewLine + "Select this game again to fix the folders setup.", "Warning", MessageBoxIcon.Warning));
				EnvironmentInfo.Settings.CompletedSetup[p_gmfGameModeFactory.GameModeDescriptor.ModeId] = false;
				EnvironmentInfo.Settings.Save();
				Status = TaskStatus.Retrying;
				return false;
			}

			ServiceManager svmServices = InitializeServices(gmdGameMode, mrpModRepository, nfuFileUtility, p_scxUIContext, out p_vwmErrorMessage);
			if (svmServices == null)
			{
				ShowMessage(p_vwmErrorMessage);
				EnvironmentInfo.Settings.CompletedSetup[p_gmfGameModeFactory.GameModeDescriptor.ModeId] = false;
				EnvironmentInfo.Settings.Save();
				Status = TaskStatus.Retrying;
				return false;
			}
			StepOverallProgress();

			UpgradeMismatchedVersionMods(svmServices.ModInstallLog, svmServices.ModManager);
			StepOverallProgress();

			if (!UninstallMissingMods(gmdGameMode, EnvironmentInfo, svmServices.ModManager))
			{
				if (Status == TaskStatus.Retrying)
				{
					if (svmServices != null)
						DisposeServices(svmServices);
					EnvironmentInfo.Settings.CompletedSetup[p_gmfGameModeFactory.GameModeDescriptor.ModeId] = false;
					EnvironmentInfo.Settings.Save();
				}
				p_vwmErrorMessage = null;
				return false;
			}
			StepOverallProgress();

			svmServices.ModManager.LoadQueuedMods();
			StepOverallProgress();

			GameMode = gmdGameMode;
			Services = svmServices;

			p_vwmErrorMessage = null;
			return true;
		}
		/// <summary>
		/// Builds the game mode.
		/// </summary>
		/// <param name="p_futFileUtility">The file utility class to be used by the game mode.</param>
		/// <param name="p_imsWarning">The resultant warning resultant from the creation of the game mode.
		/// <c>null</c> if there are no warnings.</param>
		/// <returns>The game mode.</returns>
		public IGameMode BuildGameMode(FileUtil p_futFileUtility, out ViewMessage p_imsWarning)
		{
			GamebryoGameModeBase gmdGameMode = null;
			if (EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId] == null)
				EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId] = new PerGameModeSettings<object>();
			if (!EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId].ContainsKey("AskAboutReadOnlySettingsFiles"))
			{
				EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId]["AskAboutReadOnlySettingsFiles"] = true;
				EnvironmentInfo.Settings.CustomGameModeSettings[GameModeDescriptor.ModeId]["UnReadOnlySettingsFiles"] = true;
				EnvironmentInfo.Settings.Save();
			}

			/*if (File.Exists("FO3Edit.exe"))
				m_lstTools.Add(new Command<MainForm>("FO3Edit", "Launches FO3Edit, if it is installed.", LaunchFO3Edit));
			m_lstTools.Add(new CheckedCommand<MainForm>("Archive Invalidation", "Toggles Archive Invalidation.", Fallout3.Tools.ArchiveInvalidation.IsActive(), ToggleArchiveInvalidation));
			*/

			try
			{
				gmdGameMode = InstantiateGameMode(p_futFileUtility);

				if (!File.Exists(((GamebryoGameModeBase)gmdGameMode).SettingsFiles.IniPath))
					p_imsWarning = new ViewMessage(String.Format("You have no {0} INI file. Please run {0} to initialize the file before installing any mods or turning on Archive Invalidation.", gmdGameMode.Name), null, "Missing INI", MessageBoxIcon.Warning);
				else
					p_imsWarning = null;
			}
			catch(SorterException e)
			{
				gmdGameMode = null;
				p_imsWarning = new ViewMessage(String.Format(e.Message), null, "SorterException", MessageBoxIcon.Error);
			}
			
			return gmdGameMode;
		}
		/// <summary>
		/// Displays a message.
		/// </summary>
		/// <param name="p_vwmMessage">The properties of the message to dislpay.</param>
		/// <returns>The return value of the displayed message.</returns>
		private object ShowMessage(ViewMessage p_vwmMessage)
		{
			if (InvokeRequired)
				return Invoke((ShowMessageDelegate)ShowMessage, p_vwmMessage);
			if (String.IsNullOrEmpty(p_vwmMessage.Details))
			{
				bool booFound = true;
				MessageBoxButtons mbbOptions = MessageBoxButtons.OK;
				switch (p_vwmMessage.Options)
				{
					case ExtendedMessageBoxButtons.Abort | ExtendedMessageBoxButtons.Retry | ExtendedMessageBoxButtons.Ignore:
						mbbOptions = MessageBoxButtons.AbortRetryIgnore;
						break;
					case ExtendedMessageBoxButtons.OK:
						mbbOptions = MessageBoxButtons.OK;
						break;
					case ExtendedMessageBoxButtons.OK | ExtendedMessageBoxButtons.Cancel:
						mbbOptions = MessageBoxButtons.OKCancel;
						break;
					case ExtendedMessageBoxButtons.Retry | ExtendedMessageBoxButtons.Cancel:
						mbbOptions = MessageBoxButtons.RetryCancel;
						break;
					case ExtendedMessageBoxButtons.Yes | ExtendedMessageBoxButtons.No:
						mbbOptions = MessageBoxButtons.YesNo;
						break;
					case ExtendedMessageBoxButtons.Yes | ExtendedMessageBoxButtons.No | ExtendedMessageBoxButtons.Cancel:
						mbbOptions = MessageBoxButtons.YesNoCancel;
						break;
					default:
						booFound = false;
						break;
				}
				if (booFound)
					return MessageBox.Show(this, p_vwmMessage.Message, p_vwmMessage.Title, mbbOptions, p_vwmMessage.MessageType);
			}
			return ExtendedMessageBox.Show(this, p_vwmMessage.Message, p_vwmMessage.Title, p_vwmMessage.Details, p_vwmMessage.Options, p_vwmMessage.MessageType);
		}