C# 中如何动态调用非托管DLL(一)转载

隐藏行号 复制代码 这是一段程序代码。
  1. using System;
    
  2. using System.Collections.Generic;
    
  3. using System.Linq;
    
  4. using System.Text;
    
  5. using System.Runtime.InteropServices;
    
  6. using System.Reflection;
    
  7. using System.Reflection.Emit;
    
  8. 
    
  9. namespace IdeaSoft.ECEMonitor.Utils
    
  10. {
    
  11.     /// <summary> 
    
  12.     /// 参数传递方式枚举 ,ByValue 表示值传递 ,ByRef 表示址传递 
    
  13.     /// </summary> 
    
  14.     public enum ModePass
    
  15.     {
    
  16.         ByValue = 0x0001,
    
  17.         ByRef = 0x0002
    
  18.     }
    
  19. 
    
  20.     public class DllLoader
    
  21.     {
    
  22.         /// <summary> 
    
  23.         /// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName); 
    
  24.         /// </summary> 
    
  25.         /// <param name="lpFileName">DLL 文件名 </param> 
    
  26.         /// <returns> 函数库模块的句柄 </returns> 
    
  27.         [DllImport("kernel32.dll")]
    
  28.         static extern IntPtr LoadLibrary(string lpFileName);
    
  29. 
    
  30.         /// <summary> 
    
  31.         /// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName); 
    
  32.         /// </summary> 
    
  33.         /// <param name="hModule"> 包含需调用函数的函数库模块的句柄 </param> 
    
  34.         /// <param name="lpProcName"> 调用函数的名称 </param> 
    
  35.         /// <returns> 函数指针 </returns> 
    
  36.         [DllImport("kernel32.dll")]
    
  37.         static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
    
  38. 
    
  39.         /// <summary> 
    
  40.         /// 原型是 : BOOL FreeLibrary(HMODULE hModule); 
    
  41.         /// </summary> 
    
  42.         /// <param name="hModule"> 需释放的函数库模块的句柄 </param> 
    
  43.         /// <returns> 是否已释放指定的 Dll</returns> 
    
  44.         [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
    
  45.         static extern bool FreeLibrary(IntPtr hModule);
    
  46. 
    
  47.         /// <summary> 
    
  48.         /// Loadlibrary 返回的函数库模块的句柄 
    
  49.         /// </summary> 
    
  50.         private IntPtr hModule = IntPtr.Zero;
    
  51.         /// <summary> 
    
  52.         /// GetProcAddress 返回的函数指针 
    
  53.         /// </summary> 
    
  54.         private IntPtr farProc = IntPtr.Zero;
    
  55. 
    
  56.         /// <summary> 
    
  57.         /// 装载 Dll 
    
  58.         /// </summary> 
    
  59.         /// <param name="lpFileName">DLL 文件名 </param> 
    
  60.         public void LoadDll(string lpFileName)
    
  61.         {
    
  62.             hModule = LoadLibrary(lpFileName);
    
  63.             if (hModule == IntPtr.Zero)
    
  64.                 throw (new Exception(" 没有找到 :" + lpFileName + "."));
    
  65.         }
    
  66. 
    
  67.         /// <summary>
    
  68.         /// 若已有已装载Dll的句柄,可以使用LoadDll方法的第二个版本:
    
  69.         /// </summary>
    
  70.         /// <param name="HMODULE"></param>
    
  71.         public void LoadDll(IntPtr HMODULE)
    
  72.         {
    
  73.             if (HMODULE == IntPtr.Zero)
    
  74.                 throw (new Exception(" 所传入的函数库模块的句柄 HMODULE 为空 ."));
    
  75.             hModule = HMODULE;
    
  76.         }
    
  77. 
    
  78.         /// <summary> 
    
  79.         /// 获得函数指针 
    
  80.         /// </summary> 
    
  81.         /// <param name="lpProcName"> 调用函数的名称 </param> 
    
  82.         public void LoadFun(string lpProcName)
    
  83.         {
    
  84.             // 若函数库模块的句柄为空,则抛出异常 
    
  85.             if (hModule == IntPtr.Zero)
    
  86.                 throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
    
  87. 
    
  88.             // 取得函数指针 
    
  89.             farProc = GetProcAddress(hModule, lpProcName);
    
  90. 
    
  91.             // 若函数指针,则抛出异常 
    
  92.             if (farProc == IntPtr.Zero)
    
  93.                 throw (new Exception(" 没有找到 :" + lpProcName + " 这个函数的入口点 "));
    
  94. 
    
  95.         }
    
  96. 
    
  97.         /// <summary> 
    
  98.         /// 获得函数指针 
    
  99.         /// </summary> 
    
  100.         /// <param name="lpFileName"> 包含需调用函数的 DLL 文件名 </param> 
    
  101.         /// <param name="lpProcName"> 调用函数的名称 </param> 
    
  102.         public void LoadFun(string lpFileName, string lpProcName)
    
  103.         {
    
  104.             // 取得函数库模块的句柄 
    
  105.             hModule = LoadLibrary(lpFileName);
    
  106.             // 若函数库模块的句柄为空,则抛出异常 
    
  107.             if (hModule == IntPtr.Zero)
    
  108.                 throw (new Exception(" 没有找到 :" + lpFileName + "."));
    
  109. 
    
  110.             // 取得函数指针 
    
  111.             farProc = GetProcAddress(hModule, lpProcName);
    
  112. 
    
  113.             // 若函数指针,则抛出异常 
    
  114.             if (farProc == IntPtr.Zero)
    
  115.                 throw (new Exception(" 没有找到 :" + lpProcName + " 这个函数的入口点 "));
    
  116.         }
    
  117. 
    
  118.         /// <summary> 
    
  119.         /// 卸载 Dll 
    
  120.         /// </summary> 
    
  121.         public void UnLoadDll()
    
  122.         {
    
  123.             FreeLibrary(hModule);
    
  124.             hModule = IntPtr.Zero;
    
  125.             farProc = IntPtr.Zero;
    
  126.         }
    
  127. 
    
  128.         /// <summary> 
    
  129.         /// 调用所设定的函数 
    
  130.         /// </summary> 
    
  131.         /// <param name="ObjArray_Parameter"> 实参 </param> 
    
  132.         /// <param name="TypeArray_ParameterType"> 实参类型 </param> 
    
  133.         /// <param name="ModePassArray_Parameter"> 实参传送方式 </param> 
    
  134.         /// <param name="Type_Return"> 返回类型 </param> 
    
  135.         /// <returns> 返回所调用函数的 object</returns> 
    
  136. 
    
  137.         public object Invoke(object[] ObjArray_Parameter, Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter, Type Type_Return)
    
  138.         {
    
  139.             // 下面 3 个 if 是进行安全检查 , 若不能通过 , 则抛出异常 
    
  140.             if (hModule == IntPtr.Zero)
    
  141.                 throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
    
  142. 
    
  143.             if (farProc == IntPtr.Zero)
    
  144.                 throw (new Exception(" 函数指针为空 , 请确保已进行 LoadFun 操作 !"));
    
  145. 
    
  146.             if (ObjArray_Parameter.Length != ModePassArray_Parameter.Length)
    
  147.                 throw (new Exception(" 参数个数及其传递方式的个数不匹配 ."));
    
  148. 
    
  149.             // 下面是创建 MyAssemblyName 对象并设置其 Name 属性 
    
  150.             AssemblyName MyAssemblyName = new AssemblyName();
    
  151.             MyAssemblyName.Name = "InvokeFun";
    
  152. 
    
  153.             // 生成单模块配件 
    
  154.             AssemblyBuilder MyAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName, AssemblyBuilderAccess.Run);
    
  155.             ModuleBuilder MyModuleBuilder = MyAssemblyBuilder.DefineDynamicModule("InvokeDll");
    
  156. 
    
  157.             // 定义要调用的方法 , 方法名为“ MyFun ”,返回类型是“ Type_Return ”参数类型是“ TypeArray_ParameterType ” 
    
  158.             MethodBuilder MyMethodBuilder = MyModuleBuilder.DefineGlobalMethod("MyFun", MethodAttributes.Public | MethodAttributes.Static, Type_Return, TypeArray_ParameterType);
    
  159.             
    
  160.             // 获取一个 ILGenerator ,用于发送所需的 IL 
    
  161.             ILGenerator IL = MyMethodBuilder.GetILGenerator();
    
  162. 
    
  163.             int i;
    
  164.             for (i = 0; i < ObjArray_Parameter.Length; i++)
    
  165.             {
    
  166.                 // 用循环将参数依次压入堆栈 
    
  167.                 switch (ModePassArray_Parameter[i])
    
  168.                 {
    
  169.                     case ModePass.ByValue:
    
  170.                         IL.Emit(OpCodes.Ldarg, i);
    
  171.                         break;
    
  172.                     case ModePass.ByRef:
    
  173.                         IL.Emit(OpCodes.Ldarga, i);
    
  174.                         break;
    
  175.                     default:
    
  176.                         throw (new Exception(" 第 " + (i + 1).ToString() + " 个参数没有给定正确的传递方式 ."));
    
  177.                 }
    
  178.             }
    
  179. 
    
  180.             if (IntPtr.Size == 4)
    
  181.             {
    
  182.                 // 判断处理器类型 
    
  183.                 IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32());
    
  184.             }
    
  185.             else if (IntPtr.Size == 8)
    
  186.             {
    
  187.                 IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64());
    
  188.             }
    
  189.             else
    
  190.             {
    
  191.                 throw new PlatformNotSupportedException();
    
  192.             }
    
  193.             IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, Type_Return, TypeArray_ParameterType);
    
  194.             IL.Emit(OpCodes.Ret); // 返回值 
    
  195.             MyModuleBuilder.CreateGlobalFunctions();
    
  196. 
    
  197.             // 取得方法信息 
    
  198.             MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("MyFun");
    
  199.             return MyMethodInfo.Invoke(null, ObjArray_Parameter);// 调用方法,并返回其值 
    
  200.         }
    
  201. 
    
  202. 
    
  203.         /// <summary> 
    
  204.         /// 调用所设定的函数 
    
  205.         /// </summary> 
    
  206.         /// <param name="IntPtr_Function"> 函数指针 </param> 
    
  207.         /// <param name="ObjArray_Parameter"> 实参 </param> 
    
  208.         /// <param name="TypeArray_ParameterType"> 实参类型 </param> 
    
  209.         /// <param name="ModePassArray_Parameter"> 实参传送方式 </param> 
    
  210.         /// <param name="Type_Return"> 返回类型 </param> 
    
  211.         /// <returns> 返回所调用函数的 object</returns> 
    
  212.         public object Invoke(IntPtr IntPtr_Function, object[] ObjArray_Parameter, Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter, Type Type_Return)
    
  213.         {
    
  214.             // 下面 2 个 if 是进行安全检查 , 若不能通过 , 则抛出异常 
    
  215.             if (hModule == IntPtr.Zero)
    
  216.                 throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
    
  217. 
    
  218.             if (IntPtr_Function == IntPtr.Zero)
    
  219.                 throw (new Exception(" 函数指针 IntPtr_Function 为空 !"));
    
  220. 
    
  221.             farProc = IntPtr_Function;
    
  222.             return Invoke(ObjArray_Parameter, TypeArray_ParameterType, ModePassArray_Parameter, Type_Return);
    
  223. 
    
  224.         }
    
  225. 
    
  226.     }
    
  227. }
    
posted @ 2009-09-01 09:12  chillwind  阅读(741)  评论(0)    收藏  举报