initial checkin of yaulw (locally)

This commit is contained in:
Donald Duck
2016-02-15 12:32:26 -05:00
commit 857eda29e3
115 changed files with 27392 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PhoneHome.Lib.Assembly;
// Downloaded from
// http://www.codeproject.com/Articles/2670/Accessing-alternative-data-streams-of-files-on-an
using Trinet.Core.IO.Ntfs;
using System.IO;
namespace PhoneHome
{
/// <summary>
/// Wrapper class arround Alternate Data Streams
/// * IMP * Registrate 'Later' Medisoft Demo Registration Work-arround
/// Medisoft has a 30 day trial where they don't enter a serial number. However, this can
/// be bypassed, since registration is terrible at what it does. So we must make sure that
/// the 30 days haven't passed, and we deal with it here with PhoneHome via AlternateStreams
/// </summary>
internal static class AlternateDataStreamWrapper
{
/// <summary>
/// Read the Timestamp found in the Alternative Stream
/// </summary>
/// <returns>Dt found or DT.Min (if none found)</returns>
internal static DateTime ReadDateTimeStamp()
{
try
{
string s_curDir = Path.GetDirectoryName(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileNameNPath(AssemblyW.AssemblyST.Executing));
SafeNativeMethods.Win32StreamInfo s_streamInfo = new SafeNativeMethods.Win32StreamInfo() { StreamAttributes = FileStreamAttributes.None, StreamName = "phdt", StreamSize = 20, StreamType = FileStreamType.Data };
AlternateDataStreamInfo adataStream = new AlternateDataStreamInfo(s_curDir, s_streamInfo);
using (FileStream fs = adataStream.OpenRead())
using (StreamReader sr = new StreamReader(fs))
{
string strLine = sr.ReadLine();
DateTime dtFound = DateTime.Parse(strLine);
return dtFound;
}
}
catch (Exception e) { string Message = e.Message; }
return DateTime.MinValue;
}
/// <summary>
/// Write the passed in Timestamp to the Alternative Stream
/// </summary>
/// <param name="dtStamp">Timestamp to write</param>
internal static void WriteDateTimeStamp(DateTime dtStamp)
{
try
{
string s_curDir = Path.GetDirectoryName(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileNameNPath(AssemblyW.AssemblyST.Executing));
SafeNativeMethods.Win32StreamInfo s_streamInfo = new SafeNativeMethods.Win32StreamInfo() { StreamAttributes = FileStreamAttributes.None, StreamName = "phdt", StreamSize = 20, StreamType = FileStreamType.Data };
AlternateDataStreamInfo adataStream = new AlternateDataStreamInfo(s_curDir, s_streamInfo);
using (FileStream fs = adataStream.OpenWrite())
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(dtStamp.ToShortDateString());
}
}
catch (Exception e) { string Message = e.Message; }
}
}
}

839
@integrate/App.xaml.cs Normal file
View File

@@ -0,0 +1,839 @@
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
}
}

161
@integrate/AppState.cs Normal file
View File

@@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Watchdog.WatchdogLib.Other;
namespace Watchdog
{
/// <summary>
/// Keeps Track of RunTime State Variables/Objects
/// </summary>
public static class AppState
{
private static object s_LockObject = new Object();
#region Internal State Check Functions
/// <returns>true if the Process Monitor is running, false otherwise</returns>
internal static bool IsMonitorRunning()
{
lock (s_LockObject)
{
return AppState.State.GetStateValue<bool>(AppState.StateKey.ProcessMonitorStarted_bool, false);
}
}
/// <returns>true if the Scheduler is running, false otherwise</returns>
internal static bool IsSchedulerRunning()
{
lock (s_LockObject)
{
return AppState.State.GetStateValue<bool>(AppState.StateKey.SchedulerIsRunning_bool, false);
}
}
/// <returns>true if the Process Monitor encountered errors, false otherwise</returns>
internal static bool DidMonitorEncounterErrors()
{
lock (s_LockObject)
{
return AppState.State.GetStateValue<bool>(AppState.StateKey.ProcessMonitorEncounteredErrors_bool, false);
}
}
/// <returns>true if the Application is called with Command-Line Parameters, false otherwise</returns>
internal static bool IsInCommandLinePrmsMode()
{
lock (s_LockObject)
{
return AppState.State.GetStateValue<bool>(AppState.StateKey.IsInCommandLineMode_bool, false);
}
}
/// <returns>true if the Application is attached to a Console Window For Output, false otherwise</returns>
internal static bool IsAttachedToConsoleWindow()
{
lock (s_LockObject)
{
return AppState.State.GetStateValue<bool>(AppState.StateKey.IsAttachedToConsoleWindow_bool, false);
}
}
/// <returns>When the application is in commandline mode, we want to make sure that a 'real' monitor instance is running,
/// in order to communicate with it, this keeps track if that other instance is available</returns>
internal static bool InCommandLineMode_IsMonitorInstanceAvailable()
{
lock (s_LockObject)
{
return AppState.State.GetStateValue<bool>(AppState.StateKey.InCommandLineMode_IsMonitorInstanceAvailable_bool, false);
}
}
#endregion
#region Internal State Set Functions
/// <summary>
/// Use this to set the Monitor is Running state to true/false
/// </summary>
internal static bool MonitorIsRunning(bool bIsRunning)
{
lock (s_LockObject)
{
return AppState.State.SetStateValue<bool>(AppState.StateKey.ProcessMonitorStarted_bool, bIsRunning);
}
}
/// <summary>
/// Use this to set the Scheduler is Running state to true/false
/// </summary>
internal static bool SchedulerIsRunning(bool bIsRunning)
{
lock (s_LockObject)
{
return AppState.State.SetStateValue<bool>(AppState.StateKey.SchedulerIsRunning_bool, bIsRunning);
}
}
/// <summary>
/// Use this to set the Monitor's Error State
/// </summary>
internal static bool MonitorEncounterErrors(bool bErrorsOccured)
{
lock (s_LockObject)
{
return AppState.State.SetStateValue<bool>(AppState.StateKey.ProcessMonitorEncounteredErrors_bool, bErrorsOccured);
}
}
/// <summary>
/// Use this to set that the Application is called with Command-Line Parameters
/// </summary>
internal static bool CommandLinePrmsMode(bool bIsInCommandLinePrmsMode)
{
lock (s_LockObject)
{
return AppState.State.SetStateValue<bool>(AppState.StateKey.IsInCommandLineMode_bool, bIsInCommandLinePrmsMode);
}
}
/// <summary>
/// Use this to set that the Application is attached to a Console Window for Output
/// </summary>
internal static bool AttachedToConsoleWindow(bool bItIsAttached)
{
lock (s_LockObject)
{
return AppState.State.SetStateValue<bool>(AppState.StateKey.IsAttachedToConsoleWindow_bool, bItIsAttached);
}
}
/// <summary>
/// Use this to set that the Application can communicate with the 'real' monitor instance that is running.
/// </summary>
internal static bool CommandLineMode_IsMonitorInstanceAvailable(bool bIsAvailable)
{
lock (s_LockObject)
{
return AppState.State.GetStateValue<bool>(AppState.StateKey.InCommandLineMode_IsMonitorInstanceAvailable_bool, bIsAvailable);
}
}
#endregion
/// <summary>
/// Various Keys that we can use to save/get the GUI State
/// </summary>
internal enum StateKey
{
ProcessMonitorStarted_bool,
ProcessMonitorEncounteredErrors_bool,
SchedulerIsRunning_bool,
IsInCommandLineMode_bool,
IsAttachedToConsoleWindow_bool,
InCommandLineMode_IsMonitorInstanceAvailable_bool,
}
// Initialize BkgdState
internal static readonly StateM State = new StateM(typeof(StateKey));
}
}

View File

