840 lines
40 KiB
C#
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
|
|
}
|
|
}
|