2021-06-03

C#调用C/C++的动态连接库函数(DLL)
1 数据类型对应转换

  • handle------------IntPtr

  • hwnd--------------IntPtr

  • char*-------------string

  • int*--------------ref int

  • int&--------------ref int

  • void*-------------IntPtr

  • unsigned char*-----ref byte

  • Struct需要再C#中重新定义一个Struct

  • CallBack回调函数需要封装在一个委托里,delegate static extern int FunCallBack(string str);

    注意:在每个函数的前面加上public static extern 返回的数据类型,如果不加public,函数默认为私有函数,调用会出错。

2 在C#中调用C/C++的DL封装库时注意两个问题:
2.1 数据类型转换问题:
首先是数据类型的转换,因为C#是.Net语言,利用的是.net的基本数据类型,所以实际上是将C/c++的数据类型与.net的基本数据类型进行一一对应。

PS:一个C++原函数是:
    int_stdcall FunctionName(undigned 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语言的规范。

我们可以通过下表来进行这种转换。

C#调用C++ DLL的转换表之后再将CLR的数据类型表示方式转换为C#的表示方式,这样一来函数的参数类型问题就解决了。
2.2 指针或地址参数传递问题
下一个问题,如果要调用的函数的参数是指针或是地址变量,怎么做?
对于这种情况可以使用C#提供的非安全代码来解决,但是,毕竟是非托管代码,垃圾资源处理不好的话,对应用程序是很不利的,所以还是使用C#提供的ref和out修饰符比较好。
番外:ref和out:
(1、out与ref区别:
1、使用ref型参数时,传入的参数必须先被初始化,对out而言,必须在方法中对其完成初始化。

2、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字,以满足匹配。

3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。

4、ref传进去的参数在函数内部可以直接使用,而out不可。

5、系统对ref的限制是更少一些的。
6、若要使用 ref 参数,必须将参数作为 ref 参数显式传递到方法,ref 参数的值被传递到 ref 参数。
7、当希望方法返回多个值时,声明 out 方法非常有用;使用 out 参数的方法仍然可以返回一个值。

扩展资料:
out:标识一个参数值会受影响的参数,但在传入方法时,该参数无需先初始化。
ref:标识一个参数值可能会受影响的参数。
C#旨在设计成为一种“简单、现代、通用”,以及面向对象的程序设计语言,此种语言的实现,应提供对于以下软件工程要素的支持:强类型检查、数组维度检查、未初始化的变量引用检测、自动垃圾收集(Garbage Collection,指一种自动内存释放技术)。软件必须做到强大、持久,并具有较强的编程生产力。此种语言为在分布式环境中的开发提供适用的组件开发应用。
为使程序员容易迁移到这种语言,源代码的可移植性十分重要,尤其是对于那些已熟悉C和C++的程序员而言。对国际化的支持非常重要。C#适合为独立和嵌入式的系统编写程序,从使用复杂操作系统的大型系统到特定应用的小型系统均适用。
2、首先:两者都是按地址传递的,使用后都将改变原来参数的数值。
其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所以你必须初始化一次。这个就是两个的区别,或者说就像有的网友说的,ref是有进有出,out是只出不进。
ref和out的区别在C# 中,既可以通过值也可以通过引用传递参数。通过引用传递参数允许函数成员更改参数的值,并保持该更改。若要通过引用传递参数, 可使用ref或out关键字。ref和out这两个关键字都能够提供相似的功效,其作用也很像C中的指针变量。它们的区别是:
1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化。
2、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字。以满足匹配。
3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。
方法参数上的 out 方法参数关键字使方法引用传递到方法的同一个变量。当控制传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
当希望方法返回多个值时,声明 out 方法非常有用。使用 out 参数的方法仍然可以返回一个值。一个方法可以有一个以上的 out 参数。
若要使用 out 参数,必须将参数作为 out 参数显式传递到方法。out 参数的值不会传递到 out 参数。
不必初始化作为 out 参数传递的变量。然而,必须在方法返回之前为 out 参数赋值。
属性不是变量,不能作为 out 参数传递。
扩展资料:
当希望方法返回多个值时,声明 out方法很有用。使用 out参数的方法仍然可以将变量用作返回类型(请参见 return),但它还可以将一个或多个对象作为 out参数返回给调用方法。此示例使用 out在一个方法调用中返回三个变量。请注意,第三个参数所赋的值为 Null。这样便允许方法有选择地返回值。
ref是net的关键字,ref关键字–让参数按照引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中;也等同将值类型的数据使用引用方式传参。若要使用ref参数,则方法定义和调用方法都必须显式使用ref关键字。ref是 Reference的缩写。)

PS:int_stdcall FunctionName(unsigned char &param1,unsigned char*param2);
在C#中对其调用的方法是:
[DLLImport(“file”)]
extern static int FunctionName(ref byte param1,ref byte param2) ;
这里会有疑问,&是取地址,*是传送指针,为何都只用ref就行了呢?这里可以理解为ref可能是一个具有重载性特性的修饰符,会自动识别是取地址还是传送指针。
在实际情况中,我们利用参数传递地址更多还是用在传递数组首地址上。
如:
Byte[] param1=new param1(6);
在这里我们声明了一个数组,现在要将其首地址传送出去,只要将param1数组的第一个元素用ref修饰,具体如下:
[DLLImport(“file”)]
extern static int FunctionName(ref byte param1[0],ref byte param2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值