C++托管与C#中的数据类型转换

接上一篇文章 C++封装成托管模式供C#调用过程 在C#调用C++托管库的过程中,C++托管库一般只是封装为真正C++动态链接库(DLL)的一个外壳,其不做任何逻辑功能,但是会存在数据类型及结构上的转换问题,本文就是用于介绍数据类型转换过程中需要考虑的问题。
数据类型很多,限于篇幅原因,文章主要讲解几种常见且较复杂的数据类型。
1. C#句柄与C++窗体句柄类型的转换, IntPtr<—>HWND;
2. C# String类型 与 C++ String 类型转换
3. C#数据地址与C++指针转换
4. C#结构体与C++结构体转换

一、C#句柄IntPtr与C++窗体句柄HWND的转换
在C++托管代码中可以直接引入C#数据类型IntPtr, 然后可以转换成HWND类型,转换过程如下:

C#调用环境接口:CSharp_InterfaceCLR(IntPtr InputDataSharp)
C++ CLR 托管环境接口:CPP_InterfaceCLR(IntPtr InputDataClr)
C++环境中接口:CPP_Interface(HWND InputData); 
CSharp_InterfaceCLR(InputDataSharp)
--->CPP_InterfaceCLR(InputDataClr)   //InputDataSharp 可以直接赋值给 InputDataClr
--->CPP_Interface((HWND) (InputDataClr.ToInt32()));  //把InputDataClr.ToInt32()强制转换成HWND

二、C# String类型 与 C++ String 类型转换
在讲解转换之前,需要说一个符号^,C++/CLI中使用gcnew关键字表示在托管堆上分配内存,并且为了与以前的指针区分,用^来替换* ,就语义上来说区别大致如下:
1)gcnew返回的是一个句柄(Handle),而new返回的是实际的内存地址;
2)gcnew创建的对象由虚拟机托管,而new创建的对象必须自己来管理和释放。
从开发者的角度,不论是句柄还是其他的类型,总会是对某块内存地址的引用,可以理解为指针。

C#调用环境接口:CSharp_InterfaceCLR(string InputDataSharp)
C++ CLR 托管环境接口:CPP_InterfaceCLR(String^ InputDataClr)
C++环境中接口:CPP_Interface(string InputData); 
CSharp_InterfaceCLR(InputDataSharp)
--->CPP_InterfaceCLR(InputDataClr)   //InputDataSharp 可以直接赋值给 InputDataClr
//把String^类型的string转换为C++ string的过程如下:
std::string InputData = marshal_as<std::string>(InputDataClr);
--->CPP_Interface(InputData);  

//注意在托管代码中需要添加如下信息:
#include 
using namespace msclr::interop;
using namespace System;

三、 C#数据地址与C++指针转换
C#中的变量地址可以通过IntPtr传递到CLR,然后CLR(托管C++)转换为一个数值,在C++代码中直接通过指针强制转换即可完成地址在C#与C++直接的转换。
具体过程可以如下:

C#调用环境接口:CSharp_InterfaceCLR(IntPtr InputDataSharp)
C++ CLR 托管环境接口:CPP_InterfaceCLR(IntPtr InputDataClr)
C++环境中接口:CPP_Interface(Void* InputData); 
CSharp_InterfaceCLR(InputDataSharp)
--->CPP_InterfaceCLR(InputDataClr)   //InputDataSharp 可以直接赋值给 InputDataClr
--->CPP_Interface((void*)InputDataClr.ToInt32());  //把InputDataClr.ToInt32()强制转换成void*, 也可以通过InputDataClr.ToPointer(),然后在C++代码里面把void*转成相应的类型

//c#中使用指针:在需要使用指针的地方 加 unsafe

关于其他指针类型转换需要注意:
unsigned char** ppImage <===> IntPtr ppImage 双指针类型参数,都可以用 ref IntPtr
int& Variable <===> ref int Variable
int*, int& <===> ref int
char* 的操作 <===> c#:StringBuilder;
函数指针使用: c++: typedef int (*function)(int); <===>c#:public delegate int function(int);
关于函数指针的使用会在C++调用C#注册的回调函数一章中详细说明。

四、 C#结构体与C++结构体转换
C++中 Struct需要在C#里重新定义一个Struct与之对应起来。
说明如下:

typedef struct
{
    char   CharArray[256];
    INT32  IntegerVariable;
    INT32  IntegerVariable1;
    UINT16 UnsignedIntegerVariable;
    bool   BoolType;
    //string StringVariable 不可以用string类型,可以使用char*代替
} STRUCT;

//法1.
[StructLayout(LayoutKind.Sequential)]
public struct STRUCT
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public char[] CharArray;
    public Int32 IntegerVariable;
    public UInt16 UnsignedIntegerVariable;
    public Boolean BoolType;
}
可以使用一个C#函数做转换
public StructType ConverBytesToStructure(byte[] bytesBuffer)
{
    // check the length。
    if (bytesBuffer.Length != Marshal.SizeOf(typeof(STRUCT)))
    {
        throw new ArgumentException("bytesBuffer is not same as structObject for the length of byte.");
    }

    IntPtr bufferHandler = Marshal.AllocHGlobal(bytesBuffer.Length);
    for (int index = 0; index < bytesBuffer.Length; index++)
    {
        Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]);
    }
    STRUCT structObject = (STRUCT)Marshal.PtrToStructure(bufferHandler, typeof(STRUCT));
    Marshal.FreeHGlobal(bufferHandler);
    return structObject;
}

FileStream file = File.OpenRead(@"C:/Path");
byte[] buffer = new byte[Marshal.SizeOf(typeof(STRUCT))];
file.Read(buffer, 0, buffer.Length);
STRUCT testValue = CommonTools.ConverBytesToStructure(buffer);
string sCharArray = new string(testValue.CharArray);

//法2. 就不需要再写转换函数
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct STRUCT
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string CharArray;
    public Int32 IntegerVariable;
    public UInt16 UnsignedIntegerVariable;
    public Boolean BoolType;
}

其他数据类型的转换列表如下:
基本数据类型转换:
C++托管与C#中的数据类型转换_第1张图片

Windows编程数据类型
C++托管与C#中的数据类型转换_第2张图片

其他归类表格总结:
C++托管与C#中的数据类型转换_第3张图片

C++托管与C#中的数据类型转换_第4张图片

C++托管与C#中的数据类型转换_第5张图片

你可能感兴趣的:(编程技术)