warensoft 工作室博客园首页

Warensoft 工作室:承接.NET应用项目开发,游戏开发

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅  :: 管理 ::
  42 随笔 :: 0 文章 :: 195 评论 :: 0 引用
< 2016年11月 >
30 31 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 1 2 3
4 5 6 7 8 9 10

公告

昵称: 王宇 warensoft
园龄: 6年10个月
粉丝: 145
关注: 3

+加关注

搜索

 
 

常用链接

  • 我的随笔
  • 我的评论
  • 我的参与
  • 最新评论
  • 我的标签

我的标签

  • unity3d http socket(3)
  • 数据结构(3)
  • 游戏(2)
  • unity3d warensoft dataservice(2)
  • VSTS(2)
  • ASP.NET Web Game(2)
  • asp.net web game 计时程序(1)
  • asp.net4.0 ajax dataview template(1)
  • asp.net4.0 ajax wcf ado.net data service(1)
  • asp.net4.0 ajax wcf dataview template(1)
  • 更多

随笔档案(42)

  • 2013年8月 (1)
  • 2012年5月 (1)
  • 2012年4月 (5)
  • 2012年2月 (2)
  • 2011年12月 (1)
  • 2011年9月 (1)
  • 2011年7月 (1)
  • 2011年6月 (1)
  • 2011年4月 (1)
  • 2010年8月 (1)
  • 2010年7月 (5)
  • 2010年6月 (5)
  • 2010年3月 (17)

相册(2)

  • aa(2)

积分与排名

  • 积分 - 49289
  • 排名 - 4973

最新评论

  • 1. Re:C#与C/C++的交互
  • 第五步中,要用wcout
  • --流浪在寂寞古城
  • 2. Re:C#与C/C++的交互
  • 第五步中,传递字符串我的到的是
  • --流浪在寂寞古城
  • 3. Re:C#与C/C++的交互
  • 写得真好
  • --曹瑞卿
  • 4. Re:在Windows平台下使用MONO
  • @YTYT2002YTYT是啊,看不到图。...
  • --青蛙Frog1228
  • 5. Re:利用C++/CLI 封装Native C++ 提升.NET web game性能
  • 博主可能要考虑下C++ Release下对空循环优化问题。其实如果高频度调用,建议还是用C#原生代码,这样可以减少调用时托管参数传递到原生函数接口之间转换带来的消耗,.JIT也可以根据实际情况生成更优......
  • --taozebra

阅读排行榜

  • 1. C#委托及 事件(47937)
  • 2. C#与C/C++的交互(31023)
  • 3. 再谈为什么要使用MONO(12190)
  • 4. VS2008 VS2010连接TFS(8637)
  • 5. Warensoft Unity3D通信库使用向导2-利用UnityHttpClient类实现Http通信(5518)

评论排行榜

  • 1. C#委托及 事件(46)
  • 2. 再谈为什么要使用MONO(22)
  • 3. C#与C/C++的交互(20)
  • 4. ASP.NET Web Game 构架设计2--数据库设计(12)
  • 5. C++ Builder XE2 在3D场景中加载2D控件(10)

推荐排行榜

  • 1. C#委托及 事件(34)
  • 2. C#与C/C++的交互(15)
  • 3. 再谈为什么要使用MONO(4)
  • 4. Warensoft Unity3D 通信库项目简介(3)
  • 5. ASP.NET Ajax实例—Javascript直接调用服务器C#代码(3)

C#与C/C++的交互

C#与C/C++的交互


欢迎转载,请注明出处及作者

最近在编写Warensoft3D游戏引擎,并预计明年年初发布测试版本,底层引擎使用DirectX和MONO来编写,上层的逻辑使用C#来编写,因此编写了大量C#与C++互调的代码,现在经验写出来与大家分享,并希望后来者少走弯路。

C#与C++交互,总体来说可以有两种方法:

  • 利用C++/CLI作为代理中间层
  • 利用PInvoke实现直接调用

第一种方法:实现起来比较简单直观,并且可以实现C#调用C++所写的类,但是问题是MONO构架不支持C++/CLI功能,因此无法实现脱离Microsoft .NET Framework跨平台运行。

