zoukankan      html  css  js  c++  java
  • .net 互操作之p/invoke 数据封送(结构体中的字符串,其他字段,内存布局)(4)

    一.字符串封送

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

    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;
         //用MarshalAsUnmanagedType来指定 
         [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);
            }
  • 相关阅读:
    Gin+Gorm小项目
    python实现监控信息收集
    Vue引入Stylus
    Go搭建一个Web服务器
    saltstack高效运维
    04-01 Django之模板层
    03-01 Django之视图层
    02-01 Django之路由层
    HTTP协议
    01-01 Web应用
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/1809623.html
Copyright © 2011-2022 走看看