在实际项目工作中,经常用到C#调用C++ 或者C编写的dll文件。
dll支持一般函数声明和类的定义声明,但是一般为了简化,都是 采用函数声明的方式。这里主要并不是写 dll的编写。
先在vs中创建一个dll项目
添加一个新的cpp文件 测试代码如下:
struct Student //定义了一个结构体,结构体中包含了基本类型,字符串类型和数组,基本上能满足很多情况了
{
int no;
char name[10];
int score[4];
};
extern "C" __declspec(dllexport) void __stdcall returnString(char* s) //这是返回一个字符串的方法,和下面的可以作为对比。即返回字符串可以将字符串的指针作为参数或者作为函数返回值这两种方式
{
strcpy(s,"123456");
}
//extern "C" __declspec(dllexport) char* __stdcall returnString()
//{
// return "aaaaaa";
//}
extern "C" __declspec(dllexport) int __stdcall returnInt() //这是一个基本功能,返回了一个基本类型的值
{
return 123;
}
extern "C" __declspec(dllexport) void __stdcall returnIntArray(int *a) // 这是返回了一个基本类型的数组
{
for (int i=0;i<10;i++)
{
a[i] = i+1;
}
}
extern "C" __declspec(dllexport) void __stdcall returnStruct(Student & stu) //这是返回了一个结构体类型 注意:为什么我们一般在返回时使用参数返回,而不是使用函数体返回,因为有的时候会需要返回多个参数值,我们就一致习惯采用这种方式
{
stu.no = 100;
strcpy(stu.name,"csl");
for (int j=0;j<4;j++)
{
stu.score[j] = j*2+14;
}
}
//extern "C" __declspec(dllexport) void __stdcall returnStructArray(Student* stu) //这是返回了一个结构体指针类型,即返回值是一个结构体数组,可以返回多个结构体对象 和下面的方式是一样的
//{
// //stu = (Student*)malloc(sizeof(Student)*10);
// for (int i=0;i<10;i++)
// {
// stu[i].no = i+1;
// strcpy(stu[i].name,"csl");
// }
//
//}
extern "C" __declspec(dllexport) void __stdcall returnStructArray(Student stu[])
{
//stu = (Student*)malloc(sizeof(Student)*10);
for (int i=0;i<10;i++)
{
stu[i].no = i+1;
strcpy(stu[i].name,"csl");
for (int j=0;j<4;j++)
{
stu[i].score[j] = j*2+14;
}
}
}
------------C#中的调用---------------
public struct Student
{
public int no;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] // 指定数组尺寸
public Int32[] score;
}; //结构体声明
//调用函数的声明
[DllImport("E:\\C#\\TestLibDLL\\Debug\\TestLibDLL.dll")]
public static extern void returnString(StringBuilder s); // 字符串类型直接使用stringbuilder
[DllImport("E:\\C#\\TestLibDLL\\Debug\\TestLibDLL.dll")]
public static extern int returnInt();//返回基本类型
[DllImport("E:\\C#\\TestLibDLL\\Debug\\TestLibDLL.dll")]
public static extern void returnIntArray(int[] a); //返回数组 因为数组是引用类型,所以直接这么声明
[DllImport("E:\\C#\\TestLibDLL\\Debug\\TestLibDLL.dll")]
public static extern void returnStruct(out Student stu); //返回结构体 因为C++定义中使用得&引用,所以我们C#中需要使用out or ref
[DllImport("E:\\C#\\TestLibDLL\\Debug\\TestLibDLL.dll")]
public static extern void returnStructArray(IntPtr ptr); //对于返回结构体的数组,网上的说法是使用MarshalAs操作内存指针 自己试过用 student[]数组作为参数,得不到结果 ,使用指针的确可以
//具体操作
static void Main(string[] args)
{
//string s ;
// s = returnString();
//Console.WriteLine(s);
StringBuilder s = new StringBuilder();
returnString(s);
Console.WriteLine(s.ToString());
int nInt = returnInt();
Console.WriteLine(nInt);
int[] arrayList = new int[10];
returnIntArray(arrayList);
Student stu = new Student();
returnStruct(out stu);
Student[] stus = new Student[10];
int size = Marshal.SizeOf(typeof(Student)) * 10;
IntPtr ptr = Marshal.AllocHGlobal(size);
returnStructArray(ptr);
for (int i = 0; i < 10; i++)
{
IntPtr temp = (IntPtr)(UInt32)(ptr + i * size / 10);
stus[i] = (Student)Marshal.PtrToStructure(temp, typeof(Student));
}
Marshal.FreeHGlobal(ptr); //释放内存
Console.ReadKey();
}