Files
Yaulw/@integrate/App.xaml.cs
2016-02-15 12:32:26 -05:00

840 lines
40 KiB
C#

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using Watchdog.WatchdogLib.File;
using WatchdogLib.Tools;
using Watchdog.WatchdogLib.Process;
using Watchdog.WatchdogLib.WinForms;
using Watchdog.WatchdogLib.Assembly;
using WatchdogLib.File;
using System.Reflection;
using Watchdog.WatchdogLib.Other;
using Watchdog.WatchdogLib.Monitor;
using System.Diagnostics;
using Forms = System.Windows.Forms;
using Watchdog.WatchdogLib.Net;
using System.IO;
using System.Net;
namespace Watchdog
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
/// <summary>
/// Main Application Object
/// </summary>
public App()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
#region Application Constants
// Application Constants
internal static readonly string APPLICATION_NAME_SHORT = AppResx.GetString("APPLICATION_NAME_SHORT");
internal static readonly string APPLICATION_NAME_LONG = AppResx.GetString("APPLICATION_NAME_LONG");
internal static readonly string SUPPORT_PHONENUMBER = AppResx.GetString("SUPPORT_PHONENUMBER");
internal static readonly int APPLICATION_VERSION_MAJOR = AssemblyW.GetAssemblyVersion(AssemblyW.AssemblyST.Executing).Major;
internal static readonly int APPLICATION_VERSION_MINOR = AssemblyW.GetAssemblyVersion(AssemblyW.AssemblyST.Executing).Minor;
internal static readonly int APPLICATION_VERSION_BUILDNUMBER = AssemblyW.GetAssemblyVersion(AssemblyW.AssemblyST.Executing).Build;
internal static readonly int APPLICATION_VERSION_REVISION = AssemblyW.GetAssemblyVersion(AssemblyW.AssemblyST.Executing).Revision;
internal static string APPLICATION_VERSION { get { return (APPLICATION_VERSION_MAJOR.ToString() + "." + APPLICATION_VERSION_MINOR.ToString() + "." + APPLICATION_VERSION_BUILDNUMBER.ToString() + "." + APPLICATION_VERSION_REVISION.ToString()); } }
/// <summary>
/// This is the Product ID Generated for our Product via ClickOnce and our Certificate.
/// As long as the Certificate Stays the same This ID stays the same.
/// ~we are using this to overide the uninstall icon in Add/Remove * Branding *
/// </summary>
internal static readonly string APPLICATION_PRODUCT_CLICKONCE_ID = "6f02138d8632343a";
internal static readonly string APPLICATION_PRODUCT_CLICKONCE_URL = "http://www.medisoft.com/Watchdog/Publish/Watchdog.application";
internal static string APPLICATION_CLICKONCE_PUBLISHER { get { return AssemblyW.GetAssemblyCompany(AssemblyW.AssemblyST.Executing); } }
internal static string APPLICATION_CLICKONCE_PRODUCT { get { return AssemblyW.GetAssemblyProductName(AssemblyW.AssemblyST.Executing); } }
internal static string APPLICATION_CLICKONCE_STARTMENU_LINK
{
get { return string.Concat(Environment.GetFolderPath(Environment.SpecialFolder.Programs), "\\", APPLICATION_CLICKONCE_PUBLISHER, "\\", APPLICATION_CLICKONCE_PRODUCT , ".appref-ms"); }
}
// Default Log File Settings
internal const int LOG_FILE_FILE_SIZE_IN_MB = 2;
internal const int LOG_FILE_NUM_OF_BACKUPS = 4;
// Log File Constants
internal static readonly string FILE_EXTENSION_LOG_DEFAULT = AppResx.GetString("FILE_EXTENSION_LOG_DEFAULT");
internal static readonly string LOG_NAME_APPMAIN = AppResx.GetString("APPLICATION_NAME_SHORT");
// Application Files / Dependencies
internal static string APP_LOG_FILENAME { get { return (LOG_NAME_APPMAIN + "." + FILE_EXTENSION_LOG_DEFAULT); } }
internal static string APP_LOG_FILENAMEANDPATH
{
get
{
// Make sure Subpath begin|end with a slash, as needed
string commondir = PathNaming.PathEndsWithSlash(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
string subpath = PathNaming.PathBeginsWithNoSlash(PathNaming.PathEndsWithSlash(AppResx.GetString("LOG_FILE_SUBPATH")));
string filename = LOG_NAME_APPMAIN + "." + FILE_EXTENSION_LOG_DEFAULT;
return (commondir + subpath + filename);
}
}
internal static string APP_LOG_PATH
{
get
{
// Make sure Subpath begin|end with a slash, as needed
string commondir = PathNaming.PathEndsWithSlash(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
string subpath = PathNaming.PathBeginsWithNoSlash(PathNaming.PathEndsWithNoSlash(AppResx.GetString("LOG_FILE_SUBPATH")));
return (commondir + subpath);
}
}
internal static string APP_XML_DS_FILENAME { get { return AppResx.GetString("XMLCONFIG_FILENAME"); } }
internal static string APP_XML_DS_FILENAMEANDPATH
{
get
{
// Make sure Subpath begin|end with a slash, as needed
string commondir = PathNaming.PathEndsWithSlash(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
string subpath = PathNaming.PathBeginsWithNoSlash(PathNaming.PathEndsWithSlash(AppResx.GetString("XMLCONFIG_FILE_SUBPATH")));
string filename = AppResx.GetString("XMLCONFIG_FILENAME");
return (commondir + subpath + filename);
}
}
internal static string APP_XML_DS_PATH
{
get
{
// Make sure Subpath begin|end with a slash, as needed
string commondir = PathNaming.PathEndsWithSlash(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
string subpath = PathNaming.PathBeginsWithNoSlash(PathNaming.PathEndsWithNoSlash(AppResx.GetString("XMLCONFIG_FILE_SUBPATH")));
return (commondir + subpath);
}
}
internal static string APP_INI_SETTINGS_FILENAME { get { return AppResx.GetString("INISETTINGS_FILENAME"); } }
internal static string APP_INI_SETTINGS_FILENAMEANDPATH
{
get
{
// Make sure Subpath begin|end with a slash, as needed
string commondir = PathNaming.PathEndsWithSlash(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
string subpath = PathNaming.PathBeginsWithNoSlash(PathNaming.PathEndsWithSlash(AppResx.GetString("INISETTINGS_SUBPATH")));
string filename = AppResx.GetString("INISETTINGS_FILENAME");
return (commondir + subpath + filename);
}
}
internal static string APP_INI_SETTINGS_PATH
{
get
{
// Make sure Subpath begin|end with a slash, as needed
string commondir = PathNaming.PathEndsWithSlash(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
string subpath = PathNaming.PathBeginsWithNoSlash(PathNaming.PathEndsWithNoSlash(AppResx.GetString("INISETTINGS_SUBPATH")));
return (commondir + subpath);
}
}
#endregion
#region Application Help
// Application's Main Help Object
internal static CHMFile chmhelp = null;
#endregion
#region Xml Configuration
// Application's Main Xml Object
internal static MonitorDataStore xmlfile = null;
#endregion
#region Ini Configuration
// Application's Main Ini Object
internal static INIFile inifile = new INIFile(APP_INI_SETTINGS_FILENAMEANDPATH, typeof(Ini_Setting));
internal enum Ini_Setting
{
MonitorSettings__Start_With_Windows,
MonitorSettings__Monitor_On_Start,
MonitorSettings__Max_Fail_Count,
MonitorSettings__Max_Fail_Count_Per_Hour,
MonitorSettings__Default_Exe_Running_Filter,
MonitorSettings__Default_Services_Names_Running_Filter,
MonitorSettings__Sheduler_StartDateTime,
MonitorSettings__Sheduler_RepeatEveryNHoursOrMinutes,
MonitorSettings__Sheduler_RepeatIsHour,
MonitorSettings__Sheduler_LastRun_DateTime,
MonitorSettings__Scheduler_Restarts_Services,
MonitorSettings__ShedulerBackup_StartDateTime,
MonitorSettings__ShedulerBackup_ForDurationNHoursOrMinutes,
MonitorSettings__ShedulerBackup_DurationIsHour,
MonitorSettings__ShedulerBackup_LastRun_DateTime,
MonitorSettings__ShedulerBackup_StopInsteadOfPause,
MonitorSettings__ShedulerBackup_StopServices,
WindowSettings__AboutWindow_TopLeft,
WindowSettings__SettingsWindow_TopLeft,
WindowSettings__LogViewerWindow_TopLeft,
WindowsSettings__LockWorkstation_With_Windows,
WindowsSettings__AutoLogin_With_Windows,
WindowsSettings__CreateExeHardLink_In_RootPath,
EmailSettings__EnableEmailNotifications,
EmailSettings__SmtpServer,
EmailSettings__SenderEmail,
EmailSettings__ReveiverEmail,
EmailSettings__SmtpPort,
EmailSettings__SmtpRequiresAuth,
EmailSettings__SmtpRequiresSSL,
EmailSettings__SmtpUsername,
EmailSettings__SmtpPassword,
EmailSettings__Custom_Message_Text,
}
// Wrapper class arround Ini Settings
internal static Settings setting = new Settings();
#endregion
#region Command Line Parameters
// Application's CmdLine Parser
internal static CMDline cmdline = new CMDline(typeof(App.CommandLine_Option), typeof(App.CommandLine_Flag));
/// <summary>
/// CommandLine Flags for Application
/// </summary>
public enum CommandLine_Flag
{
START,
PAUSE,
RESTART,
RESTART_ALL,
STOP,
STOP_ALL,
SHOW_PROCESSES,
SHOW_SERVICES,
LOCK,
RUNASSERVICE,
UNINSTALL,
}
/// <summary>
/// CommandLine Options for Application
/// </summary>
public enum CommandLine_Option
{
ADD_SERVICE,
REMOVE_SERVICE,
ADD_PROCESS,
REMOVE_PROCESS,
}
#endregion
#region Logging Configuration
// Application's Main Log Object
internal static Logging log = null;
/// <summary>
/// Create a Logging_Configuration Object with Default Application Settings
/// </summary>
/// <param name="LogFileNameNPath">Specify the LogFile and Path to Log to</param>
/// <param name="Detail">Specify Logging Details Setting</param>
/// <param name="UseExclusiveFileLock">true, to only allow exclusive (one process) access to file</param>
/// <returns>a Logging_Configuration object to use Utilities.GenericUtilities.File.Logging</returns>
//private static Logging_Configuration CreateDefaultLoggingConfiguration(string LogFileNameNPath, Logging_Detail Detail = Logging_Detail.ERROR, bool UseExclusiveFileLock = false)
private static Logging_Configuration CreateDefaultLoggingConfiguration(string LogFileNameNPath, Logging_Detail Detail, bool UseExclusiveFileLock)
{
Logging_Configuration config;
config.LogFileNameNPath = LogFileNameNPath;
config.maxFileSizeInMB = LOG_FILE_FILE_SIZE_IN_MB;
config.numOfBackupLogFiles = LOG_FILE_NUM_OF_BACKUPS;
config.Detail = Detail;
config.UseExclusiveFileLock = UseExclusiveFileLock;
return config;
}
/// <summary>
/// Responsible for creating the AppMain Logging Object
/// </summary>
public static Logging CreateAppMainLogging()
{
// Log FileNameNPath * Debug mode set logging level to Debug, Release to Info *
#if DEBUG
return Logging.AddGlobalLoggerConfiguration(LOG_NAME_APPMAIN, CreateDefaultLoggingConfiguration(APP_LOG_FILENAMEANDPATH, Logging_Detail.DEBUG, false));
#else
return Logging.AddGlobalLoggerConfiguration(LOG_NAME_APPMAIN, CreateDefaultLoggingConfiguration(APP_LOG_FILENAMEANDPATH, Logging_Detail.INFO, false));
#endif
}
/// <summary>
/// Retrieve the AppMain Logging Object, It must have been created by calling CreateAppMainLogging()
/// </summary>
/// <returns></returns>
public static Logging GetAppMainLogging()
{
return Logging.GetLogger(LOG_NAME_APPMAIN);
}
#endregion
#region Message Box Configuration
/// <summary>
/// We also want to initialize the MsgBox Class here
/// </summary>
public static void ConfigureAppMainMsgBox()
{
// Fatal Errors
MsgBox.MsgBox_FatalErrorTitleHeader = AppResx.GetStringFormated("APPLICATION_FATAL_ERROR", APPLICATION_NAME_SHORT);
MsgBox.MsgBox_FatalErrorHeader = AppResx.GetString("FATAL_ERROR_HEADER");
MsgBox.MsgBox_FatalErrorFooter = AppResx.GetStringFormated("FATAL_ERROR_APPLICATION_WILL_EXIT", APPLICATION_NAME_LONG) +
AppResx.GetStringFormated("CONTACT_SUPPORT_URGENTLY", SUPPORT_PHONENUMBER) +
AppResx.GetStringFormated("ERROR_LOG_FILE_LOCATION", APP_LOG_FILENAME, APP_LOG_PATH);
// Errors
MsgBox.MsgBox_ErrorTitleHeader = AppResx.GetStringFormated("APPLICATION_ERROR", APPLICATION_NAME_SHORT);
MsgBox.MsgBox_ErrorHeader = AppResx.GetString("ERROR_HEADER");
MsgBox.MsgBox_ErrorFooter = AppResx.GetStringFormated("CONTACT_SUPPORT_NICELY", SUPPORT_PHONENUMBER) +
AppResx.GetStringFormated("ERROR_LOG_FILE_LOCATION", APP_LOG_FILENAME, APP_LOG_PATH);
// Info
MsgBox.MsgBox_InfoTitleHeader = AppResx.GetStringFormated("APPLICATION_INFO", APPLICATION_NAME_SHORT);
// * For Debugging *
//MsgBox.ShowError("01234567890123456789012345678901234567890123456789012345678901234");
//MsgBox.ShowFatalError("01234567890123456789012345678901234567890123456789012345678901234");
}
#endregion
#region Application State
/// <summary>
/// Various Keys that we can use to save/get the GUI State
/// </summary>
internal enum StateKey
{
Monitor_Started_bool,
Monitor_ErrorsOccured_bool,
Scheduler_Started_bool,
SchedulerBackup_Started_bool,
SpecialMode_Paused_Mode_bool,
SpecialMode_CommandLine_Mode_bool,
SpecialMode_RunAsService_Mode_bool,
SpecialCircum_CommandLine_ConsoleWindowIsAttached_bool,
SpecialCircum_CommandLine_MonitorInstanceExists_bool,
SpecialCircum_DontCloseApplicationsOnExit_bool,
Help_Is_Available_bool,
}
/// <summary>
/// State of the System
/// </summary>
public enum StateSystem
{
Running,
Paused,
Stopped,
Error
}
// Initialize BkgdState
internal static readonly StateM State = new StateM(typeof(StateKey));
#endregion
#region Application State - Monitor State
/// <summary>
/// Returns the state of the System (icon to display)
/// </summary>
/// <returns>Application State for System</returns>
internal static StateSystem State_GetSystemState()
{
if (State.GetStateValue<bool>(App.StateKey.Monitor_Started_bool, false))
{
// Error and Pause are Special 'Running' States
if (State.GetStateValue<bool>(App.StateKey.SpecialMode_Paused_Mode_bool, false))
return StateSystem.Paused;
if (State.GetStateValue<bool>(App.StateKey.Monitor_ErrorsOccured_bool, false))
return StateSystem.Error;
else
return StateSystem.Running;
}
else
{
return StateSystem.Stopped;
}
}
/// <summary>
/// Is the Monitor Currently in a 'Running' State
/// </summary>
/// <returns>true if yes, false otherwise</returns>
internal static bool State_MonitorIsInRunningState() { return State.GetStateValue<bool>(App.StateKey.Monitor_Started_bool, false); }
/// <summary>
/// Sets the System into an Error State
/// </summary>
/// <param name="strCustomErrorMessageToNotify">Error Message to Notify to User</param>
internal static void State_Error_SetErrorState(string strErrorMessageToNotify)
{
App.State.SetStateValue<bool>(App.StateKey.Monitor_ErrorsOccured_bool, true);
if (!String.IsNullOrEmpty(strErrorMessageToNotify))
{
////
// Application entered an Error State * Better Notify User, if specified *
////
if (App.setting.EmailNotificationEnabled && App.setting.EmailSettingsValid)
{
bool bIsSend = Emailer.SendEmail(App.setting.EmailStmpServer, App.setting.EmailSenderEmail, App.APPLICATION_NAME_SHORT,
App.setting.EmailReceiverEmail, AppResx.GetStringFormated("ERRORSTATE_EMAIL_SUBJECT", App.APPLICATION_NAME_SHORT),
AppResx.GetStringFormated("ERRORSTATE_EMAIL_BODY", App.APPLICATION_NAME_SHORT, strErrorMessageToNotify ,App.setting.EmailCustomMessageText),
App.setting.EmailSmtpPort, String.Empty, App.setting.EmailStmpServerRequiresAuth, App.setting.EmailSmtpUsername, App.setting.EmailSmtpPassword,
App.setting.EmailStmpServerRequiresSSL, 30);
if (!bIsSend)
App.log.Error("Failed to Send ERRORSTATE_EMAIL");
else
App.log.Info(String.Format("Email (ERRORSTATE_EMAIL) Notification send to {0}", App.setting.EmailReceiverEmail));
}
}
}
/// <summary>
/// Error State Reset
/// </summary>
internal static void State_Error_ResetErrorState() { App.State.SetStateValue<bool>(App.StateKey.Monitor_ErrorsOccured_bool, false); }
/// <summary>
/// Set Main Monitor to Started
/// </summary>
internal static void State_MonitorStarted() { App.State.SetStateValue<bool>(App.StateKey.Monitor_Started_bool, true); App.State.SetStateValue<bool>(App.StateKey.SpecialMode_Paused_Mode_bool, false); }
/// <summary>
/// Set Main Monitor to Stopped
/// </summary>
internal static void State_MonitorStopped() { App.State.SetStateValue<bool>(App.StateKey.Monitor_Started_bool, false); App.State.SetStateValue<bool>(App.StateKey.SpecialMode_Paused_Mode_bool, false); }
/// <summary>
/// Set Main Monitor to Paused
/// </summary>
internal static void State_MonitorPaused() { App.State.SetStateValue<bool>(App.StateKey.SpecialMode_Paused_Mode_bool, true); }
/// <summary>
/// Is the System in a Paused State?
/// </summary>
/// <returns>true if yes, false if no</returns>
internal static bool State_IsMonitorPaused() { return App.State.GetStateValue<bool>(App.StateKey.SpecialMode_Paused_Mode_bool, false); }
#endregion
#region Application State - Scheduler State
/// <summary>
/// Is the Scheduler Executing?
/// </summary>
/// <returns>true if yes, false if no</returns>
internal static bool State_IsSchedulerExecuting() { return App.State.GetStateValue<bool>(App.StateKey.Scheduler_Started_bool, false); }
/// <summary>
/// Scheduler Execution Started
/// </summary>
internal static void State_SchedulerExecution_Started() { App.State.SetStateValue<bool>(App.StateKey.Scheduler_Started_bool, true); }
/// <summary>
/// Scheduler Execution Stopped
/// </summary>
internal static void State_SchedulerExecution_Stopped() { App.State.SetStateValue<bool>(App.StateKey.Scheduler_Started_bool, false); }
/// <summary>
/// Is the Scheduler Executing?
/// </summary>
/// <returns>true if yes, false if no</returns>
internal static bool State_IsSchedulerBackupExecuting() { return App.State.GetStateValue<bool>(App.StateKey.SchedulerBackup_Started_bool, false); }
/// <summary>
/// Scheduler Execution Started
/// </summary>
internal static void State_SchedulerBackupExecution_Started() { App.State.SetStateValue<bool>(App.StateKey.SchedulerBackup_Started_bool, true); }
/// <summary>
/// Scheduler Execution Stopped
/// </summary>
internal static void State_SchedulerBackupExecution_Stopped() { App.State.SetStateValue<bool>(App.StateKey.SchedulerBackup_Started_bool, false); }
#endregion
#region Application State - CommandLine State
/// <summary>
/// Set Application into CommandLine Mode
/// </summary>
internal static void State_SpecialMode_CommandLineSet() { App.State.SetStateValue<bool>(App.StateKey.SpecialMode_CommandLine_Mode_bool, true); }
/// <summary>
/// Is Application in CommandLine Mode?
/// </summary>
/// <returns>true if yes, false if no</returns>
internal static bool State_SpecialMode_IsCommandLineSet() { return App.State.GetStateValue<bool>(App.StateKey.SpecialMode_CommandLine_Mode_bool, false); }
/// <summary>
/// Set Application into RunAsService Mode
/// </summary>
internal static void State_SpecialMode_RunAsServiceSet() { App.State.SetStateValue<bool>(App.StateKey.SpecialMode_RunAsService_Mode_bool, true); }
/// <summary>
/// Is Application in RunAsService Mode?
/// </summary>
/// <returns>true if yes, false if no</returns>
internal static bool State_SpecialMode_IsRunAsServiceSet() { return App.State.GetStateValue<bool>(App.StateKey.SpecialMode_RunAsService_Mode_bool, false); }
/// <summary>
/// Special Circumstance - Set Console as Attached
/// </summary>
internal static void State_SpecialCircum_ConsoleWindowIsAttached() { App.State.SetStateValue<bool>(App.StateKey.SpecialCircum_CommandLine_ConsoleWindowIsAttached_bool, true); }
/// <summary>
/// Special Circumstance - Was Console Window Attached?
/// </summary>
internal static bool State_SpecialCircum_IsConsoleWindowIsAttached() { return App.State.GetStateValue<bool>(App.StateKey.SpecialCircum_CommandLine_ConsoleWindowIsAttached_bool, false); }
/// <summary>
/// Special Circumstance - Set Communication with Main Instance via WCF as Succeeded
/// </summary>
internal static void State_SpecialCircum_MainMonitorInstance_CommSuccees() { App.State.SetStateValue<bool>(App.StateKey.SpecialCircum_CommandLine_MonitorInstanceExists_bool, true); }
/// <summary>
/// Special Circumstance - Did Communication with Mai Instance via WCF Succeed?
/// </summary>
/// <returns>true if yes, false if no</returns>
internal static bool State_SpecialCircum_DidMainMonitorInstanceCommSucceed() { return App.State.GetStateValue<bool>(App.StateKey.SpecialCircum_CommandLine_MonitorInstanceExists_bool, false); }
#endregion
#region Applicaton State - Special States
/// <summary>
/// Special Circumstance - Set that the Application won't close Applications on Exit * Useful for Auto-Updating the Software *
/// </summary>
internal static void State_SpecialCircum_DontCloseApplicationsOnExit() { App.State.SetStateValue<bool>(App.StateKey.SpecialCircum_DontCloseApplicationsOnExit_bool, true); }
/// <summary>
/// Special Circumstance - Check to see if we should Close Applications when Exiting
/// </summary>
/// <returns>true if yes, don't close, false if no</returns>
internal static bool State_SpecialCircum_ShouldWeNotCloseApplicationsOnExit() { return App.State.GetStateValue<bool>(App.StateKey.SpecialCircum_DontCloseApplicationsOnExit_bool, false); }
/// <summary>
/// Check to see if html is available
/// </summary>
/// <returns>true, if available, false otherwise</returns>
internal static bool State_HtmlHelpIsAvailable() { return App.State.GetStateValue<bool>(App.StateKey.Help_Is_Available_bool, false); }
/// <summary>
/// Set Html Help File as available
/// </summary>
internal static void State_HtmlHelpAvailable() { App.State.SetStateValue<bool>(App.StateKey.Help_Is_Available_bool, true); }
#endregion
#region Unhandled Expections! IMP - Show WinForm and Log
/// <summary>
/// * Generic Unhandled Exception Handler *
/// Handles all unhandled Exceptions for the Entire AppDomain.
/// First Show a Window Message Box, so that we can for sure capture the message
/// Second Log it
/// </summary>
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = (Exception)e.ExceptionObject;
// Exeption to capture error information
string exceptionMessage = AppResx.GetString("FATAL_ERROR_HEADER");
exceptionMessage = AppResx.GetStringFormated("FATAL_ERROR_APPLICATION_WILL_EXIT", APPLICATION_NAME_LONG);
exceptionMessage += ex.Message + "\n\n";
if (!String.IsNullOrEmpty(ex.StackTrace))
exceptionMessage += ex.StackTrace.Substring(0, 880) + "\n\n";
if(!String.IsNullOrEmpty(ex.InnerException.Message))
exceptionMessage += ex.InnerException.Message + "\n\n";
if (!String.IsNullOrEmpty(ex.Source))
exceptionMessage += ex.Source + "\n\n";
// Polite Message to Show in Message Box
string PoliteExceptionMessage = exceptionMessage +
AppResx.GetStringFormated("CONTACT_SUPPORT_URGENTLY", SUPPORT_PHONENUMBER) +
AppResx.GetStringFormated("ERROR_LOG_FILE_LOCATION", APP_LOG_FILENAME, APP_LOG_PATH);
// Show Message Box First - Guaranteed to work (Polite Exception Message)
MessageBox.Show(PoliteExceptionMessage, AppResx.GetStringFormated("APPLICATION_FATAL_ERROR", APPLICATION_NAME_SHORT), MessageBoxButton.OK, MessageBoxImage.Error);
// Log the Error to the Main Log File
CreateAppMainLogging().Fatal(exceptionMessage, ex);
}
#endregion
#region Fatal Exception! IMP - Show WinForm, Log, and Exit the Application
/// <summary>
/// Some Events continue execution, even though a fatal exception occured (.net!)
/// This flag allows those functions to check for this and stop processing
/// </summary>
public static bool s_FatalErrorOccured = false;
/// <summary>
/// Custom User Specified Fatal Exception Occured * Stops Application Execution *
/// </summary>
/// <param name="Message">Message to show/log</param>
//public static void FatalExceptionStopExecution(string Message, bool bShowMessageBox = true)
public static void FatalExceptionStopExecution(string Message, bool bShowMessageBox)
{
s_FatalErrorOccured = true;
log.Fatal(Message);
if(bShowMessageBox && !App.State_SpecialMode_IsRunAsServiceSet())
MsgBox.ShowFatalError(Message, "", Forms.MessageBoxButtons.OK);
App.Current.Shutdown();
// To make 100% sure, that we are exiting... (not needed)
//System.Diagnostics.Process.GetCurrentProcess().Kill();
}
#endregion
#region Application Multi-File Assembly Handling
/// <summary>
/// A way to embed multiple dlls into one exe:
/// http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
/// </summary>
/// <returns>a loaded assembly if found, null otherwise</returns>
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string curAssemblyName = AssemblyW.GetAssemblyName(AssemblyW.AssemblyST.Executing);
String resourceName = curAssemblyName + ".Components." + new AssemblyName(args.Name).Name + ".dll";
//string[] resources = AssemblyW.SpecializedAssemblyInfo.GetAssemblyResourceNames(AssemblyW.AssemblyST.Entry);
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
if(stream != null)
{
using (stream)
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
return null;
}
#endregion
#region Application Startup N' Exit
/// <summary>
/// Handles the Application StartUp event
/// </summary>
private void Application_Startup(object sender, StartupEventArgs e)
{
// We need to make sure that the Permissions are set correctly for
// the ProgramData/AllUser folder for ALL our configuration files
Installer.GrantFullPermissionToFolderForUserOrGroup(APP_XML_DS_PATH, "Everyone");
// Create the First Main Log Instance
log = CreateAppMainLogging();
// Parse the Command Line
cmdline.Parse(e.Args);
// Delay Start * Imp. for Auto-Update Feature
string[] activationData = null;
if(AppDomain.CurrentDomain.SetupInformation.ActivationArguments != null)
activationData = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
if (activationData != null && activationData.Length > 0)
{
uint uDelayStart = 0;
if (uint.TryParse(activationData[0], out uDelayStart) && (uDelayStart > 0))
{
App.log.Info(String.Format("Auto Update Delay Start Called with {0} Seconds", uDelayStart));
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(uDelayStart));
}
}
// If Command-Line has params, we are being launched in Command-Line Mode * Hence, we put
// the app into a different State *
if (cmdline.HasParams && !cmdline.GetFlagValue(CommandLine_Flag.RUNASSERVICE)) // RunAsService is NOT Command-line Mode
{
App.State_SpecialMode_CommandLineSet();
log.Info(AppResx.GetStringFormated("APPLICATION_STARTED_COMMANDLINE_MODE", APPLICATION_NAME_SHORT, cmdline.ParsedArgs(), APPLICATION_VERSION));
}
else if (cmdline.HasParams && cmdline.GetFlagValue(CommandLine_Flag.RUNASSERVICE)) // RunAsService is it's own Mode
{
State_SpecialMode_RunAsServiceSet();
log.Info(AppResx.GetStringFormated("APPLICATION_STARTED_SERVICE_MODE", APPLICATION_NAME_SHORT, cmdline.ParsedArgs(), APPLICATION_VERSION));
}
else
{
log.Info(AppResx.GetStringFormated("APPLICATION_STARTED", APPLICATION_NAME_SHORT, APPLICATION_VERSION));
}
// Configure our Message Boxes
ConfigureAppMainMsgBox();
// Create the Xml File Instance * To Read/Write DataStore *
// ~Also, don't allow the configuration to add this Application to the Configuration
DelegateCollection.Void_Param1_Exception_Func XmlFileExceptionHandler = delegate(Exception ex)
{
App.log.Error("Saving MonitorDataStore XMLFile Error Thrown", ex);
if(!App.State_SpecialMode_IsRunAsServiceSet())
MsgBox.ShowError("Saving XMLDataStore XMLFile Error " + ex.Message, "", Forms.MessageBoxButtons.OK);
};
List<string> excludedProcessNames = new List<String>();
excludedProcessNames.Add(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileName(AssemblyW.AssemblyST.Entry));
xmlfile = new MonitorDataStore(App.APP_XML_DS_FILENAMEANDPATH, excludedProcessNames, XmlFileExceptionHandler);
// If this is a Debug build, enable * Performance Tracing *
#if DEBUG
TraceM.EnableTracing = true;
#endif
// Make sure that the File Name of this Assembly matches the Assembly Name,
// this allows us to enforce for sure that only One Instance of this program is running
// i.e. someone could run this program otherwise by just changing the filename
string entryAssemblyName = AssemblyW.GetAssemblyName(AssemblyW.AssemblyST.Entry);
string entryAssemblyFileName = AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileName(AssemblyW.AssemblyST.Entry);
if (String.Compare(entryAssemblyName, entryAssemblyFileName, true) != 0)
FatalExceptionStopExecution(AppResx.GetStringFormated("FATAL_ERROR_ASSEMBLY_FILENAME_MISMATCH", entryAssemblyName, entryAssemblyFileName), true);
// Check that this is the ONLY Instance running on this Machine
// ~We only allow one instance of this app to be running... (Only Do this if NOT in Command-Line Mode)
if (!s_FatalErrorOccured && !App.State_SpecialMode_IsCommandLineSet())
{
// Check if there are other instances. Start/Stop/Etc won't work if other instances are not running
bool bAnotherInstanceIsRunning = true;
#if DEBUG
bAnotherInstanceIsRunning = !ProcessW.IsTheOnlyProcessRunning(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileName(AssemblyW.AssemblyST.Entry).ToLower(), false);
#else
bAnotherInstanceIsRunning = !ProcessW.IsTheOnlyProcessRunning(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileName(AssemblyW.AssemblyST.Entry).ToLower(), true);
#endif
if (bAnotherInstanceIsRunning)
{
// Alert the User and ask the User, if they would like to close that process,
// * Could be that The Application Errored out, yet still remains running, so they are trying to restart it *
Process[] ps = null;
#if DEBUG
ps = ProcessW.AllRunningProcessesOf(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileName(AssemblyW.AssemblyST.Entry).ToLower(), false, true);
#else
ps = ProcessW.AllRunningProcessesOf(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileName(AssemblyW.AssemblyST.Entry).ToLower(), true, true);
#endif
Forms.DialogResult dr = System.Windows.Forms.DialogResult.Ignore;
if (!App.State_SpecialMode_IsRunAsServiceSet())
{
string msg = AppResx.GetStringFormated("FATAL_ERROR_OTHER_INSTANCES", App.APPLICATION_NAME_SHORT);
msg += "\nWould you like to try to force close the other instance(s)?\n";
msg += "\nClicking 'Yes' will force all other instances to close.";
msg += "\nClicking 'No' will close this instance.";
dr = MsgBox.ShowInfo(msg, "Other Instance Found", Forms.MessageBoxButtons.YesNo);
}
// Check Dialog Result (If in GUI MODE)
if (dr == Forms.DialogResult.Yes)
{
// try to kill all other instances
bool bSuccess = true;
foreach (Process p in ps)
{
if(Process.GetCurrentProcess().Id != p.Id)
bSuccess = PStarter.KillProcess((uint)p.Id, false, 1, true, 2);
if (!bSuccess)
break;
}
if (!bSuccess)
{
App.log.Error("Error occured closing other instances");
FatalExceptionStopExecution(AppResx.GetStringFormated("FATAL_ERROR_OTHER_INSTANCES", App.APPLICATION_NAME_SHORT), false);
}
else
{
// * Opportunity To Start the WCF Host *
WCFHost.StartHost();
// Refresh the taskbar, after killing any instances
Watchdog.WatchdogLib.Win32.Functions.RefreshTaskbarNotificationArea();
}
}
else
{
FatalExceptionStopExecution(AppResx.GetStringFormated("FATAL_ERROR_OTHER_INSTANCES", App.APPLICATION_NAME_SHORT), false);
}
}
else
{
// * Opportunity To Start the WCF Host *
WCFHost.StartHost();
// * Opportunity to load the chm help file *
// ~Force a new chm file write, if an upgrade occured
try
{
#if DEBUG
bool bForceCreationOfNewCHMFile = true;
#else
bool bForceCreationOfNewCHMFile = (App.APPLICATION_VERSION != App.setting.LastProgramVersion);
#endif
string curAssemblyName = AssemblyW.GetAssemblyName(AssemblyW.AssemblyST.Executing);
App.chmhelp = new CHMFile(Assembly.GetExecutingAssembly().GetManifestResourceStream(curAssemblyName + "." + "Watchdog.chm"), App.APPLICATION_NAME_SHORT, bForceCreationOfNewCHMFile);
if (App.chmhelp != null)
App.State_HtmlHelpAvailable(); // Html Help loaded successfully
if (bForceCreationOfNewCHMFile && (App.chmhelp != null))
App.setting.LastProgramVersion = App.APPLICATION_VERSION;
}
catch (Exception ex)
{
App.log.Error("Failed to create chm Helf File", ex);
}
}
}
else if (!s_FatalErrorOccured && App.State_SpecialMode_IsCommandLineSet())
{
// We are called with CmdLine Parameters * Try Attaching to the console, in case we got called from a Command Window *
bool bAttachSuccess = Watchdog.WatchdogLib.Win32.Kernel32.AttachConsole(-1);
App.log.Info(String.Format("CommandLineMode - Attached to Console is {0}", bAttachSuccess));
if (bAttachSuccess)
App.State_SpecialCircum_ConsoleWindowIsAttached();
}
}
/// <summary>
/// Handles the Application Exit event.
/// </summary>
private void Application_Exit(object sender, ExitEventArgs e)
{
if (!App.State_SpecialMode_IsCommandLineSet())
{
log.Info(AppResx.GetStringFormated("APPLICATION_ENDED", APPLICATION_NAME_SHORT, APPLICATION_VERSION));
// * Opportunity To Stop the WCF Host *
WCFHost.StopHost();
}
else if(App.State_SpecialMode_IsCommandLineSet())
{
if(App.State_SpecialCircum_IsConsoleWindowIsAttached())
{
bool bFreeSuccess = Watchdog.WatchdogLib.Win32.Kernel32.FreeConsole();
App.log.Info(String.Format("CommandLineMode - Free from Console is {0}", bFreeSuccess));
}
log.Info(AppResx.GetStringFormated("APPLICATION_ENDED_COMMANDLINE_MODE", APPLICATION_NAME_SHORT, APPLICATION_VERSION));
}
}
#endregion
}
}