csharp/askguanyu/DevLib/Source/DevLib.AddIn.NET20/Resources/Program.cs

Resources
Program.cs
//-----------------------------------------------------------------------
// 
//     Copyright (c) YuGuan Corporation. All rights reserved.
// 
//-----------------------------------------------------------------------
namespace DevLib.AddIn
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Diagnostics.Codeastysis;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading;

    /// 
    /// Clast Program.
    /// 
    [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "Reviewed.")]
    [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "Reviewed.")]
    internal clast Program
    {
        /// 
        /// Method Main, entry point.
        /// 
        /// Command line arguments.
        private static void Main(string[] args)
        {
            //// args[0] = AddInDomain astembly path
            //// args[1] = GUID
            //// args[2] = PID
            //// args[3] = AddInDomainSetup file
            //// args[4] = Redirect output or not

            if (args.Length < 4)
            {
                ProgramInternalLogger.Log(true, new ArgumentNullException("args"));

                Console.WriteLine(@"
args[0] = AddInDomain astembly path
args[1] = GUID
args[2] = PID
args[3] = AddInDomainSetup file
args[4] = Redirect output or not");

                return;
            }

            bool redirectOutput = false;

            bool.TryParse(args[4], out redirectOutput);

            try
            {
                ProgramInternalLogger.Log(redirectOutput, "AddInDomain is started");
                ProgramInternalLogger.Log(redirectOutput, Environment.CommandLine);

                Dictionary resolveDict = new Dictionary();
                resolveDict.Add(new astemblyName("$[AddInastemblyName]"), args[0]);

                astemblyResolver resolver = new astemblyResolver(resolveDict);

                resolver.Mount();

                Type hostType = Type.GetType("$[AddInActivatorHostTypeName]");

                if (hostType != null)
                {
                    ProgramInternalLogger.Log(redirectOutput, "Succeeded: Type.GetType($[AddInActivatorHostTypeName])");
                }
                else
                {
                    ProgramInternalLogger.Log(redirectOutput, string.Format("Could not load AddInActivatorHost type $[AddInActivatorHostTypeName] by using resolver with $[AddInastemblyName] mapped to {0}", args[0]));
                    throw new TypeLoadException(string.Format("Could not load AddInActivatorHost type $[AddInActivatorHostTypeName] by using resolver with $[AddInastemblyName] mapped to {0}", args[0]));
                }

                MethodInfo methodInfo = hostType.GetMethod("Run", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string[]) }, null);

                if (methodInfo != null)
                {
                    ProgramInternalLogger.Log(redirectOutput, "Succeeded: GetMethod on AddInActivatorHost");
                }
                else
                {
                    ProgramInternalLogger.Log(redirectOutput, "'Run' method on AddInActivatorHost was not found.");
                    throw new Exception("'Run' method on AddInActivatorHost was not found.");
                }

                ProgramInternalLogger.Log(redirectOutput, "Begin Invoke AddInActivatorHost method.");

                methodInfo.Invoke(null, new object[] { args });
            }
            catch (Exception e)
            {
                ProgramInternalLogger.Log(redirectOutput, string.Format("Summary: Failed to launch AddInActivatorHost:\r\n{0}", e.ToString()));
            }
        }
    }

    /// 
    /// Clast astemblyResolver.
    /// 
    [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClast", Justification = "Reviewed.")]
    public clast astemblyResolver : MarshalByRefObject
    {
        /// 
        /// Readonly Field _astemblyDictionary.
        /// 
        private readonly Dictionary _astemblyDictionary;

        /// 
        /// Initializes a new instance of the  clast.
        /// 
        /// Instance of Dictionary.
        public astemblyResolver(Dictionary dict)
        {
            this._astemblyDictionary = new Dictionary();

            if (dict != null)
            {
                foreach (KeyValuePair item in dict)
                {
                    Dictionary subDict;

                    if (!this._astemblyDictionary.TryGetValue(item.Key.Name, out subDict))
                    {
                        this._astemblyDictionary[item.Key.Name] = subDict = new Dictionary();
                    }

                    subDict[item.Key] = item.Value;
                }
            }
        }

        /// 
        /// Gives the  an infinite lifetime by preventing a lease from being created.
        /// 
        /// The operation is attempted on an unloaded application domain.
        /// Always null.
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
        public override object InitializeLifetimeService()
        {
            return null;
        }

        /// 
        /// Subscribe events.
        /// 
        [EnvironmentPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
        public void Mount()
        {
            AppDomain.CurrentDomain.astemblyResolve += this.Resolve;
            AppDomain.CurrentDomain.ReflectionOnlyastemblyResolve += this.ReflectionOnlyResolve;
        }

        /// 
        /// Unsubscribe events.
        /// 
        [EnvironmentPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
        public void Unmount()
        {
            AppDomain.CurrentDomain.astemblyResolve -= this.Resolve;
            AppDomain.CurrentDomain.ReflectionOnlyastemblyResolve -= this.ReflectionOnlyResolve;
        }

        /// 
        /// Static Method PublicKeysTokenEqual.
        /// 
        /// Left token.
        /// Right token.
        /// true if equals; otherwise, false.
        private static bool PublicKeysTokenEqual(byte[] left, byte[] right)
        {
            if (left == null || right == null)
            {
                return left == right;
            }

            if (left.Length != right.Length)
            {
                return false;
            }

            for (int i = 0; i < left.Length; i++)
            {
                if (left[i] != right[i])
                {
                    return false;
                }
            }

            return true;
        }

        /// 
        /// Method Resolve.
        /// 
        /// Event sender.
        /// Instance of ResolveEventArgs.
        /// Instance of astembly.
        private astembly Resolve(object sender, ResolveEventArgs args)
        {
            string astemblyFile = this.FindastemblyName(args.Name);

            if (astemblyFile != null)
            {
                return astembly.LoadFrom(astemblyFile);
            }

            return null;
        }

        /// 
        /// Method ReflectionOnlyResolve.
        /// 
        /// Event sender.
        /// Instance of ResolveEventArgs.
        /// Instance of astembly.
        private astembly ReflectionOnlyResolve(object sender, ResolveEventArgs args)
        {
            string astemblyFile = this.FindastemblyName(args.Name);

            if (astemblyFile != null)
            {
                return astembly.ReflectionOnlyLoadFrom(astemblyFile);
            }

            return null;
        }

        /// 
        /// Method FindastemblyName.
        /// 
        /// The display name of the astembly, as returned by the  property.
        /// astemblyName string.
        private string FindastemblyName(string name)
        {
            astemblyName astemblyName = new astemblyName(name);
            Dictionary subDict;

            if (!this._astemblyDictionary.TryGetValue(astemblyName.Name, out subDict))
            {
                return null;
            }

            foreach (KeyValuePair item in subDict)
            {
                if (astemblyName.Version != null && !astemblyName.Version.Equals(item.Key.Version))
                {
                    continue;
                }

                if (astemblyName.CultureInfo != null && !astemblyName.CultureInfo.Equals(item.Key.CultureInfo))
                {
                    continue;
                }

                if (!PublicKeysTokenEqual(astemblyName.GetPublicKeyToken(), item.Key.GetPublicKeyToken()))
                {
                    continue;
                }

                return item.Value;
            }

            return null;
        }
    }

    /// 
    /// Program internal logger.
    /// 
    [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClast", Justification = "Reviewed.")]
    internal static clast ProgramInternalLogger
    {
        /// 
        /// Field Executingastembly.
        /// 
        private static readonly string Executingastembly = Path.GetFullPath(new Uri(astembly.GetExecutingastembly().CodeBase).LocalPath);

        /// 
        /// Field GlobalDebugFlagFile.
        /// 
        private static readonly string GlobalDebugFlagFile = Path.Combine(Path.GetDirectoryName(Executingastembly), "DevLib#Debug");

        /// 
        /// Field DebugFlagFile.
        /// 
        private static readonly string DebugFlagFile = Executingastembly + "#Debug";

        /// 
        /// Field LogFile.
        /// 
        private static readonly string LogFile = Executingastembly + ".log";

        /// 
        /// Field LogFileBackup.
        /// 
        private static readonly string LogFileBackup = Path.ChangeExtension(LogFile, ".log.bak");

        /// 
        /// Field SyncRoot.
        /// 
        private static readonly object SyncRoot = new object();

        /// 
        /// Method Log.
        /// 
        /// Redirect output to current console or not.
        /// Diagnostic messages or objects to log.
        public static void Log(bool redirectOutput, params object[] objs)
        {
#if DEBUG
            if (objs != null)
            {
                lock (SyncRoot)
                {
                    if (objs != null)
                    {
                        try
                        {
                            string message = RenderLog(objs);
                            Debug.WriteLine(message);

                            if (redirectOutput)
                            {
                                Console.WriteLine(message);
                            }

                            AppendToFile(message);
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine(e.ToString());
                            Console.WriteLine(e.ToString());
                        }
                    }
                }
            }
#else
            if (File.Exists(GlobalDebugFlagFile) || File.Exists(DebugFlagFile))
            {
                if (objs != null)
                {
                    lock (SyncRoot)
                    {
                        if (objs != null)
                        {
                            try
                            {
                                string message = RenderLog(objs);

                                if (redirectOutput)
                                {
                                    Console.WriteLine(message);
                                }

                                AppendToFile(message);
                            }
                            catch
                            {
                            }
                        }
                    }
                }
            }
#endif
        }

        /// 
        /// Builds a readable representation of the stack trace.
        /// 
        /// The number of frames up the stack to skip.
        /// A readable representation of the stack trace.
        public static string GetStackFrameInfo(int skipFrames)
        {
            StackFrame stackFrame = new StackFrame(skipFrames < 1 ? 1 : skipFrames + 1, true);

            MethodBase method = stackFrame.GetMethod();

            if (method != null)
            {
                StringBuilder result = new StringBuilder();

                result.Append(method.Name);

                if (method is MethodInfo && ((MethodInfo)method).IsGenericMethod)
                {
                    Type[] genericArguments = ((MethodInfo)method).GetGenericArguments();

                    result.Append("");
                }

                result.Append(" in ");
                result.Append(Path.GetFileName(stackFrame.GetFileName()) ?? "");
                result.Append(":");
                result.Append(stackFrame.GetFileLineNumber());

                return result.ToString();
            }
            else
            {
                return "";
            }
        }

        /// 
        /// Render parameters into a string.
        /// 
        /// Diagnostic messages or objects to log.
        /// The rendered layout string.
        private static string RenderLog(object[] objs)
        {
            StringBuilder result = new StringBuilder();

            result.Append(DateTimeOffset.Now.ToString("o", CultureInfo.InvariantCulture));
            result.Append("|INTL|");
            result.Append(Environment.UserName);
            result.Append("|");
            result.Append(Thread.CurrentThread.ManagedThreadId.ToString("000"));
            result.Append("|");

            if (objs != null && objs.Length > 0)
            {
                foreach (object item in objs)
                {
                    result.Append(" [");
                    result.Append(item == null ? string.Empty : item.ToString());
                    result.Append("]");
                }
            }

            result.Append(" |");
            result.Append(GetStackFrameInfo(2));
            result.Append(Environment.NewLine);

            return result.ToString();
        }

        /// 
        /// Append log message to the file.
        /// 
        /// Log message to append.
        private static void AppendToFile(string message)
        {
            try
            {
            }
            finally
            {
                FileStream fileStream = null;

                try
                {
                    fileStream = new FileStream(LogFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete);

                    if (fileStream.Length > 10485760)
                    {
                        try
                        {
                            File.Copy(LogFile, LogFileBackup, true);
                        }
                        catch
                        {
                        }

                        fileStream.SetLength(0);
                    }

                    byte[] bytes = Encoding.UTF8.GetBytes(message);

                    fileStream.Seek(0, SeekOrigin.End);
                    fileStream.Write(bytes, 0, bytes.Length);
                    fileStream.Flush();
                }
                catch
                {
                }
                finally
                {
                    if (fileStream != null)
                    {
                        fileStream.Dispose();
                        fileStream = null;
                    }
                }
            }
        }
    }
}