12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328 |
- #region Apache License
- //
- // Licensed to the Apache Software Foundation (ASF) under one or more
- // contributor license agreements. See the NOTICE file distributed with
- // this work for additional information regarding copyright ownership.
- // The ASF licenses this file to you under the Apache License, Version 2.0
- // (the "License"); you may not use this file except in compliance with
- // the License. You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- #endregion
- using System;
- #if NETSTANDARD1_3
- using System.Globalization;
- #else
- using System.Configuration;
- #endif
- using System.Reflection;
- using System.Text;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Collections;
- namespace log4net.Util
- {
- /// <summary>
- /// Utility class for system specific information.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Utility class of static methods for system specific information.
- /// </para>
- /// </remarks>
- /// <author>Nicko Cadell</author>
- /// <author>Gert Driesen</author>
- /// <author>Alexey Solofnenko</author>
- public sealed class SystemInfo
- {
- #region Private Constants
- private const string DEFAULT_NULL_TEXT = "(null)";
- private const string DEFAULT_NOT_AVAILABLE_TEXT = "NOT AVAILABLE";
- #endregion
- #region Private Instance Constructors
- /// <summary>
- /// Private constructor to prevent instances.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Only static methods are exposed from this type.
- /// </para>
- /// </remarks>
- private SystemInfo()
- {
- }
- #endregion Private Instance Constructors
- #region Public Static Constructor
- /// <summary>
- /// Initialize default values for private static fields.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Only static methods are exposed from this type.
- /// </para>
- /// </remarks>
- static SystemInfo()
- {
- string nullText = DEFAULT_NULL_TEXT;
- string notAvailableText = DEFAULT_NOT_AVAILABLE_TEXT;
- #if !NETCF
- // Look for log4net.NullText in AppSettings
- string nullTextAppSettingsKey = SystemInfo.GetAppSetting("log4net.NullText");
- if (nullTextAppSettingsKey != null && nullTextAppSettingsKey.Length > 0)
- {
- LogLog.Debug(declaringType, "Initializing NullText value to [" + nullTextAppSettingsKey + "].");
- nullText = nullTextAppSettingsKey;
- }
- // Look for log4net.NotAvailableText in AppSettings
- string notAvailableTextAppSettingsKey = SystemInfo.GetAppSetting("log4net.NotAvailableText");
- if (notAvailableTextAppSettingsKey != null && notAvailableTextAppSettingsKey.Length > 0)
- {
- LogLog.Debug(declaringType, "Initializing NotAvailableText value to [" + notAvailableTextAppSettingsKey + "].");
- notAvailableText = notAvailableTextAppSettingsKey;
- }
- #endif
- s_notAvailableText = notAvailableText;
- s_nullText = nullText;
- }
- #endregion
- #region Public Static Properties
- /// <summary>
- /// Gets the system dependent line terminator.
- /// </summary>
- /// <value>
- /// The system dependent line terminator.
- /// </value>
- /// <remarks>
- /// <para>
- /// Gets the system dependent line terminator.
- /// </para>
- /// </remarks>
- public static string NewLine
- {
- get
- {
- #if NETCF
- return "\r\n";
- #else
- return System.Environment.NewLine;
- #endif
- }
- }
- /// <summary>
- /// Gets the base directory for this <see cref="AppDomain"/>.
- /// </summary>
- /// <value>The base directory path for the current <see cref="AppDomain"/>.</value>
- /// <remarks>
- /// <para>
- /// Gets the base directory for this <see cref="AppDomain"/>.
- /// </para>
- /// <para>
- /// The value returned may be either a local file path or a URI.
- /// </para>
- /// </remarks>
- public static string ApplicationBaseDirectory
- {
- get
- {
- #if NETCF
- - return System.IO.Path.GetDirectoryName(SystemInfo.EntryAssemblyLocation) + System.IO.Path.DirectorySeparatorChar;
- #elif NETSTANDARD1_3
- return Directory.GetCurrentDirectory();
- #else
- return AppDomain.CurrentDomain.BaseDirectory;
- #endif
- }
- }
- /// <summary>
- /// Gets the path to the configuration file for the current <see cref="AppDomain"/>.
- /// </summary>
- /// <value>The path to the configuration file for the current <see cref="AppDomain"/>.</value>
- /// <remarks>
- /// <para>
- /// The .NET Compact Framework 1.0 does not have a concept of a configuration
- /// file. For this runtime, we use the entry assembly location as the root for
- /// the configuration file name.
- /// </para>
- /// <para>
- /// The value returned may be either a local file path or a URI.
- /// </para>
- /// </remarks>
- public static string ConfigurationFileLocation
- {
- get
- {
- #if NETCF || NETSTANDARD1_3
- return SystemInfo.EntryAssemblyLocation+".config";
- #else
- return System.AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
- #endif
- }
- }
- /// <summary>
- /// Gets the path to the file that first executed in the current <see cref="AppDomain"/>.
- /// </summary>
- /// <value>The path to the entry assembly.</value>
- /// <remarks>
- /// <para>
- /// Gets the path to the file that first executed in the current <see cref="AppDomain"/>.
- /// </para>
- /// </remarks>
- public static string EntryAssemblyLocation
- {
- get
- {
- #if NETCF
- return SystemInfo.NativeEntryAssemblyLocation;
- #elif NETSTANDARD1_3 // TODO GetEntryAssembly is available for netstandard1.5
- return AppContext.BaseDirectory;
- #else
- return System.Reflection.Assembly.GetEntryAssembly().Location;
- #endif
- }
- }
- /// <summary>
- /// Gets the ID of the current thread.
- /// </summary>
- /// <value>The ID of the current thread.</value>
- /// <remarks>
- /// <para>
- /// On the .NET framework, the <c>AppDomain.GetCurrentThreadId</c> method
- /// is used to obtain the thread ID for the current thread. This is the
- /// operating system ID for the thread.
- /// </para>
- /// <para>
- /// On the .NET Compact Framework 1.0 it is not possible to get the
- /// operating system thread ID for the current thread. The native method
- /// <c>GetCurrentThreadId</c> is implemented inline in a header file
- /// and cannot be called.
- /// </para>
- /// <para>
- /// On the .NET Framework 2.0 the <c>Thread.ManagedThreadId</c> is used as this
- /// gives a stable id unrelated to the operating system thread ID which may
- /// change if the runtime is using fibers.
- /// </para>
- /// </remarks>
- public static int CurrentThreadId
- {
- get
- {
- #if NETCF_1_0
- return System.Threading.Thread.CurrentThread.GetHashCode();
- #elif NET_2_0 || NETCF_2_0 || MONO_2_0 || MONO_3_5 || MONO_4_0 || NETSTANDARD1_3
- return System.Threading.Thread.CurrentThread.ManagedThreadId;
- #else
- return AppDomain.GetCurrentThreadId();
- #endif
- }
- }
- /// <summary>
- /// Get the host name or machine name for the current machine
- /// </summary>
- /// <value>
- /// The hostname or machine name
- /// </value>
- /// <remarks>
- /// <para>
- /// Get the host name or machine name for the current machine
- /// </para>
- /// <para>
- /// The host name (<see cref="System.Net.Dns.GetHostName"/>) or
- /// the machine name (<c>Environment.MachineName</c>) for
- /// the current machine, or if neither of these are available
- /// then <c>NOT AVAILABLE</c> is returned.
- /// </para>
- /// </remarks>
- public static string HostName
- {
- get
- {
- if (s_hostName == null)
- {
- // Get the DNS host name of the current machine
- try
- {
- // Lookup the host name
- s_hostName = System.Net.Dns.GetHostName();
- }
- catch (System.Net.Sockets.SocketException)
- {
- LogLog.Debug(declaringType, "Socket exception occurred while getting the dns hostname. Error Ignored.");
- }
- catch (System.Security.SecurityException)
- {
- // We may get a security exception looking up the hostname
- // You must have Unrestricted DnsPermission to access resource
- LogLog.Debug(declaringType, "Security exception occurred while getting the dns hostname. Error Ignored.");
- }
- catch (Exception ex)
- {
- LogLog.Debug(declaringType, "Some other exception occurred while getting the dns hostname. Error Ignored.", ex);
- }
- // Get the NETBIOS machine name of the current machine
- if (s_hostName == null || s_hostName.Length == 0)
- {
- try
- {
- #if NETSTANDARD1_3
- s_hostName = Environment.GetEnvironmentVariable("COMPUTERNAME");
- #elif (!SSCLI && !NETCF)
- s_hostName = Environment.MachineName;
- #endif
- }
- catch(InvalidOperationException)
- {
- }
- catch(System.Security.SecurityException)
- {
- // We may get a security exception looking up the machine name
- // You must have Unrestricted EnvironmentPermission to access resource
- }
- }
- // Couldn't find a value
- if (s_hostName == null || s_hostName.Length == 0)
- {
- s_hostName = s_notAvailableText;
- LogLog.Debug(declaringType, "Could not determine the hostname. Error Ignored. Empty host name will be used");
- }
- }
- return s_hostName;
- }
- }
- /// <summary>
- /// Get this application's friendly name
- /// </summary>
- /// <value>
- /// The friendly name of this application as a string
- /// </value>
- /// <remarks>
- /// <para>
- /// If available the name of the application is retrieved from
- /// the <c>AppDomain</c> using <c>AppDomain.CurrentDomain.FriendlyName</c>.
- /// </para>
- /// <para>
- /// Otherwise the file name of the entry assembly is used.
- /// </para>
- /// </remarks>
- public static string ApplicationFriendlyName
- {
- get
- {
- if (s_appFriendlyName == null)
- {
- try
- {
- #if !(NETCF || NETSTANDARD1_3)
- s_appFriendlyName = AppDomain.CurrentDomain.FriendlyName;
- #endif
- }
- catch(System.Security.SecurityException)
- {
- // This security exception will occur if the caller does not have
- // some undefined set of SecurityPermission flags.
- LogLog.Debug(declaringType, "Security exception while trying to get current domain friendly name. Error Ignored.");
- }
- if (s_appFriendlyName == null || s_appFriendlyName.Length == 0)
- {
- try
- {
- string assemblyLocation = SystemInfo.EntryAssemblyLocation;
- s_appFriendlyName = System.IO.Path.GetFileName(assemblyLocation);
- }
- catch(System.Security.SecurityException)
- {
- // Caller needs path discovery permission
- }
- }
- if (s_appFriendlyName == null || s_appFriendlyName.Length == 0)
- {
- s_appFriendlyName = s_notAvailableText;
- }
- }
- return s_appFriendlyName;
- }
- }
- /// <summary>
- /// Get the start time for the current process.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This is the time at which the log4net library was loaded into the
- /// AppDomain. Due to reports of a hang in the call to <c>System.Diagnostics.Process.StartTime</c>
- /// this is not the start time for the current process.
- /// </para>
- /// <para>
- /// The log4net library should be loaded by an application early during its
- /// startup, therefore this start time should be a good approximation for
- /// the actual start time.
- /// </para>
- /// <para>
- /// Note that AppDomains may be loaded and unloaded within the
- /// same process without the process terminating, however this start time
- /// will be set per AppDomain.
- /// </para>
- /// </remarks>
- [Obsolete("Use ProcessStartTimeUtc and convert to local time if needed.")]
- public static DateTime ProcessStartTime
- {
- get { return s_processStartTimeUtc.ToLocalTime(); }
- }
- /// <summary>
- /// Get the UTC start time for the current process.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This is the UTC time at which the log4net library was loaded into the
- /// AppDomain. Due to reports of a hang in the call to <c>System.Diagnostics.Process.StartTime</c>
- /// this is not the start time for the current process.
- /// </para>
- /// <para>
- /// The log4net library should be loaded by an application early during its
- /// startup, therefore this start time should be a good approximation for
- /// the actual start time.
- /// </para>
- /// <para>
- /// Note that AppDomains may be loaded and unloaded within the
- /// same process without the process terminating, however this start time
- /// will be set per AppDomain.
- /// </para>
- /// </remarks>
- public static DateTime ProcessStartTimeUtc
- {
- get { return s_processStartTimeUtc; }
- }
- /// <summary>
- /// Text to output when a <c>null</c> is encountered.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Use this value to indicate a <c>null</c> has been encountered while
- /// outputting a string representation of an item.
- /// </para>
- /// <para>
- /// The default value is <c>(null)</c>. This value can be overridden by specifying
- /// a value for the <c>log4net.NullText</c> appSetting in the application's
- /// .config file.
- /// </para>
- /// </remarks>
- public static string NullText
- {
- get { return s_nullText; }
- set { s_nullText = value; }
- }
- /// <summary>
- /// Text to output when an unsupported feature is requested.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Use this value when an unsupported feature is requested.
- /// </para>
- /// <para>
- /// The default value is <c>NOT AVAILABLE</c>. This value can be overridden by specifying
- /// a value for the <c>log4net.NotAvailableText</c> appSetting in the application's
- /// .config file.
- /// </para>
- /// </remarks>
- public static string NotAvailableText
- {
- get { return s_notAvailableText; }
- set { s_notAvailableText = value; }
- }
- #endregion Public Static Properties
- #region Public Static Methods
- /// <summary>
- /// Gets the assembly location path for the specified assembly.
- /// </summary>
- /// <param name="myAssembly">The assembly to get the location for.</param>
- /// <returns>The location of the assembly.</returns>
- /// <remarks>
- /// <para>
- /// This method does not guarantee to return the correct path
- /// to the assembly. If only tries to give an indication as to
- /// where the assembly was loaded from.
- /// </para>
- /// </remarks>
- public static string AssemblyLocationInfo(Assembly myAssembly)
- {
- #if NETCF
- return "Not supported on Microsoft .NET Compact Framework";
- #elif NETSTANDARD1_3 // TODO Assembly.Location available in netstandard1.5
- return "Not supported on .NET Core";
- #else
- if (myAssembly.GlobalAssemblyCache)
- {
- return "Global Assembly Cache";
- }
- else
- {
- try
- {
- #if NET_4_0 || MONO_4_0
- if (myAssembly.IsDynamic)
- {
- return "Dynamic Assembly";
- }
- #else
- if (myAssembly is System.Reflection.Emit.AssemblyBuilder)
- {
- return "Dynamic Assembly";
- }
- else if(myAssembly.GetType().FullName == "System.Reflection.Emit.InternalAssemblyBuilder")
- {
- return "Dynamic Assembly";
- }
- #endif
- else
- {
- // This call requires FileIOPermission for access to the path
- // if we don't have permission then we just ignore it and
- // carry on.
- return myAssembly.Location;
- }
- }
- catch (NotSupportedException)
- {
- // The location information may be unavailable for dynamic assemblies and a NotSupportedException
- // is thrown in those cases. See: http://msdn.microsoft.com/de-de/library/system.reflection.assembly.location.aspx
- return "Dynamic Assembly";
- }
- catch (TargetInvocationException ex)
- {
- return "Location Detect Failed (" + ex.Message + ")";
- }
- catch (ArgumentException ex)
- {
- return "Location Detect Failed (" + ex.Message + ")";
- }
- catch (System.Security.SecurityException)
- {
- return "Location Permission Denied";
- }
- }
- #endif
- }
- /// <summary>
- /// Gets the fully qualified name of the <see cref="Type" />, including
- /// the name of the assembly from which the <see cref="Type" /> was
- /// loaded.
- /// </summary>
- /// <param name="type">The <see cref="Type" /> to get the fully qualified name for.</param>
- /// <returns>The fully qualified name for the <see cref="Type" />.</returns>
- /// <remarks>
- /// <para>
- /// This is equivalent to the <c>Type.AssemblyQualifiedName</c> property,
- /// but this method works on the .NET Compact Framework 1.0 as well as
- /// the full .NET runtime.
- /// </para>
- /// </remarks>
- public static string AssemblyQualifiedName(Type type)
- {
- return type.FullName + ", "
- #if NETSTANDARD1_3
- + type.GetTypeInfo().Assembly.FullName;
- #else
- + type.Assembly.FullName;
- #endif
- }
- /// <summary>
- /// Gets the short name of the <see cref="Assembly" />.
- /// </summary>
- /// <param name="myAssembly">The <see cref="Assembly" /> to get the name for.</param>
- /// <returns>The short name of the <see cref="Assembly" />.</returns>
- /// <remarks>
- /// <para>
- /// The short name of the assembly is the <see cref="Assembly.FullName" />
- /// without the version, culture, or public key. i.e. it is just the
- /// assembly's file name without the extension.
- /// </para>
- /// <para>
- /// Use this rather than <c>Assembly.GetName().Name</c> because that
- /// is not available on the Compact Framework.
- /// </para>
- /// <para>
- /// Because of a FileIOPermission security demand we cannot do
- /// the obvious Assembly.GetName().Name. We are allowed to get
- /// the <see cref="Assembly.FullName" /> of the assembly so we
- /// start from there and strip out just the assembly name.
- /// </para>
- /// </remarks>
- public static string AssemblyShortName(Assembly myAssembly)
- {
- string name = myAssembly.FullName;
- int offset = name.IndexOf(',');
- if (offset > 0)
- {
- name = name.Substring(0, offset);
- }
- return name.Trim();
- // TODO: Do we need to unescape the assembly name string?
- // Doc says '\' is an escape char but has this already been
- // done by the string loader?
- }
- /// <summary>
- /// Gets the file name portion of the <see cref="Assembly" />, including the extension.
- /// </summary>
- /// <param name="myAssembly">The <see cref="Assembly" /> to get the file name for.</param>
- /// <returns>The file name of the assembly.</returns>
- /// <remarks>
- /// <para>
- /// Gets the file name portion of the <see cref="Assembly" />, including the extension.
- /// </para>
- /// </remarks>
- public static string AssemblyFileName(Assembly myAssembly)
- {
- #if NETCF || NETSTANDARD1_3 // TODO Assembly.Location is in netstandard1.5 System.Reflection
- // This is not very good because it assumes that only
- // the entry assembly can be an EXE. In fact multiple
- // EXEs can be loaded in to a process.
- string assemblyShortName = SystemInfo.AssemblyShortName(myAssembly);
- string entryAssemblyShortName = System.IO.Path.GetFileNameWithoutExtension(SystemInfo.EntryAssemblyLocation);
- if (string.Compare(assemblyShortName, entryAssemblyShortName, true) == 0)
- {
- // assembly is entry assembly
- return assemblyShortName + ".exe";
- }
- else
- {
- // assembly is not entry assembly
- return assemblyShortName + ".dll";
- }
- #else
- return System.IO.Path.GetFileName(myAssembly.Location);
- #endif
- }
- /// <summary>
- /// Loads the type specified in the type string.
- /// </summary>
- /// <param name="relativeType">A sibling type to use to load the type.</param>
- /// <param name="typeName">The name of the type to load.</param>
- /// <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
- /// <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
- /// <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
- /// <remarks>
- /// <para>
- /// If the type name is fully qualified, i.e. if contains an assembly name in
- /// the type name, the type will be loaded from the system using
- /// <see cref="M:Type.GetType(string,bool)"/>.
- /// </para>
- /// <para>
- /// If the type name is not fully qualified, it will be loaded from the assembly
- /// containing the specified relative type. If the type is not found in the assembly
- /// then all the loaded assemblies will be searched for the type.
- /// </para>
- /// </remarks>
- public static Type GetTypeFromString(Type relativeType, string typeName, bool throwOnError, bool ignoreCase)
- {
- #if NETSTANDARD1_3
- return GetTypeFromString(relativeType.GetTypeInfo().Assembly, typeName, throwOnError, ignoreCase);
- #else
- return GetTypeFromString(relativeType.Assembly, typeName, throwOnError, ignoreCase);
- #endif
- }
- #if !NETSTANDARD1_3
- /// <summary>
- /// Loads the type specified in the type string.
- /// </summary>
- /// <param name="typeName">The name of the type to load.</param>
- /// <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
- /// <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
- /// <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
- /// <remarks>
- /// <para>
- /// If the type name is fully qualified, i.e. if contains an assembly name in
- /// the type name, the type will be loaded from the system using
- /// <see cref="M:Type.GetType(string,bool)"/>.
- /// </para>
- /// <para>
- /// If the type name is not fully qualified it will be loaded from the
- /// assembly that is directly calling this method. If the type is not found
- /// in the assembly then all the loaded assemblies will be searched for the type.
- /// </para>
- /// </remarks>
- public static Type GetTypeFromString(string typeName, bool throwOnError, bool ignoreCase)
- {
- return GetTypeFromString(Assembly.GetCallingAssembly(), typeName, throwOnError, ignoreCase);
- }
- #endif
- /// <summary>
- /// Loads the type specified in the type string.
- /// </summary>
- /// <param name="relativeAssembly">An assembly to load the type from.</param>
- /// <param name="typeName">The name of the type to load.</param>
- /// <param name="throwOnError">Flag set to <c>true</c> to throw an exception if the type cannot be loaded.</param>
- /// <param name="ignoreCase"><c>true</c> to ignore the case of the type name; otherwise, <c>false</c></param>
- /// <returns>The type loaded or <c>null</c> if it could not be loaded.</returns>
- /// <remarks>
- /// <para>
- /// If the type name is fully qualified, i.e. if contains an assembly name in
- /// the type name, the type will be loaded from the system using
- /// <see cref="M:Type.GetType(string,bool)"/>.
- /// </para>
- /// <para>
- /// If the type name is not fully qualified it will be loaded from the specified
- /// assembly. If the type is not found in the assembly then all the loaded assemblies
- /// will be searched for the type.
- /// </para>
- /// </remarks>
- public static Type GetTypeFromString(Assembly relativeAssembly, string typeName, bool throwOnError, bool ignoreCase)
- {
- // Check if the type name specifies the assembly name
- if(typeName.IndexOf(',') == -1)
- {
- //LogLog.Debug(declaringType, "SystemInfo: Loading type ["+typeName+"] from assembly ["+relativeAssembly.FullName+"]");
- #if NETSTANDARD1_3
- return relativeAssembly.GetType(typeName, throwOnError, ignoreCase);
- #elif NETCF
- return relativeAssembly.GetType(typeName, throwOnError);
- #else
- // Attempt to lookup the type from the relativeAssembly
- Type type = relativeAssembly.GetType(typeName, false, ignoreCase);
- if (type != null)
- {
- // Found type in relative assembly
- //LogLog.Debug(declaringType, "SystemInfo: Loaded type ["+typeName+"] from assembly ["+relativeAssembly.FullName+"]");
- return type;
- }
- Assembly[] loadedAssemblies = null;
- try
- {
- loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
- }
- catch(System.Security.SecurityException)
- {
- // Insufficient permissions to get the list of loaded assemblies
- }
- if (loadedAssemblies != null)
- {
- Type fallback = null;
- // Search the loaded assemblies for the type
- foreach (Assembly assembly in loadedAssemblies)
- {
- Type t = assembly.GetType(typeName, false, ignoreCase);
- if (t != null)
- {
- // Found type in loaded assembly
- LogLog.Debug(declaringType, "Loaded type ["+typeName+"] from assembly ["+assembly.FullName+"] by searching loaded assemblies.");
- if (assembly.GlobalAssemblyCache)
- {
- fallback = t;
- }
- else
- {
- return t;
- }
- }
- }
- if (fallback != null)
- {
- return fallback;
- }
- }
- // Didn't find the type
- if (throwOnError)
- {
- throw new TypeLoadException("Could not load type ["+typeName+"]. Tried assembly ["+relativeAssembly.FullName+"] and all loaded assemblies");
- }
- return null;
- #endif
- }
- else
- {
- // Includes explicit assembly name
- //LogLog.Debug(declaringType, "SystemInfo: Loading type ["+typeName+"] from global Type");
- #if NETCF
- // In NETCF 2 and 3 arg versions seem to behave differently
- // https://issues.apache.org/jira/browse/LOG4NET-113
- return Type.GetType(typeName, throwOnError);
- #else
- return Type.GetType(typeName, throwOnError, ignoreCase);
- #endif
- }
- }
- /// <summary>
- /// Generate a new guid
- /// </summary>
- /// <returns>A new Guid</returns>
- /// <remarks>
- /// <para>
- /// Generate a new guid
- /// </para>
- /// </remarks>
- public static Guid NewGuid()
- {
- #if NETCF_1_0
- return PocketGuid.NewGuid();
- #else
- return Guid.NewGuid();
- #endif
- }
- /// <summary>
- /// Create an <see cref="ArgumentOutOfRangeException"/>
- /// </summary>
- /// <param name="parameterName">The name of the parameter that caused the exception</param>
- /// <param name="actualValue">The value of the argument that causes this exception</param>
- /// <param name="message">The message that describes the error</param>
- /// <returns>the ArgumentOutOfRangeException object</returns>
- /// <remarks>
- /// <para>
- /// Create a new instance of the <see cref="ArgumentOutOfRangeException"/> class
- /// with a specified error message, the parameter name, and the value
- /// of the argument.
- /// </para>
- /// <para>
- /// The Compact Framework does not support the 3 parameter constructor for the
- /// <see cref="ArgumentOutOfRangeException"/> type. This method provides an
- /// implementation that works for all platforms.
- /// </para>
- /// </remarks>
- public static ArgumentOutOfRangeException CreateArgumentOutOfRangeException(string parameterName, object actualValue, string message)
- {
- #if NETCF_1_0
- return new ArgumentOutOfRangeException(message + " [param=" + parameterName + "] [value=" + actualValue + "]");
- #elif NETCF_2_0
- return new ArgumentOutOfRangeException(parameterName, message + " [value=" + actualValue + "]");
- #else
- return new ArgumentOutOfRangeException(parameterName, actualValue, message);
- #endif
- }
- /// <summary>
- /// Parse a string into an <see cref="Int32"/> value
- /// </summary>
- /// <param name="s">the string to parse</param>
- /// <param name="val">out param where the parsed value is placed</param>
- /// <returns><c>true</c> if the string was able to be parsed into an integer</returns>
- /// <remarks>
- /// <para>
- /// Attempts to parse the string into an integer. If the string cannot
- /// be parsed then this method returns <c>false</c>. The method does not throw an exception.
- /// </para>
- /// </remarks>
- public static bool TryParse(string s, out int val)
- {
- #if NETCF
- val = 0;
- try
- {
- val = int.Parse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture);
- return true;
- }
- catch
- {
- }
- return false;
- #else
- // Initialise out param
- val = 0;
- try
- {
- double doubleVal;
- if (Double.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out doubleVal))
- {
- val = Convert.ToInt32(doubleVal);
- return true;
- }
- }
- catch
- {
- // Ignore exception, just return false
- }
- return false;
- #endif
- }
- /// <summary>
- /// Parse a string into an <see cref="Int64"/> value
- /// </summary>
- /// <param name="s">the string to parse</param>
- /// <param name="val">out param where the parsed value is placed</param>
- /// <returns><c>true</c> if the string was able to be parsed into an integer</returns>
- /// <remarks>
- /// <para>
- /// Attempts to parse the string into an integer. If the string cannot
- /// be parsed then this method returns <c>false</c>. The method does not throw an exception.
- /// </para>
- /// </remarks>
- public static bool TryParse(string s, out long val)
- {
- #if NETCF
- val = 0;
- try
- {
- val = long.Parse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture);
- return true;
- }
- catch
- {
- }
- return false;
- #else
- // Initialise out param
- val = 0;
- try
- {
- double doubleVal;
- if (Double.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out doubleVal))
- {
- val = Convert.ToInt64(doubleVal);
- return true;
- }
- }
- catch
- {
- // Ignore exception, just return false
- }
- return false;
- #endif
- }
- /// <summary>
- /// Parse a string into an <see cref="Int16"/> value
- /// </summary>
- /// <param name="s">the string to parse</param>
- /// <param name="val">out param where the parsed value is placed</param>
- /// <returns><c>true</c> if the string was able to be parsed into an integer</returns>
- /// <remarks>
- /// <para>
- /// Attempts to parse the string into an integer. If the string cannot
- /// be parsed then this method returns <c>false</c>. The method does not throw an exception.
- /// </para>
- /// </remarks>
- public static bool TryParse(string s, out short val)
- {
- #if NETCF
- val = 0;
- try
- {
- val = short.Parse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture);
- return true;
- }
- catch
- {
- }
- return false;
- #else
- // Initialise out param
- val = 0;
- try
- {
- double doubleVal;
- if (Double.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out doubleVal))
- {
- val = Convert.ToInt16(doubleVal);
- return true;
- }
- }
- catch
- {
- // Ignore exception, just return false
- }
- return false;
- #endif
- }
- /// <summary>
- /// Lookup an application setting
- /// </summary>
- /// <param name="key">the application settings key to lookup</param>
- /// <returns>the value for the key, or <c>null</c></returns>
- /// <remarks>
- /// <para>
- /// Configuration APIs are not supported under the Compact Framework
- /// </para>
- /// </remarks>
- public static string GetAppSetting(string key)
- {
- try
- {
- #if NETCF || NETSTANDARD1_3
- // Configuration APIs are not suported under the Compact Framework
- #elif NET_2_0
- return ConfigurationManager.AppSettings[key];
- #else
- return ConfigurationSettings.AppSettings[key];
- #endif
- }
- catch(Exception ex)
- {
- // If an exception is thrown here then it looks like the config file does not parse correctly.
- LogLog.Error(declaringType, "Exception while reading ConfigurationSettings. Check your .config file is well formed XML.", ex);
- }
- return null;
- }
- /// <summary>
- /// Convert a path into a fully qualified local file path.
- /// </summary>
- /// <param name="path">The path to convert.</param>
- /// <returns>The fully qualified path.</returns>
- /// <remarks>
- /// <para>
- /// Converts the path specified to a fully
- /// qualified path. If the path is relative it is
- /// taken as relative from the application base
- /// directory.
- /// </para>
- /// <para>
- /// The path specified must be a local file path, a URI is not supported.
- /// </para>
- /// </remarks>
- public static string ConvertToFullPath(string path)
- {
- if (path == null)
- {
- throw new ArgumentNullException("path");
- }
- string baseDirectory = "";
- try
- {
- string applicationBaseDirectory = SystemInfo.ApplicationBaseDirectory;
- if (applicationBaseDirectory != null)
- {
- // applicationBaseDirectory may be a URI not a local file path
- Uri applicationBaseDirectoryUri = new Uri(applicationBaseDirectory);
- if (applicationBaseDirectoryUri.IsFile)
- {
- baseDirectory = applicationBaseDirectoryUri.LocalPath;
- }
- }
- }
- catch
- {
- // Ignore URI exceptions & SecurityExceptions from SystemInfo.ApplicationBaseDirectory
- }
- if (baseDirectory != null && baseDirectory.Length > 0)
- {
- // Note that Path.Combine will return the second path if it is rooted
- return Path.GetFullPath(Path.Combine(baseDirectory, path));
- }
- return Path.GetFullPath(path);
- }
- /// <summary>
- /// Creates a new case-insensitive instance of the <see cref="Hashtable"/> class with the default initial capacity.
- /// </summary>
- /// <returns>A new case-insensitive instance of the <see cref="Hashtable"/> class with the default initial capacity</returns>
- /// <remarks>
- /// <para>
- /// The new Hashtable instance uses the default load factor, the CaseInsensitiveHashCodeProvider, and the CaseInsensitiveComparer.
- /// </para>
- /// </remarks>
- public static Hashtable CreateCaseInsensitiveHashtable()
- {
- #if NETCF_1_0
- return new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
- #elif NETCF_2_0 || NET_2_0 || MONO_2_0 || MONO_3_5 || MONO_4_0
- return new Hashtable(StringComparer.OrdinalIgnoreCase);
- #else
- return System.Collections.Specialized.CollectionsUtil.CreateCaseInsensitiveHashtable();
- #endif
- }
- /// <summary>
- /// Tests two strings for equality, the ignoring case.
- /// </summary>
- /// <remarks>
- /// If the platform permits, culture information is ignored completely (ordinal comparison).
- /// The aim of this method is to provide a fast comparison that deals with <c>null</c> and ignores different casing.
- /// It is not supposed to deal with various, culture-specific habits.
- /// Use it to compare against pure ASCII constants, like keywords etc.
- /// </remarks>
- /// <param name="a">The one string.</param>
- /// <param name="b">The other string.</param>
- /// <returns><c>true</c> if the strings are equal, <c>false</c> otherwise.</returns>
- public static Boolean EqualsIgnoringCase(String a, String b)
- {
- #if NET_1_0 || NET_1_1 || NETCF_1_0
- return string.Compare(a, b, true, System.Globalization.CultureInfo.InvariantCulture) == 0
- #elif NETSTANDARD1_3
- return CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0;
- #else // >= .NET-2.0
- return String.Equals(a, b, StringComparison.OrdinalIgnoreCase);
- #endif
- }
- #endregion Public Static Methods
- #region Private Static Methods
- #if NETCF
- private static string NativeEntryAssemblyLocation
- {
- get
- {
- StringBuilder moduleName = null;
- IntPtr moduleHandle = GetModuleHandle(IntPtr.Zero);
- if (moduleHandle != IntPtr.Zero)
- {
- moduleName = new StringBuilder(255);
- if (GetModuleFileName(moduleHandle, moduleName, moduleName.Capacity) == 0)
- {
- throw new NotSupportedException(NativeError.GetLastError().ToString());
- }
- }
- else
- {
- throw new NotSupportedException(NativeError.GetLastError().ToString());
- }
- return moduleName.ToString();
- }
- }
- [DllImport("CoreDll.dll", SetLastError=true, CharSet=CharSet.Unicode)]
- private static extern IntPtr GetModuleHandle(IntPtr ModuleName);
- [DllImport("CoreDll.dll", SetLastError=true, CharSet=CharSet.Unicode)]
- private static extern Int32 GetModuleFileName(
- IntPtr hModule,
- StringBuilder ModuleName,
- Int32 cch);
- #endif
- #endregion Private Static Methods
- #region Public Static Fields
- /// <summary>
- /// Gets an empty array of types.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The <c>Type.EmptyTypes</c> field is not available on
- /// the .NET Compact Framework 1.0.
- /// </para>
- /// </remarks>
- public static readonly Type[] EmptyTypes = new Type[0];
- #endregion Public Static Fields
- #region Private Static Fields
- /// <summary>
- /// The fully qualified type of the SystemInfo class.
- /// </summary>
- /// <remarks>
- /// Used by the internal logger to record the Type of the
- /// log message.
- /// </remarks>
- private readonly static Type declaringType = typeof(SystemInfo);
- /// <summary>
- /// Cache the host name for the current machine
- /// </summary>
- private static string s_hostName;
- /// <summary>
- /// Cache the application friendly name
- /// </summary>
- private static string s_appFriendlyName;
- /// <summary>
- /// Text to output when a <c>null</c> is encountered.
- /// </summary>
- private static string s_nullText;
- /// <summary>
- /// Text to output when an unsupported feature is requested.
- /// </summary>
- private static string s_notAvailableText;
- /// <summary>
- /// Start time for the current process.
- /// </summary>
- private static DateTime s_processStartTimeUtc = DateTime.UtcNow;
- #endregion
- #region Compact Framework Helper Classes
- #if NETCF_1_0
- /// <summary>
- /// Generate GUIDs on the .NET Compact Framework.
- /// </summary>
- public class PocketGuid
- {
- // guid variant types
- private enum GuidVariant
- {
- ReservedNCS = 0x00,
- Standard = 0x02,
- ReservedMicrosoft = 0x06,
- ReservedFuture = 0x07
- }
- // guid version types
- private enum GuidVersion
- {
- TimeBased = 0x01,
- Reserved = 0x02,
- NameBased = 0x03,
- Random = 0x04
- }
- // constants that are used in the class
- private class Const
- {
- // number of bytes in guid
- public const int ByteArraySize = 16;
- // multiplex variant info
- public const int VariantByte = 8;
- public const int VariantByteMask = 0x3f;
- public const int VariantByteShift = 6;
- // multiplex version info
- public const int VersionByte = 7;
- public const int VersionByteMask = 0x0f;
- public const int VersionByteShift = 4;
- }
- // imports for the crypto api functions
- private class WinApi
- {
- public const uint PROV_RSA_FULL = 1;
- public const uint CRYPT_VERIFYCONTEXT = 0xf0000000;
- [DllImport("CoreDll.dll")]
- public static extern bool CryptAcquireContext(
- ref IntPtr phProv, string pszContainer, string pszProvider,
- uint dwProvType, uint dwFlags);
- [DllImport("CoreDll.dll")]
- public static extern bool CryptReleaseContext(
- IntPtr hProv, uint dwFlags);
- [DllImport("CoreDll.dll")]
- public static extern bool CryptGenRandom(
- IntPtr hProv, int dwLen, byte[] pbBuffer);
- }
- // all static methods
- private PocketGuid()
- {
- }
- /// <summary>
- /// Return a new System.Guid object.
- /// </summary>
- public static Guid NewGuid()
- {
- IntPtr hCryptProv = IntPtr.Zero;
- Guid guid = Guid.Empty;
- try
- {
- // holds random bits for guid
- byte[] bits = new byte[Const.ByteArraySize];
- // get crypto provider handle
- if (!WinApi.CryptAcquireContext(ref hCryptProv, null, null,
- WinApi.PROV_RSA_FULL, WinApi.CRYPT_VERIFYCONTEXT))
- {
- throw new SystemException(
- "Failed to acquire cryptography handle.");
- }
- // generate a 128 bit (16 byte) cryptographically random number
- if (!WinApi.CryptGenRandom(hCryptProv, bits.Length, bits))
- {
- throw new SystemException(
- "Failed to generate cryptography random bytes.");
- }
- // set the variant
- bits[Const.VariantByte] &= Const.VariantByteMask;
- bits[Const.VariantByte] |=
- ((int)GuidVariant.Standard << Const.VariantByteShift);
- // set the version
- bits[Const.VersionByte] &= Const.VersionByteMask;
- bits[Const.VersionByte] |=
- ((int)GuidVersion.Random << Const.VersionByteShift);
- // create the new System.Guid object
- guid = new Guid(bits);
- }
- finally
- {
- // release the crypto provider handle
- if (hCryptProv != IntPtr.Zero)
- WinApi.CryptReleaseContext(hCryptProv, 0);
- }
- return guid;
- }
- }
- #endif
- #endregion Compact Framework Helper Classes
- }
- }
|