通过外部配置文件中的函数描述,动态的去c 调用外部程序dll中相应的函数,函数描述包括函数名称,形参类型等!

> 博客详情
C#调用C++编写的COM DLL
在C#调用C++编写的COM DLL封装库时会出现两个问题:
1.& 数据类型转换问题
2.& 指针或地址参数传送问题
&&& 首先是数据类型转换问题。因为C#是.NET语言,利用的是.NET的基本数据类型,所以实际上是将C++的数据类型与.NET的基本数据类型进行对应。
&&& 例如C++的原有函数是:
int __stdcall FunctionName(unsigned char param1, unsigned short param2)
&&& 其中的参数数据类型在C#中,必须转为对应的数据类型。如:
[DllImport(“ COM DLL path/file ”)]
extern static int FunctionName(byte param1, ushort param2)
&&& 因为调用的是__stdcall函数,所以使用了P/Invoke的调用方法。其中的方法FunctionName必须声明为静态外部函数,即加上 extern static声明头。我们可以看到,在调用的过程中,unsigned char变为了byte,unsigned short变为了ushort。变换后,参数的数据类型不变,只是声明方式必须改为.NET语言的规范。
&&& 我们可以通过下表来进行这种转换:
Win32 Types
char, INT8, SBYTE, CHAR&
System.SByte
short, short int, INT16, SHORT
System.Int16
int, long, long int, INT32, LONG32, BOOL&, INT
System.Int32
__int64, INT64, LONGLONG
System.Int64
unsigned char, UINT8, UCHAR&, BYTE
System.Byte
unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR&, __wchar_t
System.UInt16
unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT
System.UInt32
unsigned __int64, UINT64, DWORDLONG, ULONGLONG
System.UInt64
float, FLOAT
System.Single
double, long double, DOUBLE
System.Double
&&& 之后再将CLR的数据类型表示方式转换为C#的表示方式。这样一来,函数的参数类型问题就可以解决了。
&&& 现在,我们再来考虑下一个问题,如果要调用的函数参数是指针或是地址变量,怎么办?
&&& 对于这种情况可以使用C#提供的非安全代码来进行解决,但是,毕竟是非托管代码,垃圾资源处理不好的话对应用程序是很不利的。所以还是使用C#提供的 ref以及out修饰字比较好。
&&& 同上面一样,我们也举一个例子:
int __stdcall FunctionName(unsigned char &param1, unsigned char *param2)
&&& 在C#中对其进行调用的方法是:
[DllImport(“ COM DLL path/file ”)]
extern static int FunctionName(ref byte param1, ref byte param2)
&&& 看到这,可能有人会问,&是取地址,*是传送指针,为何都只用ref就可以了呢?一种可能的解释是ref是一个具有重载特性的修饰符,会自动识别 是取地址还是传送指针。
&&& 在实际的情况中,我们利用参数传递地址更多还是用在传送数组首地址上。
如:byte[] param1 = new param1(6);
&&& 在这里我们声明了一个数组,现在要将其的首地址传送过去,只要将param1数组的第一个元素用ref修饰。具体如下:
[DllImport(“ COM DLL path/file ”)]
extern static int FunctionName(ref byte param1[1], ref byte param2)
C#调用DLL函数方法
http://www.csharpwin.net/ddwstp/net/csharp/.shtml
http://www.csharpwin.net/ddwstp/net/csharp/.shtml
首先,理解托管代码与非托管代码的区别:
&&& 1.托管代码所申请的资源统一由.Net Framework管理,你不用操心,非托管代码所申请的内存等资源则需要你手动去释放&&
&&& 2.非托管程序运行会很快,是二进制的,托管程序好写,但是速度就差的很多,资源会用的很多
&&& 3.“程序"一般都是在对操作系统进行直接或者间接的操作&&
&&& "托管程序"是需要通过访问公共语言运行时(cls)才能访问操作系统的程序,而“非托管程序”不用通过访问公共语言运行时(cls)可以直接访问操作系 统的程序&&
&&& 4.vb.net,C#等写的程序是托管程序,VC++可以写托管程序,如果用到了内存管理,则只能编译为非托管程序
&&& VC++写托管的是要用.net的库,因为我们没有用.net,所以只用了非托管方式。
&&& (一)&C#调用DLL中的非托管函数一般方法
&&& 首先,应该在C#语言源程序中声明外部方法,其基本形式是:
&&& [DLLImport(“DLL文件”)]
&&& 修饰符 extern 返回变量类型 方法名称 (参数列表)
&&& 其中:
&&& DLL文件:包含定义外部方法的库文件。
&&& 修饰符: 访问修饰符,除了abstract以外在声明方法时可以使用的修饰符。
&&& 返回变量类型:在DLL文件中你需调用方法的返回变量类型。
&&& 方法名称:在DLL文件中你需调用方法的名称。
&&& 参数列表:在DLL文件中你需调用方法的列表。
&&& 注意:需要在程序声明中使用System.Runtime.InteropServices命名空间。
&&& DllImport只能放置在方法声明上。
&&& DLL文件必须位于程序当前目录或系统定义的查询路径中(即:系统环境变量中Path所设置的路径)。
&&& 返回变量类型、方法名称、参数列表一定要与DLL文件中的定义相一致。
&&& 其它可选的 DllImportAttribute 属性:
&&& CharSet 指示用在入口点中的字符集,如:CharSet=CharSet.Ansi;
&&& SetLastError 指示方法是否保留 Win32"上一错误",如:SetLastError=true;
&&& ExactSpelling 指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配,如:ExactSpelling=false;
&&& PreserveSig指示方法的签名应当被保留还是被转换, 如:PreserveSig=true;
&&& CallingConvention指示入口点的调用约定, 如:CallingConvention=CallingConvention.Winapi;
&&& 此外,关于“数据封送处理”及“封送数字和逻辑标量”请参阅其它一些文章。
&&& 举例:
&&& New file,选择visual C# Class。在文件中,创建一个public的类。把待测试的函数在这个类中作声明。
public&class&ClassName&&& &&
{&&&&&& &&
&&&[DllImport("xxx.dll",&EntryPoint&=&"xx")] &
&&&&&&&&public&static&extern&int&StartVideo(
int&nDevNum,&int&SwitchingChans,&IntPtr&Main,&IntPtr&hwndPreview); &&
&&& Xxx为待测试的dll名称,xx为dll中提供的方法函数。若要使用其它函数名,可以使用EntryPoint属性设置。
&&& 如何用DllImport调用DLL中的非托管函数,但是这个是全局的函数,假若DLL中的非托管函数有一个静态变量S,每次调用这个函数的时候,静态变 量S就自动加1。结果,当需要重新计数时,就不能得出想要的结果。所以,要注意啊,用DllImport调用DLL中的非托管函数是全局的、静态的函数。
&&& 以上介绍的就是C#调用DLL函数方法(上),剩下的内容将在C#调用DLL函数方法(下)中继续给大家讲解。
& 因为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.InteropS&&
using&System.R&&&
using&System.Reflection.E&&
&&& 3. 在namespace test中,“public class dld”的上面,添加如下代码声明参数传递方式枚举:
&&&&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); &
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&private&IntPtr&hModule&=&IntPtr.Z &
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&private&IntPtr&farProc&=&IntPtr.Z &
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&public&void&LoadDll(string&lpFileName) &
&&&&&&&&{ &
&&&&&&&&&&&&hModule&=&LoadLibrary(lpFileName); &
&&&&&&&&&&&&if&(hModule&==&IntPtr.Zero) &
&&&&&&&&&&&&&&&&throw&(new&Exception("&没有找到&:"&+&lpFileName&+&".")); &
&&&&&&&&} &
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&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&+&"&这个函数的入口点&")); &&
&&&&&&&&} &
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&public&void&UnLoadDll() &&
&&&&&&&&{ &
&&&&&&&&&&&FreeLibrary(hModule); &&
&&&&&&&&&&&&hModule&=&IntPtr.Z &&
&&&&&&&&&&&&farProc&=&IntPtr.Z &
&&&&&&&&} &
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&public&object&Invoke(
object[]&ObjArray_Parameter,&Type[]&TypeArray_ParameterType,
&ModePass[]&ModePassArray_Parameter,&Type&Type_Return) &
&&&&&&&&{ &
&&&&&&&&&&&&&
&&&&&&&&&&&&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("&参数个数及其传递方式的个数不匹配&.")); &
&&&&&&&&&&&&
&&&&&&&&&&&&AssemblyName&MyAssemblyName&=&new&AssemblyName(); &
&&&&&&&&&&&&MyAssemblyName.Name&=&"InvokeFun"; &
&&&&&&&&&&&&&
&&&&&&&&&&&&AssemblyBuilder&MyAssemblyBuilder&=&
AppDomain.CurrentDomain.DefineDynamicAssembly(
MyAssemblyName,&AssemblyBuilderAccess.Run); &
&&&&&&&&&&&&ModuleBuilder&MyModuleBuilder&=&MyAssemblyBuilder.DefineDynamicModule(
"InvokeDll"); &
&&&&&&&&&&&&
&&&&&&&&&&&&MethodBuilder&MyMethodBuilder&=&MyModuleBuilder.DefineGlobalMethod(
"MyFun",&MethodAttributes.Public&|&MethodAttributes.Static,
Type_Return,&TypeArray_ParameterType); &
&&&&&&&&&&&&&
&&&&&&&&&&&&ILGenerator&IL&=&MyMethodBuilder.GetILGenerator(); &
&&&&&&&&&&&&int&i; &
&&&&&&&&&&&&for&(i&=&0;&i&&&&ObjArray_Parameter.L&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[]&{&};& &&
&&&&&&&&&&&&Type[]&ParameterTypes&=&new&Type[]&{&};&&
&&&&&&&&&&&&ModePass[]&themode&=&new&ModePass[]&{&};&&
&&&&&&&&&&&&Type&Type_Return&=&typeof(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函数方法就介绍完了,希望对大家有所帮助。
人打赏支持
码字总数 313790
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥&VC++在ActiveX控件中动态调用外部DLL函数
秒后自动跳转到登录页
快捷登录:
举报类型:
不规范:上传重复资源
不规范:标题与实际内容不符
不规范:资源无法下载或使用
其他不规范行为
违规:资源涉及侵权
违规:含有危害国家安全等内容
违规:含有反动/色情等内容
违规:广告内容
详细原因:
任何违反下载中心规定的资源,欢迎Down友监督举报,第一举报人可获5-10下载豆奖励。
视频课程推荐
VC++在ActiveX控件中动态调用外部DLL函数
上传时间:
技术分类:
资源评价:
(1位用户参与评价)
已被下载&66&次
一个VC++系统相关的编程实例,程序演示如何在ActiveX控件中动态调用来自外部的DLL函数,虽然不常用,但很修复研究一下,以帮助您更好的学习VC++技术。
本资料共包含以下附件:
VC++在ActiveX控件中动态调用外部DLL函数.rar
51CTO下载中心常见问题:
1.如何获得下载豆?
1)上传资料
2)评论资料
3)每天在首页签到领取
4)购买VIP会员服务,无需下载豆下载资源
5)更多途径:点击此处
2.如何删除自己的资料?
下载资料意味着您已同意遵守以下协议:
1.资料的所有权益归上传用户所有
2.未经权益所有人同意,不得将资料中的内容挪作商业或盈利用途
3.51CTO下载中心仅提供资料交流平台,并不对任何资料负责
4.本站资料中如有侵权或不适当内容,请邮件与我们联系()
5.本站不保证资源的准确性、安全性和完整性, 同时也不承担用户因使用这些资料对自己和他人造成任何形式的伤害或损失
下载2088次
相关专题推荐
本专题收录Java经典编程的实例源码,
在国内的开发语言中,java凭借这简单
本套视频教程是韩顺平老师,循序渐进
北京圣思园张龙(风中叶)老师的Java
讲述Arm嵌入式Linux系统下的C语言编程
这段视频是从尚学堂科技的教学课堂上
本套视频共78集,是由郝斌老师根据多
本视频专题共180集涵盖了C语言概述中
本视频专题共107集涵盖了Java概述、数
由传智播客毕向东老师讲解的Java基础
本专题为spring视频教程,共31集。教
本专题为C语言黑客编程系列视频教程,
本专题为韩顺平讲解的Java从入门到精
本专题为Java Web项目开发案例精粹视
SSH为struts+spring+hibernate的一个
本专题为疯狂Java李刚老师讲解的Stru
意见或建议:
联系方式:
您已提交成功!感谢您的宝贵意见,我们会尽快处理问题:读取外部dll中函数的地址
描述:qq函数
我在用GetProcAddress这个函数来发回qq安装路径中的KernelUtil.dll中的?SaveMsg@Msg194@Util@@YAHPB_WKKKPAUITXMsgPack@@PAUITXData@@PAUITXCallback@@@Z这个函数的地址,总是返回不出来,语句是这么写的:
GetProcAddress(hModule,&"?SaveMsg@Msg194@Util@@YAHPB_WKKKPAUITXMsgPack@@PAUITXData@@PAUITXCallback@@@Z");
但是我用这样的语句返回这个dll中的InitBugReport函数的地址就可以,现在搞不起怎么回事,是不是函数名的区别
下图就是读取的这个dll中的函数解决方案1:
说了半天,都没有看到你说的这个函数名。用&“DEPENDS”&工具查看一下确定的函数名.&如果这个&DLL&是自己定的,把每个函数前面添加&"&extern&"C"&"&修饰一下,&函数名就不在是乱码了。
解决方案2:
那些‘?’开头的&名&是&被&编译器&manglling&后的名。
http://blog.csdn.net/xt_xiaotian/article/details/5431410解决方案3:
lpProcName&
Pointer&to&a&null-terminated&string&containing&the&function&name,&or&specifies&the&function's&ordinal&value.&If&this&parameter&is&an&ordinal&value,&it&must&be&in&the&low-order&&the&high-order&word&must&be&zero.&
按&序数&试试
以上介绍了“读取外部dll中函数的地址”的问题解答,希望对有需要的网友有所帮助。
本文网址链接:/itwd/973681.html
上一篇: 下一篇:

我要回帖

更多关于 js 调用动态函数名 的文章

 

随机推荐