版权声明:本文为Jumbo原创文章,采用[知识共享 署名-非商业性使用-禁止演绎 4.0 国际 许可协议],转载前请保证理解此协议 原文出处:https://www.jianshu.com/p/d3ac316104f8
一、C#调用DLL文件时参数对应表
Wtypes.h 中的非托管类型 非托管 C 语言类型 托管类名 说明
HANDLE void* System.IntPtr 32 位
BYTE unsigned char System.Byte 8 位
SHORT short System.Int16 16 位
WORD unsigned short System.UInt16 16 位
INT int System.Int32 32 位
UINT unsigned int System.UInt32 32 位
LONG long System.Int32 32 位
BOOL long System.Int32 32 位
DWORD unsigned long System.UInt32 32 位
ULONG unsigned long System.UInt32 32 位
CHAR char System.Char 用 ANSI 修饰。
LPSTR char* System.String 或 System.StringBuilder 用 ANSI 修饰。
LPCSTR Const char* System.String 或 System.StringBuilder 用 ANSI 修饰。
LPWSTR wchar_t* System.String 或 System.StringBuilder 用 Unicode 修饰。
LPCWSTR Const wchar_t* System.String 或 System.StringBuilder 用 Unicode 修饰。
FLOAT Float System.Single 32 位
DOUBLE Double System.Double 64 位
二、C#调用C++编写的DLL函数, 以及各种类型的参数传递
1. //C++中的输出函数
2. int __declspec(dllexport) test(const int N)
3. {
4. return N+10;
5. }
对应的C#代码为:
C# Code Copy Code To Clipboard
1. [DllImport("test.dll", EntryPoint = "#1")]
2. public static extern int test(int m);
3.
4. private void button1_Click(object sender, EventArgs e)
5. {
6. textBox1.Text= test(10).ToString();
7. }
2. 如果函数有传出参数,比如:
1. //C++
2. void __declspec(dllexport) test(const int N, int& Z)
3. {
4. Z=N+10;
5. }
对应的C#代码:
C# Code Copy Code To Clipboard
1. [DllImport("test.dll", EntryPoint = "#1")]
2. public static extern double test(int m, ref int n);
3.
4. private void button1_Click(object sender, EventArgs e)
5. {
6. int N = 0;
7. test1(10, ref N);
8. textBox1.Text= N.ToString();
9. }
3. 带传入数组:
1. void __declspec(dllexport) test(const int N, const int n[], int& Z)
2. {
3. for (int i=0; i<N; i++)
4. {
5. Z+=n[i];
6. }
7. }
C#代码:
1. [DllImport("test.dll", EntryPoint = "#1")]
2. public static extern double test(int N, int[] n, ref int Z);
3.
4. private void button1_Click(object sender, EventArgs e)
5. {
6. int N = 0;
7. int[] n;
8. n = new int[10];
9. for (int i = 0; i < 10; i++)
10. {
11. n[i] = i;
12. }
13. test(n.Length, n, ref N);
14. textBox1.Text= N.ToString();
15. }
4. 带传出数组:
C++不能直接传出数组,只传出数组指针,
1. void __declspec(dllexport) test(const int M, const int n[], int *N)
2. {
3. for (int i=0; i<M; i++)
4. {
5. N[i]=n[i]+10;
6. }
7. }
对应的C#代码:
1. [DllImport("test.dll", EntryPoint = "#1")]
2. public static extern void test(int N, int[] n, [MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)] int[] Z);
3.
4. private void button1_Click(object sender, EventArgs e)
5. {
6. int N = 1000;
7. int[] n, Z;
8. n = new int[N];Z = new int[N];
9. for (int i = 0; i < N; i++)
10. {
11. n[i] = i;
12. }
13. test(n.Length, n, Z);
14. for (int i=0; i<Z.Length; i++)
15. {
16. textBox1.AppendText(Z[i].ToString()+"n");
17. }
18. }
这里声明函数入口时,注意这句 [MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)] int[] Z 在C#中数组是直接使用的,而在C++中返回的是数组的指针,这句用来转化这两种不同的类型. 关于MarshalAs的参数用法以及数组的Marshaling,可以参见这篇转帖的文章: http://www.kycis.com/blog/read.php?21
C++定义:
1. void __declspec(dllexport) test(int i, double &a, double &b, char t[5])
C#对应声明:
1. [DllImport("dll.dll", EntryPoint = "test")]
2. public static extern void test(int i, ref double a, ref double b, [Out, MarshalAs(UnmanagedType.LPArray)] char[] t);
4. char[] t = new char[5];
5. test(i, ref a, ref b, t);
字符数组的传递基本与4相似,只是mashalAs 时前面加上Out。
三、 1.普通传值,如下面代码中MotionDetect的第4个参数; 2.传引用,MotionDetect的第3个参数,nNum传进动态库后赋值再传回来; 3.引用传一个结构体,MotionDetect的第2个参数,这里其实是传一个结构体的数组,具体像加ref的传参还真不会; 4.传一个有分配内存的变量,需要用到GCHandle,因为C#是可以自动回收内存的,而GCHandle在这里的作用就是把它的内存空间Pin住,传递给C++动态库后再手动回收资源。
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class D : MonoBehaviour
{
struct Color_32
{
public byte r;
public byte g;
public byte b;
public byte a;
}
Color_32[] imageDataResult;
GCHandle pixelsHandle;
[DllImport("MotionDetectionDll")]
private static extern bool MotionDetect( System.IntPtr colors, Color_32[] imageDataResult, ref int nNum, int nChannels );
void Start()
{
imageDataResult = new Color_32[128*128];
}
void Update ()
{
int nNum = 0;
pixelsHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
bool wfDf = MotionDetect( pixelsHandle.AddrOfPinnedObject(), imageDataResult, ref nNum, 4 );
pixelsHandle.Free();
}
}
C++中是这么写的
//头文件中多加个结构体定义
#include "stdafx.h"
struct Color_32
{
byte r;
byte g;
byte b;
byte a;
};
extern "C" _declspec(dllexport) bool MotionDetect ( char* imageData, Color_32 imageDataResult[], int *nNum, int nChannels );
// CPP文件中
extern "C" _declspec(dllexport) bool MotionDetect ( char* imageData, Color_32 imageDataResult[], int *nNum, int nChannels )
{
IplImage* imgSrc = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, 4);
if(!imgSrc)
{
return false;
}
cvSetData( imgSrc, imageData, imgSrc->widthStep );
......
for ( int i=0; i< ......; i++ )
{
imageDataResult[i].r = ......;
imageDataResult[i].g = ......;
imageDataResult[i].b = ......;
imageDataResult[i].a = ......;
}
......
*nNum = 5;
nChannels = 4;
}