@@ -0,0 +1,311 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using WatchdogLib;
using Watchdog.WatchdogLib.WinForms;
using Watchdog.WatchdogLib.Win32;
namespace Watchdog
{
/// <summary>
/// Handles CommandLine Logic
/// </summary>
public static class CMDlineHandler
{
// Our WCF Client object stub
private static IWatchdog _proxyObj = null;
/// <summary>
/// Shows the Command Line Help either as a Windows Form or
/// to the Console * Depending if a Console Window is Attached *
/// </summary>
private static void ShowCommandLineHelp()
{
bool bToConsole = App.State_SpecialCircum_IsConsoleWindowIsAttached();
string cmdHelpText = "";
cmdHelpText += "\n";
cmdHelpText += "**************************************************************\n";
cmdHelpText += " Make changes to the .xml Configuration.\n";
cmdHelpText += "**************************************************************\n";
cmdHelpText += "-Add_Process \"Application Exe;Prms;WorkingDir\"\n";
cmdHelpText += "-Remove_Process \"Application Exe;Prms\"\n";
cmdHelpText += "-Add_Service \"Service Name\"\n";
cmdHelpText += "-Remove_Service \"Service Name\"\n";
cmdHelpText += "**************************************************************\n";
cmdHelpText += " View the .xml Configuration.\n";
cmdHelpText += "**************************************************************\n";
cmdHelpText += "-Show_Processes\n";
cmdHelpText += "-Show_Services\n";
cmdHelpText += "**************************************************************\n";
cmdHelpText += " Manipulate a Running Monitor Instance.\n";
cmdHelpText += "**************************************************************\n";
cmdHelpText += "-Start\n";
cmdHelpText += "-Pause\n";
cmdHelpText += "-Restart\n";
cmdHelpText += "-Restart_All\n";
cmdHelpText += "-Stop\n";
cmdHelpText += "-Stop_All\n";
cmdHelpText += "**************************************************************\n";
cmdHelpText += "-? Show Help.\n\n";
// Show Help to the User (Either to the console or a Message Window)
if (bToConsole)
Console.Write(cmdHelpText);
else
MsgBox.ShowInfo(cmdHelpText, (App.APPLICATION_NAME_SHORT + " Command Line Help"), System.Windows.Forms.MessageBoxButtons.OK);
}
/// <summary>
/// Either writes out to the console or shows a message box, if we want to alert the user
/// </summary>
/// <param name="str">string to write out</param>
private static void WriteOut(string str)
{
bool bToConsole = App.State_SpecialCircum_IsConsoleWindowIsAttached();
if (bToConsole)
Console.WriteLine("\n" + str);
else
MsgBox.ShowInfo(str, (App.APPLICATION_NAME_SHORT + " Command Line Alert"), System.Windows.Forms.MessageBoxButtons.OK);
}
/// <summary>
/// Main Entry Point for CommandLine Mode * When Application is being called with
/// CommandLine Parameters *
/// </summary>
static public void EnterCommandLineMode()
{
// Show Help?
if (App.cmdline.ShowHelp || !App.cmdline.ParamsValid)
{
ShowCommandLineHelp();
return;
}
// Check now using WCF...
// Now we need to check communication with the other instance,
// if there isn't another process, then start/stop/restart/etc,.. won't work
_proxyObj = WCFHost.GetWatchDogClientInterface();
if (_proxyObj != null)
App.State_SpecialCircum_MainMonitorInstance_CommSuccees();
else
App.log.Info("No other Instances found, Command-line parameter functionallity limited to making configuration changes only");
// Now let's go thru all the CommandLine_Flags * WCF *
DealWithApplicationStateWCFCalls_CommandLineFlags();
// Now let's go thru all the CommandLine_Flags * Non-WCF *
DealWithDisplayConfigurationNonWCFCalls_CommandLineFlags();
// Now let's go thru all the CommandLine_Options * Non-WCF *
DealWithConfigurationChanges_CommandLineOptions();
// Done Here
_proxyObj = null;
}
/// <summary>
/// Deals with all the State Changes for the Main Application
/// * Via WCF * calls into main app and makes those changes
/// </summary>
private static void DealWithApplicationStateWCFCalls_CommandLineFlags()
{
// Now let's go thru all the CommandLine_Flags * WCF *
if (App.State_SpecialCircum_DidMainMonitorInstanceCommSucceed())
{
try
{
if (App.cmdline.GetFlagValue(App.CommandLine_Flag.START))
{
_proxyObj.StartMonitoring();
}
else if (App.cmdline.GetFlagValue(App.CommandLine_Flag.STOP))
{
_proxyObj.StopMonitoring();
}
else if (App.cmdline.GetFlagValue(App.CommandLine_Flag.STOP_ALL))
{
_proxyObj.StopAllMonitoring();
}
else if (App.cmdline.GetFlagValue(App.CommandLine_Flag.RESTART))
{
_proxyObj.RestartMonitoring();
}
else if (App.cmdline.GetFlagValue(App.CommandLine_Flag.RESTART_ALL))
{
_proxyObj.RestartAllMonitoring();
}
else if (App.cmdline.GetFlagValue(App.CommandLine_Flag.PAUSE))
{
_proxyObj.PauseMonitoring();
}
}
catch (Exception ex)
{
App.log.Error("Error Occured processing CommandLine_Flag via WCF", ex);
// Alert the user
WriteOut(ex.Message);
}
}
}
/// <summary>
/// Deals with all the Flags that deal with displaying configuration. does this locally * in this process *
/// View Configuration. Also handles LockWorkstation (Feature).
/// </summary>
private static void DealWithDisplayConfigurationNonWCFCalls_CommandLineFlags()
{
if (App.cmdline.GetFlagValue(App.CommandLine_Flag.LOCK))
{
// Hidden Feature, allows us to specify in windows start-up to lock the workstation
if (!User32.LockWorkStation())
{
App.log.Error("LockWorkstation() Failed");
WriteOut("LockWorkstation Failed");
}
}
else if (App.cmdline.GetFlagValue(App.CommandLine_Flag.SHOW_PROCESSES))
{
// write out each process
string[] processes = WCFHost.ShowProcesses();
StringBuilder sb = new StringBuilder();
if (processes != null && processes.Length != 0)
{
foreach (string p in processes)
{
sb.Append(p);
sb.Append("\n");
}
}
if (sb.Length > 0)
WriteOut(sb.ToString());
}
else if (App.cmdline.GetFlagValue(App.CommandLine_Flag.SHOW_SERVICES))
{
// write out each service
string[] services = WCFHost.ShowServices();
StringBuilder sb = new StringBuilder();
if (services != null && services.Length != 0)
{
foreach (string s in services)
{
sb.Append(s);
sb.Append("\n");
}
}
if (sb.Length > 0)
WriteOut(sb.ToString());
}
}
/// <summary>
/// Deals with making configuration changes. does this locally * in this process *
/// Add/Remove Configuration
/// </summary>
private static void DealWithConfigurationChanges_CommandLineOptions()
{
string ProcessAdd = App.cmdline.GetOptionValue<string>(App.CommandLine_Option.ADD_PROCESS, String.Empty);
if (String.IsNullOrEmpty(ProcessAdd))
{
string ProcessRemove = App.cmdline.GetOptionValue<string>(App.CommandLine_Option.REMOVE_PROCESS, String.Empty);
if (String.IsNullOrEmpty(ProcessRemove))
{
string ServiceAdd = App.cmdline.GetOptionValue<string>(App.CommandLine_Option.ADD_SERVICE, String.Empty);
if (String.IsNullOrEmpty(ServiceAdd))
{
string ServiceRemove = App.cmdline.GetOptionValue<string>(App.CommandLine_Option.REMOVE_SERVICE, String.Empty);
if (!String.IsNullOrEmpty(ServiceRemove))
{
bool bRemoved = WCFHost.RemoveService(ServiceRemove);
if (bRemoved)
{
WriteOut(String.Format("Service '{0}' removed successfully from Configuration", ServiceRemove));
App.log.Info(String.Format("Service '{0}' removed successfully from Configuration", ServiceRemove));
// * Reload on Main Instance, if possible *
if (App.State_SpecialCircum_DidMainMonitorInstanceCommSucceed()) _proxyObj.ReloadConfigurationNextInterval();
App.xmlfile.ForceRefreshOnNext_ReadData = true;
}
else
{
WriteOut(String.Format("Service '{0}' failed to be removed from Configuration", ServiceRemove));
App.log.Error(String.Format("Service '{0}' failed to be removed from Configuration", ServiceRemove));
}
}
}
else
{
bool bAdded = WCFHost.AddService(ServiceAdd);
if (bAdded)
{
WriteOut(String.Format("Service '{0}' added successfully to Configuration", ServiceAdd));
App.log.Info(String.Format("Service '{0}' added successfully to Configuration", ServiceAdd));
// * Reload on Main Instance, if possible *
if (App.State_SpecialCircum_DidMainMonitorInstanceCommSucceed()) _proxyObj.ReloadConfigurationNextInterval();
App.xmlfile.ForceRefreshOnNext_ReadData = true;
}
else
{
WriteOut(String.Format("Service '{0}' failed to be added to Configuration", ServiceAdd));
App.log.Error(String.Format("Service '{0}' failed to be added to Configuration", ServiceAdd));
}
}
}
else
{
string[] pNc = ProcessRemove.Split(';');
bool bRemoved = false;
if (pNc.Length == 1)
bRemoved = WCFHost.RemoveProcess(pNc[0], String.Empty);
else if (pNc.Length == 2)
bRemoved = WCFHost.RemoveProcess(pNc[0], pNc[1]);
if (bRemoved)
{
WriteOut(String.Format("Application '{0}' with CommandLinePrms '{1}' removed successfully from Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
App.log.Info(String.Format("Application '{0}' with CommandLinePrms '{1}' removed successfully from Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
// * Reload on Main Instance, if possible *
if (App.State_SpecialCircum_DidMainMonitorInstanceCommSucceed()) _proxyObj.ReloadConfigurationNextInterval();
App.xmlfile.ForceRefreshOnNext_ReadData = true;
}
else
{
WriteOut(String.Format("Application '{0}' with CommandLinePrms '{1}' failed to be removed from Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
App.log.Error(String.Format("Application '{0}' with CommandLinePrms '{1}' failed to be removed from Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
}
}
}
else
{
string[] pNc = ProcessAdd.Split(';');
bool bAdded = false;
if(pNc.Length == 1)
bAdded = WCFHost.AddProcess(pNc[0], String.Empty, String.Empty);
else if(pNc.Length == 2)
bAdded = WCFHost.AddProcess(pNc[0], pNc[1], String.Empty);
else if (pNc.Length == 3)
bAdded = WCFHost.AddProcess(pNc[0], pNc[1], pNc[2]);
if (bAdded)
{
WriteOut(String.Format("Application '{0}' with CommandLinePrms '{1}' added successfully to Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
App.log.Info(String.Format("Application '{0}' with CommandLinePrms '{1}' added successfully to Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
// * Reload on Main Instance, if possible *
if (App.State_SpecialCircum_DidMainMonitorInstanceCommSucceed()) _proxyObj.ReloadConfigurationNextInterval();
App.xmlfile.ForceRefreshOnNext_ReadData = true;
}
else
{
WriteOut(String.Format("Application '{0}' with CommandLinePrms '{1}' failed to be added to Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
App.log.Error(String.Format("Application '{0}' with CommandLinePrms '{1}' failed to be added to Configuration", pNc[0], (pNc.Length > 1) ? pNc[1] : ""));
}
}
}
}
}

View File

@@ -0,0 +1,482 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Diagnostics;
namespace PhoneHome
{
internal class CheckActiveTwo
{
internal string ProductName = String.Empty;
internal string ProductVersion = String.Empty;
internal string SerialNumber = String.Empty;
private string _LastGeneratedKey = String.Empty;
/// <summary>
///
/// </summary>
/// <param name="ProductName"></param>
/// <param name="ProductVersion"></param>
/// <param name="SerialNumber"></param>
internal CheckActiveTwo(string ProductName, string ProductVersion, string SerialNumber)
{
if (!String.IsNullOrEmpty(ProductName) && !String.IsNullOrEmpty(ProductVersion) && !String.IsNullOrEmpty(SerialNumber))
{
this.ProductName = ProductName;
this.ProductVersion = ProductVersion;
this.SerialNumber = SerialNumber;
}
else
{
throw new ArgumentException("ProductName, ProductVersion, and SerialNumber can't be blank");
}
}
/// <summary>
///
/// </summary>
/// <param name="strEncGeneratedString"></param>
internal CheckActiveTwo(string strEncGeneratedString)
{
if (IsValidEncKey(strEncGeneratedString))
{
_LastGeneratedKey = strEncGeneratedString;
}
else
{
throw new ArgumentException("Not a valid Enc String");
}
}
#region Static Internal Utilities
/// <summary>
/// Perform checksum on string
/// </summary>
/// <param name="strAboutToBeChecksummed"></param>
/// <returns>Checksum</returns>
internal static int PerformChecksum(string strAboutToBeChecksummed)
{
if (!String.IsNullOrEmpty(strAboutToBeChecksummed))
{
int nChecksum = 0;
for (int i = 0; i < strAboutToBeChecksummed.Length; ++i)
{
if (Char.IsDigit(strAboutToBeChecksummed[i]))
nChecksum = nChecksum + int.Parse(strAboutToBeChecksummed[i].ToString());
}
return nChecksum;
}
return 0;
}
/// <summary>
/// Dash a String
/// </summary>
/// <returns></returns>
internal static string MakeIntoDashSeperatedString(string strAboutToBeDashed, int DashEveryNthCharacter)
{
if (!String.IsNullOrEmpty(strAboutToBeDashed))
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strAboutToBeDashed.Length; i++)
{
if ((i != 0) && ((i % DashEveryNthCharacter) == 0))
sb.Append("-");
sb.Append(strAboutToBeDashed[i]);
}
return sb.ToString();
}
return String.Empty;
}
/// <summary>
/// Undash a String
/// </summary>
/// <returns></returns>
internal static string MakeIntoDashUnseperatedString(string strAboutToBeUndashed)
{
if (!String.IsNullOrEmpty(strAboutToBeUndashed))
return strAboutToBeUndashed.Replace("-", "");
return String.Empty;
}
#endregion
#region Internal Methods
/// <summary>
/// Generate a new Key to use - the key can be used to verify the serial number
/// </summary>
/// <returns>a new Key</returns>
internal string GenerateNewKey()
{
// GenerateString For User to send
string KeyValue = MakeKey();
string EncrKey = EncodeShuffle(KeyValue);
_LastGeneratedKey = MakeIntoDashSeperatedString(EncrKey, 4);
// For Debugging
string UnEncoded = DecodeShuffle(EncrKey);
if (KeyValue != UnEncoded)
{
// something is terribly wrong with the Encryption
Debug.Assert(false);
}
return _LastGeneratedKey;
}
/// <summary>
/// The function should really be called 'GeneratedPIN' but for reverse engineering
/// purpose, keeping them guessin * security by obscurity *
/// </summary>
/// <returns></returns>
internal string GeneraledPiM()
{
if (!String.IsNullOrEmpty(_LastGeneratedKey))
{
int KeyChecksum = PerformChecksum(MakeKey());
int ShuffledChecksum = PerformChecksum(_LastGeneratedKey);
string Result = KeyChecksum.ToString() + ShuffledChecksum.ToString();
if (Result.Length < 4)
{
StringBuilder sb = new StringBuilder(Result);
int nRemainder = 4 - Result.Length;
while (nRemainder > 0) { sb.Append("7"); nRemainder--; }
Result = sb.ToString();
}
Result = Result.Substring(0, 4);
int nHour = DateTime.Now.ToUniversalTime().Hour;
nHour = (nHour <= 6) ? (nHour + 3) : (nHour - 2);
string strHour = String.Format("{0}", (nHour < 10) ? ("8" + nHour.ToString()) : (nHour.ToString()));
string fourdigitPin = (strHour[1] + Result[1].ToString() + strHour[0] + Result[3].ToString());
int nChecksumPin = PerformChecksum(fourdigitPin);
string strChecksumLastDigit = nChecksumPin.ToString()[nChecksumPin.ToString().Length - 1].ToString();
return fourdigitPin + strChecksumLastDigit;
}
else
{
GenerateNewKey();
return GeneraledPiM();
}
}
/// <summary>
///
/// </summary>
/// <param name="dtStamp"></param>
/// <param name="ProductName"></param>
/// <param name="ProductVersion"></param>
/// <param name="SerialNumber"></param>
/// <returns>true, if successful, false otherwise</returns>
internal bool RetrieveValues(out DateTime dtStamp, out string ProductName, out string ProductVersion, out string SerialNumber)
{
dtStamp = DateTime.MinValue;
ProductName = String.Empty;
ProductVersion = String.Empty;
SerialNumber = String.Empty;
if (!String.IsNullOrEmpty(_LastGeneratedKey))
{
string Undashed = MakeIntoDashUnseperatedString(_LastGeneratedKey);
if (UnmakeKey(DecodeShuffle(Undashed), out dtStamp, out ProductName, out ProductVersion, out SerialNumber))
{
this.ProductName = ProductName;
this.ProductVersion = ProductVersion;
this.SerialNumber = SerialNumber;
return true;
}
}
return false;
}
#endregion
#region Private Key Generation Functions
private bool ContainsOnlyDigits(string strToCheckForDigits)
{
if (!String.IsNullOrEmpty(strToCheckForDigits))
{
for (int i = 0; i < strToCheckForDigits.Length; ++i)
{
if (!Char.IsDigit(strToCheckForDigits[i]))
return false;
}
return true;
}
return false;
}
/// <summary>
/// Check to see if the Generated string being passed in is a valid generated string
/// </summary>
/// <param name="strGeneratedString"></param>
/// <returns>true if valid, false otherwise</returns>
private bool IsValidEncKey(string strEncGeneratedString)
{
string Undashed = MakeIntoDashUnseperatedString(strEncGeneratedString);
DateTime dt;
string pName, pVersion, pSerial;
if (UnmakeKey(DecodeShuffle(Undashed), out dt, out pName, out pVersion, out pSerial))
return true;
return false;
}
/// <summary>
/// Make a Key to send across (all the info the auth needs)
/// </summary>
/// <returns>Key with needed Info</returns>
private string MakeKey()
{
//string dtShortTest = DateTime.Now.ToUniversalTime().ToShortDateString().Replace("/", "");
DateTime dtUniversal = DateTime.Now.ToUniversalTime();
string dtMonth = (dtUniversal.Month > 9) ? String.Format("{0}", dtUniversal.Month) : String.Format("0{0}", dtUniversal.Month);
string dtDay = (dtUniversal.Day > 9) ? String.Format("{0}", dtUniversal.Day) : String.Format("0{0}", dtUniversal.Day);
string dtYear = dtUniversal.Year.ToString();
string dtShort = String.Format("{0}{1}{2}", dtMonth, dtDay, dtYear);
string ProductId = ProductName.Substring(0, 1); // should always be 'M' or 'L' // so we use "LMXYZ"
string strKey = dtShort + "Z" + ProductId + "Y" + ProductVersion.Split('.')[0] + "X" + SerialNumber;
return strKey;
}
/// <summary>
/// Unmake a key * Don't even know why i wrote this, prob. won't end up using this *
/// </summary>
/// <returns>true if successful, false otheriwise</returns>
private bool UnmakeKey(string strAboutToBeUnkeyed, out DateTime dtStamp, out string ProductName, out string ProductVersion, out string SerialNumber)
{
dtStamp = DateTime.MinValue;
ProductName = "";
ProductVersion = "";
SerialNumber = "";
//string strKey = dtShort + "Z" + ProductId + "Y" + ProductVersion.Split('.')[0] + "X" + SerialNumber;
//0123456Z
try
{
if (!String.IsNullOrEmpty(strAboutToBeUnkeyed))
{
int nZIndex = strAboutToBeUnkeyed.IndexOf("Z");
int nYIndex = strAboutToBeUnkeyed.IndexOf("Y");
int nXIndex = strAboutToBeUnkeyed.IndexOf("X");
if (nZIndex == -1 || nYIndex == -1 || nXIndex == -1)
return false;
// dtShort
string strDT = strAboutToBeUnkeyed.Substring(0, nZIndex);
strDT = String.Format("{0}/{1}/{2}", strDT.Substring(0, 2), strDT.Substring(2, 2), strDT.Substring(4));
dtStamp = DateTime.Parse(strDT);
// ProductId
string ProductId = strAboutToBeUnkeyed.Substring(nZIndex + 1, 1);
if (ProductId == "L")
ProductName = "Lytec";
else if (ProductId == "M")
ProductName = "Medisoft";
else
return false;
// ProductVersion
string strProductVersion = strAboutToBeUnkeyed.Substring(nYIndex + 1, (nXIndex - nYIndex - 1));
if (!String.IsNullOrEmpty(strProductVersion) && ContainsOnlyDigits(strProductVersion))
ProductVersion = strProductVersion;
else
return false;
// Serial Number
SerialNumber = strAboutToBeUnkeyed.Substring(nXIndex + 1);
return !String.IsNullOrEmpty(SerialNumber) && ContainsOnlyDigits(SerialNumber);
}
}
catch (Exception) { /* ignore */ }
return false;
}
/// <summary>
/// * Simple Encoder *
/// </summary>
/// <param name="strAboutToBeEncodeShuffled"></param>
/// <returns></returns>
private string EncodeShuffle(string strAboutToBeEncodeShuffled)
{
const string Char_CodeLib = "ABCDEFGHIJKNOPQRSTUVW"; //20 - W is never used
const string Char_CodeLibExcluded = "LMXYZ"; //5
if (!String.IsNullOrEmpty(strAboutToBeEncodeShuffled))
{
List<char> ResultStr = new List<char>(strAboutToBeEncodeShuffled);
int nCount = ResultStr.Count;
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 3)
{
char c = ResultStr[i];
if (char.IsDigit(c))
{
int nChar = int.Parse(c.ToString());
ResultStr[i] = Char_CodeLib[nChar]; // 0..9
}
}
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 4)
{
char c = ResultStr[i];
if (char.IsDigit(c))
{
int nChar = int.Parse(c.ToString());
ResultStr[i] = Char_CodeLib[nChar + 10]; // 10..19
}
}
// Add Randomness to the end of the string
Random random = new Random();
int nRand = random.Next(1, 9);
// Perform a Random Shift * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + 2)
{
char c = ResultStr[i];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()))
{
int nIndexShifted = Char_CodeLib.IndexOf(c) + nRand;
int nIndexShiftedAdj = nIndexShifted % 21;
ResultStr[i] = Char_CodeLib[nIndexShiftedAdj]; // 0..20
}
}
// Perform another Random Swap * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + nRand)
{
char c = ResultStr[i];
int nOpposite = nCount - i - 1;
char o = ResultStr[nOpposite];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()) &&
char.IsLetter(o) && !Char_CodeLibExcluded.Contains(o.ToString()))
{
// swap
ResultStr[i] = o;
ResultStr[nOpposite] = c;
}
}
// Perform a Reversal
for (int i = 0; i < (nCount / 2); ++i)
{
char N1 = ResultStr[i];
char N2 = ResultStr[nCount - 1 - i];
// swap
ResultStr[i] = N2;
ResultStr[nCount - 1 - i] = N1;
}
// Add the Randomness to the string for proper decoding to occur
ResultStr.Add(Char.Parse(nRand.ToString()));
// And Return
return new String(ResultStr.ToArray());
}
return String.Empty;
}
/// <summary>
/// * Simple Decoder *
/// </summary>
/// <param name="strAboutToBeDecodeShuffled"></param>
/// <returns></returns>
private string DecodeShuffle(string strAboutToBeDecodeShuffled)
{
const string Char_CodeLib = "ABCDEFGHIJKNOPQRSTUVW"; //20
const string Char_CodeLibExcluded = "LMXYZ"; //5
try
{
if (!String.IsNullOrEmpty(strAboutToBeDecodeShuffled))
{
List<char> ResultStr = new List<char>(strAboutToBeDecodeShuffled);
// retrieve Randomness Factor
char cLast = ResultStr[ResultStr.Count - 1];
ResultStr.RemoveAt(ResultStr.Count - 1);
int nCount = ResultStr.Count;
int nRand = int.Parse(cLast.ToString());
// Perform a Reversal
for (int i = 0; i < (nCount / 2); ++i)
{
char N1 = ResultStr[i];
char N2 = ResultStr[nCount - 1 - i];
// swap
ResultStr[i] = N2;
ResultStr[nCount - 1 - i] = N1;
}
// Perform another Random Swap * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + nRand)
{
char c = ResultStr[i];
int nOpposite = nCount - i - 1;
char o = ResultStr[nOpposite];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()) &&
char.IsLetter(o) && !Char_CodeLibExcluded.Contains(o.ToString()))
{
// swap
ResultStr[i] = o;
ResultStr[nOpposite] = c;
}
}
// Perform a Random Shift * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + 2)
{
char c = ResultStr[i];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()))
{
int nIndexShifted = Char_CodeLib.IndexOf(c) - nRand;
int nIndexShiftedAdj = (nIndexShifted < 0)? 21 + nIndexShifted : nIndexShifted;
ResultStr[i] = Char_CodeLib[nIndexShiftedAdj]; // 0..20
}
}
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 4)
{
char c = ResultStr[i];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()))
{
int nIndex = Char_CodeLib.IndexOf(c);
if (nIndex >= 10)
{
nIndex = nIndex - 10;
if (nIndex >= 0 && nIndex <= 9)
ResultStr[i] = Char.Parse(nIndex.ToString()); // 11..19
}
}
}
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 3)
{
char c = ResultStr[i];
if (char.IsLetter(c))
{
int nIndex = Char_CodeLib.IndexOf(c);
if (nIndex >= 0 && nIndex <= 9)
ResultStr[i] = Char.Parse(nIndex.ToString()); // 1..9
}
}
// And Return
return new String(ResultStr.ToArray());
}
}
catch (Exception) { /* ignore */ }
return String.Empty;
}
#endregion
}
}

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Deployment.Application;
using Forms = System.Windows.Forms;
using System.Windows;
using System.Diagnostics;
using Watchdog.WatchdogLib.WinForms;
using System.IO;
namespace Watchdog
{
/// <summary>
/// Responsible for Dynamically Checking if there is an update available via ClickOnce
/// </summary>
public static class ClickOnceUpdater
{
/// <summary>
/// Construction
/// </summary>
static ClickOnceUpdater(){}
/// <summary>
/// Installs the Update and Restarts the Current Instance
/// </summary>
/// <returns>false if an error occured, if succesful * Will Restart the App *</returns>
internal static bool InstallUpdateAndRestartIfSuccessful()
{
try
{
UpdateCheckInfo info = null;
ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
if (ad != null)
{
// Log this to make sure we are sane
App.log.Info("Success in retrieving Application Deployment Manifest. This is a ClickOnce App");
try
{
info = ad.CheckForDetailedUpdate();
}
catch (DeploymentDownloadException dde)
{
MsgBox.ShowInfo("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message, "Unable to Download", System.Windows.Forms.MessageBoxButtons.OK);
App.log.Info("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
return false;
}
catch (InvalidDeploymentException ide)
{
MsgBox.ShowError("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message, "Invalid Deployment", System.Windows.Forms.MessageBoxButtons.OK);
App.log.Error("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
return false;
}
catch (InvalidOperationException ioe)
{
MsgBox.ShowError("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message, "Invalid Operation", System.Windows.Forms.MessageBoxButtons.OK);
App.log.Error("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
return false;
}
if (info.UpdateAvailable)
{
Boolean doUpdate = true;
if (!info.IsUpdateRequired)
{
Forms.DialogResult dr = MsgBox.ShowInfo("An update is available. Would you like to update\nthe application now?", "Update Available", Forms.MessageBoxButtons.OKCancel);
if (!(Forms.DialogResult.OK == dr))
doUpdate = false;
}
else
{
// Display a message that the app MUST reboot. Display the minimum required version.
MsgBox.ShowInfo("This application has detected a mandatory update from your\ncurrent " +
"version to version " + info.MinimumRequiredVersion.ToString() +
".\nThe application will now install\nthe update and restart.",
"Update Available", System.Windows.Forms.MessageBoxButtons.OK);
App.log.Info("This application has detected a mandatory update from your current " +
"version to version " + info.MinimumRequiredVersion.ToString() +
". The application will now install the update and restart.");
}
if (doUpdate)
{
try
{
ad.Update();
App.log.Info("The application has been upgraded,and will now restart.");
// Restart the Application * Imp! Auto-Delay the Start of the new Watchdog Instance *
if(File.Exists(App.APPLICATION_CLICKONCE_STARTMENU_LINK))
Process.Start(App.APPLICATION_CLICKONCE_STARTMENU_LINK, "15");
// Auto-Update * No Need to Close Applications *
App.State_SpecialCircum_DontCloseApplicationsOnExit();
Application.Current.Shutdown();
return true;
}
catch (DeploymentDownloadException dde)
{
MsgBox.ShowError("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde, "Update Error", System.Windows.Forms.MessageBoxButtons.OK);
App.log.Error("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
return false;
}
}
}
else
{
App.log.Info("Newer Version not available at this time.");
MsgBox.ShowInfo("A newer version of the application\nis not available at this time. \n\nPlease try again later.", "Newer Version not available", System.Windows.Forms.MessageBoxButtons.OK);
}
}
}
catch (Exception) { /* ignore */ }
return false;
}
}
}

View File

@@ -0,0 +1,276 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BridgeConnector.Lib.Process;
using BridgeConnector.Lib.Tools;
using System.IO;
using BridgeConnector.Lib.File;
using BridgeConnector.Lib.XML;
using System.Reflection;
namespace Component.All
{
/// <summary>
/// Common Functions and Helpers Useful for all Installing activities.
/// </summary>
public static class Common
{
#region Public Definitions
public const string INSTALLED_COMPONENT_CONFIG_XML_FILENAME = "InstalledComponentConfig.xml";
public const string EMBEDDED_COMPONENT_CONFIG_XML_FILENAME = "EmbeddedComponentConfig.xml";
/// <summary>
/// Allow Setting of Log by external Assembly
/// </summary>
public static Logging Log
{
get
{
return s_Log;
}
set
{
if (value != null)
s_Log = value;
}
}
#endregion
#region Private Statics
private static ISReadWrite s_isrw = null;
private static XSerializer s_serializer = null;
private static ComponentConfig s_EmbeddedComponentConfig = null;
private static ComponentConfig s_InstalledComponentConfig = null;
private static Logging s_Log = null;
#endregion
#region Construction
/// <summary>
/// Responsible for reading in embedded and installed configuration
/// </summary>
static Common()
{
s_isrw = new ISReadWrite(INSTALLED_COMPONENT_CONFIG_XML_FILENAME);
s_serializer = new XSerializer();
//# Read in from Resource (Embedded Components)
s_EmbeddedComponentConfig = s_serializer.ReadFromResource<ComponentConfig>(Assembly.GetExecutingAssembly().GetManifestResourceStream("Component.All." + EMBEDDED_COMPONENT_CONFIG_XML_FILENAME));
if (s_EmbeddedComponentConfig == null)
throw new Exception("Could not read in EmbeddedComponentConfig"); // should never happen
//# Read in from IS (Currently Installed Components)
s_InstalledComponentConfig = s_isrw.ReadFromIS<ComponentConfig>();
if (s_InstalledComponentConfig == null)
s_InstalledComponentConfig = new ComponentConfig();
}
#endregion
#region Public Statics
/// <summary>
/// Retrieve the EmbeddedComponentConfig
/// </summary>
/// <returns>the EmbeddedComponentConfig</returns>
public static ComponentConfig EmbeddedConfig
{
get
{
return s_EmbeddedComponentConfig;
}
}
/// <summary>
/// Retrieve the InstalledComponentConfig
/// </summary>
/// <returns>the InstalledComponentConfig or null, if not existent</returns>
public static ComponentConfig InstalledConfig
{
get
{
return s_InstalledComponentConfig;
}
}
/// <summary>
/// Allows Caller to write out any changes to InstalledConfig back to the File
/// </summary>
public static void WriteOutChangesToInstalledConfig()
{
s_isrw.WriteToIS<ComponentConfig>(s_InstalledComponentConfig);
}
/// <summary>
/// Checks to see if any Components are installed. If this returns false, then this is a Fresh Install
/// </summary>
/// <returns>true, if any components are installed, false otherwise</returns>
public static bool AreAnyComponentsInstalled()
{
bool bIsInstalled = (InstalledConfig != null) && (InstalledConfig.BinaryComponents.Components.Length > 0 || InstalledConfig.SetupComponents.Components.Length > 0);
return bIsInstalled;
}
/// <summary>
/// Retrieves the Index for the Component that matches the specified Unique Label
/// </summary>
/// <param name="UniqueLabel">label to search components for</param>
/// <param name="components">a component array</param>
/// <returns>a value >=0 or -1, if not found</returns>
public static int GetIndexForComponentUniqueLabel(string UniqueLabel, ComponentConfig.Component[] components)
{
if (String.IsNullOrEmpty(UniqueLabel) || components == null || components.Length <= 0)
return -1;
for (int i = 0; i < components.Length; ++i)
{
if (String.Compare(components[i].UniqueLabel, UniqueLabel, true) == 0)
return i;
}
return -1;
}
/// <summary>
/// Spawn a Setup Process (Setup.exe for example)
/// </summary>
public static void PSetupSpwan(string SetupFileNameNPath, string param_s)
{
PStarter.StartProcess(PStartInfo.CreateProcess(SetupFileNameNPath, param_s, "", true, System.Diagnostics.ProcessWindowStyle.Hidden, false), true, false);
}
/// <summary>
/// Spawn a MSI Setup Process (*.msi)
/// </summary>
public static void PSetupMSIEXEC(string param_s)
{
string msiexec = System.Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\msiexec.exe";
PStarter.StartProcess(PStartInfo.CreateProcess(msiexec, param_s, "", true, System.Diagnostics.ProcessWindowStyle.Hidden, false), true, false);
}
/// <summary>
/// Run a command on the commandline * Hidden *
/// </summary>
/// <param name="cmdline">cmd to run</param>
public static string RunCmdLine(string cmdline)
{
string result = PStarter.RunDosCommand(cmdline);
return result;
}
/// <summary>
/// Use this to get the complete path to a .net framework utility like gacutil.exe or
/// installutil.exe.. any .net framework utility. Will fall back to look in the %temp% folder,
/// if not found, giving the opportunity to deploy the util directly with the components
/// </summary>
/// <param name="UtilFileName">the utility in .net you are looking for like gacutil.exe</param>
/// <returns>the full filenameNpath or "", if no existing file found</returns>
public static string GetNetFrameworkUtilFileNameNPathFile(string UtilFileName)
{
string windir = System.Environment.GetEnvironmentVariable("windir", EnvironmentVariableTarget.Machine);
string NetFramework1_0 = windir + "\\Microsoft.Net\\Framework\\v1.0.3705";
string NetFramework1_1 = windir + "\\Microsoft.Net\\Framework\\v1.1.4322";
string NetFramework2_0 = windir + "\\Microsoft.Net\\Framework\\v2.0.50727";
string NetFramework3_0 = windir + "\\Microsoft.Net\\Framework\\v3.0";
string NetFramework3_5 = windir + "\\Microsoft.Net\\Framework\\v3.5";
string NetFramework4_0 = windir + "\\Microsoft.Net\\Framework\\v4.0.30319";
string TempPath = PathNaming.PathEndsWithNoSlash(Path.GetTempPath()); // We use this as a Fallback, in case file doesn't exist in the framework
string[] Frameworks = new string[] { NetFramework2_0, NetFramework4_0, NetFramework1_0, NetFramework1_1, NetFramework3_0, NetFramework3_5, TempPath };
string NetUtilFileNameNPath = "";
foreach (string framework in Frameworks)
{
if (File.Exists(framework + "\\" + UtilFileName))
{
NetUtilFileNameNPath = framework + "\\" + UtilFileName;
return NetUtilFileNameNPath;
}
};
return NetUtilFileNameNPath;
}
/// <summary>
/// Quick Helper to get the Program Files Path for the specific system
/// </summary>
/// <returns>Program Files path with a '/' at the end</returns>
public static string GetProgramFilesPathOnSystemWithEndSlash()
{
string ProgramFiles = System.Environment.GetEnvironmentVariable("ProgramFiles(x86)");
if (String.IsNullOrEmpty(ProgramFiles))
ProgramFiles = System.Environment.GetEnvironmentVariable("ProgramFiles");
return PathNaming.PathEndsWithSlash(ProgramFiles);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string SetOwnership()
{
// in order to do any of this, sadly, we must first install the windows resource kit
//subinacl /subdirectories *.* /setowner=domainname\user
return String.Empty;
}
/// <summary>
/// To grant the specified User or group Full Control permissions to the folder and its contents
/// </summary>
/// <param name="FolderNPath">full path to folder/directory</param>
/// <param name="UserOrGroup">domainname\administrator, any windows user or group</param>
/// <returns></returns>
public static bool GrantFullPermissionToFolderForUserOrGroup(string FolderNPath, string UserOrGroup)
{
if (Directory.Exists(FolderNPath))
{
string command = String.Format("cacls \"{0}\" /t /e /g {1}:f", FolderNPath, UserOrGroup);
if (command.Contains("Invalid arguments."))
return false;
else
return true;
}
return false;
}
/// <summary>
/// Stop a service
/// </summary>
/// <param name="ServiceName">name of service to stop</param>
/// <returns>true if successful, false otherwise</returns>
public static bool StopService(string ServiceName)
{
bool bSuccess = true;
if (ServiceW.DoesServiceExist(ServiceName))
bSuccess = ServiceW.StopService(ServiceName, true, 120);
return bSuccess;
}
/// <summary>
/// start a service
/// </summary>
/// <param name="ServiceName">name of a service to start</param>
/// <returns>true if successful, false otherwise</returns>
public static bool StartService(string ServiceName)
{
bool bSuccess = true;
if (ServiceW.DoesServiceExist(ServiceName))
bSuccess = ServiceW.StartService(ServiceName, 120);
return bSuccess;
}
/// <summary>
/// Does Service Exist
/// </summary>
/// <param name="ServiceName">Name of service to check</param>
/// <returns>true if successful, false otherwise</returns>
public static bool ServiceExists(string ServiceName)
{
return ServiceW.DoesServiceExist(ServiceName);
}
#endregion
}
}

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
namespace Component.All
{
/// <summary>
/// Install Configuration
/// </summary>
public enum InstallConfig
{
LytecMD,
MedisoftClinical,
}
/// <summary>
/// Common Functions and Helpers Useful for Lytec, Medisoft Installing activities
/// </summary>
public static class Common_MediLytec
{
/// <summary>
/// Common/Ofted used #Defs/Definitions associated with Lytec/Medisoft
/// </summary>
public static class MediLytecPoundDef
{
public const string BRIDGE_SERVICE_TITLE = "BridgeService";
public const string BRIDGE_SERVICE_ASSEMBLY = "BridgeService.exe";
public const string BRIDGE_SERVICE_NAME = "McKesson Bridge Service";
public const string MIRTH_SERVICE_NAME = "Mirth Connect Service";
public const string POSTGRE_SERVICE_NAME = "Mirth_Connect_PostgreSQL_Server";
public const string POSTGRE_SERVER_PORT = "5432";
}
/// <summary>
/// Retrieve the Configuration (Lytec/Medisoft) from the Registry
/// </summary>
/// <returns>Lytec/Medisoft</returns>
public static InstallConfig RetrieveInstallConfigFromRegistry()
{
bool bIsLytecInstalled = false;
try
{
RegistryKey reg = Registry.LocalMachine.OpenSubKey("Software\\Lytec", false);
bIsLytecInstalled = (reg != null);
if (!bIsLytecInstalled) // also check Wow64
{
reg = Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\Lytec", false);
bIsLytecInstalled = (reg != null);
}
}
catch (Exception) { /* ignore */ }
if (bIsLytecInstalled)
return InstallConfig.LytecMD;
else
return InstallConfig.MedisoftClinical;
}
}
}

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{94CB1BBA-5CF1-4155-827E-1527032D3921}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Component.All</RootNamespace>
<AssemblyName>Component.All</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\Output\Debug\Components\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\Output\Release\Components\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Common.cs" />
<Compile Include="Common_MediLytec.cs" />
<Compile Include="ComponentConfig.cs" />
<Compile Include="Component_Binary_Manager.cs" />
<Compile Include="Component_Setup_Manager.cs" />
<Compile Include="GenericInstaller.cs" />
<Compile Include="IInstallComponent.cs" />
<Compile Include="IManageComponents.cs" />
<Compile Include="ISetup.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BridgeConnectorLib\BridgeConnectorLib.csproj">
<Project>{9F60FBD1-0DA0-4558-971F-5BA9EE44493A}</Project>
<Name>BridgeConnectorLib</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="EmbeddedComponentConfig.xml" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,223 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Collections;
using BridgeConnector.Lib.Tools;
using System.IO;
namespace Component.All
{
/// <summary>
/// Serializable Xml Object used to store all Configuration data
/// </summary>
[XmlRoot("ComponentConfig", Namespace = "BridgeConnect", IsNullable = false)]
public class ComponentConfig
{
public ComponentW BinaryComponents = null;
public ComponentW SetupComponents = null;
/// <summary>
/// XML Embedded Component Configuration
/// </summary>
public ComponentConfig()
{
BinaryComponents = new ComponentW();
SetupComponents = new ComponentW();
}
/// <summary>
/// Wrapper class for multiple Components
/// </summary>
public class ComponentW
{
private ArrayList m_ArrayList;
public ComponentW()
{
m_ArrayList = new ArrayList();
}
[XmlElement("Component")]
public Component[] Components
{
get
{
Component[] components = new Component[m_ArrayList.Count];
m_ArrayList.CopyTo(components);
return components;
}
set
{
if (value == null) return;
Component[] components = (Component[])value;
m_ArrayList.Clear();
foreach (Component component in components)
AddUpdateComponent(component.UniqueLabel, component.Version, component.FileName);
}
}
#region Public Helpers
/// <summary>
/// Call this function to Add/Update a component
/// </summary>
/// <param name="UniqueLabel">unique label used to identify a component</param>
/// <param name="Version">Version of the component</param>
/// <param name="FileName">FileName of the component</param>
public void AddUpdateComponent(string UniqueLabel, string Version, string FileName)
{
int nIndex = GetIndexForComponent(UniqueLabel);
if (nIndex != -1)
{
Component component = ((Component)m_ArrayList[nIndex]);
component.UniqueLabel = UniqueLabel;
component.Version = Version;
component.FileName = FileName;
}
else
{
m_ArrayList.Add(new Component(UniqueLabel, Version, FileName));
}
}
/// <summary>
/// Call this function to remove a component from the list
/// </summary>
/// <param name="UniqueLabel">unique label used to identify a component</param>
public void RemoveComponent(string UniqueLabel)
{
int nIndex = GetIndexForComponent(UniqueLabel);
if (nIndex != -1)
m_ArrayList.RemoveAt(nIndex);
}
/// <summary>
/// Checks to see if a component already exists
/// </summary>
/// <param name="UniqueLabel">unique name identifying the component</param>
/// <returns>true for yes, no otherwise</returns>
public bool ComponentExists(string UniqueLabel)
{
return (GetIndexForComponent(UniqueLabel) != -1);
}
/// <summary>
/// Retrieves the component for the specified UniqueLabel
/// </summary>
/// <param name="UniqueLabel">unique name identifying the component</param>
/// <returns>the Component for the Label, or null if not found</returns>
public Component GetComponent(string UniqueLabel)
{
int nIndex = GetIndexForComponent(UniqueLabel);
if (nIndex != -1)
return (Component) m_ArrayList[nIndex];
else
return null;
}
#endregion
#region Internal & Private Helpers
/// <summary>
/// gets the index in the array list for the specified component
/// </summary>
/// <param name="UniqueLabel">unique name identifying the component</param>
/// <returns>index >= 0 or -1 if not found</returns>
private int GetIndexForComponent(string UniqueLabel)
{
for (int i = 0; i < m_ArrayList.Count; ++i)
{
Component component = (Component)m_ArrayList[i];
if (String.Compare(component.UniqueLabel, UniqueLabel, true) == 0)
return i;
}
return -1;
}
#endregion
}
/// <summary>
/// specify the Component
/// </summary>
public class Component : IComparable
{
public Component() { }
public Component(string UniqueLabel, string Version, string FileName) { this.UniqueLabel = UniqueLabel; this.Version = Version; this.FileName = FileName; }
[XmlText]
public string FileName = "";
/// <summary>
/// In case a component has multiple files, seperated by a ';', internally we should always call this
/// </summary>
public string[] FileNames
{
get
{
if (!String.IsNullOrEmpty(FileName))
{
if (FileName.Contains(';'))
return FileName.Split(';');
else
return new string[] { FileName };
}
return new string[] { };
}
}
[XmlAttribute("UniqueLabel")]
public string UniqueLabel = "";
[XmlAttribute("Version")]
public string Version = "";
/// <summary>
/// In case a component has multiple files, seperated by a ';', internally we should always call this
/// </summary>
public string[] TempFileNamesNPath
{
get
{
string[] files = FileNames;
List<string> tFiles = new List<string>();
if (files != null)
{
string strPath = PathNaming.PathEndsWithSlash(Path.GetTempPath());
foreach (string file in files)
tFiles.Add(strPath + file);
return tFiles.ToArray();
}
return new string[] { };
}
}
#region IComparable Members
/// <summary>
/// Compares the Components Unique Label and Version
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public int CompareTo(object obj)
{
if (obj is Component)
{
Component c = (Component)obj;
int nCompare = String.Compare(this.UniqueLabel, c.UniqueLabel, true);
if (nCompare == 0)
nCompare = String.Compare(this.Version, c.Version, true);
return nCompare;
}
else
{
throw new ArgumentException("object is not a Component");
}
}
#endregion
}
}
}

View File

@@ -0,0 +1,277 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BridgeConnector.Lib.File;
using System.Xml.Serialization;
using System.Collections;
using BridgeConnector.Lib.XML;
using System.Resources;
using System.Reflection;
using System.IO;
using BridgeConnector.Lib.Tools;
using BridgeConnector.Lib.Assembly;
namespace Component.All
{
/// <summary>
/// Responsible for extracting the Components that are embedded in this dll
/// into the temporary directory for the installer to consume
/// </summary>
public class Component_Binary_Manager : IDisposable, IManageComponents
{
#region Private Members
private bool _disposed = false;
private Dictionary<string, Assembly> _componentsLoaded = new Dictionary<string, Assembly>();
#endregion
#region Construction
/// <summary>
/// Constructor
/// </summary>
public Component_Binary_Manager()
{
}
/// <summary>
/// Finalizer
/// </summary>
~Component_Binary_Manager()
{
Dispose(true);
}
#endregion
#region IManageComponents Members
/// <summary>
/// Checks if there are Newer Components embedded then that were installed on the system
/// </summary>
/// <returns>true, if newer components were found, false otherwise</returns>
public bool AreNewerComponentsAvailable()
{
//# If nothing is installed, no need to continue
if (GetAllInstalledComponents() == null)
return true;
// if the lengths don't match, something must get installed
if (GetAllInstalledComponents().Length != GetAllEmbeddedComponents().Length)
return true;
// # Otherwise, let's determine 1 by 1
foreach (ComponentConfig.Component component in GetAllEmbeddedComponents())
{
int nIndex = Common.GetIndexForComponentUniqueLabel(component.UniqueLabel, GetAllInstalledComponents());
if (nIndex == -1)
return true;
else if(GetAllInstalledComponents()[nIndex].CompareTo(component) != 0)
return true;
}
return false;
}
/// <summary>
/// Returns the Component Definition containing the temporary file (extracted component)
/// for all Newer components found on the system
/// </summary>
/// <param name="setupEventObj">Setup Event Object is passed, for component manager to pass down to it's components</param>
/// <returns>a list of newer binary components, or empty list for none</returns>
public IInstallComponent[] GetNewerComponents(ref SetupEvents setupEventObj)
{
// # Extract all, or let's determine 1 by 1 and extract
bool bInstalledCompsFound = (GetAllInstalledComponents() != null);
foreach (ComponentConfig.Component component in GetAllEmbeddedComponents())
{
bool bExtract = true;
if (bInstalledCompsFound)
{
int nIndex = Common.GetIndexForComponentUniqueLabel(component.UniqueLabel, GetAllInstalledComponents());
if (nIndex != -1)
bExtract = (GetAllInstalledComponents()[nIndex].CompareTo(component) != 0);
}
// mark component for Installation * Extract to File System *
if (bExtract)
{
if (!ExtractComponentFromResourceToTempFileLocation(component))
Common.Log.Error(String.Format("Failed to Extract Component {0}", component.UniqueLabel));
}
}
List<IInstallComponent> ComponentsToInstall = new List<IInstallComponent>();
if (_componentsLoaded.Count > 0)
{
foreach(Assembly asm in _componentsLoaded.Values)
{
IInstallComponent installComp = null;
Type[] types = asm.GetTypes();
foreach (Type t in types)
{
if (t.GetInterface(typeof(IInstallComponent).Name) != null)
{
installComp = (IInstallComponent) asm.CreateInstance(t.FullName);
break;
}
}
// Check IInstallComponent was found
if (installComp == null)
{
Common.Log.Error(String.Format("Component {0} contains no IInstallComponent Definition.", AssemblyW.GetAssemblyName(asm)));
continue;
}
// Check if class also implements ISetup
if(installComp is ISetup)
((ISetup) installComp).ComponentLoaded(ref setupEventObj);
// Add to Install Components
ComponentsToInstall.Add(installComp);
}
}
return ComponentsToInstall.ToArray();
}
/// <summary>
/// Retrieves the list of all installed components, in order to uninstall
/// </summary>
/// <returns>a list of all installed components, null otherwise</returns>
public IInstallComponent[] GetAllInstalledComponents(string ComponentsSeperatedbySemiColonOrBlankForAll, ref SetupEvents setupEventObj)
{
// TO DO:
return null;
}
/// <summary>
/// Retrieves the list of all installed components
/// </summary>
/// <returns>a list of all installed components, null otherwise</returns>
public ComponentConfig.Component[] GetAllInstalledComponents()
{
if (Common.InstalledConfig != null && Common.InstalledConfig.BinaryComponents.Components.Length > 0)
return Common.InstalledConfig.BinaryComponents.Components;
return null;
}
/// <summary>
/// Retrieves the list of all installed componentsW
/// </summary>
/// <returns>a list of all installed componentsW, null otherwise</returns>
public ComponentConfig.ComponentW GetAllInstalledComponentsW()
{
return Common.InstalledConfig.BinaryComponents;
}
/// <summary>
/// Retrieves the list of all Embedded components
/// </summary>
/// <returns>a list of all embedded components, null otherwise</returns>
public ComponentConfig.Component[] GetAllEmbeddedComponents()
{
if (Common.EmbeddedConfig != null && Common.EmbeddedConfig.BinaryComponents.Components.Length > 0)
return Common.EmbeddedConfig.BinaryComponents.Components;
return null;
}
#endregion
#region Private Helpers
/// <summary>
/// Private Helper to physically extract the bits from the resource and write them to a temporary
/// file location
/// </summary>
/// <param name="component">Component, whose files are to be extracted</param>
/// <returns>true, if successful, false otherwise</returns>
private bool ExtractComponentFromResourceToTempFileLocation(ComponentConfig.Component component)
{
if (component != null)
{
// Extract the component to the Temp Directory,
// if it is not already there...
for (int i = 0; i < component.FileNames.Length; ++i)
{
// First try loading the assembly
string asmName = "Component.Binary." + component.UniqueLabel;
Assembly asm = Assembly.Load(asmName);
if (asm == null)
return false;
else
_componentsLoaded[component.UniqueLabel] = asm; // <- imp
string FileName = component.FileNames[i];
string TempFileNameNPath = component.TempFileNamesNPath[i];
if (!File.Exists(TempFileNameNPath))
{
using (BinaryReader br = new BinaryReader(asm.GetManifestResourceStream(asmName + "." + FileName)))
using (BinaryWriter bw = new BinaryWriter(new FileStream(TempFileNameNPath, FileMode.Create)))
{
byte[] buffer = new byte[64 * 1024];
int numread = br.Read(buffer, 0, buffer.Length);
while (numread > 0)
{
bw.Write(buffer, 0, numread);
numread = br.Read(buffer, 0, buffer.Length);
}
bw.Flush();
}
}
}
return true;
}
return false;
}
#endregion
#region IDisposable Members
/// <summary>
/// Dispose of all extracted files
/// </summary>
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer
GC.SuppressFinalize(this);
}
/// <summary>
/// Make sure to conserve disk space, to delete all files that were extracted
/// by this program
/// </summary>
/// <param name="disposing">if true, delete all files extracted by this dll</param>
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// When Disposing, Delete all Temporary Files on the System that may exist
foreach (ComponentConfig.Component component in GetAllEmbeddedComponents())
{
foreach (string tFileNameNPath in component.TempFileNamesNPath)
{
if (File.Exists(tFileNameNPath))
File.Delete(tFileNameNPath);
}
}
_componentsLoaded.Clear();
_componentsLoaded = null;
}
// Indicate that the instance has been disposed.
_disposed = true;
}
}
#endregion
}
}

View File

@@ -0,0 +1,213 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using BridgeConnector.Lib.Assembly;
namespace Component.All
{
/// <summary>
/// Responsible for working with setup components which don't require any special treatment
/// </summary>
public class Component_Setup_Manager : IDisposable, IManageComponents
{
#region Private Members
private bool _disposed = false;
private Dictionary<string, Assembly> _componentsLoaded = new Dictionary<string, Assembly>();
#endregion
#region Construction
/// <summary>
/// Constructor
/// </summary>
public Component_Setup_Manager()
{
}
/// <summary>
/// Finalizer
/// </summary>
~Component_Setup_Manager()
{
Dispose(true);
}
#endregion
#region IManageComponents Members
/// <summary>
/// Checks if there are Newer Components embedded then that were installed on the system
/// </summary>
/// <returns>true, if newer components were found, false otherwise</returns>
public bool AreNewerComponentsAvailable()
{
//# If nothing is installed, no need to continue
if (GetAllInstalledComponents() == null)
return true;
// if the lengths don't match, something must get installed
if (GetAllInstalledComponents().Length != GetAllEmbeddedComponents().Length)
return true;
// # Otherwise, let's determine 1 by 1
foreach (ComponentConfig.Component component in GetAllEmbeddedComponents())
{
int nIndex = Common.GetIndexForComponentUniqueLabel(component.UniqueLabel, GetAllInstalledComponents());
if (nIndex == -1)
return true;
else if (GetAllInstalledComponents()[nIndex].CompareTo(component) != 0)
return true;
}
return false;
}
/// <summary>
/// Returns the Component Definitions for all Newer components found on the system
/// </summary>
/// <returns>a list of newer setup components, or empty list for none</returns>
public IInstallComponent[] GetNewerComponents(ref SetupEvents setupEventObj)
{
// # Extract all, or let's determine 1 by 1 and extract
bool bInstalledCompsFound = (GetAllInstalledComponents() != null);
foreach (ComponentConfig.Component component in GetAllEmbeddedComponents())
{
bool bInstall = true;
if (bInstalledCompsFound)
{
int nIndex = Common.GetIndexForComponentUniqueLabel(component.UniqueLabel, GetAllInstalledComponents());
if (nIndex != -1)
bInstall = (GetAllInstalledComponents()[nIndex].CompareTo(component) != 0);
}
// mark component for Installation
if (bInstall)
{
string asmName = "Component.Setup." + component.UniqueLabel;
_componentsLoaded[component.UniqueLabel] = Assembly.Load(asmName);
}
}
List<IInstallComponent> ComponentsToInstall = new List<IInstallComponent>();
if (_componentsLoaded.Count > 0)
{
foreach (Assembly asm in _componentsLoaded.Values)
{
IInstallComponent installComp = null;
Type[] types = asm.GetTypes();
foreach (Type t in types)
{
if (t.GetInterface(typeof(IInstallComponent).Name) != null)
{
installComp = (IInstallComponent)asm.CreateInstance(t.FullName);
break;
}
}
// Check IInstallComponent was found
if (installComp == null)
{
Common.Log.Error(String.Format("Component {0} contains no IInstallComponent Definition.", AssemblyW.GetAssemblyName(asm)));
continue;
}
// Check if class also implements ISetup
if (installComp is ISetup)
((ISetup)installComp).ComponentLoaded(ref setupEventObj);
// Add to Install Components
ComponentsToInstall.Add(installComp);
}
}
return ComponentsToInstall.ToArray();
}
/// <summary>
/// Retrieves the list of all installed components, in order to uninstall
/// </summary>
/// <returns>a list of all installed components, null otherwise</returns>
public IInstallComponent[] GetAllInstalledComponents(string ComponentsSeperatedbySemiColonOrBlankForAll, ref SetupEvents setupEventObj)
{
// TO DO:
//string[] ComponentsUniqueLabels = null;
//if (!String.IsNullOrEmpty(ComponentsSeperatedbySemiColonOrBlankForAll))
// ComponentsUniqueLabels = ComponentsSeperatedbySemiColonOrBlankForAll.Split(';');
return null;
}
/// <summary>
/// Retrieves the list of all installed components
/// </summary>
/// <returns>a list of all installed components, null otherwise</returns>
public ComponentConfig.Component[] GetAllInstalledComponents()
{
if (Common.InstalledConfig != null && Common.InstalledConfig.SetupComponents.Components.Length > 0)
return Common.InstalledConfig.SetupComponents.Components;
return null;
}
/// <summary>
/// Retrieves the list of all installed componentsW
/// </summary>
/// <returns>a list of all installed componentsW, null otherwise</returns>
public ComponentConfig.ComponentW GetAllInstalledComponentsW()
{
return Common.InstalledConfig.SetupComponents;
}
/// <summary>
/// Retrieves the list of all Embedded components
/// </summary>
/// <returns>a list of all embedded components, null otherwise</returns>
public ComponentConfig.Component[] GetAllEmbeddedComponents()
{
if (Common.EmbeddedConfig != null && Common.EmbeddedConfig.SetupComponents.Components.Length > 0)
return Common.EmbeddedConfig.SetupComponents.Components;
return null;
}
#endregion
#region IDisposable Members
/// <summary>
/// Dispose of all extracted files
/// </summary>
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer
GC.SuppressFinalize(this);
}
/// <summary>
/// Make sure to conserve disk space, to delete all files that were extracted
/// by this program
/// </summary>
/// <param name="disposing">if true, delete all files extracted by this dll</param>
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_componentsLoaded.Clear();
_componentsLoaded = null;
}
// Indicate that the instance has been disposed.
_disposed = true;
}
}
#endregion
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<ComponentConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="BridgeConnect">
<BinaryComponents>
<Component UniqueLabel="Java" Version="1.6.0_27">jre-6u27-windows-i586-s.exe</Component>
<Component UniqueLabel="PostgreSql" Version="9.1.1-1">postgresql-9.1.1-1-windows.exe</Component>
<Component UniqueLabel="PostgreSql_Admin" Version="1.14.0">pgadmin3-1.14.0.msi</Component>
<Component UniqueLabel="PostgreSql_Devart" Version="5.50.228.0">Devart.Data.dll;Devart.Data.PostgreSql.dll;Devart.Data.PostgreSql.xml;gacutil.exe;gacutil.exe.config</Component>
<Component UniqueLabel="Mirth" Version="2.1.1.5490.b781">mirthconnect-2.1.1.5490.b781-windows.exe</Component>
</BinaryComponents>
<SetupComponents>
<Component UniqueLabel="BridgeService" Version="1.0.0.0">BridgeService.exe</Component>
</SetupComponents>
</ComponentConfig>

View File

@@ -0,0 +1,328 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BridgeConnector.Lib.Thread;
namespace Component.All
{
/// <summary>
/// Calls GenericInstaller in order to perform an install/uninstall
/// * Does so in a threaded fashion *
/// </summary>
public class GenericInstall
{
// Let the Caller know that a) the thread Completed b) it did so successfully
public static bool s_PerformInstallCompleted = false;
public static bool s_PerformInstallCompletedSuccessfully = false;
// Let the Caller know that a) the thread Completed b) it did so successfully
public static bool s_PerformUninstallCompleted = false;
public static bool s_PerformUninstallCompletedSuccessfully = false;
// Private ComponentMgmtObjects
private static GenericInstaller<Component_Binary_Manager> s_binaryInstaller = null;
private static GenericInstaller<Component_Setup_Manager> s_setupInstaller = null;
private static SetupEvents s_SetupEvents = new SetupEvents();
/// <summary>
/// Perform a Threaded Install
/// </summary>
public static void PerformInstall()
{
TStarter.ThreadMethod tMethod = delegate()
{
s_PerformInstallCompleted = false;
s_PerformInstallCompletedSuccessfully = false;
bool bBinaryInstallNeeded = false;
bool bSetupInstallNeeded = false;
// # Let's see if we need to update/install Binary Components
if(s_binaryInstaller == null)
s_binaryInstaller = new GenericInstaller<Component_Binary_Manager>();
bBinaryInstallNeeded = s_binaryInstaller.IsInstallNeeded(ref s_SetupEvents);
// # Let's see if we need to update/install Setup Components
if(s_setupInstaller == null)
s_setupInstaller = new GenericInstaller<Component_Setup_Manager>();
bSetupInstallNeeded = s_setupInstaller.IsInstallNeeded(ref s_SetupEvents);
// # Let's Install, Baby...
if (bBinaryInstallNeeded || bSetupInstallNeeded)
{
// # Trigger Start Install Event
s_SetupEvents.Raise_Before_Install_Event();
bool bBinarySuccess = true;
bool bSetupbSuccess = true;
// update/install Binary Components
if (bBinaryInstallNeeded)
bBinarySuccess = s_binaryInstaller.Install();
// update/install Setup Components
if (bSetupInstallNeeded)
bSetupbSuccess = s_setupInstaller.Install();
// # Trigger End Install Event
if (bBinaryInstallNeeded || bSetupInstallNeeded)
s_SetupEvents.Raise_After_Install_Event();
// # We fail if one of them fails
s_PerformInstallCompletedSuccessfully = bBinarySuccess && bSetupbSuccess;
}
// # Let External Callers know that this Thread Completed
s_PerformInstallCompleted = true;
};
TStarter.StartThread(tMethod, "PerformInstall", System.Threading.ApartmentState.MTA, false, System.Threading.ThreadPriority.Normal);
}
/// <summary>
/// Perform a Threaded Uninstall
/// </summary>
public static void PerformUninstall(string ComponentsSeperatedbySemiColonOrBlankForAll)
{
s_PerformUninstallCompleted = false;
s_PerformUninstallCompletedSuccessfully = false;
}
/// <summary>
/// Call this function to let every object know that either PerformInstall or PerformUninstall was called,
/// the Gui then may have made some other modifications, and we are now completed
/// </summary>
public static void SetupMainCompleted()
{
// Notify all components that Setup is now complete
s_SetupEvents.Raise_Ending_Setup_Event();
// # Imp! - We must call dispose on our Setup Objects
if (s_binaryInstaller != null)
{
s_binaryInstaller.Dispose();
s_binaryInstaller = null;
}
if (s_setupInstaller != null)
{
s_setupInstaller.Dispose();
s_setupInstaller = null;
}
}
}
/// <summary>
/// Generic Install Class used for IManageComponents
/// </summary>
/// <typeparam name="T">IManageComponents responsible for Installing</typeparam>
public class GenericInstaller<T> : IDisposable where T : IManageComponents, IDisposable, new()
{
#region Private Members
private T _ComponentMGR = default(T);
private IInstallComponent[] _ComponentsToPerformWorkOn = null;
private bool _disposed = false;
#endregion
#region Construction
/// <summary>
/// Construct the T Object
/// </summary>
public GenericInstaller()
{
_ComponentMGR = new T();
}
/// <summary>
/// Finalizer
/// </summary>
~GenericInstaller()
{
Dispose(true);
}
#endregion
#region Public Methods
/// <summary>
///
/// </summary>
/// <param name="setupEventObj"></param>
/// <returns></returns>
public bool IsInstallNeeded(ref SetupEvents setupEventObj)
{
if (_ComponentMGR.AreNewerComponentsAvailable())
{
Common.Log.Info(String.Format("Newer Components available for Type {0}.", _ComponentMGR.GetType().Name));
_ComponentsToPerformWorkOn = _ComponentMGR.GetNewerComponents(ref setupEventObj);
if (_ComponentsToPerformWorkOn != null && _ComponentsToPerformWorkOn.Length > 0)
{
Common.Log.Info(String.Format("Found {0} Newer Components.", _ComponentsToPerformWorkOn.Length));
return true;
}
}
Common.Log.Info(String.Format("No Newer Components available for Type {0}.", _ComponentMGR.GetType().Name));
return false;
}
/// <summary>
/// Perform Install on the IManageComponents specified when Constructing the GenericInstaller Object
/// </summary>
/// <returns>true if no error occurs, false otherwise</returns>
public bool Install()
{
bool bErrorsOccured = false;
List<ComponentConfig.Component> successfullyInstalledComponents = new List<ComponentConfig.Component>();
if (_ComponentsToPerformWorkOn != null && _ComponentsToPerformWorkOn.Length > 0)
{
// # Start Install
foreach (IInstallComponent installComp in _ComponentsToPerformWorkOn)
{
ComponentConfig.Component component = installComp.GetComponent();
if (installComp.BEFORE_INSTALLING_COMPONENT())
{
Common.Log.Info(String.Format("Installing Component {0} with Version {1}.", component.UniqueLabel, component.Version));
bool bInstallSuccess = installComp.INSTALL_COMPONENT();
bInstallSuccess = bInstallSuccess && installComp.AFTER_INSTALLING_COMPONENT();
if (bInstallSuccess)
{
Common.Log.Info(String.Format("Component {0} with version {1} was correctly installed.", component.UniqueLabel, component.Version));
successfullyInstalledComponents.Add(component);
}
else
{
bErrorsOccured = true;
string msg = String.Format("Component {0} with version {1} was not correctly installed.", component.UniqueLabel, component.Version);
Common.Log.Error(msg);
}
}
}
// # End Install
// Add any installed components to the Installed Configuration
foreach (ComponentConfig.Component component in successfullyInstalledComponents)
_ComponentMGR.GetAllInstalledComponentsW().AddUpdateComponent(component.UniqueLabel, component.Version, component.FileName);
// Write out the installed Configuration
Common.WriteOutChangesToInstalledConfig();
}
Common.Log.Info(String.Format("Exiting Install() for Type {0} with bErrorsOccured set to = {1}", _ComponentMGR.GetType().Name, bErrorsOccured));
return !bErrorsOccured;
}
/// <summary>
///
/// </summary>
/// <param name="setupEventObj"></param>
/// <returns></returns>
public bool IsUninstallNeeded(ref SetupEvents setupEventObj, string ComponentsSeperatedbySemiColonOrBlankForAll)
{
if(_ComponentMGR.GetAllInstalledComponents() != null)
{
Common.Log.Info(String.Format("Installed Components available for Type {0}.", _ComponentMGR.GetType().Name));
_ComponentsToPerformWorkOn = _ComponentMGR.GetAllInstalledComponents(ComponentsSeperatedbySemiColonOrBlankForAll, ref setupEventObj);
if (_ComponentsToPerformWorkOn != null && _ComponentsToPerformWorkOn.Length > 0)
{
Common.Log.Info(String.Format("Found {0} Components to Uninstall.", _ComponentsToPerformWorkOn.Length));
return true;
}
}
Common.Log.Info(String.Format("No Installed Components to Uninstall for Type {0}.", _ComponentMGR.GetType().Name));
return false;
}
/// <summary>
/// Perform Uninstall on the IManageComponents specified when Constructing the GenericInstaller Object
/// </summary>
/// <param name="ComponentsSeperatedbySemiColonOrBlankForAll">coma-seperated Unique Labels of components to uninstall, blank for all</param>
/// <returns>true if no error occurs, false otherwise</returns>
public bool Uninstall(ref SetupEvents setupEventObj, string ComponentsSeperatedbySemiColonOrBlankForAll)
{
bool bErrorsOccured = false;
List<ComponentConfig.Component> successfullyUninstalledComponents = new List<ComponentConfig.Component>();
if (_ComponentsToPerformWorkOn != null && _ComponentsToPerformWorkOn.Length > 0)
{
// # Start Uninstall
foreach (IInstallComponent uninstallComp in _ComponentsToPerformWorkOn)
{
if (!uninstallComp.SUPPORTS_UNINSTALL()) // Not all components support uninstall * although they should, we should allow for this contigency
continue;
ComponentConfig.Component component = uninstallComp.GetComponent();
if (uninstallComp.BEFORE_UNINSTALLING_COMPONENT())
{
Common.Log.Info(String.Format("About to Uninstall Component {0} with Version {1}.", component.UniqueLabel, component.Version));
bool bUninstallSuccess = uninstallComp.UNINSTALL_COMPONENT();
if (!bUninstallSuccess)
bErrorsOccured = true;
bUninstallSuccess = bUninstallSuccess && uninstallComp.AFTER_UNINSTALLING_COMPONENT();
if (bUninstallSuccess)
{
Common.Log.Info(String.Format("Component {0} with version {1} was uninstalled.", component.UniqueLabel, component.Version));
successfullyUninstalledComponents.Add(component);
}
else
{
string msg = String.Format("Component {0} with version {1} was not uninstalled.", component.UniqueLabel, component.Version);
Common.Log.Error(msg);
}
}
}
// # End Uninstall
// Remove any uninstalled components from the Installed Configuration
foreach (ComponentConfig.Component component in successfullyUninstalledComponents)
_ComponentMGR.GetAllInstalledComponentsW().RemoveComponent(component.UniqueLabel);
// Write out the installed Configuration
Common.WriteOutChangesToInstalledConfig();
}
Common.Log.Info(String.Format("Exiting Uninstall() for Type {0} with bErrorsOccured set to = {1}", _ComponentMGR.GetType().Name, bErrorsOccured));
return !bErrorsOccured;
}
#endregion
#region IDisposable Members
/// <summary>
/// Dispose of all extracted files
/// </summary>
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer
GC.SuppressFinalize(this);
}
/// <summary>
/// Make sure to call Dispose on the ComponentMGR for it to perform any cleanup
/// </summary>
/// <param name="disposing">if true, dispose ComponentMGR</param>
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_ComponentMGR.Dispose();
_ComponentMGR = default(T);
}
// Indicate that the instance has been disposed.
_disposed = true;
}
}
#endregion
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Component.All
{
/// <summary>
/// All Components that install themselves must support this interface
/// </summary>
public interface IInstallComponent
{
/// <summary>
/// Get the Corresponding Component for this IInstallComponent
/// </summary>
/// <returns>the component for this IInstallCompoent</returns>
ComponentConfig.Component GetComponent();
/// <summary>
/// Used to determine if the component is needed to install
/// </summary>
/// <returns>true to continue to Install, false otherwise</returns>
bool BEFORE_INSTALLING_COMPONENT();
/// <summary>
/// Used to install a component
/// </summary>
/// <returns>true, if install was successful, false otherwise</returns>
bool INSTALL_COMPONENT();
/// <summary>
/// Used to do any validation after install occured
/// </summary>
/// <returns>true, if validation was successful, false otherwise</returns>
bool AFTER_INSTALLING_COMPONENT();
/// <summary>
/// Used to determine if the component supports uninstalling
/// </summary>
/// <returns>true, if component supports uninstalling, false otherwise</returns>
bool SUPPORTS_UNINSTALL();
/// <summary>
/// Used to determine if the component is needed to uninstall
/// </summary>
/// <returns>true to continue to uninstall, false otherwise</returns>
bool BEFORE_UNINSTALLING_COMPONENT();
/// <summary>
/// Used to uninstall a component
/// </summary>
/// <returns>true, if uninstall was successful, false otherwise</returns>
bool UNINSTALL_COMPONENT();
/// <summary>
/// Used to do any validation after uninstall occured
/// </summary>
/// <returns>true, if validation was successful, false otherwise</returns>
bool AFTER_UNINSTALLING_COMPONENT();
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Component.All
{
/// <summary>
/// Used by the Binary and Setup Component Manager,
/// could possible be reused later for a new Component Manager
/// </summary>
public interface IManageComponents
{
/// <summary>
/// Quick Check to see if newer Components are available
/// </summary>
/// <returns>true, if newer components are available, false otherwise</returns>
bool AreNewerComponentsAvailable();
/// <summary>
/// Retrieves the list of newer components that need to be installed
/// </summary>
/// <param name="setupEventObj">Setup Event Object is passed, for component manager to pass down to it's components</param>
/// <returns>a list of newer components to install, null otherwise</returns>
IInstallComponent[] GetNewerComponents(ref SetupEvents setupEventObj);
/// <summary>
/// Retrieves the list of all installed components, in order to uninstall
/// </summary>
/// <param name="ComponentsSeperatedbySemiColonOrBlankForAll">Specify Component Filter</param>
/// <param name="setupEventObj">Setup Event Object is passed, for component manager to pass down to it's components</param>
/// <returns>a list of all installed components, null otherwise</returns>
IInstallComponent[] GetAllInstalledComponents(string ComponentsSeperatedbySemiColonOrBlankForAll, ref SetupEvents setupEventObj);
/// <summary>
/// Retrieves the list of all installed components
/// </summary>
/// <returns>a list of all installed components, null otherwise</returns>
ComponentConfig.Component[] GetAllInstalledComponents();
/// <summary>
/// Retrieves the list of all installed componentsW
/// </summary>
/// <returns>a list of all installed componentsW, null otherwise</returns>
ComponentConfig.ComponentW GetAllInstalledComponentsW();
/// <summary>
/// Retrieves the list of all Embedded components
/// </summary>
/// <returns>a list of all embedded components, null otherwise</returns>
ComponentConfig.Component[] GetAllEmbeddedComponents();
}
}

View File

@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Component.All
{
/// <summary>
/// Class is passed into ISetup ComponentLoaded() giving each component
/// a chance to subscribe to it
/// </summary>
public class SetupEvents
{
#region Events
/// <summary>
/// Delegate used to handle Setup Events
/// </summary>
public delegate void SetupEvent();
/// <summary>
/// Called after the entire Setup Application ends
/// </summary>
public event SetupEvent Ending_Setup;
/// <summary>
/// Called before the entire Install Process Begins
/// </summary>
public event SetupEvent Before_Install;
/// <summary>
/// Called after the entire Install Process ends
/// </summary>
public event SetupEvent After_Install;
/// <summary>
/// Called before the entire Uninstall Process Begins
/// </summary>
public event SetupEvent Before_Uninstall;
/// <summary>
/// Called after the entire Uninstall Process ends
/// </summary>
public event SetupEvent After_Uninstall;
#endregion
# region Event Raisers
/// <summary>
/// Raise the Ending Setup Event
/// </summary>
public void Raise_Ending_Setup_Event()
{
if (Ending_Setup != null)
Ending_Setup();
}
/// <summary>
/// Raise the Before Install Event
/// </summary>
public void Raise_Before_Install_Event()
{
if (Before_Install != null)
Before_Install();
}
/// <summary>
/// Raise the After Install Event
/// </summary>
public void Raise_After_Install_Event()
{
if (After_Install != null)
After_Install();
}
/// <summary>
/// Raise the Before Uninstall Event
/// </summary>
public void Raise_Before_Uninstall_Event()
{
if (Before_Uninstall != null)
Before_Uninstall();
}
/// <summary>
/// Raise the After Uninstall Event
/// </summary>
public void Raise_After_Uninstall_Event()
{
if (After_Uninstall != null)
After_Uninstall();
}
#endregion
}
/// <summary>
/// All Components that install themselves will implement this interface, if they are interested to
/// listen to / Handle Setup Events
/// </summary>
public interface ISetup
{
/// <summary>
/// Called when the Component is loaded. Components are only loaded
/// when an Install on them is iminent. The component has a chance to
/// listen to/handle events in the setup process.
/// </summary>
void ComponentLoaded(ref SetupEvents subscribeToDesiredEvents);
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Components")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("Components")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ae8a648a-90cf-48ce-9b71-6e6b4cc417aa")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,7 @@
<Window x:Class="Watchdog.HiddenMainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="Window_Loaded" Closed="Window_Closed">
<Grid>
</Grid>
</Window>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Component.All;
using BridgeConnector.Lib.File;
namespace Component.Binary.Mirth
{
public class InstallComponent : IInstallComponent , ISetup
{
public const string MIRTH_SERVICE_NAME = Common_MediLytec.MediLytecPoundDef.MIRTH_SERVICE_NAME;
private const string POSTGRE_SERVICE_NAME = Common_MediLytec.MediLytecPoundDef.POSTGRE_SERVICE_NAME;
#region IInstallComponent Members
public ComponentConfig.Component GetComponent()
{
return Common.EmbeddedConfig.BinaryComponents.GetComponent("Mirth");
}
public bool BEFORE_INSTALLING_COMPONENT()
{
bool bSuccess = Common.StopService(MIRTH_SERVICE_NAME);
if (!bSuccess)
{
Common.Log.Error(String.Format("Failed to stop {0}", MIRTH_SERVICE_NAME));
return false;
}
string result = Common.RunCmdLine("netsh firewall set portopening tcp 8080 MirthConnectAdministrator ENABLE ALL");
bSuccess = result.Contains("successfully") || result.Contains("Ok.") || result.Contains("The service has not been started");
if (bSuccess)
{
result = Common.RunCmdLine("netsh firewall set portopening tcp 8443 MirthConnectServer ENABLE ALL");
bSuccess = result.Contains("successfully") || result.Contains("Ok.") || result.Contains("The service has not been started");
}
if (bSuccess)
{
result = Common.RunCmdLine("netsh firewall set portopening tcp 1099 MirthConnectJMX ENABLE ALL");
bSuccess = result.Contains("successfully") || result.Contains("Ok.") || result.Contains("The service has not been started");
}
if (!bSuccess)
{
Common.Log.Error(String.Format("Errors occured opening up ports for '{0}'", MIRTH_SERVICE_NAME));
}
return bSuccess;
}
public bool INSTALL_COMPONENT()
{
Common.PSetupSpwan(GetComponent().TempFileNamesNPath[0], "-q -overwrite");
return true;
}
public bool AFTER_INSTALLING_COMPONENT()
{
if (!Common.ServiceExists(MIRTH_SERVICE_NAME))
{
Common.Log.Error(String.Format("Service '{0}' does not exist. Something went wrong with Setup", MIRTH_SERVICE_NAME));
return false;
}
// Make sure Service is stopped
Common.StopService(MIRTH_SERVICE_NAME);
// # Configure Mirth to work with PostgreSQL, if possible
if (Common.ServiceExists(POSTGRE_SERVICE_NAME))
{
//SetupMirthToUsePostgreSQL("mirthdb", "postgres", "Clinical$1");
}
return true;
}
public bool SUPPORTS_UNINSTALL()
{
return false;
}
public bool BEFORE_UNINSTALLING_COMPONENT()
{
return false;
}
public bool UNINSTALL_COMPONENT()
{
return false;
}
public bool AFTER_UNINSTALLING_COMPONENT()
{
return false;
}
#endregion
#region ISetup Members
public void ComponentLoaded(ref SetupEvents subscribeToDesiredEvents)
{
subscribeToDesiredEvents.Before_Install += new SetupEvents.SetupEvent(subscribeToDesiredEvents_Before_Install);
subscribeToDesiredEvents.After_Install += new SetupEvents.SetupEvent(subscribeToDesiredEvents_After_Install);
subscribeToDesiredEvents.Ending_Setup += new SetupEvents.SetupEvent(subscribeToDesiredEvents_Ending_Setup);
}
void subscribeToDesiredEvents_Ending_Setup()
{
// Make Sure at the end that both Mirth and Postgresql are started
Common.StartService(POSTGRE_SERVICE_NAME);
Common.StartService(MIRTH_SERVICE_NAME);
}
void subscribeToDesiredEvents_Before_Install()
{
}
void subscribeToDesiredEvents_After_Install()
{
}
#endregion
#region Private Helpers
/// <summary>
/// Function is responsible fore writing Postgresql Information to the Mirth Configuration
/// * The Mirth Service needs to be stopped/started for this configuration to take affect,
/// ideally this should only be called with the mirth service stopped *
/// </summary>
private void SetupMirthToUsePostgreSQL(string dbname, string user, string password)
{
// Open Mirth Configuration
LineReplacer replacer = new LineReplacer((Common.GetProgramFilesPathOnSystemWithEndSlash() + "Mirth Connect\\conf\\mirth.properties"), Encoding.ASCII);
LineReplace_Rule DBurl = new LineReplace_Rule();
DBurl.StartsWith = "database.url =";
DBurl.ReplaceLineWith = String.Format("database.url = jdbc:postgresql://localhost:5432/{0}", dbname);
DBurl.Comparer = LineReplace_ComparerModifier.None;
replacer.AddUpdateRule("DBurl", DBurl);
LineReplace_Rule DBuser = new LineReplace_Rule();
DBuser.StartsWith = "database.username =";
DBuser.ReplaceLineWith = String.Format("database.username = {0}", user);
DBuser.Comparer = LineReplace_ComparerModifier.None;
replacer.AddUpdateRule("DBuser", DBuser);
LineReplace_Rule DBpass = new LineReplace_Rule();
DBpass.StartsWith = "database.password =";
DBpass.ReplaceLineWith = String.Format("database.password = {0}", password);
DBpass.Comparer = LineReplace_ComparerModifier.None;
replacer.AddUpdateRule("DBpass", DBpass);
// Replace Lines in Mirth Configuration
replacer.ReplaceLines();
}
#endregion
}
}

View File

@@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Component.All;
using Microsoft.Win32;
namespace Component.Binary.Java
{
public class InstallComponent : IInstallComponent , ISetup
{
#region IInstallComponent Members
/// <summary>
/// Get the Component bound to this IInstallComponent
/// </summary>
/// <returns></returns>
public ComponentConfig.Component GetComponent()
{
return Common.EmbeddedConfig.BinaryComponents.GetComponent("Java");
}
/// <summary>
/// We only want to install Java if an earlier version is installed
/// </summary>
/// <returns>true, if an earlier version or none is installed, false otherwise</returns>
public bool BEFORE_INSTALLING_COMPONENT()
{
// If we get here, just in case always just install the java version
// to make sure everything works as expected
//string Version = GetLatestJavaVersionFromTheRegistry();
//if (!String.IsNullOrEmpty(Version))
//{
// int nCompare = String.Compare(Version, GetComponent().Version);
// if (nCompare < 0)
// return true;
// else
// return false;
//}
return true;
}
/// <summary>
/// Installs Java on the system
/// </summary>
/// <returns>Returns true if the Component installs, false otherwise</returns>
public bool INSTALL_COMPONENT()
{
Common.PSetupSpwan(GetComponent().TempFileNamesNPath[0], "/s /v \"/qn ADDLOCAL=ALL IEXPLORER=1 REBOOT=Supress\"");
return true;
}
/// <summary>
/// Make sure that the version in the registry matches the component
/// </summary>
/// <returns>true, if the version in the registry matches what we installed, false otherwise</returns>
public bool AFTER_INSTALLING_COMPONENT()
{
string Version = GetLatestJavaVersionFromTheRegistry();
if (!String.IsNullOrEmpty(Version))
{
int nCompare = String.Compare(GetComponent().Version, Version);
if (nCompare != 0)
return false;
else
return true;
}
return false;
}
/// <summary>
/// Check to see, if this component supports uninstalling
/// </summary>
/// <returns>true, if uninstall is supported, false otherwise</returns>
public bool SUPPORTS_UNINSTALL()
{
return true;
}
/// <summary>
/// Check if we can uninstall the java version
/// </summary>
/// <returns>true, if version is installed, false otherwise</returns>
public bool BEFORE_UNINSTALLING_COMPONENT()
{
string[] Versions = GetAllJavaVersionFromTheRegistry();
if (Versions != null && Versions.Length > 0)
{
if (Versions.Contains(GetComponent().Version))
return true;
}
return false;
}
/// <summary>
/// Uninstalls Java on the system
/// </summary>
/// <returns>Returns true if the Component installs, false otherwise</returns>
public bool UNINSTALL_COMPONENT()
{
Common.PSetupSpwan(GetComponent().TempFileNamesNPath[0], "/s /v \"/qn REBOOT=Supress\" /x");
return true;
}
/// <summary>
/// Check to make sure that the version we uninstalled doesn't exist anymore
/// </summary>
/// <returns>true if version was removed, false otherwise</returns>
public bool AFTER_UNINSTALLING_COMPONENT()
{
string[] Versions = GetAllJavaVersionFromTheRegistry();
if (Versions != null && Versions.Length > 0)
{
if (Versions.Contains(GetComponent().Version))
return false;
}
return true;
}
#endregion
#region ISetup Members
public void ComponentLoaded(ref SetupEvents subscribeToDesiredEvents)
{
subscribeToDesiredEvents.Before_Install += new SetupEvents.SetupEvent(subscribeToDesiredEvents_Before_Install);
subscribeToDesiredEvents.After_Install += new SetupEvents.SetupEvent(subscribeToDesiredEvents_After_Install);
}
void subscribeToDesiredEvents_Before_Install()
{
}
void subscribeToDesiredEvents_After_Install()
{
}
#endregion
#region Private Helpers
/// <summary>
/// Use this function to check the java version in the registry
/// </summary>
/// <returns>The Java Version found in the registry or String.Empty, if not found</returns>
string GetLatestJavaVersionFromTheRegistry()
{
string[] Versions = GetAllJavaVersionFromTheRegistry();
if (Versions != null && Versions.Length > 0)
{
string strVersion = Versions[Versions.Length - 1];
if (!String.IsNullOrEmpty(strVersion))
return strVersion;
}
return String.Empty;
}
/// <summary>
/// Use this function to check all the java versions in the registry
/// </summary>
/// <returns>The Java Versions found in the registry or null, if none found</returns>
string[] GetAllJavaVersionFromTheRegistry()
{
bool bIsJavaInstalled = false;
try
{
RegistryKey reg = Registry.LocalMachine.OpenSubKey("Software\\JavaSoft\\Java Plug-in", false);
bIsJavaInstalled = (reg != null);
if(reg == null)
reg = Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\JavaSoft\\Java Plug-in", false);
bIsJavaInstalled = (reg != null);
if (bIsJavaInstalled)
{
string[] SubKeys = reg.GetSubKeyNames();
if (SubKeys != null && SubKeys.Length > 0)
return SubKeys;
}
}
catch (Exception) { /* ignore */ }
return null;
}
#endregion
}
}

View File

@@ -0,0 +1,254 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Component.All;
using Microsoft.Win32;
using BridgeConnector.Lib.Assembly;
using System.IO;
using BridgeConnector.Lib.XML;
using BridgeConnector;
namespace Component.Setup.BridgeService
{
public class InstallComponent : IInstallComponent , ISetup
{
#region Private Helpers
public const string BRIDGE_SERVICE_TITLE = Common_MediLytec.MediLytecPoundDef.BRIDGE_SERVICE_TITLE;
public const string BRIDGE_SERVICE_ASSEMBLY = Common_MediLytec.MediLytecPoundDef.BRIDGE_SERVICE_ASSEMBLY;
public const string BRIDGE_SERVICE_NAME = Common_MediLytec.MediLytecPoundDef.BRIDGE_SERVICE_NAME;
/// <summary>
/// Write Service Configuration to the ImagePath for the Service
/// </summary>
/// <returns></returns>
public static bool WriteServiceConfigurationToServiceInRegistry(InstallConfig config)
{
try
{
using (RegistryKey service = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\services\\" + BRIDGE_SERVICE_TITLE, true))
{
// # Determine Image Path Parameter
string ImagePathParameter = "";
switch (config)
{
case InstallConfig.LytecMD:
ImagePathParameter = " /Lytec";
break;
case InstallConfig.MedisoftClinical:
ImagePathParameter = " /Medisoft";
break;
}
// # Set Image Path Parameter
string serviceAssembly = "\"" + AssemblyW.SpecializedAssemblyInfo.GetAssemblyPath(AssemblyW.AssemblyST.Executing) + "\\" + BRIDGE_SERVICE_ASSEMBLY + "\"";
service.SetValue("ImagePath", serviceAssembly + ImagePathParameter);
return true;
}
}
catch (Exception) { /* ignore */ }
return false;
}
#endregion
#region IInstallComponent Members
public ComponentConfig.Component GetComponent()
{
return Common.EmbeddedConfig.SetupComponents.GetComponent("BridgeService");
}
public bool BEFORE_INSTALLING_COMPONENT()
{
// Stop Service BRIDGE_SERVICE_NAME
if (!Common.StopService(BRIDGE_SERVICE_NAME))
{
Common.Log.Error(String.Format("Couldn't stop the {0} Service.", BRIDGE_SERVICE_NAME));
return false;
}
// Read the Service Configuration from the Registry
InstallConfig config = Common_MediLytec.RetrieveInstallConfigFromRegistry();
if (config == InstallConfig.LytecMD)
{
bool bSuccess = false;
string result = Common.RunCmdLine("netsh firewall set portopening tcp 5000 BridgeService_LytecBridgeIn ENABLE ALL");
bSuccess = result.Contains("successfully") || result.Contains("Ok.") || result.Contains("The service has not been started");
if (bSuccess)
{
result = Common.RunCmdLine("netsh firewall set portopening tcp 5001 BridgeService_LytecMirthOut ENABLE ALL");
bSuccess = result.Contains("successfully") || result.Contains("Ok.") || result.Contains("The service has not been started");
}
if (bSuccess)
{
return true;
}
else
{
Common.Log.Error(String.Format("Opening up ports for Lytec '{0}' failed", BRIDGE_SERVICE_NAME));
return false;
}
}
else if (config == InstallConfig.MedisoftClinical)
{
bool bSuccess = false;
string result = Common.RunCmdLine("netsh firewall set portopening tcp 7000 BridgeService_MedisoftBridgeIn ENABLE ALL");
bSuccess = result.Contains("successfully") || result.Contains("Ok.") || result.Contains("The service has not been started");
if (bSuccess)
{
result = Common.RunCmdLine("netsh firewall set portopening tcp 7001 BridgeService_MedisoftMirthOut ENABLE ALL");
bSuccess = result.Contains("successfully") || result.Contains("Ok.") || result.Contains("The service has not been started");
}
if (bSuccess)
{
return true;
}
else
{
Common.Log.Error(String.Format("Opening up ports for Medisoft '{0}' failed", BRIDGE_SERVICE_NAME));
return false;
}
}
return true;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public bool INSTALL_COMPONENT()
{
// Uninstall Bridge Service, if it exists, and re-install
if (Common.ServiceExists(BRIDGE_SERVICE_NAME))
UNINSTALL_COMPONENT();
string installUtil = Common.GetNetFrameworkUtilFileNameNPathFile("installutil.exe");
string serviceAssembly = AssemblyW.SpecializedAssemblyInfo.GetAssemblyPath(AssemblyW.AssemblyST.Entry) + "\\" + BRIDGE_SERVICE_ASSEMBLY;
if (!String.IsNullOrEmpty(installUtil))
{
Common.StopService(BRIDGE_SERVICE_NAME);
string result = Common.RunCmdLine(installUtil + " \"" + serviceAssembly + "\"");
bool bSuccess = !result.Contains("failed");
if (bSuccess)
{
// Write the Service Configuration to the Registry
InstallConfig config = Common_MediLytec.RetrieveInstallConfigFromRegistry();
bSuccess = WriteServiceConfigurationToServiceInRegistry(config);
}
if (!bSuccess)
{
Common.Log.Error(String.Format("Errors Occured installing {0}.", BRIDGE_SERVICE_NAME));
}
return bSuccess;
}
return false;
}
public bool AFTER_INSTALLING_COMPONENT()
{
// Make sure service exists
if (!Common.ServiceExists(BRIDGE_SERVICE_NAME))
{
Common.Log.Error(String.Format("Service {0} does Not Exist. Install Failed", BRIDGE_SERVICE_NAME));
return false;
}
// Make sure Service is stopped
Common.StopService(BRIDGE_SERVICE_NAME);
return true;
}
public bool SUPPORTS_UNINSTALL()
{
return false;
}
public bool BEFORE_UNINSTALLING_COMPONENT()
{
// Stop Service BRIDGE_SERVICE_NAME
if (!Common.StopService(BRIDGE_SERVICE_NAME))
{
Common.Log.Error(String.Format("Couldn't stop the {0} Service.", BRIDGE_SERVICE_NAME));
return false;
}
return true;
}
public bool UNINSTALL_COMPONENT()
{
if (Common.ServiceExists(BRIDGE_SERVICE_NAME))
{
Common.StopService(BRIDGE_SERVICE_NAME);
string installUtil = Common.GetNetFrameworkUtilFileNameNPathFile("installutil.exe");
string serviceAssembly = AssemblyW.SpecializedAssemblyInfo.GetAssemblyPath(AssemblyW.AssemblyST.Entry) + "\\" + BRIDGE_SERVICE_ASSEMBLY;
if (!String.IsNullOrEmpty(installUtil))
{
string result = Common.RunCmdLine(installUtil + " /u \"" + serviceAssembly + "\"");
bool bSuccess = !result.Contains("failed");
if(!bSuccess)
Common.Log.Error(String.Format("Errors Occured uninstalling {0}.", BRIDGE_SERVICE_NAME));
return bSuccess;
}
}
return false;
}
public bool AFTER_UNINSTALLING_COMPONENT()
{
if (Common.ServiceExists(BRIDGE_SERVICE_NAME))
{
Common.Log.Error(String.Format("Service {0} Still Exists. Uninstall Failed", BRIDGE_SERVICE_NAME));
return false;
}
return true;
}
#endregion
#region ISetup Members
public void ComponentLoaded(ref SetupEvents subscribeToDesiredEvents)
{
subscribeToDesiredEvents.Before_Install += new SetupEvents.SetupEvent(subscribeToDesiredEvents_Before_Install);
subscribeToDesiredEvents.After_Install += new SetupEvents.SetupEvent(subscribeToDesiredEvents_After_Install);
subscribeToDesiredEvents.Ending_Setup += new SetupEvents.SetupEvent(subscribeToDesiredEvents_Ending_Setup);
}
void subscribeToDesiredEvents_Ending_Setup()
{
if (Common.ServiceExists(BRIDGE_SERVICE_NAME))
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\McKesson\\Bridge\\BridgeConfig.xml";
if (File.Exists(path))
{
XSerializer serialize = new XSerializer();
XMLConfig config = serialize.ReadFromFile<XMLConfig>(path);
if (config != null)
{
// Read the Service Configuration from the Registry
InstallConfig sconfig = Common_MediLytec.RetrieveInstallConfigFromRegistry();
if (sconfig == InstallConfig.LytecMD && !String.IsNullOrEmpty(config.DefaultMapping.Lytec))
Common.StartService(BRIDGE_SERVICE_NAME);
else if(sconfig == InstallConfig.MedisoftClinical && !String.IsNullOrEmpty(config.DefaultMapping.Medisoft))
Common.StartService(BRIDGE_SERVICE_NAME);
}
}
}
}
void subscribeToDesiredEvents_Before_Install()
{
}
void subscribeToDesiredEvents_After_Install()
{
}
#endregion
}
}

240
@integrate/Logging.cs Normal file
View File

@@ -0,0 +1,240 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
// Log4Net Declarations
using log4net.Appender;
using log4net.Core;
using log4net.Layout;
using log4net.Config;
using log4net;
using Diag = System.Diagnostics;
using BridgeConnector.Lib.Other;
namespace BridgeConnector.Lib.File
{
/// <summary>
/// Logging Detail
/// </summary>
public enum Logging_Detail
{
NONE,
ERROR,
INFO,
DEBUG
}
/// <summary>
/// Used to Configure a Logger Instance in the Logging Class via AddGlobalLoggerConfiguration()
/// </summary>
public struct Logging_Configuration
{
public string LogFileNameNPath;
public Logging_Detail Detail;
public bool UseExclusiveFileLock;
public int maxFileSizeInMB;
public int numOfBackupLogFiles;
public string PatternLayout;
}
/// <summary>
/// Is a Wrapper Object around Log4Net's Rolling File Appender.
/// Use it by calling AddGlobalLoggerConfiguration() with a valid Logging Configuration.
/// You can configure multipe Logger Instances distinguished by Name.
/// subsequent calls can call GetLogger() with the named Logger instance to receive a valid logger object
/// </summary>
public class Logging
{
#region Private Static Members
private static Dictionary<string, Logging_Configuration> _loggerConfigurationMap = new Dictionary<string, Logging_Configuration>();
private static Dictionary<string, ILog> _loggerObjects = new Dictionary<string, ILog>();
private static bool s_IsVSHosted = false;
#endregion
#region Private Construction
private Logging() { s_IsVSHosted = Diag.Process.GetCurrentProcess().ProcessName.Contains("vshost"); }
#endregion
#region Internal Members
internal ILog _Log4NetLog = null; // Initialized by GetLogger()
#endregion
#region Public Log Methods
public void Info(object message) { if (_Log4NetLog != null) _Log4NetLog.Info(MessageHeader() + message); }
public void Info(object message, int nPlusMinus) { if (_Log4NetLog != null) _Log4NetLog.Info(MessageHeader(nPlusMinus) + message); }
public void Info(object message, Exception exception) { if (_Log4NetLog != null) _Log4NetLog.Info(MessageHeader() + message, exception); }
public void Debug(object message) { if (_Log4NetLog != null) _Log4NetLog.Debug(MessageHeader() + message); }
public void Debug(object message, int nPlusMinus) { if (_Log4NetLog != null) _Log4NetLog.Debug(MessageHeader(nPlusMinus) + message); }
public void Debug(object message, Exception exception) { if (_Log4NetLog != null) _Log4NetLog.Debug(MessageHeader() + message, exception); }
public void Error(object message) { if (_Log4NetLog != null) _Log4NetLog.Error(MessageHeader() + message); }
public void Error(object message, int nPlusMinus) { if (_Log4NetLog != null) _Log4NetLog.Error(MessageHeader(nPlusMinus) + message); }
public void Error(object message, Exception exception) { if (_Log4NetLog != null) _Log4NetLog.Error(MessageHeader() + message, exception); }
public void Fatal(object message) { if (_Log4NetLog != null) _Log4NetLog.Fatal(MessageHeader() + message); }
public void Fatal(object message, int nPlusMinus) { if (_Log4NetLog != null) _Log4NetLog.Fatal(MessageHeader(nPlusMinus) + message); }
public void Fatal(object message, Exception exception) { if (_Log4NetLog != null) _Log4NetLog.Fatal(MessageHeader() + message, exception); }
/// <returns>
/// Message Header to be shown on every log message
/// </returns>
private string MessageHeader()
{
if (s_IsVSHosted)
return MessageHeader(0);
else
return StackWalker.GetMethodNameFromStack(-2) + "()- ";
}
/// <returns>
/// Message Header to be shown on every log message
/// </returns>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
private string MessageHeader(int nPlusMinus)
{
// When Running this from via VS it behaves differently then when
// running it outside of it, when running it regularly, each foreach loop
// is it's own stackframe! ~weird but true. Only use the nPlusMinus when not running
// inside VS
if(s_IsVSHosted)
return StackWalker.GetMethodNameFromStack(nPlusMinus) + "()- ";
else
return StackWalker.GetMethodNameFromStack(nPlusMinus - 1) + "()- ";
}
#endregion
#region Public Static Configuration and Logger Creation Methods
/// <summary>
/// Used to add a new Configuration and Logger Instance onto a Static Map.
/// Will create one logger instance per unique name.
/// </summary>
/// <param name="Name">a name for the logger instance</param>
/// <param name="Configuration">a valid configuration to use on the instance</param>
/// <returns>a logging object that can be used to log</returns>
public static Logging AddGlobalLoggerConfiguration(string Name, Logging_Configuration Configuration)
{
// Must have a Valid Input
if (string.IsNullOrEmpty(Name))
throw new ArgumentException("Name Is Invalid");
if (!_loggerObjects.Keys.Contains(Name.ToLower()))
{
// Create the Repository
log4net.Repository.ILoggerRepository repository = LogManager.CreateRepository(Name.ToLower());
// Create FileAppender Configuration
RollingFileAppender appender = RollingFileAppenderCreator(Configuration);
// Run the Configuration against the Repository
BasicConfigurator.Configure(repository, appender);
// Add Configuration to our Static Map
_loggerConfigurationMap[Name.ToLower()] = Configuration;
// Last, but not least, Create the new Logging Instance Object and Store it
_loggerObjects[Name.ToLower()] = LogManager.GetLogger(Name.ToLower(), Name.ToLower());
}
// Let the Caller get the Logging Object
return GetLogger(Name);
}
/// <summary>
/// Used to retrieve a named logging instance that has already been created via a previous call
/// to AddGlobalLoggerConfiguration().
/// </summary>
/// <param name="Name">a name for a previously created Logging instance</param>
/// <returns>a Logging object that can be used to log</returns>
public static Logging GetLogger(string Name)
{
if (_loggerObjects.Keys.Contains(Name.ToLower()))
{
Logging logger = new Logging();
logger._Log4NetLog = _loggerObjects[Name.ToLower()];
return logger;
}
else
throw new ArgumentException("Must call AddGlobalLoggerConfiguration() with a Configuration Before calling this Function");
}
#endregion
#region Private Static Helper Methods
/// <summary>
/// Creates a Log4Net RollingFileAppender with the specified configuration
/// </summary>
/// <param name="config">a valid configuration</param>
/// <returns>a Log4Net RollingFileAppender Object</returns>
private static RollingFileAppender RollingFileAppenderCreator(Logging_Configuration config)
{
#region Input Validation
if (config.maxFileSizeInMB <= 0)
throw new ArgumentException("Logging_Configuration - Invalid maxFileSizeInMB");
if (config.numOfBackupLogFiles < 0)
throw new ArgumentException("Logging_Configuration - Invalid numOfBackupLogFiles");
if (String.IsNullOrEmpty(config.LogFileNameNPath))
throw new Exception("Logging_Configuration - Invalid LogFileNameNPath");
if (!Directory.Exists(Path.GetDirectoryName(config.LogFileNameNPath)))
Directory.CreateDirectory(Path.GetDirectoryName(config.LogFileNameNPath));
#endregion
// Create and Set Layout for FileAppender
RollingFileAppender rfAppender = new RollingFileAppender();
if (!String.IsNullOrEmpty(config.PatternLayout))
rfAppender.Layout = new PatternLayout(config.PatternLayout);
else
rfAppender.Layout = new PatternLayout("%date{dd MMM HH:mm:ss,fff} [%thread] %level - %message%newline");
//rfAppender.Layout = new PatternLayout("%date{dd MMM yyyy HH:mm:ss,fff} [%thread] %level %logger - %message%newline");
// Locking Minimal allows us to run Log4Net from multiple processes
if (config.UseExclusiveFileLock)
rfAppender.LockingModel = new FileAppender.ExclusiveLock();
else
rfAppender.LockingModel = new FileAppender.MinimalLock();
// Configure FileName and always set Appent to true
rfAppender.File = config.LogFileNameNPath;
rfAppender.AppendToFile = true;
// According to the listings on the blog site
// http://blog.aggregatedintelligence.com/2009/08/log4net-logging-levels-available.html
// Error, will log Error, Fatal
// Info, will log Info, Error, and Fatal
// Debug, will log Info, Error, Fatal and Debug
if (config.Detail == Logging_Detail.NONE)
rfAppender.Threshold = Level.Off;
else if (config.Detail == Logging_Detail.ERROR)
rfAppender.Threshold = Level.Error;
else if (config.Detail == Logging_Detail.INFO)
rfAppender.Threshold = Level.Info;
else if (config.Detail == Logging_Detail.DEBUG)
rfAppender.Threshold = Level.Debug;
rfAppender.MaximumFileSize = String.Format("{0}MB", config.maxFileSizeInMB);
rfAppender.MaxSizeRollBackups = config.numOfBackupLogFiles;
rfAppender.RollingStyle = RollingFileAppender.RollingMode.Size; // Setting to RollingMode.Size will make MaxSizeRollBackups work
rfAppender.ActivateOptions();
return rfAppender;
}
#endregion
}
}

482
@integrate/MsgBox.cs Normal file
View File

@@ -0,0 +1,482 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Watchdog.WatchdogLib.Win32;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using WPFWin = System.Windows;
using WPFWinInterop = System.Windows.Interop;
namespace Watchdog.WatchdogLib.WinForms
{
/// <summary>
/// MsgBox is a WindowsForms MessageBox that can be centered to the Parent
/// </summary>
public static class MsgBox
{
#region Private Static Members
private static User32.WindowsHookProc _hookProcDelegate = null;
private static int _hHook = 0;
private static string _title = null;
private static string _msg = null;
private static IntPtr _hIcon = IntPtr.Zero;
private static bool _IsDesktopOwner = false;
private static bool _ShowFatal = false;
// Delegate to make All Message Boxes Thread-Safe
private delegate DialogResult ShowMsgBoxDelegate(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon, Icon TitleBarIcon);
#endregion
#region Public Properties
public static Icon DefaultTitleBarIcon { get; set; }
public static uint MaxNumberOfCharactersPerLine { get; set; }
public const uint DefaultNumberOfCharactersPerLine = 62;
#endregion
#region Public Header Properties
public static bool ShowHeader { get; set; }
public static string MsgBox_ErrorHeader { get; set; }
public static string MsgBox_FatalErrorHeader { get; set; }
public static string MsgBox_WarningHeader { get; set; }
public static string MsgBox_InfoHeader { get; set; }
#endregion
#region Public Footer Properties
public static bool ShowFooter { get; set; }
public static string MsgBox_ErrorFooter { get; set; }
public static string MsgBox_FatalErrorFooter { get; set; }
public static string MsgBox_WarningFooter { get; set; }
public static string MsgBox_InfoFooter { get; set; }
#endregion
#region Public Title Header Properties
public static bool ShowTitleHeader { get; set; }
public static string MsgBox_ErrorTitleHeader { get; set; }
public static string MsgBox_FatalErrorTitleHeader { get; set; }
public static string MsgBox_WarningTitleHeader { get; set; }
public static string MsgBox_InfoTitleHeader { get; set; }
#endregion
#region Construction
static MsgBox()
{
DefaultTitleBarIcon = null;
MaxNumberOfCharactersPerLine = DefaultNumberOfCharactersPerLine;
// Header Init
MsgBox_FatalErrorHeader = String.Empty;
MsgBox_ErrorHeader = String.Empty;
MsgBox_WarningHeader = String.Empty;
MsgBox_InfoHeader = String.Empty;
ShowHeader = true;
// Footer Init
MsgBox_FatalErrorFooter = String.Empty;
MsgBox_ErrorFooter = String.Empty;
MsgBox_WarningFooter = String.Empty;
MsgBox_InfoFooter = String.Empty;
ShowFooter = true;
// Title Header Init
MsgBox_FatalErrorTitleHeader = String.Empty;
MsgBox_ErrorTitleHeader = String.Empty;
MsgBox_WarningTitleHeader = String.Empty;
MsgBox_InfoTitleHeader = String.Empty;
ShowTitleHeader = true;
}
#endregion
#region Public Static Methods
/// <summary>
/// Shows a custom Message Box (centered to parent), with the DefaultTitleBarIcon
/// </summary>
public static DialogResult Show(WPFWin.Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon)
{
if (parent != null)
{
WPFWinInterop.WindowInteropHelper interop = new WPFWinInterop.WindowInteropHelper(parent);
if(interop.Handle != IntPtr.Zero)
return Show(Watchdog.WatchdogLib.Win32.Convert.ConverthWndToIWin32Window(interop.Handle), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
}
return Show(Functions.GetDestopWindow(), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
}
/// <summary>
/// Shows a custom Message Box (centered to parent), with the DefaultTitleBarIcon
/// </summary>
public static DialogResult Show(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon)
{
return Show(parent, Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
}
/// <summary>
/// Shows a custom Message Box (centered to Desktop), with the DefaultTitleBarIcon
/// </summary>
public static DialogResult Show(String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon)
{
return Show(Functions.GetDestopWindow(), Title, Text, MsgBoxButtons, MsgBoxIcon, DefaultTitleBarIcon);
}
/// <summary>
/// *Main MessageBox Show Function* allows you to center the Message Box to the Parent
/// </summary>
/// <returns>Result of Dialog </returns>
public static DialogResult Show(IWin32Window parent, String Title, String Text, MessageBoxButtons MsgBoxButtons, MessageBoxIcon MsgBoxIcon, Icon TitleBarIcon)
{
ISynchronizeInvoke InvokeObject = null;
if (parent != null && parent is ISynchronizeInvoke)
InvokeObject = (ISynchronizeInvoke)parent;
// Invoke if we need to * Make MessageBoxes generally Thread-safe *
if ((InvokeObject != null) && InvokeObject.InvokeRequired)
{
DialogResult result = (DialogResult)InvokeObject.Invoke(new ShowMsgBoxDelegate(MsgBox.Show), new object[] { parent, Title, Text, MsgBoxButtons, MsgBoxIcon, TitleBarIcon });
return result;
}
else
{
return MsgBox.ShowInternal(parent, Text, Title, MsgBoxButtons, MsgBoxIcon, TitleBarIcon);
}
}
#endregion
#region Public Static Methods Extended
/// <summary>
/// Shows Warning MessageBox
/// </summary>
//public static DialogResult ShowWarning(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowWarning(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Exclamation);
}
/// <summary>
/// Shows Warning MessageBox
/// </summary>
//public static DialogResult ShowWarning(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowWarning(String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Exclamation);
}
/// <summary>
/// Shows Fatal Error MessageBox
/// </summary>
//public static DialogResult ShowFatalError(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowFatalError(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
_ShowFatal = true;
DialogResult dr = Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
_ShowFatal = false;
return dr;
}
/// <summary>
/// Shows Fatal Error MessageBox
/// </summary>
//public static DialogResult ShowFatalError(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowFatalError(String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
_ShowFatal = true;
DialogResult dr = Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
_ShowFatal = false;
return dr;
}
/// <summary>
/// Shows Error MessageBox
/// </summary>
//public static DialogResult ShowError(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowError(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
}
/// <summary>
/// Shows Error MessageBox
/// </summary>
//public static DialogResult ShowError(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowError(String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Error);
}
/// <summary>
/// Shows Information MessageBox
/// </summary>
//public static DialogResult ShowInfo(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowInfo(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.Information);
}
/// <summary>
/// Shows Information MessageBox
/// </summary>
//public static DialogResult ShowInfo(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowInfo(String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.Information);
}
/// <summary>
/// Shows Default MessageBox
/// </summary>
//public static DialogResult ShowDefault(IWin32Window parent, String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowDefault(IWin32Window parent, String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(parent, Title, Text, MsgBoxButtons, MessageBoxIcon.None);
}
/// <summary>
/// Shows Default MessageBox
/// </summary>
//public static DialogResult ShowDefault(String Text, String Title = "", MessageBoxButtons MsgBoxButtons = MessageBoxButtons.OK)
public static DialogResult ShowDefault(String Text, String Title, MessageBoxButtons MsgBoxButtons)
{
return Show(Title, Text, MsgBoxButtons, MessageBoxIcon.None);
}
#endregion
#region Private Methods
/// <summary>
///
/// </summary>
/// <param name="owner"></param>
/// <param name="msg"></param>
/// <param name="title"></param>
/// <param name="btns"></param>
/// <param name="icon"></param>
/// <param name="TitleBarIcon"></param>
/// <returns></returns>
private static DialogResult ShowInternal(IWin32Window owner, string msg, string title, MessageBoxButtons btns, MessageBoxIcon icon, Icon TitleBarIcon)
{
// Create a callback delegate
_hookProcDelegate = new User32.WindowsHookProc(HookCallback);
#region Header Action
if (ShowHeader)
{
if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorHeader) && _ShowFatal)
msg = MsgBox_FatalErrorHeader + msg;
else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorHeader) && !_ShowFatal)
msg = MsgBox_ErrorHeader + msg;
else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningHeader))
msg = MsgBox_WarningHeader + msg;
else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoHeader))
msg = MsgBox_InfoHeader + msg;
}
#endregion
#region Footer Action
if (ShowFooter)
{
if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorFooter) && _ShowFatal)
msg = msg + MsgBox_FatalErrorFooter;
else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorFooter) && !_ShowFatal)
msg = msg + MsgBox_ErrorFooter;
else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningFooter))
msg = msg + MsgBox_WarningFooter;
else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoFooter))
msg = msg + MsgBox_InfoFooter;
}
#endregion
#region Title Header
if (ShowTitleHeader)
{
if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_FatalErrorTitleHeader) && _ShowFatal)
title = MsgBox_FatalErrorTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
else if (icon == MessageBoxIcon.Error && !String.IsNullOrEmpty(MsgBox_ErrorTitleHeader) && !_ShowFatal)
title = MsgBox_ErrorTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
else if (icon == MessageBoxIcon.Exclamation && !String.IsNullOrEmpty(MsgBox_WarningTitleHeader))
title = MsgBox_WarningTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
else if (icon == MessageBoxIcon.Information && !String.IsNullOrEmpty(MsgBox_InfoTitleHeader))
title = MsgBox_InfoTitleHeader + ((!String.IsNullOrEmpty(title)) ? (" (" + title + ")") : "");
}
#endregion
#region Text Padding
// Stripe last \n, if exists
if (!String.IsNullOrEmpty(msg) && (msg.Length > 0) && (msg[msg.Length - 1] == '\n'))
msg = msg.Remove(msg.Length - 1);
// Make sure the text looks good, by using padding
if (!String.IsNullOrEmpty(msg) && (msg.Length > 0) && (msg.Length < MaxNumberOfCharactersPerLine))
{
string[] lines = msg.Split('\n');
StringBuilder sb = new StringBuilder();
foreach (string line in lines)
{
sb.Append(line.PadRight((int)MaxNumberOfCharactersPerLine));
sb.Append("\n");
}
msg = sb.ToString();
}
else if (!String.IsNullOrEmpty(msg) && (msg.Length > 0) && (msg.Length > MaxNumberOfCharactersPerLine))
{
// Incredible and amazing Padding code
string[] lines = msg.Split('\n');
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lines.Length; ++i)
{
if (lines[i].Length < MaxNumberOfCharactersPerLine)
{
sb.Append(lines[i].PadRight((int)MaxNumberOfCharactersPerLine));
sb.Append("\n");
}
else if (lines[i].Length > MaxNumberOfCharactersPerLine)
{
// truncate
for (int j = 0; j < lines[i].Length; j = j + (int)MaxNumberOfCharactersPerLine)
{
string strSub = lines[i].Substring(j, ((lines[i].Length - j) > (int)MaxNumberOfCharactersPerLine) ? (int)MaxNumberOfCharactersPerLine : (lines[i].Length - j));
if (strSub.Length == (int)MaxNumberOfCharactersPerLine)
{
sb.Append(strSub);
sb.Append("\n");
}
else
{
sb.Append(strSub.PadRight((int)MaxNumberOfCharactersPerLine));
sb.Append("\n");
}
}
}
else
{
sb.Append(lines[i]);
sb.Append("\n");
}
}
// Write nicely formatted Message out
msg = sb.ToString();
}
else
{
// do nothing, string is miracioulsy exactly correct
}
#endregion
// Remember the title & message that we'll look for.
// The hook sees *all* windows, so we need to make sure we operate on the right one.
_msg = msg;
_title = title;
// if Owner is the Desktop Window
_IsDesktopOwner = (owner.Handle == Functions.GetDestopWindow().Handle);
// Icon could not be present
if (TitleBarIcon != null)
_hIcon = TitleBarIcon.ToBitmap().GetHicon();
// Set the hook.
// Suppress "GetCurrentThreadId() is deprecated" warning.
// It's documented that Thread.ManagedThreadId doesn't work with SetWindowsHookEx()
#pragma warning disable 0618
_hHook = User32.SetWindowsHookEx(Definitions.WH_CBT, _hookProcDelegate, IntPtr.Zero, AppDomain.GetCurrentThreadId());
#pragma warning restore 0618
// Pop a standard MessageBox. The hook will center it.
DialogResult rslt = DialogResult.None;
if (_IsDesktopOwner)
rslt = MessageBox.Show(_msg, _title, btns, icon);
else
rslt = MessageBox.Show(owner, _msg, _title, btns, icon);
// Release hook, clean up (may have already occurred)
Unhook();
return rslt;
}
private static void Unhook()
{
User32.UnhookWindowsHookEx(_hHook);
_hHook = 0;
_hookProcDelegate = null;
_msg = null;
_title = null;
}
private static int HookCallback(int code, IntPtr wParam, IntPtr lParam)
{
int hHook = _hHook; // Local copy for CallNextHookEx() JIC we release _hHook
// Look for HCBT_ACTIVATE, *not* HCBT_CREATEWND:
// child controls haven't yet been created upon HCBT_CREATEWND.
if (code == Definitions.HCBT_ACTIVATE)
{
string cls = Functions.GetWindowClassName(wParam);
if (cls == "#32770") // MessageBoxes are Dialog boxes
{
string title = Functions.GetWindowText(wParam);
string msg = Functions.GetDlgItemText(wParam, 0xFFFF); // -1 aka IDC_STATIC
if ((title == _title) && (msg == _msg))
{
// Only Center the Window, if the Owner is NOT the Desktop
if (!_IsDesktopOwner)
CenterWindowOnParent(wParam);
Unhook(); // Release hook - we've done what we needed
// Now we also want to set the Icon on the Dialog
if (_hIcon != IntPtr.Zero)
{
User32.SendMessage(wParam, (int)Definitions.WM.WM_SETICON, (IntPtr)1, _hIcon);
User32.SendMessage(wParam, (int)Definitions.WM.WM_SETICON, (IntPtr)0, _hIcon);
}
}
}
}
return User32.CallNextHookEx(hHook, code, wParam, lParam);
}
// Boilerplate window-centering code.
// Split out of HookCallback() for clarity.
private static void CenterWindowOnParent(IntPtr hChildWnd)
{
// Get child (MessageBox) size
Structures.RECT rcChild = new Structures.RECT();
User32.GetWindowRect(hChildWnd, out rcChild);
int cxChild = rcChild.right - rcChild.left;
int cyChild = rcChild.bottom - rcChild.top;
// Get parent (Form) size & location
IntPtr hParent = User32.GetParent(hChildWnd);
Structures.RECT rcParent = new Structures.RECT();
User32.GetWindowRect(hParent, out rcParent);
int cxParent = rcParent.right - rcParent.left;
int cyParent = rcParent.bottom - rcParent.top;
// Center the MessageBox on the Form
int x = rcParent.left + (cxParent - cxChild) / 2;
int y = rcParent.top + (cyParent - cyChild) / 2;
uint uFlags = 0x15; // SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE;
User32.SetWindowPos(hChildWnd, IntPtr.Zero, x, y, 0, 0, uFlags);
}
#endregion
}
}