第二种方法:简单的实现并不麻烦,只要添加DllImportAttribute特性即可以导入C/C++的函数,但是问题是PInvoke不能简单的实现对C++类的调用。在Warensoft3D中为了可以使用MONO实现跨平台(当然DirectX是不能跨平台的),所以使用了本方法,下面将对本方法展开详细的说明。

测试平台:

Windows7 64位,VS2010,.NET4.0

注意事项:

PInvoke从功能上来说,只支持函数调用,在被导出的函数前面一定要添加extern "C"来指明导出函数的时候使用C语言方式编译和连接,这样保证函数定义的名字和导出的名字相同,否则如果默认按C++方式导出,那个函数的名字就会变得乱七八糟,我们的程序就无法找到入口点了。

本文将说明以下几点:

  • 互调的基本原理
  • 基本数据类型的传递
  • 指针的传递
  • 函数指针的传递
  • 结构体的传递
  1. 互调的基本原理

    首先,我们来看一个再常规不过的概念—"数据类型"

    我们知道在大多数的静态语言中定义变量的时候都要先指定其数据类型,所谓数据类型,都是人们强加的一个便于记忆的名称,究其本质就是指明了这个数据在内存里到底是占用了几个字节,程序在运行的时候,首先找到这个数据的地址,然后再按着该类型的长度,读取相对应的内存,然后再处理。

    了解了前面这个事儿,所有编程语言之间进行互调就有点门道儿了。对于不同语言之间的互调,只要将该数据的指针(内存地址)传递给另一个语言,在另一个语言中根据通信协议将指针所指向的数据存储入长度对应的数据类型即可,当然要满足以下几点:

    1. 对于像Java,.NET这样有运行时虚拟机编程语言来讲,由于虚拟机会让堆内存来回转移,因此,在进行互调的时候,要保证正在被互调的数据所在的内存一定要固定,不能被转移。
    2. 有一些编程语言支持指针,有一些语言不支持指针(如Java),这个问题并不重要,所谓指针,其实就是一个内存地址,对于32位OS的指针是一个32位整数,而对于64位机OS的指针是一个64位整数。因为大多数语言中都有整型数,所以可以利用整型来接收指针。
  2. 基本数据类型的传递

互调过程中,最基本要传递的无非是数值和字符,即:int,long,float,char等等,但是此类型非彼类型,C/C++与C#中有一些数据类型长度是不一样的,下表中列出常见数据类型的异同:

C/C++

C#

长度

short

short

2Bytes

int

int

4Bytes

long(该类型在传递的时候常常会弄混)

int

4Bytes

bool

bool

1Byte

char(Ascii码字符)

byte

1Byte

wchar_t(Unicode字符,该类型与C#中的Char兼容)

char

2Bytes

float

float

4Bytes

double

double

8Bytes

最容易弄混的是就是long,char两个类型,在C/C++中long和int都是4个字节,都对应着C#中的int类型,而C/C++中的char类型占一个字节,用来表示一个ASCII码字符,在C#中能够表示一个字节的是byte类型。与C#中char类型对应的应该是C/C++中的wchar_t类型,对应的是一个2字节的Unicode字符。

下面通过实例来说明调用过程:

第一步:

建立一个C++的Win32DLL,如下图所示:

这里要注意选择"Export symbols"导出符号。点击完成。

第二步:

由于项目的名称是"TestCPPDLL",因此,会自动生成TestCPPDLL.h和TestCPPDLL.cpp两个文件,.h文件是要导出内容的声明文件,为了能清楚的说明问题,我们将TestCPPDLL.h和TestCPPDLL.cpp两个文件中的所有内容都删除,然后在TestCPPDLL.h中添加如下内容:

第一行代码中定义了一个名为"TESTCPPDLL_API"的宏,该宏对应的内容是"__declspec(dllexport)"意思是将后面修饰的内容定义为DLL中要导出的内容。当然你也可以不使用这个宏,可以直接将"__declspec(dllexport)"写在要导出的函数前面。

第二行中的"EXTERN_C",是在"winnt.h"中定义的宏,在函数前面添加"EXTERN_C"等同于在函数前面添加extern "C",意思是该函数在编译和连接时使用C语言的方式,以保证函数名字不变。

第二行的代码是一个函数的声明,说明该函数可以被模块外部调用,其定义实现在TestCPPDLL.cpp中,TestCPPDLL.cpp的代码如下所示:

第三步:

在编译C++DLL之前,需要做以下配置,在项目属性对话框中选择"C/C++"|"Advanced",将Compile AS 选项的值改为"C++"。然后确定,并编译。

生成的DLL文件如下图所示:

第四步:

首先,添加一个C#的应用程序,如果要在C#中调用C++的DLL文件,先要在C#的类中添加一个静态方法,并且使用DllImportAttribute对该方法进行修饰,代码如下所示:

DllImport中的第一个参数是指明DLL文件的位置,第二个参数"EntryPoint"用来指明对应的C/C++中的函数名称是什么。"extern"关键字表明该处声明的这个Add方法是一个外部调用。

该方法声明完毕之后,就可以像调用一个普通的静态方法一样去使用了。

下面是示例程序:

class Program

{

[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "Add")]

extern static int Add(int a, int b);

static void Main(string[] args)

{

int c = Add(1,2);

Console.WriteLine(c);

Console.Read();

}

}

