C#中怎么调用DLL函数

今天就跟大家聊聊有关C#中怎么调用DLL函数,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

创新互联专注为客户提供全方位的互联网综合服务,包含不限于成都网站制作、做网站、长汀网络推广、成都微信小程序、长汀网络营销、长汀企业策划、长汀品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联为所有大学生创业者提供长汀建站搭建服务,24小时服务热线:13518219792,官方网址:www.cdcxhl.com

因为C#中使用DllImport是不能像动态load/unload assembly那样,所以只能借助API函数了。在kernel32.dll中,与动态库调用有关的函数包括[3]:

①LoadLibrary(或MFC 的AfxLoadLibrary),装载动态库。

②GetProcAddress,获取要引入的函数,将符号名或标识号转换为DLL内部地址。

③FreeLibrary(或MFC的AfxFreeLibrary),释放动态链接库。

它们的原型分别是:

HMODULE LoadLibrary(LPCTSTR lpFileName);

FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);

BOOL FreeLibrary(HMODULE hModule);

现在,我们可以用IntPtr hModule=LoadLibrary(“Count.dll”);来获得Dll的句柄,用IntPtr farProc=GetProcAddress(hModule,”_count@4”);来获得函数的入口地址。

但是,知道函数的入口地址后,怎样调用这个函数呢?因为在C#中是没有函数指针的,没有像C++那样的函数指针调用方式来调用函数,所以我们得借助其它方法。经过研究,发现我们可以通过结合使用System.Reflection.Emit及System.Reflection.Assembly里的类和函数达到我们的目的。为了以后使用方便及实现代码的复用,我们可以编写一个类。

1) dld类的编写:

1.打开项目“Test”,打开类视图,右击“Tzb”,选择“添加”-->“类”,类名设置为“dld”,即dynamic loading dll 的每个单词的开头字母。

2.添加所需的命名空间及声明参数传递方式枚举:

using System.Runtime.InteropServices; // 用DllImport 需用此命名空间   using System.Reflection; // 使用Assembly 类需用此命名空间   using System.Reflection.Emit; // 使用ILGenerator 需用此命名空间

3. 在namespace test中,“public class dld”的上面,添加如下代码声明参数传递方式枚举:

/// < summary>        /// 参数传递方式枚举,ByValue 表示值传递,ByRef 表示址传递       /// < /summary>        public enum ModePass       {           ByValue = 0x0001,           ByRef = 0x0002   }

4、在public class DLD中,添加如下代码:

