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++string类型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 <msclr\marshal_cppstd.h>
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++代码⾥⾯把vo //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++中 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<StructType>(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<STRUCT>(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;
}
其他数据类型的转换列表如下: 基本数据类型转换:
Windows编程数据类型
其他归类表格总结:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论