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 { /// /// Interaction logic for App.xaml /// public partial class App : Application { /// /// Main Application Object /// 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()); } } /// /// 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 * /// 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)); /// /// CommandLine Flags for Application /// public enum CommandLine_Flag { START, PAUSE, RESTART, RESTART_ALL, STOP, STOP_ALL, SHOW_PROCESSES, SHOW_SERVICES, LOCK, RUNASSERVICE, UNINSTALL, } /// /// CommandLine Options for Application /// 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; /// /// Create a Logging_Configuration Object with Default Application Settings /// /// Specify the LogFile and Path to Log to /// Specify Logging Details Setting /// true, to only allow exclusive (one process) access to file /// a Logging_Configuration object to use Utilities.GenericUtilities.File.Logging //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; } /// /// Responsible for creating the AppMain Logging Object /// 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 } /// /// Retrieve the AppMain Logging Object, It must have been created by calling CreateAppMainLogging() /// /// public static Logging GetAppMainLogging() { return Logging.GetLogger(LOG_NAME_APPMAIN); } #endregion #region Message Box Configuration /// /// We also want to initialize the MsgBox Class here /// 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 /// /// Various Keys that we can use to save/get the GUI State /// 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, } /// /// State of the System /// public enum StateSystem { Running, Paused, Stopped, Error } // Initialize BkgdState internal static readonly StateM State = new StateM(typeof(StateKey)); #endregion #region Application State - Monitor State /// /// Returns the state of the System (icon to display) /// /// Application State for System internal static StateSystem State_GetSystemState() { if (State.GetStateValue(App.StateKey.Monitor_Started_bool, false)) { // Error and Pause are Special 'Running' States if (State.GetStateValue(App.StateKey.SpecialMode_Paused_Mode_bool, false)) return StateSystem.Paused; if (State.GetStateValue(App.StateKey.Monitor_ErrorsOccured_bool, false)) return StateSystem.Error; else return StateSystem.Running; } else { return StateSystem.Stopped; } } /// /// Is the Monitor Currently in a 'Running' State /// /// true if yes, false otherwise internal static bool State_MonitorIsInRunningState() { return State.GetStateValue(App.StateKey.Monitor_Started_bool, false); } /// /// Sets the System into an Error State /// /// Error Message to Notify to User internal static void State_Error_SetErrorState(string strErrorMessageToNotify) { App.State.SetStateValue(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)); } } } /// /// Error State Reset /// internal static void State_Error_ResetErrorState() { App.State.SetStateValue(App.StateKey.Monitor_ErrorsOccured_bool, false); } /// /// Set Main Monitor to Started /// internal static void State_MonitorStarted() { App.State.SetStateValue(App.StateKey.Monitor_Started_bool, true); App.State.SetStateValue(App.StateKey.SpecialMode_Paused_Mode_bool, false); } /// /// Set Main Monitor to Stopped /// internal static void State_MonitorStopped() { App.State.SetStateValue(App.StateKey.Monitor_Started_bool, false); App.State.SetStateValue(App.StateKey.SpecialMode_Paused_Mode_bool, false); } /// /// Set Main Monitor to Paused /// internal static void State_MonitorPaused() { App.State.SetStateValue(App.StateKey.SpecialMode_Paused_Mode_bool, true); } /// /// Is the System in a Paused State? /// /// true if yes, false if no internal static bool State_IsMonitorPaused() { return App.State.GetStateValue(App.StateKey.SpecialMode_Paused_Mode_bool, false); } #endregion #region Application State - Scheduler State /// /// Is the Scheduler Executing? /// /// true if yes, false if no internal static bool State_IsSchedulerExecuting() { return App.State.GetStateValue(App.StateKey.Scheduler_Started_bool, false); } /// /// Scheduler Execution Started /// internal static void State_SchedulerExecution_Started() { App.State.SetStateValue(App.StateKey.Scheduler_Started_bool, true); } /// /// Scheduler Execution Stopped /// internal static void State_SchedulerExecution_Stopped() { App.State.SetStateValue(App.StateKey.Scheduler_Started_bool, false); } /// /// Is the Scheduler Executing? /// /// true if yes, false if no internal static bool State_IsSchedulerBackupExecuting() { return App.State.GetStateValue(App.StateKey.SchedulerBackup_Started_bool, false); } /// /// Scheduler Execution Started /// internal static void State_SchedulerBackupExecution_Started() { App.State.SetStateValue(App.StateKey.SchedulerBackup_Started_bool, true); } /// /// Scheduler Execution Stopped /// internal static void State_SchedulerBackupExecution_Stopped() { App.State.SetStateValue(App.StateKey.SchedulerBackup_Started_bool, false); } #endregion #region Application State - CommandLine State /// /// Set Application into CommandLine Mode /// internal static void State_SpecialMode_CommandLineSet() { App.State.SetStateValue(App.StateKey.SpecialMode_CommandLine_Mode_bool, true); } /// /// Is Application in CommandLine Mode? /// /// true if yes, false if no internal static bool State_SpecialMode_IsCommandLineSet() { return App.State.GetStateValue(App.StateKey.SpecialMode_CommandLine_Mode_bool, false); } /// /// Set Application into RunAsService Mode /// internal static void State_SpecialMode_RunAsServiceSet() { App.State.SetStateValue(App.StateKey.SpecialMode_RunAsService_Mode_bool, true); } /// /// Is Application in RunAsService Mode? /// /// true if yes, false if no internal static bool State_SpecialMode_IsRunAsServiceSet() { return App.State.GetStateValue(App.StateKey.SpecialMode_RunAsService_Mode_bool, false); } /// /// Special Circumstance - Set Console as Attached /// internal static void State_SpecialCircum_ConsoleWindowIsAttached() { App.State.SetStateValue(App.StateKey.SpecialCircum_CommandLine_ConsoleWindowIsAttached_bool, true); } /// /// Special Circumstance - Was Console Window Attached? /// internal static bool State_SpecialCircum_IsConsoleWindowIsAttached() { return App.State.GetStateValue(App.StateKey.SpecialCircum_CommandLine_ConsoleWindowIsAttached_bool, false); } /// /// Special Circumstance - Set Communication with Main Instance via WCF as Succeeded /// internal static void State_SpecialCircum_MainMonitorInstance_CommSuccees() { App.State.SetStateValue(App.StateKey.SpecialCircum_CommandLine_MonitorInstanceExists_bool, true); } /// /// Special Circumstance - Did Communication with Mai Instance via WCF Succeed? /// /// true if yes, false if no internal static bool State_SpecialCircum_DidMainMonitorInstanceCommSucceed() { return App.State.GetStateValue(App.StateKey.SpecialCircum_CommandLine_MonitorInstanceExists_bool, false); } #endregion #region Applicaton State - Special States /// /// Special Circumstance - Set that the Application won't close Applications on Exit * Useful for Auto-Updating the Software * /// internal static void State_SpecialCircum_DontCloseApplicationsOnExit() { App.State.SetStateValue(App.StateKey.SpecialCircum_DontCloseApplicationsOnExit_bool, true); } /// /// Special Circumstance - Check to see if we should Close Applications when Exiting /// /// true if yes, don't close, false if no internal static bool State_SpecialCircum_ShouldWeNotCloseApplicationsOnExit() { return App.State.GetStateValue(App.StateKey.SpecialCircum_DontCloseApplicationsOnExit_bool, false); } /// /// Check to see if html is available /// /// true, if available, false otherwise internal static bool State_HtmlHelpIsAvailable() { return App.State.GetStateValue(App.StateKey.Help_Is_Available_bool, false); } /// /// Set Html Help File as available /// internal static void State_HtmlHelpAvailable() { App.State.SetStateValue(App.StateKey.Help_Is_Available_bool, true); } #endregion #region Unhandled Expections! IMP - Show WinForm and Log /// /// * 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 /// 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 /// /// Some Events continue execution, even though a fatal exception occured (.net!) /// This flag allows those functions to check for this and stop processing /// public static bool s_FatalErrorOccured = false; /// /// Custom User Specified Fatal Exception Occured * Stops Application Execution * /// /// Message to show/log //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 /// /// 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 /// /// a loaded assembly if found, null otherwise 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 /// /// Handles the Application StartUp event /// 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 excludedProcessNames = new List(); 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(); } } /// /// Handles the Application Exit event. /// 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 } }