142 lines
5.8 KiB
C#
142 lines
5.8 KiB
C#
#region Copyright (c) Microsoft Corporation.
|
|
//
|
|
// The source code of UnmanagedLibrary.cs is quoted from Mike Stall's article:
|
|
//
|
|
// Type-safe Managed wrappers for kernel32!GetProcAddress
|
|
// http://blogs.msdn.com/jmstall/archive/2007/01/06/Typesafe-GetProcAddress.aspx
|
|
//
|
|
// This source is subject to the Microsoft Public License.
|
|
// See http://www.opensource.org/licenses/MS-PL.
|
|
// All other rights reserved.
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
|
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
#endregion
|
|
|
|
#region Using Directives
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Permissions;
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
|
#endregion
|
|
|
|
namespace MaterialSkin.Gesture
|
|
{
|
|
/// <summary>
|
|
/// Utility class to wrap an unmanaged DLL and be responsible for freeing it.
|
|
/// </summary>
|
|
/// <remarks>This is a managed wrapper over the native LoadLibrary, GetProcAddress, and
|
|
/// FreeLibrary calls.
|
|
/// </remarks>
|
|
public sealed class UnmanagedLibrary : IDisposable
|
|
{
|
|
#region Safe Handles and Native imports
|
|
|
|
// See http://msdn.microsoft.com/msdnmag/issues/05/10/Reliability/ for more about safe handles.
|
|
[SecurityPermission( SecurityAction.LinkDemand, UnmanagedCode = true )]
|
|
sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private SafeLibraryHandle() : base( true ) { }
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
return NativeMethods.FreeLibrary( handle );
|
|
}
|
|
}
|
|
|
|
static class NativeMethods
|
|
{
|
|
const string KERNEL32 = "kernel32";
|
|
[DllImport( KERNEL32, CharSet = CharSet.Auto, BestFitMapping = false, SetLastError = true )]
|
|
public static extern SafeLibraryHandle LoadLibrary( string fileName );
|
|
|
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
|
[DllImport( KERNEL32, SetLastError = true )]
|
|
[return: MarshalAs( UnmanagedType.Bool )]
|
|
public static extern bool FreeLibrary( IntPtr hModule );
|
|
|
|
[DllImport( KERNEL32 )]
|
|
public static extern IntPtr GetProcAddress( SafeLibraryHandle hModule, String procname );
|
|
}
|
|
|
|
#endregion // Safe Handles and Native imports
|
|
|
|
/// <summary>
|
|
/// Constructor to load a dll and be responible for freeing it.
|
|
/// </summary>
|
|
/// <param name="fileName">full path name of dll to load</param>
|
|
/// <exception cref="FileNotFoundException">if fileName can't be found</exception>
|
|
/// <remarks>Throws exceptions on failure. Most common failure would be file-not-found, or
|
|
/// that the file is not a loadable image.</remarks>
|
|
public UnmanagedLibrary( string fileName )
|
|
{
|
|
m_hLibrary = NativeMethods.LoadLibrary( fileName );
|
|
if ( m_hLibrary.IsInvalid )
|
|
{
|
|
int hr = Marshal.GetHRForLastWin32Error();
|
|
Marshal.ThrowExceptionForHR( hr );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dynamically lookup a function in the dll via kernel32!GetProcAddress.
|
|
/// </summary>
|
|
/// <param name="functionName">raw name of the function in the export table.</param>
|
|
/// <returns>null if function is not found. Else a delegate to the unmanaged function.
|
|
/// </returns>
|
|
/// <remarks>GetProcAddress results are valid as long as the dll is not yet unloaded. This
|
|
/// is very very dangerous to use since you need to ensure that the dll is not unloaded
|
|
/// until after you're done with any objects implemented by the dll. For example, if you
|
|
/// get a delegate that then gets an IUnknown implemented by this dll,
|
|
/// you can not dispose this library until that IUnknown is collected. Else, you may free
|
|
/// the library and then the CLR may call release on that IUnknown and it will crash.</remarks>
|
|
public TDelegate GetUnmanagedFunction<TDelegate>( string functionName ) where TDelegate : class
|
|
{
|
|
IntPtr p = NativeMethods.GetProcAddress( m_hLibrary, functionName );
|
|
|
|
// Failure is a common case, especially for adaptive code.
|
|
if ( p == IntPtr.Zero )
|
|
{
|
|
return null;
|
|
}
|
|
Delegate function = Marshal.GetDelegateForFunctionPointer( p, typeof( TDelegate ) );
|
|
|
|
// Ideally, we'd just make the constraint on TDelegate be
|
|
// System.Delegate, but compiler error CS0702 (constrained can't be System.Delegate)
|
|
// prevents that. So we make the constraint system.object and do the cast from object-->TDelegate.
|
|
object o = function;
|
|
|
|
return (TDelegate)o;
|
|
}
|
|
|
|
#region IDisposable Members
|
|
/// <summary>
|
|
/// Call FreeLibrary on the unmanaged dll. All function pointers
|
|
/// handed out from this class become invalid after this.
|
|
/// </summary>
|
|
/// <remarks>This is very dangerous because it suddenly invalidate
|
|
/// everything retrieved from this dll. This includes any functions
|
|
/// handed out via GetProcAddress, and potentially any objects returned
|
|
/// from those functions (which may have an implemention in the
|
|
/// dll).
|
|
/// </remarks>
|
|
public void Dispose()
|
|
{
|
|
if ( !m_hLibrary.IsClosed )
|
|
{
|
|
m_hLibrary.Close();
|
|
}
|
|
}
|
|
|
|
// Unmanaged resource. CLR will ensure SafeHandles get freed, without requiring a finalizer on this class.
|
|
SafeLibraryHandle m_hLibrary;
|
|
|
|
#endregion
|
|
}
|
|
} |