没有合适的资源?快使用搜索试试~ 我知道了~
C#调C++动态类库(DLL) (2).docx
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 148 浏览量
2023-02-27
19:46:04
上传
评论
收藏 152KB DOCX 举报
温馨提示
试读
12页
.
资源推荐
资源详情
资源评论
在 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 语言的规范。
我们可以通过下表来进行这种转换:
unsigned char, UINT8, UCHAR , System.Byte
BYTE
unsigned short, UINT16, USHORT, System.UInt16
WORD, ATOM, WCHAR ,
__wchar_t
System.UInt64
System.Single
System.Double
double, long double, DOUBLE
之后再将 CLR 的数据类型表示方式转换为 C#的表示方式。这样一来,函数
的参数类型问题就可以解决了。
现在,我们再来考虑下一个问题,如果要调用的函数参数是指针或是地址变
量,怎么办?
对于这种情况可以使用 C#提供的非安全代码来进行解决,但是,毕竟是非托
管代码,垃圾资源处理不好的话对应用程序是很不利的。所以还是使用 C#提供
的 ref 以及 out 修饰字比较好。
同上面一样,我们也举一个例子:
int __stdcall FunctionName(unsigned char ¶m1, 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 或 C++ 或 Delphi 编写的,如何利用旧模块对于开
发人员来说,有三种可用方法供选择: 第一、将 C 或 C++ 函数用 C# 彻底改写一遍,这样整个项目
代码比较统一,维护也方便一些。但是尽管微软以及某些书籍说,C# 和 C++ 如何接近,但是改写起来还
是很痛苦的事情,特别是 C++ 里的指针和内存操作; 第二、将 C 或 C++ 函数封装成 COM,在 C# 中
调用 COM 比较方便,只是在封装时需要处理 C 或 C++ 类型和 COM 类型之间的转换,也有一些麻烦,另
外 COM 还需要注册,注册次数多了又可能导致混乱; 第三、将 C 或 C++ 函数封装成动态链接库,
在开发新项目中使用了新的语言开发 C# 和新的技术方案 WEB Service,但是在新
封装的过程简单,工作量不大。因此我决定采用加载动态链接库的方法实现,于是产生了在 C# 中如何调
用自定义的动态链接库问题,我在网上搜索相关主题,发现一篇调用系统 API 的文章,但是没有说明如何
解决此问题,在 MSDN 上也没有相关详细说明。基于此,我决定自己从简单出发,逐步试验,看看能否达
到自己的目标。 (说明一点:我这里改写为什么很怕麻烦,我改写的代码是变长加密算法函数,代码
有 600多行,对算法本身不熟悉,算法中指针和内存操作太多,要想保证算法正确,最可行的方法就是少
动代码,否则只要有一点点差错,就不能肯定算法与以前兼容) 二、技术实现 下面看看如何逐
步实现动态库的加载,类型的匹配,动态链接库函数导出的定义,这个不需要多说,大家参考下面宏定义
即可: #define LIBEXPORT_API extern "C" __declspec(dllexport) 第一步,我先从简单的调
用出发,定义了一个简单的函数,该函数仅仅实现一个整数加法求和: LIBEXPORT_API int mySum(int
a,int b){ return a+b;}
public class RefComm
EntryPoint=" mySum ",
public static extern
int mySum (int a,int b);
}
在 C#中调用测试:
int iSum = RefComm.mySum(2,3);
运行查看结果 iSum为 5,调用正确。
第一步试验完成,说明在 C#中能够调用自定义的动态链接库函数。
第二步,我定义了字符串操作的函数(简单起见,还是采用前面的函数名),返回结果为字符串:
LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a); return a;} C# 导入定义:
EntryPoint=" mySum ",
CallingConvention=CallingConvention.StdCall)] public
static extern string mySum (string a, string b);
string strTmp= RefComm.mySum("12345", strDest);
运行查看结果 strTmp 为"12345",但是 strDest为空。我修改动态链接库实现,返回结果为串 b:
修改 C# 导入定义,
将串 b 修改为 ref方式:
EntryPoint=" mySum ",
public static extern
string strTmp= RefComm.mySum("12345", ref
运行查看结果 strTmp 和 strDest 均不对,含不可见字符。再修改 C# 导入定义,将
EntryPoint=" mySum ",
public static extern
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
string mySum (string a, string b);
在 C#中再调用测试: string strDest="";
strDest);
但是在函数出口参数中没能进行输出。再次修改 C# 导入定义,将串 b 修改为引用(ref):
string strTmp= RefComm. mySum("12345", ref
运行查看结果 strTmp 为"12345",但是串 strDest 没有赋值。第二步实现函数返回串,
EntryPoint=" mySum ",
public static extern
string mySum (string a, ref string b);
第三步,修改动态链接库实现,将 b 修改为双重指针:
LIBEXPORT_API char *mySum(char *a,char **b){sprintf((*b),"%s",a); return *b;} C#导入定义:
剩余11页未读,继续阅读
资源评论
xxpr_ybgg
- 粉丝: 6507
- 资源: 3万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功