//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. // //----------------------------------------------------------------------- namespace Microsoft.Isam.Esent.Interop { using System; using System.Globalization; using System.Runtime.InteropServices; using System.Security; using System.Text; using System.Threading; using Microsoft.Isam.Esent.Interop.Implementation; /// /// Contains several helper functions that are useful in the test binary. /// In particular, it contains functionality that is not available in /// reduced-functionality environments (such as CoreClr). /// internal static class LibraryHelpers { /// Provides a platform-specific character used to separate directory levels in a path string that reflects a hierarchical file system organization. /// 1 public static readonly char DirectorySeparatorChar = '\\'; /// Provides a platform-specific alternate character used to separate directory levels in a path string that reflects a hierarchical file system organization. /// 1 public static readonly char AltDirectorySeparatorChar = '/'; /// /// Gets an ASCII encoder. /// public static Encoding EncodingASCII { get { #if MANAGEDESENT_ON_CORECLR return SlowAsciiEncoding.Encoding; #else return Encoding.ASCII; #endif } } /// /// Gets a new ASCII encoder. It's preferred to use EncodingASCII, but some applications (e.g. tests) /// may want a different Encoding object. /// public static Encoding NewEncodingASCII { get { #if MANAGEDESENT_ON_CORECLR return new SlowAsciiEncoding(); #else return new ASCIIEncoding(); #endif } } // This should be dead code when running on Core CLR; This is only called by // GetIndexInfoFromIndexlist() when called on a pre-Win8 system, and Core CLR // is only on Win8 anyway. #if !MANAGEDESENT_ON_CORECLR /// /// Creates a CultureInfo object when given the LCID. /// /// /// The lcid passed in. /// /// /// A CultureInfo object. /// public static CultureInfo CreateCultureInfoByLcid(int lcid) { return new CultureInfo(lcid); } #endif // !MANAGEDESENT_ON_CORECLR /// /// Allocates memory on the native heap. /// /// A pointer to native memory. /// The size of the memory desired. public static IntPtr MarshalAllocHGlobal(int size) { #if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA return Win32.NativeMethods.LocalAlloc(0, new UIntPtr((uint)size)); #else return Marshal.AllocHGlobal(size); #endif } /// /// Frees memory that was allocated on the native heap. /// /// A pointer to native memory. public static void MarshalFreeHGlobal(IntPtr buffer) { #if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA Win32.NativeMethods.LocalFree(buffer); #else Marshal.FreeHGlobal(buffer); #endif } /// Copies the contents of a managed into unmanaged memory. /// The address, in unmanaged memory, to where the was copied, or 0 if is null. /// A managed string to be copied. /// The method could not allocate enough native heap memory. /// The parameter exceeds the maximum length allowed by the operating system. public static IntPtr MarshalStringToHGlobalUni(string managedString) { #if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA return MyStringToHGlobalUni(managedString); #else return Marshal.StringToHGlobalUni(managedString); #endif } /// /// Retrieves the managed ID of the current thread. /// /// The ID of the current thread. public static int GetCurrentManagedThreadId() { #if MANAGEDESENT_ON_CORECLR return Environment.CurrentManagedThreadId; #else return Thread.CurrentThread.ManagedThreadId; #endif } /// /// Cancels an requested for the current thread. /// /// Abort was not invoked on the current thread. The caller does not have the required security permission for the current thread. 2 public static void ThreadResetAbort() { #if MANAGEDESENT_ON_CORECLR // Do nothing. #else Thread.ResetAbort(); #endif } // FUTURE-2013/12/16-martinc. It appears that all of this hacking for running on Core CLR may no longer be necessary. // We initially ported to an early version of Core CLR that had a lot of functionality missing. By the time // Windows Store Apps came out in Windows 8, many of these functions were added back. #if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA // System.Runtime.InteropServices.Marshal /// Copies the contents of a managed into unmanaged memory. /// The address, in unmanaged memory, to where the was copied, or 0 if is null. /// A managed string to be copied. /// The method could not allocate enough native heap memory. /// The parameter exceeds the maximum length allowed by the operating system. [SecurityCritical] private static unsafe IntPtr MyStringToHGlobalUni(string managedString) { if (managedString == null) { return IntPtr.Zero; } int charCountWithNull = managedString.Length + 1; int byteCount = charCountWithNull * sizeof(char); if (byteCount < managedString.Length) { throw new ArgumentOutOfRangeException("managedString"); } UIntPtr sizetdwBytes = new UIntPtr((uint)byteCount); IntPtr rawBuffer = Win32.NativeMethods.LocalAlloc(0, sizetdwBytes); if (rawBuffer == IntPtr.Zero) { throw new OutOfMemoryException(); } fixed (char* sourcePointer = managedString) { byte* destPointer = (byte*)rawBuffer; var unicodeEncoding = new System.Text.UnicodeEncoding(); int bytesWritten = unicodeEncoding.GetBytes(sourcePointer, charCountWithNull, destPointer, byteCount); } return rawBuffer; } #endif // MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA /// Returns a equivalent to the specified OLE Automation Date. /// A that represents the same date and time as . /// An OLE Automation Date value. /// The date is not a valid OLE Automation Date value. /// 1 public static DateTime FromOADate(double d) { #if MANAGEDESENT_ON_CORECLR return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified); #else return DateTime.FromOADate(d); #endif } #if MANAGEDESENT_ON_CORECLR /// /// Copied from the reflected implementation. /// /// The date, as a 64bit integer. /// The date, as a double representation. internal static double TicksToOADate(long value) { if (value == 0L) { return 0.0; } if (value < 864000000000L) { value += 599264352000000000L; } if (value < 31241376000000000L) { throw new OverflowException(); } long num = (value - 599264352000000000L) / 10000L; if (num < 0L) { long num2 = num % 86400000L; if (num2 != 0L) { num -= (86400000L + num2) * 2L; } } return (double)num / 86400000.0; } /// /// Copied from the reflected implementation. /// /// The date, as a double representation. /// The date, as a 64bit integer. internal static long DoubleDateToTicks(double value) { if (value >= 2958466.0 || value <= -657435.0) { throw new ArgumentException("value does not represent a valid date", "value"); } long num = (long)((value * 86400000.0) + ((value >= 0.0) ? 0.5 : -0.5)); if (num < 0L) { num -= (num % 86400000L) * 2L; } num += 59926435200000L; if (num < 0L || num >= 315537897600000L) { throw new ArgumentException("value does not represent a valid date", "value"); } return num * 10000L; } #endif } }