在运行C#程序之前,先要修改C#的项目属性,如下图所示:

将platform target设置为x86,并且允许非安全代码(后面有用)。

然后运行该C#程序,其结果如下图所示:

第五步:

前面的Add方法中传递的是数值类型(int),其他的数据类型,如float,double,和bool类型的传递方式是一样的,下面演示如何传递字符串。

在TestCPPDLL.h中添加一个新的函数声明,代码如下:

*content);

这里的参数是wchar_t类型的指针,对应着C#中的char类型。TestCPPDLL.cpp中添加如下代码:

TESTCPPDLL_API void __stdcall WriteString(wchar_t*content)

{

cout<<content;

}

该代码的功能就是将输入的字符串通过C++在控制台上输出。下面是在C#中的声明:

)]

extern unsafe static void WriteString(char*c);

调用过程如下所示:

//因为使用指针,因为要声明非安全域

unsafe

{

//在传递字符串时,将字符所在的内存固化,

//并取出字符数组的指针

fixed (char* p = &("hello".ToCharArray()[0]))

{

//调用方法

WriteString(p);

}

}

其运行效果如下图所示:

3. 指针的传递

根据前面介绍的数据类型对照表,我们可以直接在方法中传递指针,但是要注意的是我们常常需要将数组的指针(数据入口地址,第一个元素的地址),数据从C/C++到C#时问题不大,但是如果从C#到C/C++时一定要将数组先固化,然后再传递处理。

下面演示如何传递指针,首先在TestCPPDLL.h中添加下列声明:

//传入一个整型指针,将其所指向的内容加1

EXTERN_C TESTCPPDLL_API void __stdcall AddInt(int *i);

//传入一个整型数组的指针以及数组长度,遍历每一个元素并且输出

EXTERN_C TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arraylength);

//在C++中生成一个整型数组,并且数组指针返回给C#

EXTERN_C TESTCPPDLL_API int* __stdcall GetArrayFromCPP();

其实现写在TestCPPDLL.cpp中,代码如下所示:

TESTCPPDLL_API void __stdcall AddInt(int *i)

{

(*i)++;

}

TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arrayLength)

{

int*currentPointer=firstElement;

for (int i = 0; i < arrayLength; i++)

{

cout<<*currentPointer;

currentPointer++;

}

cout<<endl;

}

int *arrPtr;

TESTCPPDLL_API int* __stdcall GetArrayFromCPP()

{

arrPtr=new int[10];

for (int i = 0; i < 10; i++)

{

arrPtr[i]=i;

}

return arrPtr;

}

对应调用的C#代码如下所示:

