context: using System;
  using System.Diagnostics;
  using System.IO;
  using System.Reflection;
  using System.Runtime.InteropServices;
  
  namespace JocysCom.ClassLibrary.Configuration
  {
  	public partial class AssemblyInfo
  	{
  
  		public AssemblyInfo()
  		{
  			Assembly =
  				Assembly.GetEntryAssembly() ??
  				FindEntryAssembly1() ??
  				FindEntryAssembly2() ??
  				Assembly.GetCallingAssembly() ??
  				Assembly.GetExecutingAssembly();
  		}
  
  		public static AssemblyInfo _Entry;
  		public static object _EntryLock = new object();
  		public static AssemblyInfo Entry
  		{
  			get
  			{
  				lock (_EntryLock)
  				{
  					if (_Entry == null)
  						_Entry = new AssemblyInfo();
  					return _Entry;
  				}
  			}
  		}
  
  		public static string ExpandPath(string path)
  		{
  			path = Environment.ExpandEnvironmentVariables(path);
  			path = JocysCom.ClassLibrary.Text.Helper.Replace(path, Entry, false);
  			return path;
  		}
  
  		public AssemblyInfo(string strValFile)
  		{
  			Assembly = Assembly.LoadFile(strValFile);
  		}
  
  		public AssemblyInfo(Assembly assembly)
  		{
  			Assembly = assembly;
  		}
  
  		#region Entry assembly
  
  		/// <summary>
  		/// Assembly.GetEntryAssembly() returns null in web applications. Mark assembly as the entry assembly
  		/// by adding this attribute inside Properties\AssemblyInfo.cs file:
  		/// [assembly: JocysCom.ClassLibrary.Configuration.AssemblyInfo.EntryAssembly]
  		/// </summary>
  		[AttributeUsage(AttributeTargets.Assembly)]
  		public sealed class EntryAssemblyAttribute : Attribute { }
  
  		// Method 1 better works on multiple assemblies marked as entry.
  		Assembly FindEntryAssembly1()
  		{
  			var frames = new StackTrace().GetFrames();
  			Array.Reverse(frames);
  			foreach (var frame in frames)
  			{
  				var declaringType = frame.GetMethod().DeclaringType;
  				var assembly = Assembly.GetAssembly(declaringType);
  				var attribute = assembly.GetCustomAttributes(typeof(EntryAssemblyAttribute), false);
  				if (attribute.Length > 0)
  					return assembly;
  			}
  			return null;
  		}
  
  
  		// Find on current domain.
  		Assembly FindEntryAssembly2()
  		{
  			var assemblies = AppDomain.CurrentDomain.GetAssemblies();
  			foreach (var assembly in assemblies)
  			{
  				var attribute = assembly.GetCustomAttributes(typeof(EntryAssemblyAttribute), false);
  				if (attribute.Length > 0)
  					return assembly;
  			}
  			return null;
  		}
  
  		#endregion
  
  		public Assembly Assembly { get; set; }
  
  		DateTime? _BuildDateTime;
  		object BuildDateTimeLock = new object();
  
  		public DateTime BuildDateTime
  		{
  			get
  			{
  				lock (BuildDateTimeLock)
  				{
  					if (!_BuildDateTime.HasValue)
  						_BuildDateTime = GetBuildDateTime(Assembly);
  					return _BuildDateTime.Value;
  				}
  			}
  		}
  
  		object FullTitleLock = new object();
  		string _FullTitle;
  		public string FullTitle
  		{
  			get
  			{
  				lock (FullTitleLock)
  				{
  					if (string.IsNullOrEmpty(_FullTitle))
  						_FullTitle = GetTitle();
  					return _FullTitle;
  				}
  			}
  		}
  
  		public string RunMode
  		{
  			get
  			{
  				if (_RunMode == null)
  					_RunMode = SettingsParser.Current.Parse("RunMode", "");
  				return _RunMode;
  			}
  		}
  		public string _RunMode;
  
  		public string GetTitle(bool showBuild = true, bool showRunMode = true, bool showBuildDate = true, bool showArchitecture = true, bool showDescription = true, int versionNumbers = 3)
  		{
  			var s = string.Format("{0} {1} {2}", Company, Product, this.Version.ToString(versionNumbers));
  			if (showBuild)
  			{
  				// Version = major.minor.build.revision
  				switch (this.Version.Build)
  				{
  					case 0: s += " Alpha"; break;  // Alpha Release (AR)
  					case 1: s += " Beta 1"; break; // Master Beta (MB)
  					case 2: s += " Beta 2"; break; // Feature Complete (FC)
  					case 3: s += " Beta 3"; break; // Technical Preview (TP)
  					case 4: s += " RC"; break;     // Release Candidate (RC)
  					case 5: s += " RTM"; break;    // Release to Manufacturing (RTM)
  					default: break;                // General Availability (GA) - Gold
  				}
  			}
  			
  			var haveRunMode = !string.IsNullOrEmpty(RunMode);
  			// If run mode is not specified then assume live.
  			var nonLive = haveRunMode && string.Compare(RunMode, "LIVE", true) != 0;
  			if (showBuildDate || (showRunMode && nonLive))
  			{
  				s += " (";
  				if (showRunMode && nonLive)
  				{
  					s += string.Format("{0}", RunMode);
  					if (showBuildDate) s += " ";
  				}
  				if (showBuildDate)
  				{
  					s += string.Format("Build: {0:yyyy-MM-dd}", BuildDateTime);
  				}
  				s += ")";
  			}
  			if (showArchitecture)
  			{
  				switch ((Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()).GetName().ProcessorArchitecture)
  				{
  					case ProcessorArchitecture.Amd64:
  					case ProcessorArchitecture.IA64:
  						s += " 64-bit";
  						break;
  					case ProcessorArchitecture.X86:
  						s += " 32-bit";
  						break;
  					default: // Default is MSIL: Any CPU, show nothing/
  						break;
  				}
  			}
  			if (showDescription && !string.IsNullOrEmpty(Description) && !s.Contains(Description))
  			{
  				s += " - " + Description;
  			}
  
  #if NETSTANDARD // .NET Standard
  #elif NETCOREAPP // .NET Core
  #else // .NET Framework
  
  			// Add elevated tag.
  			var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
  			var isElevated = identity.Owner != identity.User;
  			// Add running user.
  			string windowsDomain = GetWindowsDomainName();
  			string windowsUser = GetWindowsUserName();
  			string processDomain = Environment.UserDomainName;
  			string processUser = Environment.UserName;
  			if (string.Compare(windowsDomain, processDomain, true) != 0 || string.Compare(windowsUser, processUser, true) != 0)
  				s += string.Format(" ({0}\\{1})", processDomain, processUser);
  			else if (isElevated)
  				s += " (Administrator)";
  			// if (WinAPI.IsVista && WinAPI.IsElevated() && WinAPI.IsInAdministratorRole) this.Text += " (Administrator)";
  #endif
  			return s.Trim();
  		}
  
  #if NETSTANDARD // .NET Standard
  #elif NETCOREAPP // .NET Core
  #else // .NET Framework
  
  		internal partial class NativeMethods
  		{
  			[DllImport("wtsapi32.dll")]
  			internal static extern bool WTSQuerySessionInformationW(
  				IntPtr hServer,
  				int SessionId,
  				int WTSInfoClass,
  				out IntPtr ppBuffer,
  				out IntPtr pBytesReturned
  			);
  
  		}
  
  		public string GetWindowsDomainName() { return GetInformation(7); }
  
  		public string GetWindowsUserName() { return GetInformation(5); }
  
  		private static string GetInformation(int WTSInfoClass)
  		{
  			// Use current context.
  			var WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
  
gt: 			var p = System.Diagnostics.Process.GetCurrentProcess();