对于一些比较复杂的C++结构体在封装成C#的时候要注意保持C++结构变量字节与C#结构体字节的对齐。
C++结构体示例:
typedef struct{
e_float64 FontSize; // 字体大小
e_float64 Angle; // 角度
e_int32 FontColor; // 文本颜色
e_int32 BackColor; // 文本背景色
e_int32 Transparent; // 背景是否透明
e_int32 Bold; // 文本粗体
e_int32 Italic; // 文本斜体
e_int32 Underline; // 文本下划线
e_int32 XOffset; // 文本X偏移
e_int32 YOffset; // 文本Y偏移
e_int8 FontName[128]; // 字体
}FONT_INFO_T;
C#封装的时候要注意保持C#的使用习惯,如上结构体,Transparent、Bold、Italic、Underline属性,在C#中一般则直接封装成bool类型,而这样封装则无法保存C++和C#结构的字节对齐,因此还需要一个中间转 换的结构体,这个转换结构体与C++结构体则必须完全保持一致,C#外部使用结构体与转换结构体又存在着一个转换,因此,封装出来的结构体必须要提供转换 方法。
先定义一个转换结构体,如下:
[StructLayout(LayoutKind.Sequential)]
internal struct Inner_HdFont
{
public double FontSize; // 字体大小
public double Angle; // 角度
public int FontColor; // 文本颜色
public int BackColor; // 文本背景色
public int Transparent; // 背景是否透明
public int Bold; // 文本粗体
public int Italic; // 文本斜体
public int Underline; // 文本下划线
public int XOffset; // 文本X偏移
public int YOffset; // 文本Y偏移
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string FontName; // 字体
}
C#最终定义结构体如下:
///<summary>
/// 字体格式
/// </summary>
public struct HdFont
{
///<summary>
/// 字体大小
///</summary>
public double Size;
///<summary>
/// 角度
///</summary>
public double Angle;
///<summary>
/// 文本颜色0xbbggrr
///</summary>
public int Color;
///<summary>
/// 文本背景色0xbbggrr
///</summary>
public int BackColor;
///<summary>
/// 背景是否透明
///</summary>
public bool Transparent;
///<summary>
/// 文本粗体
///</summary>
public bool Bold;
///<summary>
/// 文本斜体
///</summary>
public bool Italic;
///<summary>
/// 文本下划线
///</summary>
public bool Underline;
///<summary>
/// 文本X偏移
///</summary>
public int XOffset;
///<summary>
/// 文本Y偏移
///</summary>
public int YOffset;
///<summary>
/// 字体
/// </summary>
public string Name;
///<summary>
/// 将结构体转为非托管对象使用,外部申请内存和释放内存
///</summary>
///<param name="handle"></param>
public IntPtr GetFontHandle()
{
Inner_HdFont inner_font = new Inner_HdFont();
inner_font.Angle = Angle;
inner_font.BackColor = BackColor;
inner_font.Bold = (Bold == true ? 1 : 0);
inner_font.FontColor = Color;
inner_font.FontName = Name;
inner_font.FontSize= Size;
inner_font.Italic = (Italic == true ? 1 : 0);
inner_font.Transparent = (Transparent == true ? 1 : 0);
inner_font.Underline = (Underline == true ? 1 : 0);
inner_font.XOffset = XOffset;
inner_font.YOffset = YOffset;
IntPtrhandle = Marshal.AllocHGlobal(Marshal.SizeOf(inner_font));
Marshal.StructureToPtr(inner_font, handle, false);
return handle;
}
///<summary>
/// 将非托管指针转换为结构体
///</summary>
///<param name="handle"></param>
public void FromHandle(IntPtr handle)
{
Inner_HdFont inner_font = new Inner_HdFont();
inner_font = (Inner_HdFont)Marshal.PtrToStructure(handle,typeof(Inner_HdFont));
Angle =inner_font.Angle;
BackColor = inner_font.BackColor;
Bold =inner_font.Bold > 0 ? true : false;
Color =inner_font.FontColor;
Name =inner_font.FontName;
Size =inner_font.FontSize;
Italic= inner_font.Italic > 0 ? true : false;
Transparent = inner_font.Transparent > 0 ? true : false;
Underline = inner_font.Underline > 0 ? true : false;
XOffset= inner_font.XOffset;
YOffset= inner_font.YOffset;
}
///<summary>
/// 释放非托管内存
///</summary>
///<param name="hFont"></param>
public static void ReleaseFontHandle(IntPtr hFont)
{
Marshal.FreeHGlobal(hFont);
}
};
对于这样的结构体传参需要特别注意,因为封装了一个内部结构体作为模块内部转换使用,因此,在封装API的时候参数类型必须使用指针类型,而不能直接使用结构,因为内部转换结构体才是和C++原始结构体对应的,而内部转换结构体主要作用是用来数据转 换,不向外部公布,若是使用向外面公开的C#结构体则由于与C++结构体不能对应,导致出错。
C#指针参数类型使用IntPtr,C++ 参数类型使用FONT_INFO_T*。