209 lines
8.6 KiB
C#
209 lines
8.6 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
|
#if !DNXCORE50
|
|
using System.Runtime.ConstrainedExecution;
|
|
#endif
|
|
|
|
namespace Microsoft.AspNet.Cryptography.SafeHandles
|
|
{
|
|
/// <summary>
|
|
/// Represents a handle to a Windows module (DLL).
|
|
/// </summary>
|
|
internal unsafe sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
// Called by P/Invoke when returning SafeHandles
|
|
private 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>
|
|
/// Forbids this library from being unloaded. The library will remain loaded until process termination,
|
|
/// regardless of how many times FreeLibrary is called.
|
|
/// </summary>
|
|
public void ForbidUnload()
|
|
{
|
|
// from winbase.h
|
|
const uint GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 0x00000004U;
|
|
const uint GET_MODULE_HANDLE_EX_FLAG_PIN = 0x00000001U;
|
|
|
|
IntPtr unused;
|
|
bool retVal = UnsafeNativeMethods.GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, this, out unused);
|
|
if (!retVal)
|
|
{
|
|
UnsafeNativeMethods.ThrowExceptionForLastWin32Error();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formats a message string using the resource table in the specified library.
|
|
/// </summary>
|
|
public string FormatMessage(int messageId)
|
|
{
|
|
// from winbase.h
|
|
const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
|
|
const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800;
|
|
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
|
|
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
|
|
|
|
LocalAllocHandle messageHandle;
|
|
int numCharsOutput = UnsafeNativeMethods.FormatMessage(
|
|
dwFlags: FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
lpSource: this,
|
|
dwMessageId: (uint)messageId,
|
|
dwLanguageId: 0 /* ignore current culture */,
|
|
lpBuffer: out messageHandle,
|
|
nSize: 0 /* unused */,
|
|
Arguments: IntPtr.Zero /* unused */);
|
|
|
|
if (numCharsOutput != 0 && messageHandle != null && !messageHandle.IsInvalid)
|
|
{
|
|
// Successfully retrieved the message.
|
|
using (messageHandle)
|
|
{
|
|
return new String((char*)messageHandle.DangerousGetHandle(), 0, numCharsOutput).Trim();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Message not found - that's fine.
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <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);
|
|
}
|
|
|
|
#if !DNXCORE50
|
|
[SuppressUnmanagedCodeSecurity]
|
|
#endif
|
|
private static class UnsafeNativeMethods
|
|
{
|
|
#if DNXCORE50
|
|
private const string CORE_LIBRARY_LOADER_LIB = "api-ms-win-core-libraryloader-l1-1-0.dll";
|
|
private const string CORE_LOCALIZATION_LIB = "api-ms-win-core-localization-l1-2-0.dll";
|
|
#else
|
|
private const string KERNEL32_LIB = "kernel32.dll";
|
|
#endif
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx
|
|
#if DNXCORE50
|
|
[DllImport(CORE_LOCALIZATION_LIB, EntryPoint = "FormatMessageW", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)]
|
|
#else
|
|
[DllImport(KERNEL32_LIB, EntryPoint = "FormatMessageW", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)]
|
|
#endif
|
|
public static extern int FormatMessage(
|
|
[In] uint dwFlags,
|
|
[In] SafeLibraryHandle lpSource,
|
|
[In] uint dwMessageId,
|
|
[In] uint dwLanguageId,
|
|
[Out] out LocalAllocHandle lpBuffer,
|
|
[In] uint nSize,
|
|
[In] IntPtr Arguments
|
|
);
|
|
|
|
// http://msdn.microsoft.com/en-us/library/ms683152(v=vs.85).aspx
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
#if DNXCORE50
|
|
[DllImport(CORE_LIBRARY_LOADER_LIB, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)]
|
|
#else
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
[DllImport(KERNEL32_LIB, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)]
|
|
#endif
|
|
internal static extern bool FreeLibrary(IntPtr hModule);
|
|
|
|
// http://msdn.microsoft.com/en-us/library/ms683200(v=vs.85).aspx
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
#if DNXCORE50
|
|
[DllImport(CORE_LIBRARY_LOADER_LIB, EntryPoint = "GetModuleHandleExW", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
#else
|
|
[DllImport(KERNEL32_LIB, EntryPoint = "GetModuleHandleExW", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
#endif
|
|
internal static extern bool GetModuleHandleEx(
|
|
[In] uint dwFlags,
|
|
[In] SafeLibraryHandle lpModuleName, // can point to a location within the module if GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS is set
|
|
[Out] out IntPtr phModule);
|
|
|
|
// http://msdn.microsoft.com/en-us/library/ms683212(v=vs.85).aspx
|
|
#if DNXCORE50
|
|
[DllImport(CORE_LIBRARY_LOADER_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
#else
|
|
[DllImport(KERNEL32_LIB, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
#endif
|
|
internal static extern IntPtr GetProcAddress(
|
|
[In] SafeLibraryHandle hModule,
|
|
[In, MarshalAs(UnmanagedType.LPStr)] string lpProcName);
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
|
#if DNXCORE50
|
|
[DllImport(CORE_LIBRARY_LOADER_LIB, EntryPoint = "LoadLibraryExW", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
#else
|
|
[DllImport(KERNEL32_LIB, EntryPoint = "LoadLibraryExW", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
#endif
|
|
internal static extern SafeLibraryHandle LoadLibraryEx(
|
|
[In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
|
|
[In] IntPtr hFile,
|
|
[In] uint dwFlags);
|
|
|
|
internal static void ThrowExceptionForLastWin32Error()
|
|
{
|
|
int hr = Marshal.GetHRForLastWin32Error();
|
|
Marshal.ThrowExceptionForHR(hr);
|
|
}
|
|
}
|
|
}
|
|
}
|