12
@integrate/README.txt Normal file
View File

@@ -0,0 +1,12 @@
Things to go over
File->Logging.cs
Process->PStarter.cs
Thread->SingleThreadTimer.cs (new)
Watchdog->SysTray.cs
Watchdog->MsgBox.cs
Watchdog->Timer.cs
Watchdog->Installer.cs (new)
Watchdog->CHMFile.cs (new)

120
@integrate/ResxHelper.cs Normal file
View File

@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Resources;
using System.Reflection;
using System.IO;
using Watchdog.WatchdogLib.Assembly;
namespace Watchdog
{
// ResxTypes
public enum Resx
{
AppResx,
}
#region ResxHelper Wrapper Classes
/// <summary>
/// AppResx Wrapper String Resource Value Functions
/// </summary>
public static class AppResx
{
public static string GetString(string name)
{
return ResxHelper.GetStringValue(Resx.AppResx, name);
}
public static string GetStringFormated(string name, params object[] args)
{
return ResxHelper.GetStringValueFormated(Resx.AppResx, name, args);
}
}
#endregion
/// <summary>
/// Allows External Callers To Quickly gain access to the Resources Contained in this Assembly
/// </summary>
public static class ResxHelper
{
/// <summary>
/// Private static Dictionary Map of Resource Managers
/// </summary>
private static Dictionary<Resx, ResourceManager> _ResourceMap = new Dictionary<Resx, ResourceManager>();
/// <summary>
/// Static Constructor, iterates through the enumerations and loads resourceManagers internally
/// </summary>
static ResxHelper()
{
//string[] resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();
//~we shouldn't be doing this on filename (filename could change)
//string curAsmName = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().ManifestModule.Name);
string curAsmName = AssemblyW.GetAssemblyName(AssemblyW.AssemblyST.Entry);
// Create a ResourceManager for each Resource Type in this Assembly
foreach (string ResxName in Enum.GetNames(typeof(Resx)))
_ResourceMap.Add((Resx)Enum.Parse(typeof(Resx), ResxName), new ResourceManager((curAsmName + "." + ResxName), Assembly.GetExecutingAssembly()));
}
#region String Resource Value Functions
/// <summary>
/// Returns the Value of a String Resource via GetString()
/// </summary>
/// <param name="resx">Reource Type to Access</param>
/// <param name="Name">Name of String Resource to get</param>
/// <returns>the value of the resource, or "" if not found/Error Occured</returns>
public static string GetStringValue(Resx resx, string Name)
{
try
{
if (!String.IsNullOrEmpty(Name))
{
string Value = PreserverFormating(_ResourceMap[resx].GetString(Name));
return Value;
}
}
catch (Exception) { /* ignore */ }
return String.Empty;
}
/// <summary>
/// Returns a Formated String Value of a String Resource via GetString()
/// </summary>
/// <param name="resx">Reource Type to Access</param>
/// <param name="Name">Name of String Resource to get</param>
/// <param name="args">Arguments to pass into String.Format()</param>
/// <returns>the value of the resource, or "" if not found/Error Occured</returns>
public static string GetStringValueFormated(Resx resx, string Name, params object[] args)
{
String retVal = GetStringValue(resx, Name);
if (!String.IsNullOrEmpty(retVal))
return String.Format(retVal, args);
else
return String.Empty;
}
/// <summary>
/// we want to preserver formating using '\' characters that are in the resource
/// </summary>
/// <param name="Name">a string value retrieved from the resource</param>
/// <returns>a string that preserves formatting</returns>
private static string PreserverFormating(string Value)
{
if (!String.IsNullOrEmpty(Value))
{
Value = Value.Replace("\\N", "\n");
Value = Value.Replace("\\n", "\n");
Value = Value.Replace("\\T", "\t");
Value = Value.Replace("\\t", "\t");
return Value;
}
return String.Empty;
}
#endregion
}
}