[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddInt")]

extern unsafe static void AddInt(int* i);

[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddIntArray")]

extern unsafe static void AddIntArray(int* firstElement, int arraylength);

[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "GetArrayFromCPP")]

extern unsafe static int* GetArrayFromCPP();

调用过程如下所示:

unsafe

{

// 调用C++中的AddInt方法

int i = 10;

AddInt(&i);

Console.WriteLine(i);

//调用C++中的AddIntArray方法将C#中的数据传递到C++中,并在C++中输出

int[] CSArray = new int[10];

for (int iArr = 0; iArr < 10; iArr++)

{

CSArray[iArr] = iArr;

}

fixed (int* pCSArray = &CSArray[0])

{

AddIntArray(pCSArray, 10);

}

//调用C++中的GetArrayFromCPP方法获取一个C++中建立的数组

int* pArrayPointer = null;

pArrayPointer = GetArrayFromCPP();

for (int iArr = 0; iArr < 10; iArr++)

{

Console.WriteLine(*pArrayPointer);

pArrayPointer++;

}

}

4. 函数指针的传递

前面说明的都是简单数据类型的及其指针的传递,利用PInvoke我们也可以实现函数指针的传递,C#中并没有函数指针的概念,但是可以使用委托(delegate)来代替函数指针,关于C#中委托的说明,可以参考笔者前面的一个文章:《C#委托及事件》

大家可能会问,为什么要传递函数指针呢?利用PInvoke可以实现C#对C/C++函数的调用,反过来,我们能不能在C/C++程序运行的某一时刻,来调用一个C#对应的函数呢?(例如在C++中存在一个独立线程,该线程可能在任意时刻触发一个事件,并且需要通知C#)。这个时候,我们就有必要将一个C#中已经指向某一个函数的函数指针(委托)传递给C++。

想要传递函数指针,首先要在C#中定义一个委托,并且在C++中定义一个函数指针,同时要保证委托和函数指针具备相同的函数原型,我们首先编写C#的代码,如下所示:

//定义一个委托,返回值为空,存在一个整型参数

public delegate void CSCallback(int tick);

//定义一个用于回调的方法,与前面定义的委托的原型一样

//该方法会被C++所调用

static void CSCallbackFunction(int tick)

{

Console.WriteLine(tick.ToString ());

}

//定义一个委托类型的实例,

//在主程序中该委托实例将指向前面定义的CSCallbackFunction方法

static CSCallback callback;

在CS的主程序中让callback指向CSCallbackFunction方法,代码如下所示:

//调用委托所指向的方法

callback = CSCallbackFunction;

然后在C/C++中定义一个函数指针,并且添加一个用于设置函数指针的函数,TestCPPDLL.h中的代码如下所示:

//定义一个函数指针

typedef void (__stdcall *CPPCallback)(int tick);

//定义一个用于设置函数指针的方法,

//并在该函数中调用C#中传递过来的委托

EXTERN_C TESTCPPDLL_API void SetCallback(CPPCallback callback);

SetCallback函数的实现在TestCPPDLL.cpp中,代码如下所示:

TESTCPPDLL_API void SetCallback(CPPCallback callback)

{

int tick=rand();

//下面的代码是对C#中委托进行调用

callback(tick);

}

在C#中添加SetCallback函数的声明,代码如下所示:

//这里使用CSCallback委托类型来兼容C++里的CPPCallback函数指针

[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SetCallback")]

extern static void SetCallback(CSCallback callback);

在C#中的调用过程如下所示:

//让委托指向将被回调的方法

callback = CSCallbackFunction;

//将委托传递给C++

SetCallback(callback);

SetCallback方法被执行后,在C#中定义的CSCallbackFunction就会被C++所调用。

5. 结构体的传递

传递结构体的想法和传递一个int类型数据类似,struct中的数据是在内存中顺序排列的,只要保证保证以下几点,就可以直接传递结构体,甚至是结构体的指针:

  • 要传递的成员为公有的值类型字段
  • C#中结构体字段类型与C++结构体中的字段类型相兼容
  • C#结构中的字段顺序与C++结构体中的字段顺序相同,要保证该功能,需要将C#结构体标记为 [StructLayout( LayoutKind.Sequential)]

下面通过代码进行说明,首先在C#中添加一个结构体,代码如下所示:

[StructLayout( LayoutKind.Sequential)]

struct Vector3

{

public float X, Y, Z;

}

该结构体表示一个3D向量,包括X,Y,Z三个float类型的分量。

然后在TestCPPDLL.h中也定义一个相同结构的结构体,代码如下所示:

struct Vector3

{

float X,Y,Z;

};

在TestCPPDLL.h中声明一个用于传递Vector3结构体的一个函数,代码如下所示:

EXTERN_C TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector);

在TestCPPDLL.cpp中将其实现,代码如下所示:

TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector)

