|
/****************************** Module Header ******************************\
* Module Name: UnmanagedLibrary.cs
* Project: CSLoadLibrary
* Copyright (c) Microsoft Corporation.
*
* The source code of UnmanagedLibrary 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.microsoft.com/opensource/licenses.mspx#Ms-PL.
* All other rights reserved.
*
* History:
* * 1/21/2009 11:04 PM Jialiang Ge Created
\***************************************************************************/
#region Using directives
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
#endregion
/// <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.
/// </example>
/// <see cref=
/// "http://blogs.msdn.com/jmstall/archive/2007/01/06/Typesafe-GetProcAddress.aspx"
/// />
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
{
/// <summary>
/// Create safe library handle
/// </summary>
private SafeLibraryHandle() : base(true) { } // SafeLibraryHandle
/// <summary>
/// Release handle
/// </summary>
protected override bool ReleaseHandle()
{
return NativeMethods.FreeLibrary(handle);
} // ReleaseHandle()
} // class SafeLibraryHandle
/// <summary>
/// Native methods
/// </summary>
static class NativeMethods
{
const string s_kernel = "kernel32";
[DllImport(s_kernel, CharSet = CharSet.Auto,
BestFitMapping = false, SetLastError = true)]
public static extern SafeLibraryHandle LoadLibrary(string fileName);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport(s_kernel, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport(s_kernel, EntryPoint = "GetProcAddress")]
public static extern IntPtr GetProcAddress(
SafeLibraryHandle hModule, String procname);
} // class NativeMethods
#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="System.IO.FileNotFound">
/// 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);
}
} // UnmanagedLibrary(fileName)
/// <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;
} // GetUnmanagedFunction(, functionName)
#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();
}
} // Dispose()
// Unmanaged resource. CLR will ensure SafeHandles get freed, without
// requiring a finalizer on this class.
SafeLibraryHandle m_hLibrary;
#endregion
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Microsoft All-In-One Code Framework delineates the framework and skeleton of Microsoft development techniques through typical sample codes in three popular programming languages (Visual C#, VB.NET, Visual C++). Each sample is elaborately selected, composed, and documented to demonstrate one frequently-asked, tested or used coding scenario based on our support experience in MSDN newsgroups and forums. If you are a software developer, you can fill the skeleton with blood, muscle and soul. If you are a software tester or a support engineer like us, you may extend the sample codes a little to fit your specific test scenario or refer your customer to this project if the customer's question coincides with what we collected.
http://cfx.codeplex.com/