版權聲明:本文為Jumbo原創文章,采用[知識共享 署名-非商業性使用-禁止演繹 4.0 國際 許可協議],轉載前請保證理解此協議
原文出處:http://www.lxweimin.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;
}