{

cout<<"got vector3 in cpp,x:";

cout<<vector.X;

cout<<",Y:";

cout<<vector.Y;

cout<<",Z:";

cout<<vector.Z;

}

在C#中添加对SendStructFromCSToCPP函数的声明,代码如下所示:

[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SendStructFromCSToCPP")]

extern static void SendStructFromCSToCPP(Vector3 vector);

C#中的调用过程如下所示:

//建立一个Vector3的实例

Vector3 vector = new Vector3() { X =10,Y=20,Z=30 };

//将vector传递给C++并在C++中输出

SendStructFromCSToCPP(vector);

基输出效果如下所示:

完整的TestCPPDLL.h代码如下所示:

#define TESTCPPDLL_API __declspec(dllexport)EXTERN_C TESTCPPDLL_API int __stdcall Add(int a,int b);EXTERN_C TESTCPPDLL_API void __stdcall WriteString(wchar_t*content);//传入一个整型指针,将其所指向的内容加1

EXTERN_C TESTCPPDLL_API void __stdcall AddInt(int *i);//传入一个整型数组的指针以及数组长度,遍历每一个元素并且输出

EXTERN_C TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arraylength);//在C++中生成一个整型数组,并且数组指针返回给C#

EXTERN_C TESTCPPDLL_API int* __stdcall GetArrayFromCPP();//定义一个函数指针

typedef void (__stdcall *CPPCallback)(int tick);//定义一个用于设置函数指针的方法,//并在该函数中调用C#中传递过来的委托

EXTERN_C TESTCPPDLL_API void __stdcall SetCallback(CPPCallback callback);struct Vector3{float X,Y,Z;};EXTERN_C TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector);

完整的TestCPPDLL.CPP代码如下所示:

#include "stdafx.h"#include <iostream>#include "TestCPPDLL.h"using namespace std;TESTCPPDLL_API int __stdcall Add(int a,int b){return a+b;}TESTCPPDLL_API void __stdcall WriteString(wchar_t*content){wprintf(content);printf("\n");}TESTCPPDLL_API void __stdcall AddInt(int *i){(*i)++;}TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arrayLength){int*currentPointer=firstElement;for (int i = 0; i < arrayLength; i++){cout<<*currentPointer;currentPointer++;}cout<<endl;}int *arrPtr;TESTCPPDLL_API int* __stdcall GetArrayFromCPP(){arrPtr=new int[10];for (int i = 0; i < 10; i++){arrPtr[i]=i;}return arrPtr;}TESTCPPDLL_API void __stdcall SetCallback(CPPCallback callback){int tick=100;//下面的代码是对C#中委托进行调用
callback(tick);}TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector){cout<<"got vector3 in cpp,x:";cout<<vector.X;cout<<",Y:";cout<<vector.Y;cout<<",Z:";cout<<vector.Z;}

完整的C#代码如下所示:

using System;using System.Collections.Generic;using System.Runtime.InteropServices;using System.Text;namespace ConsoleApplication1{class Program{[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "Add")]extern static int Add(int a, int b);[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "WriteString")]extern unsafe static void WriteString(char* c);[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddInt")]extern unsafe static void AddInt(int* i);[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddIntArray")]extern unsafe static void AddIntArray(int* firstElement, int arraylength);[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "GetArrayFromCPP")]extern unsafe static int* GetArrayFromCPP();//定义一个委托,返回值为空,存在一个整型参数

public delegate void CSCallback(int tick);//定义一个用于回调的方法,与前面定义的委托的原型一样//该方法会被C++所调用

static void CSCallbackFunction(int tick){Console.WriteLine(tick.ToString());}//定义一个委托类型的实例,//在主程序中该委托实例将指向前面定义的CSCallbackFunction方法

static CSCallback callback;//这里使用CSCallback委托类型来兼容C++里的CPPCallback函数指针