1057
@integrate/Settings.cs Normal file

File diff suppressed because it is too large Load Diff

24
@integrate/Snippets.txt Normal file
View File

@@ -0,0 +1,24 @@
private string GetDefaultBrowserPath()
{
try
{
if (ApplicationSettings.appSettings().LogEvents)
{
CrossProductLogging.WriteEventLogFile("Begin GetDefaultBrowserPath");
}
string key = @"htmlfile\shell\open\command";
RegistryKey registryKey =
Registry.ClassesRoot.OpenSubKey(key, false);
// get default browser path
if (ApplicationSettings.appSettings().LogEvents)
{
CrossProductLogging.WriteEventLogFile("End GetDefaultBrowserPath");
}
return ((string)registryKey.GetValue(null, null)).Split('"')[1];
}
catch
{
return "";
}
}

238
@integrate/SysTray.cs Normal file
View File

@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using WatchdogLib.Thread;
using System.Timers;
namespace WatchdogLib.WinForms
{
/// <summary>
/// Wrapper Class around .Net NotifyIcon, to make it easier to work with an System Tray Icon.
/// Instantiate the object and set ContextMenu or ContextMenuStrip in order to have a right click menu.
/// Subscripe to the MouseLeftClick, and MouseLeftDoubleClick event to get accurate events to handle,
/// Call Show()/Hide() to show/hide the System Tray Icon, respectively.
/// </summary>
public class SysTray
{
#region Public Properties
public NotifyIcon trayNotify { get; private set; }
public Icon Icon { get { return trayNotify.Icon; } set { trayNotify.Icon = value; } }
public ContextMenu trayMenu { get { return trayNotify.ContextMenu; } set { trayNotify.ContextMenu = value; } }
public ContextMenuStrip trayMenuStrip { get { return trayNotify.ContextMenuStrip; } set { trayNotify.ContextMenuStrip = value; } }
public string toolTip { get { return trayNotify.Text; } set { trayNotify.Text = value; } }
public bool Visible { get { return trayNotify.Visible; } }
#endregion
#region Public Events
public delegate void SingleLeftMouseClick(MouseEventArgs e);
/// <summary>
/// Subscribe to get the Left Mouse Single Click Event
/// </summary>
public event SingleLeftMouseClick LeftMouseClick;
public delegate void DoubleLeftMouseClick(MouseEventArgs e);
/// <summary>
/// Subscribe to get the Left Mouse Double Click Event
/// </summary>
public event DoubleLeftMouseClick LeftMouseDoubleClick;
public delegate void RightMouseClick(MouseEventArgs e);
/// <summary>
/// Subscribe to get any Right Mouse Fired Event, use to redo context menu, if needed
/// </summary>
public event RightMouseClick RightMouseFired;
#endregion
#region Private Members
private TTimer SingleClickDetectTimer = null;
private TimeSpan _LastFiredEvent = new TimeSpan(DateTime.Now.Ticks);
private const int _MILISECONDS_FOR_SINGLEMOUSE_CLICKEVENT_TOCOUNT = 500;
private const int _N_SECONDS_TOIGNORE_NEXT_SIGNLEMOUSE_CLICKEVENT = 2; // to avoid tripple clicks, etc... (only sends one double click)
/// <summary>
/// Returns true if enough time since _LastFiredEvent has passed
/// </summary>
private bool EnoughTimeSinceLastEventHasElapsed
{
get
{
// 1 second is 10 Million ticks, one Milisecond is 10K
return (DateTime.Now.Ticks - _LastFiredEvent.Ticks) >= (_N_SECONDS_TOIGNORE_NEXT_SIGNLEMOUSE_CLICKEVENT * 1000 * 10000);
}
}
#endregion
#region Construction
/// <summary>
/// Construct a System Tray Icon (use public properties like ContextMenu,Icon,toolTip to customize further)
/// </summary>
/// <param name="toolTip">pass in an initial ToolTip to display, defaults to ""</param>
/// <param name="icon">if null, defaults to systemIcons.Application</param>
//public SysTray(string toolTip = "", Icon icon = null)
public SysTray(string toolTip, Icon icon)
{
// Create internal objects
this.trayNotify = new NotifyIcon();
this.SingleClickDetectTimer = new TTimer(new ElapsedEventHandler(RealSingleClickDetectTimer_ElapsedEventHandler), _MILISECONDS_FOR_SINGLEMOUSE_CLICKEVENT_TOCOUNT, false, true);
// Add Single / Double-Click Event Handlers
trayNotify.Click += new EventHandler(trayNotify_Click);
trayNotify.DoubleClick += new EventHandler(trayNotify_DoubleClick);
trayNotify.MouseDown += new MouseEventHandler(trayNotify_MouseDown);
// Set ToolTip
if (!String.IsNullOrEmpty(toolTip))
this.toolTip = toolTip;
// Set Icon
if (icon == null)
this.Icon = new Icon(SystemIcons.Application, 40, 40);
else
this.Icon = icon;
}
#endregion
#region Click Event Handlers
/// <summary>
/// Called by NotifyIcon DoubleClick Event, We filter for only the left mouse double-click,
/// event and fire event when neccessary
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void trayNotify_DoubleClick(object sender, EventArgs e)
{
MouseEventArgs args = (MouseEventArgs)e;
if (args.Button == MouseButtons.Left)
{
SingleClickDetectTimer.Stop();
if (LeftMouseDoubleClick != null && EnoughTimeSinceLastEventHasElapsed)
{
_LastFiredEvent = new TimeSpan(DateTime.Now.Ticks);
LeftMouseDoubleClick(new MouseEventArgs(MouseButtons.Left, 2, 0, 0, 0));
}
}
}
/// <summary>
// Called by NotifyIcon Click Event, We filter for only the left mouse click,
/// event and fire event when neccessary
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void trayNotify_Click(object sender, EventArgs e)
{
MouseEventArgs args = (MouseEventArgs) e;
if (args.Button == MouseButtons.Left && EnoughTimeSinceLastEventHasElapsed)
SingleClickDetectTimer.Start(); // Start Single Click Detect Timer
}
/// <summary>
/// In order to accurately re-do a context menu, we handle MouseDown for the
/// Right-Mouse click. Mouse Down comes in before the click event, which gives
/// the caller an opportunity to handle/recreate the context menu dynamically, if needed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void trayNotify_MouseDown(object sender, MouseEventArgs e)
{
MouseEventArgs args = (MouseEventArgs)e;
if (args.Button == MouseButtons.Right && (RightMouseFired != null))
RightMouseFired(args);
}
/// <summary>
/// Used to detect ONLY Single Clicks, since a single-click and then a double-click fires,
/// we want to ignore the first click,and first see if a double-click comes in, if so, ignore
/// the single click, otherwise send it. (this is done by trayNotify_Click & transNotify_DoubleClick)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RealSingleClickDetectTimer_ElapsedEventHandler(object sender, ElapsedEventArgs e)
{
SingleClickDetectTimer.Stop();
if (LeftMouseClick != null)
{
_LastFiredEvent = new TimeSpan(DateTime.Now.Ticks);
LeftMouseClick(new MouseEventArgs(MouseButtons.Left, 1, 0, 0, 0));
}
}
#endregion
#region Show N' Hide
/// <summary>
/// Show the System Tray Icon
/// </summary>
public void Show()
{
trayNotify.Visible = true;
}
/// <summary>
/// Hide the System Tray Icon
/// </summary>
public void Hide()
{
trayNotify.Visible = false;
}
#endregion
#region Public ShowBallon
/// <summary>
/// Pops up a Ballon over the System Tray Icon
/// </summary>
/// <param name="nTimeoutInSeconds">Specify the Timeout in Seconds</param>
//public void ShowBallon_Default(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds = 10)
public void ShowBallon_Default(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds)
{
trayNotify.ShowBalloonTip((nTimeoutInSeconds * 1000), BallonTipTitle, BallonTipText, ToolTipIcon.None);
}
/// <summary>
/// Pops up a Error Ballon over the System Tray Icon
/// </summary>
/// <param name="nTimeoutInSeconds">Specify the Timeout in Seconds</param>
//public void ShowBallon_Error(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds = 10)
public void ShowBallon_Error(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds)
{
trayNotify.ShowBalloonTip((nTimeoutInSeconds * 1000), BallonTipTitle, BallonTipText, ToolTipIcon.Error);
}
/// <summary>
/// Pops up a Warning Ballon over the System Tray Icon
/// </summary>
/// <param name="nTimeoutInSeconds">Specify the Timeout in Seconds</param>
//public void ShowBallon_Warning(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds = 10)
public void ShowBallon_Warning(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds)
{
trayNotify.ShowBalloonTip((nTimeoutInSeconds * 1000), BallonTipTitle, BallonTipText, ToolTipIcon.Warning);
}
/// <summary>
/// Pops up a Info Ballon over the System Tray Icon
/// </summary>
/// <param name="nTimeoutInSeconds">Specify the Timeout in Seconds</param>
//public void ShowBallon_Info(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds = 10)
public void ShowBallon_Info(string BallonTipTitle, string BallonTipText, int nTimeoutInSeconds)
{
trayNotify.ShowBalloonTip((nTimeoutInSeconds * 1000), BallonTipTitle, BallonTipText, ToolTipIcon.Info);
}
#endregion
}
}

