#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; using System.Configuration; using System.Reflection; using System.Text; using System.IO; using System.Runtime.InteropServices; using System.Collections; namespace log4net.Util { /// /// Utility class for system specific information. /// /// /// /// Utility class of static methods for system specific information. /// /// /// Nicko Cadell /// Gert Driesen /// Alexey Solofnenko 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 /// /// Private constructor to prevent instances. /// /// /// /// Only static methods are exposed from this type. /// /// private SystemInfo() { } #endregion Private Instance Constructors #region Public Static Constructor /// /// Initialize default values for private static fields. /// /// /// /// Only static methods are exposed from this type. /// /// 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 /// /// Gets the system dependent line terminator. /// /// /// The system dependent line terminator. /// /// /// /// Gets the system dependent line terminator. /// /// public static string NewLine { get { #if NETCF return "\r\n"; #else return System.Environment.NewLine; #endif } } /// /// Gets the base directory for this . /// /// The base directory path for the current . /// /// /// Gets the base directory for this . /// /// /// The value returned may be either a local file path or a URI. /// /// public static string ApplicationBaseDirectory { get { #if NETCF return System.IO.Path.GetDirectoryName(SystemInfo.EntryAssemblyLocation) + System.IO.Path.DirectorySeparatorChar; #else return AppDomain.CurrentDomain.BaseDirectory; #endif } } /// /// Gets the path to the configuration file for the current . /// /// The path to the configuration file for the current . /// /// /// 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. /// /// /// The value returned may be either a local file path or a URI. /// /// public static string ConfigurationFileLocation { get { #if NETCF return SystemInfo.EntryAssemblyLocation+".config"; #else return System.AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; #endif } } /// /// Gets the path to the file that first executed in the current . /// /// The path to the entry assembly. /// /// /// Gets the path to the file that first executed in the current . /// /// public static string EntryAssemblyLocation { get { #if NETCF return SystemInfo.NativeEntryAssemblyLocation; #else return System.Reflection.Assembly.GetEntryAssembly().Location; #endif } } /// /// Gets the ID of the current thread. /// /// The ID of the current thread. /// /// /// On the .NET framework, the AppDomain.GetCurrentThreadId method /// is used to obtain the thread ID for the current thread. This is the /// operating system ID for the thread. /// /// /// 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 /// GetCurrentThreadId is implemented inline in a header file /// and cannot be called. /// /// /// On the .NET Framework 2.0 the Thread.ManagedThreadId is used as this /// gives a stable id unrelated to the operating system thread ID which may /// change if the runtime is using fibers. /// /// 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 return System.Threading.Thread.CurrentThread.ManagedThreadId; #else return AppDomain.GetCurrentThreadId(); #endif } } /// /// Get the host name or machine name for the current machine /// /// /// The hostname or machine name /// /// /// /// Get the host name or machine name for the current machine /// /// /// The host name () or /// the machine name (Environment.MachineName) for /// the current machine, or if neither of these are available /// then NOT AVAILABLE is returned. /// /// 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 (!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; } } /// /// Get this application's friendly name /// /// /// The friendly name of this application as a string /// /// /// /// If available the name of the application is retrieved from /// the AppDomain using AppDomain.CurrentDomain.FriendlyName. /// /// /// Otherwise the file name of the entry assembly is used. /// /// public static string ApplicationFriendlyName { get { if (s_appFriendlyName == null) { try { #if !NETCF 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; } } /// /// Get the start time for the current process. /// /// /// /// This is the time at which the log4net library was loaded into the /// AppDomain. Due to reports of a hang in the call to System.Diagnostics.Process.StartTime /// this is not the start time for the current process. /// /// /// 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. /// /// /// 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. /// /// public static DateTime ProcessStartTime { get { return s_processStartTime; } } /// /// Text to output when a null is encountered. /// /// /// /// Use this value to indicate a null has been encountered while /// outputting a string representation of an item. /// /// /// The default value is (null). This value can be overridden by specifying /// a value for the log4net.NullText appSetting in the application's /// .config file. /// /// public static string NullText { get { return s_nullText; } set { s_nullText = value; } } /// /// Text to output when an unsupported feature is requested. /// /// /// /// Use this value when an unsupported feature is requested. /// /// /// The default value is NOT AVAILABLE. This value can be overridden by specifying /// a value for the log4net.NotAvailableText appSetting in the application's /// .config file. /// /// public static string NotAvailableText { get { return s_notAvailableText; } set { s_notAvailableText = value; } } #endregion Public Static Properties #region Public Static Methods /// /// Gets the assembly location path for the specified assembly. /// /// The assembly to get the location for. /// The location of the assembly. /// /// /// 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. /// /// public static string AssemblyLocationInfo(Assembly myAssembly) { #if NETCF return "Not supported on Microsoft .NET Compact Framework"; #else if (myAssembly.GlobalAssemblyCache) { return "Global Assembly Cache"; } else { try { #if NET_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 } /// /// Gets the fully qualified name of the , including /// the name of the assembly from which the was /// loaded. /// /// The to get the fully qualified name for. /// The fully qualified name for the . /// /// /// This is equivalent to the Type.AssemblyQualifiedName property, /// but this method works on the .NET Compact Framework 1.0 as well as /// the full .NET runtime. /// /// public static string AssemblyQualifiedName(Type type) { return type.FullName + ", " + type.Assembly.FullName; } /// /// Gets the short name of the . /// /// The to get the name for. /// The short name of the . /// /// /// The short name of the assembly is the /// without the version, culture, or public key. i.e. it is just the /// assembly's file name without the extension. /// /// /// Use this rather than Assembly.GetName().Name because that /// is not available on the Compact Framework. /// /// /// Because of a FileIOPermission security demand we cannot do /// the obvious Assembly.GetName().Name. We are allowed to get /// the of the assembly so we /// start from there and strip out just the assembly name. /// /// 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? } /// /// Gets the file name portion of the , including the extension. /// /// The to get the file name for. /// The file name of the assembly. /// /// /// Gets the file name portion of the , including the extension. /// /// public static string AssemblyFileName(Assembly myAssembly) { #if NETCF // 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 } /// /// Loads the type specified in the type string. /// /// A sibling type to use to load the type. /// The name of the type to load. /// Flag set to true to throw an exception if the type cannot be loaded. /// true to ignore the case of the type name; otherwise, false /// The type loaded or null if it could not be loaded. /// /// /// 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 /// . /// /// /// 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. /// /// public static Type GetTypeFromString(Type relativeType, string typeName, bool throwOnError, bool ignoreCase) { return GetTypeFromString(relativeType.Assembly, typeName, throwOnError, ignoreCase); } /// /// Loads the type specified in the type string. /// /// The name of the type to load. /// Flag set to true to throw an exception if the type cannot be loaded. /// true to ignore the case of the type name; otherwise, false /// The type loaded or null if it could not be loaded. /// /// /// 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 /// . /// /// /// 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. /// /// public static Type GetTypeFromString(string typeName, bool throwOnError, bool ignoreCase) { return GetTypeFromString(Assembly.GetCallingAssembly(), typeName, throwOnError, ignoreCase); } /// /// Loads the type specified in the type string. /// /// An assembly to load the type from. /// The name of the type to load. /// Flag set to true to throw an exception if the type cannot be loaded. /// true to ignore the case of the type name; otherwise, false /// The type loaded or null if it could not be loaded. /// /// /// 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 /// . /// /// /// 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. /// /// 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 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) { // Search the loaded assemblies for the type foreach (Assembly assembly in loadedAssemblies) { type = assembly.GetType(typeName, false, ignoreCase); if (type != null) { // Found type in loaded assembly LogLog.Debug(declaringType, "Loaded type ["+typeName+"] from assembly ["+assembly.FullName+"] by searching loaded assemblies."); return type; } } } // 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 } } /// /// Generate a new guid /// /// A new Guid /// /// /// Generate a new guid /// /// public static Guid NewGuid() { #if NETCF_1_0 return PocketGuid.NewGuid(); #else return Guid.NewGuid(); #endif } /// /// Create an /// /// The name of the parameter that caused the exception /// The value of the argument that causes this exception /// The message that describes the error /// the ArgumentOutOfRangeException object /// /// /// Create a new instance of the class /// with a specified error message, the parameter name, and the value /// of the argument. /// /// /// The Compact Framework does not support the 3 parameter constructor for the /// type. This method provides an /// implementation that works for all platforms. /// /// 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 } /// /// Parse a string into an value /// /// the string to parse /// out param where the parsed value is placed /// true if the string was able to be parsed into an integer /// /// /// Attempts to parse the string into an integer. If the string cannot /// be parsed then this method returns false. The method does not throw an exception. /// /// 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 } /// /// Parse a string into an value /// /// the string to parse /// out param where the parsed value is placed /// true if the string was able to be parsed into an integer /// /// /// Attempts to parse the string into an integer. If the string cannot /// be parsed then this method returns false. The method does not throw an exception. /// /// 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 } /// /// Parse a string into an value /// /// the string to parse /// out param where the parsed value is placed /// true if the string was able to be parsed into an integer /// /// /// Attempts to parse the string into an integer. If the string cannot /// be parsed then this method returns false. The method does not throw an exception. /// /// 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 } /// /// Lookup an application setting /// /// the application settings key to lookup /// the value for the key, or null /// /// /// Configuration APIs are not supported under the Compact Framework /// /// public static string GetAppSetting(string key) { try { #if NETCF // 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; } /// /// Convert a path into a fully qualified local file path. /// /// The path to convert. /// The fully qualified path. /// /// /// Converts the path specified to a fully /// qualified path. If the path is relative it is /// taken as relative from the application base /// directory. /// /// /// The path specified must be a local file path, a URI is not supported. /// /// 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); } /// /// Creates a new case-insensitive instance of the class with the default initial capacity. /// /// A new case-insensitive instance of the class with the default initial capacity /// /// /// The new Hashtable instance uses the default load factor, the CaseInsensitiveHashCodeProvider, and the CaseInsensitiveComparer. /// /// 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 return new Hashtable(StringComparer.OrdinalIgnoreCase); #else return System.Collections.Specialized.CollectionsUtil.CreateCaseInsensitiveHashtable(); #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 /// /// Gets an empty array of types. /// /// /// /// The Type.EmptyTypes field is not available on /// the .NET Compact Framework 1.0. /// /// public static readonly Type[] EmptyTypes = new Type[0]; #endregion Public Static Fields #region Private Static Fields /// /// The fully qualified type of the SystemInfo class. /// /// /// Used by the internal logger to record the Type of the /// log message. /// private readonly static Type declaringType = typeof(SystemInfo); /// /// Cache the host name for the current machine /// private static string s_hostName; /// /// Cache the application friendly name /// private static string s_appFriendlyName; /// /// Text to output when a null is encountered. /// private static string s_nullText; /// /// Text to output when an unsupported feature is requested. /// private static string s_notAvailableText; /// /// Start time for the current process. /// private static DateTime s_processStartTime = DateTime.Now; #endregion #region Compact Framework Helper Classes #if NETCF_1_0 /// /// Generate GUIDs on the .NET Compact Framework. /// 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() { } /// /// Return a new System.Guid object. /// 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 } }