[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SetCallback")]extern static void SetCallback(CSCallback callback);[StructLayout(LayoutKind.Sequential)]struct Vector3{public float X, Y, Z;}[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SendStructFromCSToCPP")]extern static void SendStructFromCSToCPP(Vector3 vector);static void Main(string[] args){int c = Add(1, 2);Console.WriteLine(c);//因为使用指针,因为要声明非安全域

unsafe{//在传递字符串时,将字符所在的内存固化,//并取出字符数组的指针

fixed (char* p = &("hello".ToCharArray()[0])){//调用方法

WriteString(p);}}unsafe{// 调用C++中的AddInt方法

int i = 10;AddInt(&i);Console.WriteLine(i);//调用C++中的AddIntArray方法将C#中的数据传递到C++中,并在C++中输出

int[] CSArray = new int[10];for (int iArr = 0; iArr < 10; iArr++){CSArray[iArr] = iArr;}fixed (int* pCSArray = &CSArray[0]){AddIntArray(pCSArray, 10);}//调用C++中的GetArrayFromCPP方法获取一个C++中建立的数组

int* pArrayPointer = null;pArrayPointer = GetArrayFromCPP();for (int iArr = 0; iArr < 10; iArr++){Console.WriteLine(*pArrayPointer);pArrayPointer++;}}//让委托指向将被回调的方法

callback = CSCallbackFunction;//将委托传递给C++

SetCallback(callback);//建立一个Vector3的实例

Vector3 vector = new Vector3() { X = 10, Y = 20, Z = 30 };//将vector传递给C++并在C++中输出

SendStructFromCSToCPP(vector);Console.Read();}}}

标签:  游戏
好文要顶  关注我  收藏该文 

王宇 warensoft
关注 - 3
粉丝 - 145

+加关注

15
0

« 上一篇: C++ Builder XE2 在3D场景中加载2D控件
» 下一篇: 全国首款网页版(web)真3D商城

posted on  2011-12-09 13:03  王宇 warensoft 阅读( 31023) 评论( 20)  编辑  收藏

评论

#1楼   2011-12-09 13:11  6572789 
好东西记录下来
支持(0) 反对(0)

#2楼   2011-12-09 13:11  不戒大师 
如此说来 引擎你用C++ 为啥非要选C#做显示层
支持(0) 反对(1)

#3楼 [ 楼主]  2011-12-09 13:19  王宇 warensoft 
@ 不戒大师
引擎内核用C++为了保证运行速度,程序员可以使用C#来编写其他的业务逻辑,可以使用.NET类库中的绝大多数类,这样来降低开发难度,同时也降低了入门难度,可以吸引更多的.NET程序
支持(2) 反对(0)

#4楼   2011-12-09 13:20  abyss小巫 
我们现在也是c++和c#的交互,不过用的是SCA
支持(0) 反对(0)

#5楼 [ 楼主]  2011-12-09 13:23  王宇 warensoft 
@ abyss小巫
领教了,SCA 是Service Component Architecture吗?SOA的一个实现方法?
支持(0) 反对(0)

#6楼   2011-12-09 14:12  longware 
收了,谢谢
支持(0) 反对(0)

#7楼   2011-12-09 16:09  xujif 
嘿嘿 lz,如果我没记错的话 64位linux里 long是8bit的哦,如果跨平台,小心哦
支持(0) 反对(0)

#8楼   2011-12-09 16:26  随便路过
例:
C/C++
TESTCPPDLL_API void __stdcall SayHelloWorld(const wchar_t* s){
//开启一个线程,并将s作为参数传入
}

C#
string s="hello world";
fixed(char* c=&(s.ToCharArray()[0])){
SayHelloWorld(c);
}

我们不知道c/c++dll中会对参数做怎样的处理。一旦离开了fixed语句块,上面的示例。。。。?

#9楼   2011-12-09 17:26  Sarlanori 
其实主要想看第一种调用方式的,就是通过 C# 直接调用 C++ 里的类,结果楼主直接略过了。。。
支持(0) 反对(0)

#10楼   2011-12-09 17:28  随便路过
引用 Sarlanori:其实主要想看第一种调用方式的,就是通过 C# 直接调用 C++ 里的类,结果楼主直接略过了。。。

不是不可以。但是那一堆乱七八糟的导出符号,如_ddd@XYZ,让人头痛

#11楼   2011-12-09 17:29  百分百好牛 
不错,蛮好的文章,支持一下。
支持(0) 反对(0)

#12楼   2011-12-09 21:27  空明流转 
@ 随便路过

除了mangling,调用协议也不一样。不能随便调用的。

支持(0) 反对(0)

