一、基本概念
1、c++是非托管代码,c#是非托管代码,c#调用c++需要把c++编译成dll文件后才能用。
托管代码:由公共语言运行环境执行的代码。
非托管代码:在公共语言环境的外部,由操作系统直接运行的代码。
2、dll是动态库
静态库与动态库的区别
静态库:在程序的链接阶段被复制到了程序中,和程序运行时没有关系。
动态库:在链接阶段没有被复制到程序中,而是在程序在运行时由系统动态的加载到内存。
3、问题:c++工程中一个.cpp文件引用了一个dll文件,如何改为一个c#引用这个dll文件。
c++工程中有三个文件:
.h文件:声明函数的接口。
.dll文件:函数代码。
.lib:告诉连接器调用的函数在哪个dll文件中。
c#引用时只要把dll文件拷贝到c#工程的Debug 或Release文件夹下,再添加引用即可。
二、引用过程
1、c++ dll文件拷贝到c#工程的Debug 或Release文件夹下
2、c#工程下,项目——添加引用 将这个dll文件添加引用
3、c#工程下添加一个类,用来代替原来c++工程的.cpp主程序,同时在这个类中引用dll文件。
几种常用的声明方法:
(1)一般形式
c++:
void __stdcall SetOverallMarkCounts(int count);
c#:
[DllImport("CSCInterface.dll", CallingConvention = CallingConvention.StdCall)] //dll文件名、c++ dll编码方式
public static extern void SetOverallMarkCounts(int count);//函数声明
注意:1)c++中使用的编码方式已经注明是__stdcall,故c#中使用 CallingConvention = CallingConvention.StdCall
(2)指针作为函数参数的形式
c++:
int __stdcall MarkCommand_Vector( int length, double* sitsetX, double* sitsetY);
c#:
[DllImport("CSCInterface.dll", CallingConvention = CallingConvention.StdCall)] //矢量图命令分解
public static extern int MarkCommand_Vector(int length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] sitsetX, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] sitsetY);
定义一个相同类型的数组,并在数组前面加一个 [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
(3)特殊形式
c++:
int __stdcall OpenUSB_Board(int deviceIndex,void *handle);
源码中需要给第二个参数传一个NULL,#define NULL 0
c#:
[DllImport("CSCInterface.dll", EntryPoint = "OpenUSB_Board", CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenUSB_Board(int deviceIndex, IntPtr handle);
使用IntPtr类型
c#调用时
flag = OpenUSB_Board(0, IntPtr.Zero );