您的位置:首页 > 其它

.net 互操作之p/invoke- 数据封送(结构体中的字符串,其他字段,内存布局)(4)

2010-08-26 23:49 330 查看

一.字符串封送

与传值没多大区别,内存释放也分两种,自动和手动,不再介绍

1.托管结构与函数

//typedef struct _MSEMPLOYEE
//{
//    UINT employeeID;
//    short employedYear;
//    char* displayName;
//    char* alias;
//} MSEMPLOYEE, *PMSEMPLOYEE;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct MsEmployee
{
public uint EmployeeID;
public short EmployedYear;
public string DisplayName;
public string Alias;
}

[StructLayout(LayoutKind.Sequential)]
private struct MsEmployee_IntPtrString
{
public uint EmployeeID;
public short EmployedYear;
public IntPtr DisplayName;
public IntPtr Alias;
}


// void __cdecl GetEmployeeInfo(PMSEMPLOYEE pEmployee)
[DllImport(_dllName, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
private extern static void GetEmployeeInfo(ref MsEmployee employee);

[DllImport(_dllName, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi, EntryPoint = "GetEmployeeInfo")]
private extern static void GetEmployeeInfo_IntPtrString(ref MsEmployee_IntPtrString employee);

2.非托管函数

void __cdecl GetEmployeeInfo(PMSEMPLOYEE pEmployee)
{
if(NULL != pEmployee)
{
// 我?们?应?该?根?据?pEmployee->employeeID查?找?写?信?息?回?来?
pEmployee->employedYear = 2;
pEmployee->alias = (char*)CoTaskMemAlloc(255);
pEmployee->displayName = (char*)CoTaskMemAlloc(255);

strcpy_s(pEmployee->alias, 255, "xcui");
strcpy_s(pEmployee->displayName, 255, "Xiaoyuan Cui");
}
}

3.测试

private static void TestAllocString()
{
MsEmployee employee = new MsEmployee();
employee.EmployeeID = 10001;
GetEmployeeInfo(ref employee);

Console.WriteLine("\n员?工?信?息?:");
Console.WriteLine("ID: {0}", employee.EmployeeID);
Console.WriteLine("工?龄?:{0}", employee.EmployedYear);
Console.WriteLine("Alias: {0}", employee.Alias);
Console.WriteLine("姓?名?: {0}", employee.DisplayName);
}

private static void TestAllocString_IntPtrString()
{
MsEmployee_IntPtrString employee = new MsEmployee_IntPtrString();
employee.EmployeeID = 10001;
GetEmployeeInfo_IntPtrString(ref employee);

string displayName = Marshal.PtrToStringAnsi(employee.DisplayName);
string alias = Marshal.PtrToStringAnsi(employee.Alias);

Marshal.FreeCoTaskMem(employee.DisplayName);
Marshal.FreeCoTaskMem(employee.Alias);

Console.WriteLine("\n员?工?信?息?:");
Console.WriteLine("ID: {0}", employee.EmployeeID);
Console.WriteLine("工?龄?:{0}", employee.EmployedYear);
Console.WriteLine("Alias: {0}", alias);
Console.WriteLine("姓?名?: {0}", displayName);
}

4.封送字符串数组

//typedef struct _MSEMPLOYEE2
//{
//    UINT employeeID;
//    short employedYear;
//    char displayName[255];
//    char alias[255];
//} MSEMPLOYEE2, *PMSEMPLOYEE2;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct MsEmployee2
{
public uint EmployeeID;
public short EmployedYear;
//用MarshalAs 的UnmanagedType来指定
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
public string DisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
public string Alias;
}

定义函数

// void __cdecl GetEmployeeInfo2(PMSEMPLOYEE2 pEmployee)
[DllImport(_dllName, CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
private extern static void GetEmployeeInfo2(ref MsEmployee2 employee);


void __cdecl GetEmployeeInfo2(PMSEMPLOYEE2 pEmployee)
{
if(NULL != pEmployee)
{
//
pEmployee->employedYear = 2;
strcpy_s(pEmployee->alias, 255, "jizhou");
strcpy_s(pEmployee->displayName, 255, "Jizhou Huang");
}
}

测试

private static void TestInlineString()
{
MsEmployee2 employee = new MsEmployee2();
employee.EmployeeID = 10002;
GetEmployeeInfo2(ref employee);

Console.WriteLine("\n员工信息:");
Console.WriteLine("ID: {0}", employee.EmployeeID);
Console.WriteLine("工龄:{0}", employee.EmployedYear);
Console.WriteLine("Alias: {0}", employee.Alias);
Console.WriteLine("姓名: {0}", employee.DisplayName);
}


其他字段封送

以MarshalAs标签来封送

如下封送了c++的bool类型和Win32的BOOL类型

//typedef struct _MSEMPLOYEE_EX
//{
//    UINT employeeID;
//    wchar_t* displayName;
//    char* alias;
//    bool isInRedmond;
//    BOOL isFamale;
//} MSEMPLOYEE_EX, *PMSEMPLOYEE_EX;

[StructLayout(LayoutKind.Sequential)]
private struct MsEmployeeEx
{
public uint EmployeeID;
[MarshalAs(UnmanagedType.LPWStr)]
public string DisplayName;
[MarshalAs(UnmanagedType.LPStr)]
public string Alias;
[MarshalAs(UnmanagedType.I1)]
public bool IsInRedmond;
public short EmployedYear;
[MarshalAs(UnmanagedType.Bool)]
public bool IsFamale;
}

至于内存释放也是相同两种处理方式

定义函数

void __cdecl GetEmployeeInfoEx(PMSEMPLOYEE_EX pEmployee)
{
ShowNativeStructSize(sizeof(MSEMPLOYEE_EX));

if(NULL != pEmployee)
{
pEmployee->alias = (char*)CoTaskMemAlloc(255);
pEmployee->displayName = (wchar_t*)CoTaskMemAlloc(255 * 2);

strcpy_s(pEmployee->alias, 255, "xcui");
wcscpy_s(pEmployee->displayName, 255, L"崔晓源");

pEmployee->isInRedmond = false;
pEmployee->employedYear = 2;
pEmployee->isFamale = false;
}
}

测试

private static void TestGetEmployeeEx()
{
ShowMarshalSize(typeof(MsEmployeeEx));
MsEmployeeEx employee = new MsEmployeeEx();
employee.EmployeeID = 10001;
GetEmployeeInfoEx(ref employee);

Console.WriteLine("员?工?信?息?:");
Console.WriteLine("ID: {0}", employee.EmployeeID);
Console.WriteLine("Alias: {0}", employee.Alias);
Console.WriteLine("姓?名?: {0}", employee.DisplayName);
Console.WriteLine("性?别?: {0}", employee.IsFamale ? "女?" : "男?");
Console.WriteLine("工?龄?: {0}", employee.EmployedYear);
Console.WriteLine("是?否?在?总?部?: {0}", employee.IsInRedmond ? "是?" : "否?");
}


控制内存布局

当非托管结构体太多的时候,托管结构体只需要其中几个的时候,可以控制内存布局

指定StructLayout的Pack值

//#pragma pack(1)
//typedef struct _MSEMPLOYEE_EX2
//{
//    UINT      EmployeeID;       //4 bytes -> Offset 0
//    USHORT    EmployedYear;     //2 bytes -> Offset 4
//    BYTE      CurrentLevel;     //1 bytes -> Offset 6
//    wchar_t*  Alias;            //4 bytes -> Offset 7
//    wchar_t*  DisplayName;      //4 bytes -> Offset 11
//    wchar_t*  OfficeAddress;    //4 bytes -> Offset 15
//    wchar_t*  OfficePhone;      //4 bytes -> Offset 19
//    wchar_t*  Title;            //4 bytes -> Offset 23
//    USHORT    RegionId;         //2 bytes -> Offset 27
//    int       ZipCode;          //4 bytes -> Offset 29
//    double    CurrentSalary;    //8 bytes -> Offset 33
//} MSEMPLOYEE_EX2, *PMSEMPLOYEE_EX2;
//#pragma pack()

[StructLayout(LayoutKind.Explicit, Pack = 1)]
private struct MsEmployeeEx2
{
[FieldOffset(0)]    public uint EmployeeID;
[FieldOffset(4)]    public ushort EmployedYear;
[FieldOffset(6)]    public byte CurrentLevel;
[FieldOffset(27)]   public ushort RegionId;
[FieldOffset(29)]   public int ZipCode;
[FieldOffset(33)]   public double CurrentSalary;
}

注意非托管控制传入的结构体字段需要在托管代码中定义,不然会造成内存泄露.

void __cdecl GetEmployeeInfoEx2(PMSEMPLOYEE_EX2 pEmployee)
{
_wsetlocale(LC_ALL, L"chs");

ShowNativeStructSize(sizeof(MSEMPLOYEE_EX2));

if(NULL != pEmployee)
{
pEmployee->EmployedYear = 2;
pEmployee->CurrentLevel = 60;
pEmployee->RegionId = 1100;

wprintf(L"原?邮?政?编?码?:?%d\n", pEmployee->ZipCode);
pEmployee->ZipCode = 100080;
pEmployee->CurrentSalary = 200000;
}

}

测试

private static void TestStructExactLayout()
{
ShowMarshalSize(typeof(MsEmployeeEx2));

// 创?建?一?个?对?象?,?并?赋?以?初?始?值?
MsEmployeeEx2 employee = new MsEmployeeEx2();
employee.EmployeeID = 10001;
employee.EmployedYear = 1;
employee.CurrentLevel = 59;
employee.RegionId = 1000;
employee.ZipCode = 16;
employee.CurrentSalary = 123456;

GetEmployeeInfoEx2(ref employee);

Console.WriteLine("员?工?信?息?:");
Console.WriteLine("ID: {0}", employee.EmployeeID);
Console.WriteLine("工?龄?: {0}", employee.EmployedYear);
Console.WriteLine("职?级?: {0}", employee.CurrentLevel);
Console.WriteLine("区?域?代?码?: {0}", employee.RegionId);
Console.WriteLine("邮?政?编?码?: {0}", employee.ZipCode);
Console.WriteLine("工?资?: {0}", employee.CurrentSalary);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