#13楼   2011-12-09 23:41  OctoberS 
我在使用互操作的时候都把(例如int* 直接用InPtr取代,结构体指针用ref引用,特殊类型的用marshas指定转化类型,都不用unsafe)也没有发生错误!虚心请问博主你用unsafe理由何在!或者用unsafe后在处理可以避免什么错误么?还有博主可以提供其他的一些互操作类型转换总结和注意,那就跟完美了!
支持(0) 反对(0)

#14楼   2011-12-12 10:16  eflay 
嗯,互调用中真可以完全避免指针等unsafe操作,除非你重写c++中的一些和内存有关的函数,当然那样也不该用C#
支持(0) 反对(0)

#15楼 [ 楼主]  2011-12-12 12:30  王宇 warensoft 
引用 eflay:嗯,互调用中真可以完全避免指针等unsafe操作,除非你重写c++中的一些和内存有关的函数,当然那样也不该用C#
楼上说的没错,其实指针完全可以使用IntPtr类型来代替,这样可以不使用Unsafe,同时,IntPtr可以将其中存储值转化为void*。使用指针的目的是为了比较直观的和C++交互(如内存控制)。
这次写的Blog中在编写3D游戏引擎中总结出来的,内存控制方面比较多,所以在Blog中写的也比较多。
可以利用Reflector对DotNet框架进行反编译,看看其中的代码,其中对于底层Windows机制的控制(如WinSocket,Win32 Window等),利用Marshal+IntPtr以及Unsafe+指针的方式代码的数量都差不多,所以这个问题要根据程序员的习惯和应用定位来决定
支持(0) 反对(0)

#16楼   2012-12-10 16:42  小兵传奇 
@ Sarlanori
@Sarlanori
引用 其实主要想看第一种调用方式的,就是通过 C# 直接调用 C++ 里的类,结果楼主直接略过了。。。
同想
支持(0) 反对(0)

#17楼   2015-03-19 10:22  liujiong63 
不错,学习了。
支持(0) 反对(0)

#18楼   2016-01-21 11:42  曹瑞卿 
写得真好
支持(0) 反对(0)

#19楼   2016-02-22 15:16  流浪在寂寞古城 
第五步中,传递字符串我的到的是<img src="http://images2015.cnblogs.com/blog/793044/201602/793044-20160222151621057-2026934580.png" alt="" border="0" "="" style="border: 0px; max-width: 400px;">
支持(0) 反对(0)

#20楼   2016-02-22 15:19  流浪在寂寞古城 
第五步中,要用wcout
支持(0) 反对(0)

刷新评论 刷新页面 返回顶部
注册用户登录后才能发表评论,请  登录 或  注册, 访问网站首页。
【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
【推荐】融云发布 App 社交化白皮书 IM 提升活跃超 8 倍
【推荐】网易这个云产品做了15年才面世,1年吸引10万+开发者
最新IT新闻:
·  被用户下最后通牒 Vine竟倒闭得如此凄惨
·  三星宣布在全球范围内线上独家销售部分手机配件
·  她14岁失明 却帮助上亿盲人重新“看见”世界
·  IDC:全球平板电脑出货量连降8个季度
·  微软10天尚未修复之后Google公开Windows 10高危漏洞
»  更多新闻...
最新知识库文章:

·  循序渐进地代码重构
·  技术的正宗与野路子
·  陈皓:什么是工程师文化?
·  没那么难,谈CSS的设计模式
·  程序猿媳妇儿注意事项

»  更多知识库文章...

Powered by: 
博客园 
Copyright © 王宇 warensoft