140
@integrate/TTimer.cs Normal file
View File

@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Windows.Threading;
using WinThread = System.Threading;
namespace WatchdogLib.Thread
{
/// <summary>
/// Wrapper class around Timer Objects
/// </summary>
public class TTimer : IDisposable
{
// private Members
private Timer _Timer = new Timer();
private bool _disposed = false;
private Dispatcher _Dispatcher = null;
private ElapsedEventHandler _DispatchedElapsedEvent = null;
/// <summary>
/// Creates a new Multi-threaded System.Timer
/// </summary>
/// <param name="ElapsedHandler">Event Handler for Timer</param>
/// <param name="IntervalMiliseconds">Interval in Miliseconds</param>
/// <param name="StartEnabled">True to start the timer upon creation, false otherwise</param>
/// <returns>A Timer Object, which should be Disposed by Caller</returns>
//public TTimer(ElapsedEventHandler ElapsedHandler, int IntervalMiliseconds = 1000, bool StartEnabled = false, bool bUseDispatcher = true)
public TTimer(ElapsedEventHandler ElapsedHandler, int IntervalMiliseconds, bool StartEnabled, bool bUseDispatcher)
{
if (ElapsedHandler != null)
{
_Timer = new System.Timers.Timer();
// The Primary Dispatcher thread is the thread that called us
if (bUseDispatcher)
{
_Dispatcher = Dispatcher.CurrentDispatcher;
_DispatchedElapsedEvent = ElapsedHandler;
_Timer.Elapsed += new ElapsedEventHandler(_Timer_Elapsed);
}
else
{
_Timer.Elapsed += ElapsedHandler;
}
// Set the Interval / start
_Timer.Interval = IntervalMiliseconds;
_Timer.Enabled = StartEnabled;
if (StartEnabled)
_Timer.Start();
// Keep the timer alive
GC.KeepAlive(_Timer);
}
}
/// <summary>
/// For Dispatching the Event to the Primary Dispatcher Thread
/// </summary>
void _Timer_Elapsed(object sender, ElapsedEventArgs e)
{
object[] param_s = new object[] { sender, e };
_Dispatcher.Invoke((ElapsedEventHandler)_DispatchedElapsedEvent, param_s);
}
/// <summary>
/// Manually Start the Timer
/// </summary>
public void Start()
{
Stop(); // First Stop(), an existing Timer
_Timer.Enabled = true;
_Timer.Start();
}
/// <summary>
/// Manually Start the Timer at a new Interval
/// </summary>
/// <param name="IntervalMiliseconds">Interval in Miliseconds</param>
public void Start(uint IntervalMiliseconds)
{
Stop(); // First Stop(), an existing Timer
_Timer.Interval = IntervalMiliseconds;
_Timer.Enabled = true;
_Timer.Start();
}
/// <summary>
/// Manually Start the Timer at a new Interval
/// </summary>
/// <param name="tsInterval">Interval as a TimeSpan</param>
public void Start(TimeSpan tsInterval)
{
Stop(); // First Stop(), an existing Timer
_Timer.Interval = tsInterval.TotalMilliseconds;
_Timer.Enabled = true;
_Timer.Start();
}
/// <summary>
/// Manually Stop the Timer
/// </summary>
public void Stop()
{
_Timer.Enabled = false;
_Timer.Stop();
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_Timer != null)
_Timer.Dispose();
}
// Indicate that the instance has been disposed.
_Timer = null;
_disposed = true;
}
}
#endregion
}
}