public class DLD       {           [DllImport("kernel32.dll")]           public static extern IntPtr LoadLibrary(string lpFileName);               [DllImport("kernel32.dll")]           public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProceName);               [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]           public static extern bool FreeLibrary(IntPtr hModule);               /// < summary>                /// Loadlibrary 返回的函数库模块的句柄                /// < /summary>                private IntPtr hModule = IntPtr.Zero;               /// < summary>                /// GetProcAddress 返回的函数指针                /// < /summary>                private IntPtr farProc = IntPtr.Zero;               /// < summary>                /// 装载 Dll                /// < /summary>                /// < param name="lpFileName">DLL 文件名 < /param>                public void LoadDll(string lpFileName)           {                   hModule = LoadLibrary(lpFileName);                   if (hModule == IntPtr.Zero)                       throw (new Exception(" 没有找到 :" + lpFileName + "."));           }                   /// < summary>                /// 获得函数指针                /// < /summary>                /// < param name="lpProcName"> 调用函数的名称 < /param>                public void LoadFun(string lpProcName)           { // 若函数库模块的句柄为空,则抛出异常                    if (hModule == IntPtr.Zero)                       throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));                   // 取得函数指针                    farProc = GetProcAddress(hModule, lpProcName);                   // 若函数指针,则抛出异常                    if (farProc == IntPtr.Zero)                       throw (new Exception(" 没有找到 :" + lpProcName + " 这个函数的入口点 "));               }               /// < summary>                /// 卸载 Dll                /// < /summary>                public void UnLoadDll()           {                   FreeLibrary(hModule);                   hModule = IntPtr.Zero;                   farProc = IntPtr.Zero;               }                   /// < summary>                /// 调用所设定的函数                /// < /summary>                /// < param name="ObjArray_Parameter"> 实参 < /param>                /// < param name="TypeArray_ParameterType"> 实参类型 < /param>                /// < param name="ModePassArray_Parameter"> 实参传送方式 < /param>                /// < param name="Type_Return"> 返回类型 < /param>                /// < returns> 返回所调用函数的 object< /returns>                public object Invoke(object[] ObjArray_Parameter, Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter, Type Type_Return)           {                   // 下面 3 个 if 是进行安全检查 , 若不能通过 , 则抛出异常                    if (hModule == IntPtr.Zero)                       throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));                   if (farProc == IntPtr.Zero)                       throw (new Exception(" 函数指针为空 , 请确保已进行 LoadFun 操作 !"));                   if (ObjArray_Parameter.Length != ModePassArray_Parameter.Length)                       throw (new Exception(" 参数个数及其传递方式的个数不匹配 ."));                   // 下面是创建 MyAssemblyName 对象并设置其 Name 属性                    AssemblyName MyAssemblyName = new AssemblyName();                   MyAssemblyName.Name = "InvokeFun";                   // 生成单模块配件                    AssemblyBuilder MyAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName, AssemblyBuilderAccess.Run);                   ModuleBuilder MyModuleBuilder = MyAssemblyBuilder.DefineDynamicModule("InvokeDll");                   // 定义要调用的方法 , 方法名为“ MyFun ”,返回类型是“ Type_Return ”参数类型是“ TypeArray_ParameterType ”                    MethodBuilder MyMethodBuilder = MyModuleBuilder.DefineGlobalMethod("MyFun", MethodAttributes.Public | MethodAttributes.Static, Type_Return, TypeArray_ParameterType);                   // 获取一个 ILGenerator ,用于发送所需的 IL                    ILGenerator IL = MyMethodBuilder.GetILGenerator();                   int i;                   for (i = 0; i <  ObjArray_Parameter.Length; i++)               {// 用循环将参数依次压入堆栈                        switch (ModePassArray_Parameter[i])                   {                           case ModePass.ByValue:                               IL.Emit(OpCodes.Ldarg, i);                               break;                           case ModePass.ByRef:                               IL.Emit(OpCodes.Ldarga, i);                               break;                           default:                               throw (new Exception(" 第 " + (i + 1).ToString() + " 个参数没有给定正确的传递方式 ."));                       }                   }                   if (IntPtr.Size == 4)               {// 判断处理器类型                        IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32());                   }                   else if (IntPtr.Size == 8)               {                       IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64());                   }                   else              {                       throw new PlatformNotSupportedException();                   }                   IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, Type_Return, TypeArray_ParameterType);                   IL.Emit(OpCodes.Ret); // 返回值                    MyModuleBuilder.CreateGlobalFunctions();                   // 取得方法信息                    MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("MyFun");                   return MyMethodInfo.Invoke(null, ObjArray_Parameter);// 调用方法,并返回其值                }       }

2) dld类的使用:

1.打开项目“Test”,向“Form1”窗体中添加一个按钮,和一个TestBox,Name改为txRet。视图中双击按钮,在“button1_Click”方法体上面添加代码,创建一个dld类实例,并进行测试。具体如下:

private void button1_Click(object sender, EventArgs e)           {                   int ret = 0;               dld myDLD = new dld();                   myDLD.LoadDll("xxx.dll");                   myDLD.LoadFun("InitSDK");                   object[] Parameters = new object[] { }; // 实参为0                    Type[] ParameterTypes = new Type[] { }; // 实参类型为int                    ModePass[] themode = new ModePass[] { }; // 传送方式为值传                   Type Type_Return = typeof(int); // 返回类型为int                   ret = (int)myDLD.Invoke(Parameters, ParameterTypes, themode, Type_Return);               txRet.Text = ret.ToString();               if (ret != 1)               {                   MessageBox.Show("InitSDK failed !");               }               if (ret == 1)               {                   MessageBox.Show("InitSDK Sucessed !");               }           }

其中,xxx为要测试的dll名称,InitSDK为dll中的要测试的函数。

看完上述内容,你们对C#中怎么调用DLL函数有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注创新互联行业资讯频道,感谢大家的支持。

当前题目:C#中怎么调用DLL函数
当前URL:https://www.cdcxhl.com/article40/jiesho.html

成都网站建设公司_创新互联,为您提供用户体验定制开发商城网站网站收录外贸网站建设企业建站

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

小程序开发