C#与C++类型互转

版权声明:本文为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. 如果函数只有传入参数,比如:
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

  1. 传出字符数组:
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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,226评论 0 4
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,791评论 0 27
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,605评论 18 399
  • 历史一直在重复某件事情,每一个人身上会发生相似的事情,因此我们需要重复的磨练,增加自己的阅历。适应历史的潮流,顺应...
    阳光的大男孩儿阅读 355评论 0 0
  • 偶然的机会得到雪梅老师的引荐,于是参加了《家庭公约》“一次管一生的教育”的读书计划,春节后2月7日参加了第二次的读...
    亚子_5226阅读 3,092评论 1 1