View File

@@ -0,0 +1,654 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Security.Permissions;
namespace Trinet.Core.IO.Ntfs
{
/// <summary>
/// Represents the details of an alternative data stream.
/// </summary>
[DebuggerDisplay("{FullPath}")]
public sealed class AlternateDataStreamInfo : IEquatable<AlternateDataStreamInfo>
{
#region Private Data
private readonly string _fullPath;
private readonly string _filePath;
private readonly string _streamName;
private readonly FileStreamType _streamType;
private readonly FileStreamAttributes _attributes;
private readonly long _size;
private readonly bool _exists;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="AlternateDataStreamInfo"/> class.
/// </summary>
/// <param name="filePath">
/// The full path of the file.
/// This argument must not be <see langword="null"/>.
/// </param>
/// <param name="info">
/// The <see cref="SafeNativeMethods.Win32StreamInfo"/> containing the stream information.
/// </param>
internal AlternateDataStreamInfo(string filePath, SafeNativeMethods.Win32StreamInfo info)
{
_filePath = filePath;
_streamName = info.StreamName;
_streamType = info.StreamType;
_attributes = info.StreamAttributes;
_size = info.StreamSize;
_exists = true;
_fullPath = SafeNativeMethods.BuildStreamPath(_filePath, _streamName);
}
/// <summary>
/// Initializes a new instance of the <see cref="AlternateDataStreamInfo"/> class.
/// </summary>
/// <param name="filePath">
/// The full path of the file.
/// This argument must not be <see langword="null"/>.
/// </param>
/// <param name="streamName">
/// The name of the stream
/// This argument must not be <see langword="null"/>.
/// </param>
/// <param name="fullPath">
/// The full path of the stream.
/// If this argument is <see langword="null"/>, it will be generated from the
/// <paramref name="filePath"/> and <paramref name="streamName"/> arguments.
/// </param>
/// <param name="exists">
/// <see langword="true"/> if the stream exists;
/// otherwise, <see langword="false"/>.
/// </param>
internal AlternateDataStreamInfo(string filePath, string streamName, string fullPath, bool exists)
{
if (string.IsNullOrEmpty(fullPath)) fullPath = SafeNativeMethods.BuildStreamPath(filePath, streamName);
_streamType = FileStreamType.AlternateDataStream;
_filePath = filePath;
_streamName = streamName;
_fullPath = fullPath;
_exists = exists;
if (_exists)
{
_size = SafeNativeMethods.GetFileSize(_fullPath);
}
}
#endregion
#region Properties
/// <summary>
/// Returns the full path of this stream.
/// </summary>
/// <value>
/// The full path of this stream.
/// </value>
public string FullPath
{
get { return _fullPath; }
}
/// <summary>
/// Returns the full path of the file which contains the stream.
/// </summary>
/// <value>
/// The full file-system path of the file which contains the stream.
/// </value>
public string FilePath
{
get { return _filePath; }
}
/// <summary>
/// Returns the name of the stream.
/// </summary>
/// <value>
/// The name of the stream.
/// </value>
public string Name
{
get { return _streamName; }
}
/// <summary>
/// Returns a flag indicating whether the specified stream exists.
/// </summary>
/// <value>
/// <see langword="true"/> if the stream exists;
/// otherwise, <see langword="false"/>.
/// </value>
public bool Exists
{
get { return _exists; }
}
/// <summary>
/// Returns the size of the stream, in bytes.
/// </summary>
/// <value>
/// The size of the stream, in bytes.
/// </value>
public long Size
{
get { return _size; }
}
/// <summary>
/// Returns the type of data.
/// </summary>
/// <value>
/// One of the <see cref="FileStreamType"/> values.
/// </value>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public FileStreamType StreamType
{
get { return _streamType; }
}
/// <summary>
/// Returns attributes of the data stream.
/// </summary>
/// <value>
/// A combination of <see cref="FileStreamAttributes"/> values.
/// </value>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public FileStreamAttributes Attributes
{
get { return _attributes; }
}
#endregion
#region Methods
#region -IEquatable
/// <summary>
/// Returns a <see cref="String"/> that represents the current instance.
/// </summary>
/// <returns>
/// A <see cref="String"/> that represents the current instance.
/// </returns>
public override string ToString()
{
return this.FullPath;
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="Object"/>.
/// </returns>
public override int GetHashCode()
{
var comparer = StringComparer.OrdinalIgnoreCase;
return comparer.GetHashCode(_filePath ?? string.Empty)
^ comparer.GetHashCode(_streamName ?? string.Empty);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="obj">
/// An object to compare with this object.
/// </param>
/// <returns>
/// <see langword="true"/> if the current object is equal to the <paramref name="obj"/> parameter;
/// otherwise, <see langword="false"/>.
/// </returns>
public override bool Equals(object obj)
{
if (object.ReferenceEquals(null, obj)) return false;
if (object.ReferenceEquals(this, obj)) return true;
AlternateDataStreamInfo other = obj as AlternateDataStreamInfo;
if (!object.ReferenceEquals(null, other)) return this.Equals(other);
return false;
}
/// <summary>
/// Returns a value indicating whether
/// this instance is equal to another instance.
/// </summary>
/// <param name="other">
/// The instance to compare to.
/// </param>
/// <returns>
/// <see langword="true"/> if the current object is equal to the <paramref name="other"/> parameter;
/// otherwise, <see langword="false"/>.
/// </returns>
public bool Equals(AlternateDataStreamInfo other)
{
if (object.ReferenceEquals(null, other)) return false;
if (object.ReferenceEquals(this, other)) return true;
var comparer = StringComparer.OrdinalIgnoreCase;
return comparer.Equals(this._filePath ?? string.Empty, other._filePath ?? string.Empty)
&& comparer.Equals(this._streamName ?? string.Empty, other._streamName ?? string.Empty);
}
/// <summary>
/// The equality operator.
/// </summary>
/// <param name="first">
/// The first object.
/// </param>
/// <param name="second">
/// The second object.
/// </param>
/// <returns>
/// <see langword="true"/> if the two objects are equal;
/// otherwise, <see langword="false"/>.
/// </returns>
public static bool operator ==(AlternateDataStreamInfo first, AlternateDataStreamInfo second)
{
if (object.ReferenceEquals(first, second)) return true;
if (object.ReferenceEquals(null, first)) return false;
if (object.ReferenceEquals(null, second)) return false;
return first.Equals(second);
}
/// <summary>
/// The inequality operator.
/// </summary>
/// <param name="first">
/// The first object.
/// </param>
/// <param name="second">
/// The second object.
/// </param>
/// <returns>
/// <see langword="true"/> if the two objects are not equal;
/// otherwise, <see langword="false"/>.
/// </returns>
public static bool operator !=(AlternateDataStreamInfo first, AlternateDataStreamInfo second)
{
if (object.ReferenceEquals(first, second)) return false;
if (object.ReferenceEquals(null, first)) return true;
if (object.ReferenceEquals(null, second)) return true;
return !first.Equals(second);
}
#endregion
#region -Delete
/// <summary>
/// Deletes this stream from the parent file.
/// </summary>
/// <returns>
/// <see langword="true"/> if the stream was deleted;
/// otherwise, <see langword="false"/>.
/// </returns>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
public bool Delete()
{
const FileIOPermissionAccess permAccess = FileIOPermissionAccess.Write;
new FileIOPermission(permAccess, _filePath).Demand();
return SafeNativeMethods.SafeDeleteFile(this.FullPath);
}
#endregion
#region -Open
/// <summary>
/// Calculates the access to demand.
/// </summary>
/// <param name="mode">
/// The <see cref="FileMode"/>.
/// </param>
/// <param name="access">
/// The <see cref="FileAccess"/>.
/// </param>
/// <returns>
/// The <see cref="FileIOPermissionAccess"/>.
/// </returns>
private static FileIOPermissionAccess CalculateAccess(FileMode mode, FileAccess access)
{
FileIOPermissionAccess permAccess = FileIOPermissionAccess.NoAccess;
switch (mode)
{
case FileMode.Append:
permAccess = FileIOPermissionAccess.Append;
break;
case FileMode.Create:
case FileMode.CreateNew:
case FileMode.OpenOrCreate:
case FileMode.Truncate:
permAccess = FileIOPermissionAccess.Write;
break;
case FileMode.Open:
permAccess = FileIOPermissionAccess.Read;
break;
}
switch (access)
{
case FileAccess.ReadWrite:
permAccess |= FileIOPermissionAccess.Write;
permAccess |= FileIOPermissionAccess.Read;
break;
case FileAccess.Write:
permAccess |= FileIOPermissionAccess.Write;
break;
case FileAccess.Read:
permAccess |= FileIOPermissionAccess.Read;
break;
}
return permAccess;
}
/// <summary>
/// Opens this alternate data stream.
/// </summary>
/// <param name="mode">
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
/// and determines whether the contents of existing streams are retained or overwritten.
/// </param>
/// <param name="access">
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
/// </param>
/// <param name="share">
/// A <see cref="FileShare"/> value specifying the type of access other threads have to the file.
/// </param>
/// <param name="bufferSize">
/// The size of the buffer to use.
/// </param>
/// <param name="useAsync">
/// <see langword="true"/> to enable async-IO;
/// otherwise, <see langword="false"/>.
/// </param>
/// <returns>
/// A <see cref="FileStream"/> for this alternate data stream.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="bufferSize"/> is less than or equal to zero.
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public FileStream Open(FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
{
if (0 >= bufferSize) throw new ArgumentOutOfRangeException("bufferSize", bufferSize, null);
FileIOPermissionAccess permAccess = CalculateAccess(mode, access);
new FileIOPermission(permAccess, _filePath).Demand();
SafeNativeMethods.NativeFileFlags flags = useAsync ? SafeNativeMethods.NativeFileFlags.Overlapped : 0;
var handle = SafeNativeMethods.SafeCreateFile(this.FullPath, access.ToNative(), share, IntPtr.Zero, mode, flags, IntPtr.Zero);
if (handle.IsInvalid) SafeNativeMethods.ThrowLastIOError(this.FullPath);
return new FileStream(handle, access, bufferSize, useAsync);
}
/// <summary>
/// Opens this alternate data stream.
/// </summary>
/// <param name="mode">
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
/// and determines whether the contents of existing streams are retained or overwritten.
/// </param>
/// <param name="access">
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
/// </param>
/// <param name="share">
/// A <see cref="FileShare"/> value specifying the type of access other threads have to the file.
/// </param>
/// <param name="bufferSize">
/// The size of the buffer to use.
/// </param>
/// <returns>
/// A <see cref="FileStream"/> for this alternate data stream.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="bufferSize"/> is less than or equal to zero.
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public FileStream Open(FileMode mode, FileAccess access, FileShare share, int bufferSize)
{
return this.Open(mode, access, share, bufferSize, false);
}
/// <summary>
/// Opens this alternate data stream.
/// </summary>
/// <param name="mode">
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
/// and determines whether the contents of existing streams are retained or overwritten.
/// </param>
/// <param name="access">
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
/// </param>
/// <param name="share">
/// A <see cref="FileShare"/> value specifying the type of access other threads have to the file.
/// </param>
/// <returns>
/// A <see cref="FileStream"/> for this alternate data stream.
/// </returns>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public FileStream Open(FileMode mode, FileAccess access, FileShare share)
{
return this.Open(mode, access, share, SafeNativeMethods.DefaultBufferSize, false);
}
/// <summary>
/// Opens this alternate data stream.
/// </summary>
/// <param name="mode">
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
/// and determines whether the contents of existing streams are retained or overwritten.
/// </param>
/// <param name="access">
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
/// </param>
/// <returns>
/// A <see cref="FileStream"/> for this alternate data stream.
/// </returns>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public FileStream Open(FileMode mode, FileAccess access)
{
return this.Open(mode, access, FileShare.None, SafeNativeMethods.DefaultBufferSize, false);
}
/// <summary>
/// Opens this alternate data stream.
/// </summary>
/// <param name="mode">
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
/// and determines whether the contents of existing streams are retained or overwritten.
/// </param>
/// <returns>
/// A <see cref="FileStream"/> for this alternate data stream.
/// </returns>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public FileStream Open(FileMode mode)
{
FileAccess access = (FileMode.Append == mode) ? FileAccess.Write : FileAccess.ReadWrite;
return this.Open(mode, access, FileShare.None, SafeNativeMethods.DefaultBufferSize, false);
}
#endregion
#region -OpenRead / OpenWrite / OpenText
/// <summary>
/// Opens this stream for reading.
/// </summary>
/// <returns>
/// A read-only <see cref="FileStream"/> for this stream.
/// </returns>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public FileStream OpenRead()
{
return this.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
}
/// <summary>
/// Opens this stream for writing.
/// </summary>
/// <returns>
/// A write-only <see cref="FileStream"/> for this stream.
/// </returns>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public FileStream OpenWrite()
{
return this.Open(FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
}
/// <summary>
/// Opens this stream as a text file.
/// </summary>
/// <returns>
/// A <see cref="StreamReader"/> which can be used to read the contents of this stream.
/// </returns>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
/// <exception cref="ArgumentException">
/// The path of the stream is invalid.
/// </exception>
/// <exception cref="Win32Exception">
/// There was an error opening the stream.
/// </exception>
public StreamReader OpenText()
{
Stream fileStream = this.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
return new StreamReader(fileStream);
}
#endregion
#endregion
}
}

View File

@@ -0,0 +1,32 @@
using System;
namespace Trinet.Core.IO.Ntfs
{
/// <summary>
/// Represents the attributes of a file stream.
/// </summary>
[Flags]
public enum FileStreamAttributes
{
/// <summary>
/// No attributes.
/// </summary>
None = 0,
/// <summary>
/// Set if the stream contains data that is modified when read.
/// </summary>
ModifiedWhenRead = 1,
/// <summary>
/// Set if the stream contains security data.
/// </summary>
ContainsSecurity = 2,
/// <summary>
/// Set if the stream contains properties.
/// </summary>
ContainsProperties = 4,
/// <summary>
/// Set if the stream is sparse.
/// </summary>
Sparse = 8,
}
}

View File

@@ -0,0 +1,56 @@
using System;
namespace Trinet.Core.IO.Ntfs
{
/// <summary>
/// Represents the type of data in a stream.
/// </summary>
public enum FileStreamType
{
/// <summary>
/// Unknown stream type.
/// </summary>
Unknown = 0,
/// <summary>
/// Standard data.
/// </summary>
Data = 1,
/// <summary>
/// Extended attribute data.
/// </summary>
ExtendedAttributes = 2,
/// <summary>
/// Security data.
/// </summary>
SecurityData = 3,
/// <summary>
/// Alternate data stream.
/// </summary>
AlternateDataStream = 4,
/// <summary>
/// Hard link information.
/// </summary>
Link = 5,
/// <summary>
/// Property data.
/// </summary>
PropertyData = 6,
/// <summary>
/// Object identifiers.
/// </summary>
ObjectId = 7,
/// <summary>
/// Reparse points.
/// </summary>
ReparseData = 8,
/// <summary>
/// Sparse file.
/// </summary>
SparseBlock = 9,
/// <summary>
/// Transactional data.
/// (Undocumented - BACKUP_TXFS_DATA)
/// </summary>
TransactionData = 10,
}
}

View File

@@ -0,0 +1,452 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security;
using System.Security.Permissions;
namespace Trinet.Core.IO.Ntfs
{
using Resources = Properties.Resources;
/// <summary>
/// File-system utilities.
/// </summary>
public static class FileSystem
{
#region Create FileSystemInfo
/// <summary>
/// Creates a <see cref="FileSystemInfo"/> for the specified path.
/// </summary>
/// <param name="path">
/// The path of the file or directory.
/// </param>
/// <returns>
/// The <see cref="FileSystemInfo"/> representing the file or directory.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="path"/> is <see langword="null"/> or empty.
/// </exception>
private static FileSystemInfo CreateInfo(string path)
{
if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");
path = Path.GetFullPath(path);
if (!File.Exists(path) && Directory.Exists(path)) return new DirectoryInfo(path);
return new FileInfo(path);
}
#endregion
#region List Streams
/// <summary>
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
/// Returns a read-only list of alternate data streams for the specified file.
/// </summary>
/// <param name="file">
/// The <see cref="FileSystemInfo"/> to inspect.
/// </param>
/// <returns>
/// A read-only list of <see cref="AlternateDataStreamInfo"/> objects
/// representing the alternate data streams for the specified file, if any.
/// If no streams are found, returns an empty list.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="file"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="FileNotFoundException">
/// The specified <paramref name="file"/> does not exist.
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission.
/// </exception>
public static IList<AlternateDataStreamInfo> ListAlternateDataStreams(this FileSystemInfo file)
{
if (null == file) throw new ArgumentNullException("file");
if (!file.Exists) throw new FileNotFoundException(null, file.FullName);
string path = file.FullName;
new FileIOPermission(FileIOPermissionAccess.Read, path).Demand();
return SafeNativeMethods.ListStreams(path)
.Select(s => new AlternateDataStreamInfo(path, s))
.ToList().AsReadOnly();
}
/// <summary>
/// Returns a read-only list of alternate data streams for the specified file.
/// </summary>
/// <param name="filePath">
/// The full path of the file to inspect.
/// </param>
/// <returns>
/// A read-only list of <see cref="AlternateDataStreamInfo"/> objects
/// representing the alternate data streams for the specified file, if any.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="filePath"/> is not a valid file path.
/// </exception>
/// <exception cref="FileNotFoundException">
/// The specified <paramref name="filePath"/> does not exist.
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission.
/// </exception>
public static IList<AlternateDataStreamInfo> ListAlternateDataStreams(string filePath)
{
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
return CreateInfo(filePath).ListAlternateDataStreams();
}
#endregion
#region Stream Exists
/// <summary>
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
/// Returns a flag indicating whether the specified alternate data stream exists.
/// </summary>
/// <param name="file">
/// The <see cref="FileInfo"/> to inspect.
/// </param>
/// <param name="streamName">
/// The name of the stream to find.
/// </param>
/// <returns>
/// <see langword="true"/> if the specified stream exists;
/// otherwise, <see langword="false"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="file"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="streamName"/> contains invalid characters.
/// </exception>
public static bool AlternateDataStreamExists(this FileSystemInfo file, string streamName)
{
if (null == file) throw new ArgumentNullException("file");
SafeNativeMethods.ValidateStreamName(streamName);
string path = SafeNativeMethods.BuildStreamPath(file.FullName, streamName);
return -1 != SafeNativeMethods.SafeGetFileAttributes(path);
}
/// <summary>
/// Returns a flag indicating whether the specified alternate data stream exists.
/// </summary>
/// <param name="filePath">
/// The path of the file to inspect.
/// </param>
/// <param name="streamName">
/// The name of the stream to find.
/// </param>
/// <returns>
/// <see langword="true"/> if the specified stream exists;
/// otherwise, <see langword="false"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
/// </exception>
/// <exception cref="ArgumentException">
/// <para><paramref name="filePath"/> is not a valid file path.</para>
/// <para>-or-</para>
/// <para><paramref name="streamName"/> contains invalid characters.</para>
/// </exception>
public static bool AlternateDataStreamExists(string filePath, string streamName)
{
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
return CreateInfo(filePath).AlternateDataStreamExists(streamName);
}
#endregion
#region Open Stream
/// <summary>
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
/// Opens an alternate data stream.
/// </summary>
/// <param name="file">
/// The <see cref="FileInfo"/> which contains the stream.
/// </param>
/// <param name="streamName">
/// The name of the stream to open.
/// </param>
/// <param name="mode">
/// One of the <see cref="FileMode"/> values, indicating how the stream is to be opened.
/// </param>
/// <returns>
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="file"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="FileNotFoundException">
/// The specified <paramref name="file"/> was not found.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="streamName"/> contains invalid characters.
/// </exception>
/// <exception cref="NotSupportedException">
/// <paramref name="mode"/> is either <see cref="FileMode.Truncate"/> or <see cref="FileMode.Append"/>.
/// </exception>
/// <exception cref="IOException">
/// <para><paramref name="mode"/> is <see cref="FileMode.Open"/>, and the stream doesn't exist.</para>
/// <para>-or-</para>
/// <para><paramref name="mode"/> is <see cref="FileMode.CreateNew"/>, and the stream already exists.</para>
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
public static AlternateDataStreamInfo GetAlternateDataStream(this FileSystemInfo file, string streamName, FileMode mode)
{
if (null == file) throw new ArgumentNullException("file");
if (!file.Exists) throw new FileNotFoundException(null, file.FullName);
SafeNativeMethods.ValidateStreamName(streamName);
if (FileMode.Truncate == mode || FileMode.Append == mode)
{
throw new NotSupportedException(string.Format(Resources.Culture,
Resources.Error_InvalidMode, mode));
}
FileIOPermissionAccess permAccess = (FileMode.Open == mode) ? FileIOPermissionAccess.Read : FileIOPermissionAccess.Read | FileIOPermissionAccess.Write;
new FileIOPermission(permAccess, file.FullName).Demand();
string path = SafeNativeMethods.BuildStreamPath(file.FullName, streamName);
bool exists = -1 != SafeNativeMethods.SafeGetFileAttributes(path);
if (!exists && FileMode.Open == mode)
{
throw new IOException(string.Format(Resources.Culture,
Resources.Error_StreamNotFound, streamName, file.Name));
}
if (exists && FileMode.CreateNew == mode)
{
throw new IOException(string.Format(Resources.Culture,
Resources.Error_StreamExists, streamName, file.Name));
}
return new AlternateDataStreamInfo(file.FullName, streamName, path, exists);
}
/// <summary>
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
/// Opens an alternate data stream.
/// </summary>
/// <param name="file">
/// The <see cref="FileInfo"/> which contains the stream.
/// </param>
/// <param name="streamName">
/// The name of the stream to open.
/// </param>
/// <returns>
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="file"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="FileNotFoundException">
/// The specified <paramref name="file"/> was not found.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="streamName"/> contains invalid characters.
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
public static AlternateDataStreamInfo GetAlternateDataStream(this FileSystemInfo file, string streamName)
{
return file.GetAlternateDataStream(streamName, FileMode.OpenOrCreate);
}
/// <summary>
/// Opens an alternate data stream.
/// </summary>
/// <param name="filePath">
/// The path of the file which contains the stream.
/// </param>
/// <param name="streamName">
/// The name of the stream to open.
/// </param>
/// <param name="mode">
/// One of the <see cref="FileMode"/> values, indicating how the stream is to be opened.
/// </param>
/// <returns>
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
/// </exception>
/// <exception cref="FileNotFoundException">
/// The specified <paramref name="filePath"/> was not found.
/// </exception>
/// <exception cref="ArgumentException">
/// <para><paramref name="filePath"/> is not a valid file path.</para>
/// <para>-or-</para>
/// <para><paramref name="streamName"/> contains invalid characters.</para>
/// </exception>
/// <exception cref="NotSupportedException">
/// <paramref name="mode"/> is either <see cref="FileMode.Truncate"/> or <see cref="FileMode.Append"/>.
/// </exception>
/// <exception cref="IOException">
/// <para><paramref name="mode"/> is <see cref="FileMode.Open"/>, and the stream doesn't exist.</para>
/// <para>-or-</para>
/// <para><paramref name="mode"/> is <see cref="FileMode.CreateNew"/>, and the stream already exists.</para>
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
public static AlternateDataStreamInfo GetAlternateDataStream(string filePath, string streamName, FileMode mode)
{
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
return CreateInfo(filePath).GetAlternateDataStream(streamName, mode);
}
/// <summary>
/// Opens an alternate data stream.
/// </summary>
/// <param name="filePath">
/// The path of the file which contains the stream.
/// </param>
/// <param name="streamName">
/// The name of the stream to open.
/// </param>
/// <returns>
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
/// </exception>
/// <exception cref="FileNotFoundException">
/// The specified <paramref name="filePath"/> was not found.
/// </exception>
/// <exception cref="ArgumentException">
/// <para><paramref name="filePath"/> is not a valid file path.</para>
/// <para>-or-</para>
/// <para><paramref name="streamName"/> contains invalid characters.</para>
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
public static AlternateDataStreamInfo GetAlternateDataStream(string filePath, string streamName)
{
return GetAlternateDataStream(filePath, streamName, FileMode.OpenOrCreate);
}
#endregion
#region Delete Stream
/// <summary>
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
/// Deletes the specified alternate data stream if it exists.
/// </summary>
/// <param name="file">
/// The <see cref="FileInfo"/> to inspect.
/// </param>
/// <param name="streamName">
/// The name of the stream to delete.
/// </param>
/// <returns>
/// <see langword="true"/> if the specified stream is deleted;
/// otherwise, <see langword="false"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="file"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="streamName"/> contains invalid characters.
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
public static bool DeleteAlternateDataStream(this FileSystemInfo file, string streamName)
{
if (null == file) throw new ArgumentNullException("file");
SafeNativeMethods.ValidateStreamName(streamName);
const FileIOPermissionAccess permAccess = FileIOPermissionAccess.Write;
new FileIOPermission(permAccess, file.FullName).Demand();
var result = false;
if (file.Exists)
{
string path = SafeNativeMethods.BuildStreamPath(file.FullName, streamName);
if (-1 != SafeNativeMethods.SafeGetFileAttributes(path))
{
result = SafeNativeMethods.SafeDeleteFile(path);
}
}
return result;
}
/// <summary>
/// Deletes the specified alternate data stream if it exists.
/// </summary>
/// <param name="filePath">
/// The path of the file to inspect.
/// </param>
/// <param name="streamName">
/// The name of the stream to find.
/// </param>
/// <returns>
/// <see langword="true"/> if the specified stream is deleted;
/// otherwise, <see langword="false"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
/// </exception>
/// <exception cref="ArgumentException">
/// <para><paramref name="filePath"/> is not a valid file path.</para>
/// <para>-or-</para>
/// <para><paramref name="streamName"/> contains invalid characters.</para>
/// </exception>
/// <exception cref="SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="UnauthorizedAccessException">
/// The caller does not have the required permission, or the file is read-only.
/// </exception>
/// <exception cref="IOException">
/// The specified file is in use.
/// </exception>
public static bool DeleteAlternateDataStream(string filePath, string streamName)
{
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
return CreateInfo(filePath).DeleteAlternateDataStream(streamName);
}
#endregion
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace Trinet.Core.IO.Ntfs
{
/// <summary>
/// A <see cref="SafeHandle"/> for a global memory allocation.
/// </summary>
internal sealed class SafeHGlobalHandle : SafeHandle
{
#region Private Data
private readonly int _size;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="SafeHGlobalHandle"/> class.
/// </summary>
/// <param name="toManage">
/// The initial handle value.
/// </param>
/// <param name="size">
/// The size of this memory block, in bytes.
/// </param>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private SafeHGlobalHandle(IntPtr toManage, int size) : base(IntPtr.Zero, true)
{
_size = size;
base.SetHandle(toManage);
}
/// <summary>
/// Initializes a new instance of the <see cref="SafeHGlobalHandle"/> class.
/// </summary>
private SafeHGlobalHandle() : base(IntPtr.Zero, true)
{
}
#endregion
#region Properties
/// <summary>
/// Gets a value indicating whether the handle value is invalid.
/// </summary>
/// <value>
/// <see langword="true"/> if the handle value is invalid;
/// otherwise, <see langword="false"/>.
/// </value>
public override bool IsInvalid
{
get { return IntPtr.Zero == base.handle; }
}
/// <summary>
/// Returns the size of this memory block.
/// </summary>
/// <value>
/// The size of this memory block, in bytes.
/// </value>
public int Size
{
get { return _size; }
}
#endregion
#region Methods
/// <summary>
/// Allocates memory from the unmanaged memory of the process using GlobalAlloc.
/// </summary>
/// <param name="bytes">
/// The number of bytes in memory required.
/// </param>
/// <returns>
/// A <see cref="SafeHGlobalHandle"/> representing the memory.
/// </returns>
/// <exception cref="OutOfMemoryException">
/// There is insufficient memory to satisfy the request.
/// </exception>
public static SafeHGlobalHandle Allocate(int bytes)
{
return new SafeHGlobalHandle(Marshal.AllocHGlobal(bytes), bytes);
}
/// <summary>
/// Returns an invalid handle.
/// </summary>
/// <returns>
/// An invalid <see cref="SafeHGlobalHandle"/>.
/// </returns>
public static SafeHGlobalHandle Invalid()
{
return new SafeHGlobalHandle();
}
/// <summary>
/// Executes the code required to free the handle.
/// </summary>
/// <returns>
/// <see langword="true"/> if the handle is released successfully;
/// otherwise, in the event of a catastrophic failure, <see langword="false"/>.
/// In this case, it generates a releaseHandleFailed MDA Managed Debugging Assistant.
/// </returns>
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(base.handle);
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,478 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace Trinet.Core.IO.Ntfs
{
using Resources = Properties.Resources;
/// <summary>
/// Safe native methods.
/// </summary>
internal static class SafeNativeMethods
{
#region Constants and flags
public const int MaxPath = 256;
private const string LongPathPrefix = @"\\?\";
public const char StreamSeparator = ':';
public const int DefaultBufferSize = 0x1000;
private const int ErrorFileNotFound = 2;
// "Characters whose integer representations are in the range from 1 through 31,
// except for alternate streams where these characters are allowed"
// http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx
private static readonly char[] InvalidStreamNameChars = Path.GetInvalidFileNameChars().Where(c => c < 1 || c > 31).ToArray();
[Flags]
public enum NativeFileFlags : uint
{
WriteThrough = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x8000000,
DeleteOnClose = 0x4000000,
BackupSemantics = 0x2000000,
PosixSemantics = 0x1000000,
OpenReparsePoint = 0x200000,
OpenNoRecall = 0x100000
}
[Flags]
public enum NativeFileAccess : uint
{
GenericRead = 0x80000000,
GenericWrite = 0x40000000
}
#endregion
#region P/Invoke Structures
[StructLayout(LayoutKind.Sequential)]
private struct LargeInteger
{
public readonly int Low;
public readonly int High;
public long ToInt64()
{
return (this.High * 0x100000000) + this.Low;
}
/*
public static LargeInteger FromInt64(long value)
{
return new LargeInteger
{
Low = (int)(value & 0x11111111),
High = (int)((value / 0x100000000) & 0x11111111)
};
}
*/
}
[StructLayout(LayoutKind.Sequential)]
private struct Win32StreamId
{
public readonly int StreamId;
public readonly int StreamAttributes;
public LargeInteger Size;
public readonly int StreamNameSize;
}
/*
[StructLayout(LayoutKind.Sequential)]
private struct FileInformationByHandle
{
public int dwFileAttributes;
public LargeInteger ftCreationTime;
public LargeInteger ftLastAccessTime;
public LargeInteger ftLastWriteTime;
public int dwVolumeSerialNumber;
public LargeInteger FileSize;
public int nNumberOfLinks;
public LargeInteger FileIndex;
}
*/
#endregion
#region P/Invoke Methods
[DllImport("kernel32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
private static extern int FormatMessage(
int dwFlags,
IntPtr lpSource,
int dwMessageId,
int dwLanguageId,
StringBuilder lpBuffer,
int nSize,
IntPtr vaListArguments);
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetFileAttributes(string fileName);
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetFileSizeEx(SafeFileHandle handle, out LargeInteger size);
[DllImport("kernel32.dll")]
private static extern int GetFileType(SafeFileHandle handle);
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern SafeFileHandle CreateFile(
string name,
NativeFileAccess access,
FileShare share,
IntPtr security,
FileMode mode,
NativeFileFlags flags,
IntPtr template);
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteFile(string name);
[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BackupRead(
SafeFileHandle hFile,
ref Win32StreamId pBuffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
[MarshalAs(UnmanagedType.Bool)] bool abort,
[MarshalAs(UnmanagedType.Bool)] bool processSecurity,
ref IntPtr context);
[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BackupRead(
SafeFileHandle hFile,
SafeHGlobalHandle pBuffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
[MarshalAs(UnmanagedType.Bool)] bool abort,
[MarshalAs(UnmanagedType.Bool)] bool processSecurity,
ref IntPtr context);
[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BackupSeek(
SafeFileHandle hFile,
int bytesToSeekLow,
int bytesToSeekHigh,
out int bytesSeekedLow,
out int bytesSeekedHigh,
ref IntPtr context);
#endregion
#region Utility Structures
public struct Win32StreamInfo
{
public FileStreamType StreamType;
public FileStreamAttributes StreamAttributes;
public long StreamSize;
public string StreamName;
}
#endregion
#region Utility Methods
private static int MakeHRFromErrorCode(int errorCode)
{
return (-2147024896 | errorCode);
}
private static string GetErrorMessage(int errorCode)
{
var lpBuffer = new StringBuilder(0x200);
if (0 != FormatMessage(0x3200, IntPtr.Zero, errorCode, 0, lpBuffer, lpBuffer.Capacity, IntPtr.Zero))
{
return lpBuffer.ToString();
}
return string.Format(Resources.Culture, Resources.Error_UnknownError, errorCode);
}
private static void ThrowIOError(int errorCode, string path)
{
switch (errorCode)
{
case 0:
{
break;
}
case 2: // File not found
{
if (string.IsNullOrEmpty(path)) throw new FileNotFoundException();
throw new FileNotFoundException(null, path);
}
case 3: // Directory not found
{
if (string.IsNullOrEmpty(path)) throw new DirectoryNotFoundException();
throw new DirectoryNotFoundException(string.Format(Resources.Culture, Resources.Error_DirectoryNotFound, path));
}
case 5: // Access denied
{
if (string.IsNullOrEmpty(path)) throw new UnauthorizedAccessException();
throw new UnauthorizedAccessException(string.Format(Resources.Culture, Resources.Error_AccessDenied_Path, path));
}
case 15: // Drive not found
{
if (string.IsNullOrEmpty(path)) throw new DriveNotFoundException();
throw new DriveNotFoundException(string.Format(Resources.Culture, Resources.Error_DriveNotFound, path));
}
case 32: // Sharing violation
{
if (string.IsNullOrEmpty(path)) throw new IOException(GetErrorMessage(errorCode), MakeHRFromErrorCode(errorCode));
throw new IOException(string.Format(Resources.Culture, Resources.Error_SharingViolation, path), MakeHRFromErrorCode(errorCode));
}
case 80: // File already exists
{
if (!string.IsNullOrEmpty(path))
{
throw new IOException(string.Format(Resources.Culture, Resources.Error_FileAlreadyExists, path), MakeHRFromErrorCode(errorCode));
}
break;
}
case 87: // Invalid parameter
{
throw new IOException(GetErrorMessage(errorCode), MakeHRFromErrorCode(errorCode));
}
case 183: // File or directory already exists
{
if (!string.IsNullOrEmpty(path))
{
throw new IOException(string.Format(Resources.Culture, Resources.Error_AlreadyExists, path), MakeHRFromErrorCode(errorCode));
}
break;
}
case 206: // Path too long
{
throw new PathTooLongException();
}
case 995: // Operation cancelled
{
throw new OperationCanceledException();
}
default:
{
Marshal.ThrowExceptionForHR(MakeHRFromErrorCode(errorCode));
break;
}
}
}
public static void ThrowLastIOError(string path)
{
int errorCode = Marshal.GetLastWin32Error();
if (0 != errorCode)
{
int hr = Marshal.GetHRForLastWin32Error();
if (0 <= hr) throw new Win32Exception(errorCode);
ThrowIOError(errorCode, path);
}
}
public static NativeFileAccess ToNative(this FileAccess access)
{
NativeFileAccess result = 0;
if (FileAccess.Read == (FileAccess.Read & access)) result |= NativeFileAccess.GenericRead;
if (FileAccess.Write == (FileAccess.Write & access)) result |= NativeFileAccess.GenericWrite;
return result;
}
public static string BuildStreamPath(string filePath, string streamName)
{
string result = filePath;
if (!string.IsNullOrEmpty(filePath))
{
if (1 == result.Length) result = ".\\" + result;
result += StreamSeparator + streamName + StreamSeparator + "$DATA";
if (MaxPath <= result.Length) result = LongPathPrefix + result;
}
return result;
}
public static void ValidateStreamName(string streamName)
{
if (!string.IsNullOrEmpty(streamName) && -1 != streamName.IndexOfAny(InvalidStreamNameChars))
{
throw new ArgumentException(Resources.Error_InvalidFileChars);
}
}
public static int SafeGetFileAttributes(string name)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
int result = GetFileAttributes(name);
if (-1 == result)
{
int errorCode = Marshal.GetLastWin32Error();
if (ErrorFileNotFound != errorCode) ThrowLastIOError(name);
}
return result;
}
public static bool SafeDeleteFile(string name)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
bool result = DeleteFile(name);
if (!result)
{
int errorCode = Marshal.GetLastWin32Error();
if (ErrorFileNotFound != errorCode) ThrowLastIOError(name);
}
return result;
}
public static SafeFileHandle SafeCreateFile(string path, NativeFileAccess access, FileShare share, IntPtr security, FileMode mode, NativeFileFlags flags, IntPtr template)
{
SafeFileHandle result = CreateFile(path, access, share, security, mode, flags, template);
if (!result.IsInvalid && 1 != GetFileType(result))
{
result.Dispose();
throw new NotSupportedException(string.Format(Resources.Culture,
Resources.Error_NonFile, path));
}
return result;
}
private static long GetFileSize(string path, SafeFileHandle handle)
{
long result = 0L;
if (null != handle && !handle.IsInvalid)
{
LargeInteger value;
if (GetFileSizeEx(handle, out value))
{
result = value.ToInt64();
}
else
{
ThrowLastIOError(path);
}
}
return result;
}
public static long GetFileSize(string path)
{
long result = 0L;
if (!string.IsNullOrEmpty(path))
{
using (SafeFileHandle handle = SafeCreateFile(path, NativeFileAccess.GenericRead, FileShare.Read, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
{
result = GetFileSize(path, handle);
}
}
return result;
}
public static IList<Win32StreamInfo> ListStreams(string filePath)
{
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
if (-1 != filePath.IndexOfAny(Path.GetInvalidPathChars())) throw new ArgumentException(Resources.Error_InvalidFileChars, "filePath");
var result = new List<Win32StreamInfo>();
using (SafeFileHandle hFile = SafeCreateFile(filePath, NativeFileAccess.GenericRead, FileShare.Read, IntPtr.Zero, FileMode.Open, NativeFileFlags.BackupSemantics, IntPtr.Zero))
using (var hName = new StreamName())
{
if (!hFile.IsInvalid)
{
var streamId = new Win32StreamId();
int dwStreamHeaderSize = Marshal.SizeOf(streamId);
bool finished = false;
IntPtr context = IntPtr.Zero;
int bytesRead;
string name;
try
{
while (!finished)
{
// Read the next stream header:
if (!BackupRead(hFile, ref streamId, dwStreamHeaderSize, out bytesRead, false, false, ref context))
{
finished = true;
}
else if (dwStreamHeaderSize != bytesRead)
{
finished = true;
}
else
{
// Read the stream name:
if (0 >= streamId.StreamNameSize)
{
name = null;
}
else
{
hName.EnsureCapacity(streamId.StreamNameSize);
if (!BackupRead(hFile, hName.MemoryBlock, streamId.StreamNameSize, out bytesRead, false, false, ref context))
{
name = null;
finished = true;
}
else
{
// Unicode chars are 2 bytes:
name = hName.ReadStreamName(bytesRead >> 1);
}
}
// Add the stream info to the result:
if (!string.IsNullOrEmpty(name))
{
result.Add(new Win32StreamInfo
{
StreamType = (FileStreamType)streamId.StreamId,
StreamAttributes = (FileStreamAttributes)streamId.StreamAttributes,
StreamSize = streamId.Size.ToInt64(),
StreamName = name
});
}
// Skip the contents of the stream:
int bytesSeekedLow, bytesSeekedHigh;
if (!finished && !BackupSeek(hFile, streamId.Size.Low, streamId.Size.High, out bytesSeekedLow, out bytesSeekedHigh, ref context))
{
finished = true;
}
}
}
}
finally
{
// Abort the backup:
BackupRead(hFile, hName.MemoryBlock, 0, out bytesRead, true, false, ref context);
}
}
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.Runtime.InteropServices;
namespace Trinet.Core.IO.Ntfs
{
internal sealed class StreamName : IDisposable
{
#region Private Data
private static readonly SafeHGlobalHandle _invalidBlock = SafeHGlobalHandle.Invalid();
private SafeHGlobalHandle _memoryBlock = _invalidBlock;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="StreamName"/> class.
/// </summary>
public StreamName()
{
}
#endregion
#region Properties
/// <summary>
/// Returns the handle to the block of memory.
/// </summary>
/// <value>
/// The <see cref="SafeHGlobalHandle"/> representing the block of memory.
/// </value>
public SafeHGlobalHandle MemoryBlock
{
get { return _memoryBlock; }
}
#endregion
#region Methods
/// <summary>
/// Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
if (!_memoryBlock.IsInvalid)
{
_memoryBlock.Dispose();
_memoryBlock = _invalidBlock;
}
}
/// <summary>
/// Ensures that there is sufficient memory allocated.
/// </summary>
/// <param name="capacity">
/// The required capacity of the block, in bytes.
/// </param>
/// <exception cref="OutOfMemoryException">
/// There is insufficient memory to satisfy the request.
/// </exception>
public void EnsureCapacity(int capacity)
{
int currentSize = _memoryBlock.IsInvalid ? 0 : _memoryBlock.Size;
if (capacity > currentSize)
{
if (0 != currentSize) currentSize <<= 1;
if (capacity > currentSize) currentSize = capacity;
if (!_memoryBlock.IsInvalid) _memoryBlock.Dispose();
_memoryBlock = SafeHGlobalHandle.Allocate(currentSize);
}
}
/// <summary>
/// Reads the Unicode string from the memory block.
/// </summary>
/// <param name="length">
/// The length of the string to read, in characters.
/// </param>
/// <returns>
/// The string read from the memory block.
/// </returns>
public string ReadString(int length)
{
if (0 >= length || _memoryBlock.IsInvalid) return null;
if (length > _memoryBlock.Size) length = _memoryBlock.Size;
return Marshal.PtrToStringUni(_memoryBlock.DangerousGetHandle(), length);
}
/// <summary>
/// Reads the string, and extracts the stream name.
/// </summary>
/// <param name="length">
/// The length of the string to read, in characters.
/// </param>
/// <returns>
/// The stream name.
/// </returns>
public string ReadStreamName(int length)
{
string name = this.ReadString(length);
if (!string.IsNullOrEmpty(name))
{
// Name is of the format ":NAME:$DATA\0"
int separatorIndex = name.IndexOf(SafeNativeMethods.StreamSeparator, 1);
if (-1 != separatorIndex)
{
name = name.Substring(1, separatorIndex - 1);
}
else
{
// Should never happen!
separatorIndex = name.IndexOf('\0');
if (1 < separatorIndex)
{
name = name.Substring(1, separatorIndex - 1);
}
else
{
name = null;
}
}
}
return name;
}
#endregion
}
}

322
@integrate/WCFHost.cs Normal file
View File

@@ -0,0 +1,322 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Watchdog.WatchdogLib.Monitor;
using Watchdog.WatchdogLib.WinForms;
namespace Watchdog
{
/// <summary>
/// WCF Operations Contract in order to allow the command-line process
/// to communicate with the running Application's instance
/// </summary>
[ServiceContract]
public interface IWatchdog
{
#region Application State Changes
/// <summary>
/// Starts Monitoring
/// </summary>
[OperationContract]
void StartMonitoring();
/// <summary>
/// Pauses Monitoring
/// </summary>
[OperationContract]
void PauseMonitoring();
/// <summary>
/// Restarts Monitoring
/// </summary>
[OperationContract]
void RestartMonitoring();
/// <summary>
/// Restarts All Monitoring
/// </summary>
[OperationContract]
void RestartAllMonitoring();
/// <summary>
/// Stops Monitoring
/// </summary>
[OperationContract]
void StopMonitoring();
/// <summary>
/// Stops All Monitoring
/// </summary>
[OperationContract]
void StopAllMonitoring();
/// <summary>
/// Tell the Running Application to Reload the Configuration
/// </summary>
[OperationContract]
void ReloadConfigurationNextInterval();
#endregion
#region Ping
/// <summary>
/// To Check if we can communicate with the other side
/// </summary>
/// <returns>PING_RETURN_VALUE</returns>
[OperationContract]
int Ping();
#endregion
}
/// <summary>
/// Responsible for the WCF Callbacks
/// </summary>
public class WCFHost : IWatchdog
{
#region IWatchdog Members
/// <summary>
/// Starts Monitoring
/// </summary>
public void StartMonitoring()
{
HiddenMainWindow.StartMonitoring(true, true);
}
/// <summary>
/// Pauses Monitoring
/// </summary>
public void PauseMonitoring()
{
HiddenMainWindow.PauseMonitoring(true);
}
/// <summary>
/// Restarts Monitoring
/// </summary>
public void RestartMonitoring()
{
HiddenMainWindow.RestartMonitoring(4, true);
}
/// <summary>
/// Restarts All Monitoring
/// </summary>
public void RestartAllMonitoring()
{
HiddenMainWindow.RestartAllMonitoring(4, true);
}
/// <summary>
/// Stops Monitoring
/// </summary>
public void StopMonitoring()
{
HiddenMainWindow.StopMonitoring(true, false);
}
/// <summary>
/// Stops All Monitoring
/// </summary>
public void StopAllMonitoring()
{
HiddenMainWindow.StopAllMonitoring(true);
}
/// <summary>
/// Tell the Running Application to Reload the Configuration
/// </summary>
public void ReloadConfigurationNextInterval()
{
App.xmlfile.ForceRefreshOnNext_ReadData = true;
}
/// <summary>
/// Const Value to return on Ping
/// </summary>
public const int PING_RETURN_VALUE = 10;
/// <summary>
/// To Check if we can communicate with the other side
/// </summary>
/// <returns>PING_RETURN_VALUE</returns>
public int Ping()
{
return PING_RETURN_VALUE;
}
#endregion
#region Configuration Changes / Display Configuration Statics
/// <summary>
/// Adds a Process from the Configuration and saves the xml
/// </summary>
/// <param name="ProcessExeFileNameNPath">Process Exe File name</param>
/// <param name="CommandlinePrms">Command Line Prms for Process</param>
/// <param name="WorkingDir">Working Directory</param>
/// <returns>true if successfull, false otherwise</returns>
public static bool AddProcess(string ProcessExeFileNameNPath, string CommandlinePrms, string WorkingDir)
{
WatchdogConfiguration config = App.xmlfile.ReadData(false);
bool bSuccess = config.MonitoredProcesses.AddProcessExe(ProcessExeFileNameNPath, CommandlinePrms, WorkingDir);
if (bSuccess)
App.xmlfile.SaveData();
return bSuccess;
}
/// <summary>
/// Removes a Process from the Configuration and saves the xml
/// </summary>
/// <param name="ProcessExeFileNameNPath">Process Exe File name</param>
/// <param name="CommandlinePrms">Command Line Prms for Process</param>
/// <returns>true if successfully deleted a process with matching ProcessExeFileNameNPath and CommandlinePrms</returns>
public static bool RemoveProcess(string ProcessExeFileNameNPath, string CommandlinePrms)
{
WatchdogConfiguration config = App.xmlfile.ReadData(false);
bool bSuccess = config.MonitoredProcesses.RemoveProcessExe(ProcessExeFileNameNPath, CommandlinePrms);
if (bSuccess)
App.xmlfile.SaveData();
return bSuccess;
}
/// <summary>
/// Adds a Service from the configuration and saves the xml
/// </summary>
/// <param name="ServiceName">Name of Service</param>
/// <returns>true if sucessfull, false otherwise</returns>
public static bool AddService(string ServiceName)
{
WatchdogConfiguration config = App.xmlfile.ReadData(false);
bool bSuccess = config.MonitoredServices.AddServiceExe(ServiceName);
if (bSuccess)
App.xmlfile.SaveData();
return bSuccess;
}
/// <summary>
/// Removes a Service from the configuration and saves the xml
/// </summary>
/// <param name="ServiceName">Name of Service</param>
/// <returns>true if sucessfull, false otherwise</returns>
public static bool RemoveService(string ServiceName)
{
WatchdogConfiguration config = App.xmlfile.ReadData(false);
bool bSuccess = config.MonitoredServices.RemoveServiceExe(ServiceName);
if (bSuccess)
App.xmlfile.SaveData();
return bSuccess;
}
/// <summary>
/// Returns an array of all Processes and their configurations (in a ';' seperated string)
/// </summary>
/// <returns>Process List with configuration</returns>
public static string[] ShowProcesses()
{
List<string> ProcessList = new List<String>();
WatchdogConfiguration config = App.xmlfile.ReadData(false);
string s = String.Empty;
foreach (WatchdogConfiguration.ProcessExe p in config.MonitoredProcesses.ProcessExes)
{
if (String.IsNullOrEmpty(p.CommandLinePrms) && String.IsNullOrEmpty(p.WorkingDirectory))
s = p.ProcessExeFileNameNPath;
else if (!String.IsNullOrEmpty(p.CommandLinePrms) && String.IsNullOrEmpty(p.WorkingDirectory))
s = p.ProcessExeFileNameNPath + ";" + p.CommandLinePrms;
else if (!String.IsNullOrEmpty(p.CommandLinePrms) && !String.IsNullOrEmpty(p.WorkingDirectory))
s = p.ProcessExeFileNameNPath + ";" + p.CommandLinePrms + ";" + p.WorkingDirectory;
else
continue;
ProcessList.Add(s);
}
return ProcessList.ToArray();
}
/// <summary>
/// Returns an array of all Services
/// </summary>
/// <returns>Services List</returns>
public static string[] ShowServices()
{
List<string> ProcessList = new List<String>();
WatchdogConfiguration config = App.xmlfile.ReadData(false);
foreach (WatchdogConfiguration.ServiceExe s in config.MonitoredServices.ServiceExes)
ProcessList.Add(s.Name);
return ProcessList.ToArray();
}
#endregion
#region Internal Statics
private static ServiceHost _host = null;
/// <summary>
/// Start the WCF Pipe Host (Watchdog)
/// </summary>
internal static void StartHost()
{
// Make sure it is closed
StopHost();
_host = new ServiceHost(typeof(WCFHost), new Uri[] { new Uri("net.pipe://localhost") });
_host.AddServiceEndpoint(typeof(IWatchdog), new NetNamedPipeBinding(), AppResx.GetString("APPLICATION_NAME_SHORT"));
try
{
_host.Open();
}
catch (Exception e)
{
App.log.Fatal("Unable to start WCF Pipe Host", e);
MsgBox.ShowFatalError("Unable to start WCF Pipe Host", "Pipe Host Failure", System.Windows.Forms.MessageBoxButtons.OK);
App.Current.Shutdown();
}
}
/// <summary>
/// Stop the WCF Pipe Host
/// </summary>
internal static void StopHost()
{
if (_host != null)
{
_host.Close();
_host = null;
}
}
/// <summary>
/// Called by Client to communicate with the server
/// </summary>
/// <returns>a valid IWatchDog Object or Null if error occured</returns>
internal static IWatchdog GetWatchDogClientInterface()
{
// We only should be calling this in CommandLine Mode.
if (App.State_SpecialMode_IsCommandLineSet())
{
try
{
IWatchdog watchdoginterface = null;
ChannelFactory<IWatchdog> iwatchdogFactory = new ChannelFactory<IWatchdog>(new NetNamedPipeBinding(), new EndpointAddress(("net.pipe://localhost/" + AppResx.GetString("APPLICATION_NAME_SHORT"))));
watchdoginterface = iwatchdogFactory.CreateChannel();
// Try to ping the object! ~if it fails, target object doesn't exist
if (watchdoginterface.Ping() == WCFHost.PING_RETURN_VALUE)
return watchdoginterface;
}
catch (Exception)
{
// * Ignore this error we don't want to log this*
//App.log.Error("Failed to obtain WatchDogClientInterface", e);
}
}
return null;
}
#endregion
}
}