File: NativeInterop\SafeLibraryHandle.cs
Web Access
Project: src\src\Servers\HttpSys\src\Microsoft.AspNetCore.Server.HttpSys.csproj (Microsoft.AspNetCore.Server.HttpSys)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Runtime.InteropServices;
using System.Security;
using Microsoft.Win32.SafeHandles;
 
namespace Microsoft.AspNetCore.Server.HttpSys;
 
/// <summary>
/// Represents a handle to a Windows module (DLL).
/// </summary>
internal sealed unsafe partial class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    // Called by P/Invoke when returning SafeHandles
    public SafeLibraryHandle()
        : base(ownsHandle: true)
    {
    }
 
    /// <summary>
    /// Returns a value stating whether the library exports a given proc.
    /// </summary>
    public bool DoesProcExist(string lpProcName)
    {
        IntPtr pfnProc = UnsafeNativeMethods.GetProcAddress(this, lpProcName);
        return (pfnProc != IntPtr.Zero);
    }
 
    /// <summary>
    /// Gets a delegate pointing to a given export from this library.
    /// </summary>
    public TDelegate? GetProcAddress<TDelegate>(string lpProcName, bool throwIfNotFound = true) where TDelegate : class
    {
        IntPtr pfnProc = UnsafeNativeMethods.GetProcAddress(this, lpProcName);
        if (pfnProc == IntPtr.Zero)
        {
            if (throwIfNotFound)
            {
                UnsafeNativeMethods.ThrowExceptionForLastWin32Error();
            }
            else
            {
                return null;
            }
        }
 
        return Marshal.GetDelegateForFunctionPointer<TDelegate>(pfnProc);
    }
 
    /// <summary>
    /// Opens a library. If 'filename' is not a fully-qualified path, the default search path is used.
    /// </summary>
    public static SafeLibraryHandle Open(string filename)
    {
        const uint LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800U; // from libloaderapi.h
 
        SafeLibraryHandle handle = UnsafeNativeMethods.LoadLibraryEx(filename, IntPtr.Zero, LOAD_LIBRARY_SEARCH_SYSTEM32);
        if (handle == null || handle.IsInvalid)
        {
            UnsafeNativeMethods.ThrowExceptionForLastWin32Error();
        }
        return handle!;
    }
 
    // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you.
    protected override bool ReleaseHandle()
    {
        return UnsafeNativeMethods.FreeLibrary(handle);
    }
 
    [SuppressUnmanagedCodeSecurity]
    private static partial class UnsafeNativeMethods
    {
        // http://msdn.microsoft.com/en-us/library/ms683152(v=vs.85).aspx
        [return: MarshalAs(UnmanagedType.Bool)]
        [LibraryImport("kernel32.dll")]
        internal static partial bool FreeLibrary(IntPtr hModule);
 
        // http://msdn.microsoft.com/en-us/library/ms683212(v=vs.85).aspx
        [LibraryImport("kernel32.dll", SetLastError = true)]
        internal static partial IntPtr GetProcAddress(
            SafeLibraryHandle hModule,
            [MarshalAs(UnmanagedType.LPStr)] string lpProcName);
 
        // http://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
        [LibraryImport("kernel32.dll", EntryPoint = "LoadLibraryExW", SetLastError = true)]
        internal static partial SafeLibraryHandle LoadLibraryEx(
            [MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
            IntPtr hFile,
            uint dwFlags);
 
        internal static void ThrowExceptionForLastWin32Error()
        {
            int hr = Marshal.GetHRForLastWin32Error();
            Marshal.ThrowExceptionForHR(hr);
        }
    }
}