C#与C/C++的交互相关推荐

  1. etcd 笔记(05)— etcd 代码结构、各模块功能、整体架构、各模块之间的交互、请求和应答流程

    1. etcd 项目结构和功能 etcd 项目代码的目录结构如下: $ tree ├── auth ├── build ├── client ├── clientv3 ├── contrib ├── ...

  2. Plotly_绘图画图作图交互

    20210601 https://zhuanlan.zhihu.com/p/87163211 画地图 今天就带你深入体验易于使用.文档健全.功能强大的开源 Python 绘图库 Plotly,教你如何 ...

  3. matplotlib交互模式

    Matpotlib交互模式 在运行python程序时有时候需要生成以下的 动态图模式 来显示程序运行的结果 此时需要使用matplotlib的 交互模式 ,在Ipython中时默认使用交互模式的. 在 ...

  4. Cache 与Memory架构及数据交互

    Cache 与Memory架构及数据交互

  5. Android 与 JS 的交互 以及 JS与Android 的交互

    Android与JS交互以及JS与Android 的交互 是通过WebView互相调用方法 对于Android调用JS代码的方法有2种: 通过WebView的loadUrl() 通过WebView的e ...

  6. 【TCP/IP详解 卷一:协议】第十九章 TCP的交互数据流

    19.1 引言 前一章我们介绍了TCP连接的建立与释放:三握四挥,以及状态转移图. TCP报文段分为:交互数据,以及成块数据(下一章介绍). 交互数据:例如telnet,ssh,这种类型的协议在大多数 ...

  7. 鸿蒙与微信小程序,鸿蒙远程交互应用 vs 微信小程序远程交互应用

    原标题:鸿蒙远程交互应用 vs 微信小程序远程交互应用 鸿蒙的远程交互组件应用相对复杂,访问网络时,首先要配置网络权限,华为官方文档有问题,在此引用我老师配置的模板,见附件. 过程: 导入鸿蒙的网络请 ...

  8. js怎样和硬件交互_Node.js与JavaScript

    有很多介绍nodejs的文章,也有很多教程,覆盖了服务器开发.桌面开发.移动端等等,但是鲜有文章明确的回答过一个问题:Node是什么? 这看起来是一个再简单过的问题了,真要答起来可不容易,不去深入研究 ...

  9. air调用java,AIR2.0入门教程:与Java应用交互

    在之前的一篇文章中,我介绍了如何使用AIR2.0新增的NativeProcess类与本地进程进行交互和通讯,在那个例子里面我们使用了C++ 的代码,实际上只要是基于命令行的标准输入输出,AIR2.0的 ...

  10. python图表交互控件_用djang中的交互式控件制作bokeh图表

    有两个用例: 没有服务器 如果您可以在JS中执行任何更新(不需要调用实际的python代码),那么使用CustomJS callbacks添加交互非常容易.在这个链接中有很多示例,但是一个基本的简单代 ...

最新文章

  1. 东南大学周张泉:基于知识图谱的推理技术 | 实录·Guru Talk
  2. 全排列算法的字典序排列
  3. 漫步数学分析十三——路径连通
  4. 自动工作负载信息库 AWR
  5. php原生的异步请求,原生JavaScript实现Ajax异步请求
  6. html中加入数据库,HTML中如何连接数据库?
  7. Python开发【第十九篇】:Python操作MySQL
  8. 从Spring代理的bean中获取代理对象
  9. python时间戳提取小时分钟秒,进行整点判断
  10. Github客户端下载以及使用方法
  11. 2018年人工智能之自动驾驶研究报告
  12. postman接口测试
  13. Android涂鸦画板原理详解——从初级到高级(一)
  14. 计算请假时间(不算节假日)
  15. 工信部专项认证有什么用?
  16. python入门day16——函数的递归调用、二分法、三元表达式、匿名函数
  17. 谷歌验证码recaptcha接入
  18. 建立完善的员工晋升机制_【员工晋升机制】多渠道员工晋升机制如何建立
  19. linux程序作为桌面壁纸,在Linux系统下安装壁纸程序Wonderwall,附主要功能介绍
  20. 多层感知机(MLP)简介

热门文章

  1. 怎么把二维码解码成链接地址?
  2. java double 占位符_Java输出格式化之占位符
  3. 嵌入式是什么?arm是什么?
  4. 7.24[C语言零基础 知识点总结]
  5. Homework 1 : Knowledge items of C++ (part 1)
  6. 2022年国家高新技术企业认定评审最新标准及补贴政策重点,补贴10-50万
  7. oracle11g連不上em,oracle11g em重建失败的几点解决办法
  8. c语言编写虚拟光驱软件下载,虚拟光驱(LZZ Virtual Drive)
  9. etal斜体吗 参考文献_参考文献方面毕业论文格式模板,与文下载****北京化工大学学报相关论文下载...
  10. 高斯-约当 (Gauss-Jordan) 消元法 [学习笔记]