File: net\UnsafeMethods.cs
Project: ndp\fx\src\SystemNet\System.Net.csproj (System.Net)
//------------------------------------------------------------------------------
// <copyright file="UnsafeMethods.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Net
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Win32.SafeHandles;
    using System.Security;
    using System.Runtime.InteropServices;
    using System.Runtime.ConstrainedExecution;
    using System.Threading;
    using System.Net.Sockets;
 
    [Flags]
    internal enum FormatMessageFlags : uint
    {
        FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100,
        //FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200,
        //FORMAT_MESSAGE_FROM_STRING = 0x00000400,
        FORMAT_MESSAGE_FROM_HMODULE = 0x00000800,
        FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000,
        FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
    }
 
    [System.Security.SuppressUnmanagedCodeSecurityAttribute()]
    internal static class UnsafeSystemNativeMethods
    {
        private const string KERNEL32 = "KERNEL32.dll";
 
        [System.Security.SecurityCritical]
        [DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
        internal static extern unsafe SafeLoadLibrary LoadLibraryExW( string lpwLibFileName, [In] void* hFile,  uint dwFlags);
 
        [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern unsafe bool FreeLibrary(IntPtr hModule);
 
        [System.Security.SecurityCritical]
        [DllImport(KERNEL32, ExactSpelling=true, CharSet=CharSet.Unicode, SetLastError=true)]
        internal static extern IntPtr GetModuleHandleW(string modName);
 
        [System.Security.SecurityCritical]
        [DllImport(KERNEL32, EntryPoint = "GetProcAddress", SetLastError = true, BestFitMapping = false)]
        internal extern static IntPtr GetProcAddress(SafeLoadLibrary hModule, string entryPoint);
 
        [System.Security.SecurityCritical]
        [DllImport(KERNEL32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
        internal extern static IntPtr GetProcAddress(IntPtr hModule, string entryPoint);
 
        [DllImport(KERNEL32, CharSet = CharSet.Unicode)]
        internal extern static uint FormatMessage(
                                            FormatMessageFlags dwFlags, 
                                            IntPtr lpSource, 
                                            UInt32 dwMessageId, 
                                            UInt32 dwLanguageId, 
                                            ref IntPtr lpBuffer,
                                            UInt32 nSize,
                                            IntPtr vaArguments
            );
 
        [DllImport(KERNEL32, CharSet = CharSet.Unicode)]
        internal extern static uint LocalFree(IntPtr lpMem);
 
       }
 
    // <SecurityKernel Critical="True" Ring="0">
    // <SatisfiesLinkDemand Name="SafeHandleZeroOrMinusOneIsInvalid" />
    // </SecurityKernel>
#pragma warning disable 618    // Have not migrated to v4 transparency yet
    [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
#pragma warning restore 618
    [System.Diagnostics.CodeAnalysis.SuppressMessage(
        "Microsoft.Design", 
        "CA1031:DoNotCatchGeneralExceptionTypes", 
        Justification = "We need to ensure that this class initializes in any condition.")]
    [System.Security.SuppressUnmanagedCodeSecurityAttribute()]
    internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid
    {
        private const string KERNEL32 = "kernel32.dll";
        private const string AddDllDirectory = "AddDllDirectory";
        private const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800;
 
        // KB2533623 introduced the LOAD_LIBRARY_SEARCH_SYSTEM32 flag. It also introduced
        // the AddDllDirectory function. We test for presence of AddDllDirectory as  
        // indirect evidence of support for the LOAD_LIBRARY_SEARCH_SYSTEM32 flag. 
        private static uint _flags = 0;
 
        static SafeLoadLibrary() {
            try {
                IntPtr hKernel32 = UnsafeSystemNativeMethods.GetModuleHandleW(KERNEL32);
 
                if (hKernel32 != IntPtr.Zero &&
                    UnsafeSystemNativeMethods.GetProcAddress(hKernel32, AddDllDirectory) != IntPtr.Zero) {
                    _flags = LOAD_LIBRARY_SEARCH_SYSTEM32;
                }
            }
            catch { /* noop to ensure this class can initialize */ }
        }
 
        private SafeLoadLibrary() : base(true) { }
 
        internal unsafe static SafeLoadLibrary LoadLibraryEx(string library) {
            SafeLoadLibrary result = UnsafeSystemNativeMethods.LoadLibraryExW(library, null, _flags);
            if (result.IsInvalid) {
                //NOTE:
                //IsInvalid tests the numeric value of the handle. 
                //SetHandleAsInvalid sets the handle as closed, so that further closing 
                //does not have to take place in the critical finalizer thread. 
                //
                //You would think that when you assign 0 or -1 to an instance of 
                //SafeHandleZeroOrMinusoneIsInvalid, the handle will not be closed, since after all it is invalid 
                //It turns out that the SafeHandleZetoOrMinusOneIsInvalid overrides only the IsInvalid() method
                //It does not do anything to automatically close it.
                //So we have to SetHandleAsInvalid --> Which means mark it closed -- so that
                //we will not eventually call CloseHandle on 0 or -1
                result.SetHandleAsInvalid();
            }
            return result;
        }
        protected override bool ReleaseHandle() {
            return UnsafeSystemNativeMethods.FreeLibrary(handle);
        }
    }
}