zoukankan      html  css  js  c++  java
  • C#调用C/C++动态库 封送结构体,结构体数组

    一. 结构体的传递

    Cpp代码
    #define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数  
      
    typedef struct      
    {    
        int osVersion;    
        int majorVersion;    
        int minorVersion;    
        int buildNum;    
        int platFormId;    
        char szVersion[128];    
    }OSINFO;    
      
    // 1. 获取版本信息(传递结构体指针)    
    JNAAPI bool GetVersionPtr( OSINFO *info );    
    // 2.获取版本信息(传递结构体引用)    
    JNAAPI bool GetVersionRef(OSINFO &info);    
    C#代码
    // OSINFO定义  
    [StructLayout(LayoutKind.Sequential)]  
    public struct OSINFO  
    {  
        public int osVersion;  
        public int majorVersion;  
        public int minorVersion;  
        public int buildNum;  
        public int platFormId;  
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]  
        public string szVersion;  
    }  

    可以通过二种方式来调用:

      1. 方式一(传入结构体引用),在C#中,结构体是以传值方式传递,类才是以传地址方式传递,加关键字ref即可. C端传递了两种不同类型的参数,都可以通过引用来解决.

    C#代码
    [DllImport("jnalib.dll", EntryPoint = "GetVersionPtr")]  
    public static extern bool GetVersionPtr(ref OSINFO info);  
    public static extern bool GetVersionRef(ref OSINFO info); 

      2. 方式二(传入IntPtr(平台通用指针))

    C#代码
    IntPtr pv = Marshal.AllocHGlobal(148); //结构体在使用时一定要分配空间(4*sizeof(int)+128)  
    Marshal.WriteInt32(pv,148); //向内存块里写入数值  
    if (GetVersionPtr(pv)) //直接以非托管内存块地址为参数  
    {  
        Console.WriteLine("--osVersion:{0}", Marshal.ReadInt32(pv, 0));  
        Console.WriteLine("--Major:{0}",Marshal.ReadInt32(pv, 4)); //移动4个字节  
        Console.WriteLine("--BuildNum: " + Marshal.ReadInt32(pv, 12));  
        Console.WriteLine("--szVersion: "+Marshal.PtrToStringAnsi((IntPtr)(pv.ToInt32()+20)));  
    }  
    Marshal.FreeHGlobal(pv); //处理完记得释放内存  

      

    二.结构体数组的传递

    Cpp代码
    // 传递结构体指针  
    JNAAPI bool GetVersionArray(OSINFO *info,int nLen);  

       调用代码:

    C#代码
    /** 
     * C#接口,对于包含数组类型,只能传递IntPtr 
     */   
    [DllImport("jnalib.dll", EntryPoint = "GetVersionArray")]  
    public static extern bool GetVersionArray(IntPtr p, int nLen);    
      
    // 源目标参数  
    OSINFO[] infos = new OSINFO[2];  
    for (int i = 0; i < infos.Length; i++)  
    {  
        infos[i] = new OSINFO();  
    }  
      
    IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OSINFO)) * 2);   
    GetVersionArray(pt, 2); //调用  
      
    //还原成结构体数组  
    for (int i = 0; i < 2; i++)    
    {  
    IntPtr ptr = (IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(OSINFO))); infos[i]
    =(OSINFO)Marshal.PtrToStructure(ptr,typeof(OSINFO)); Console.WriteLine("OsVersion:{0} szVersion:{1}", infos[i].osVersion, infos[i].szVersion); }

    Marshal.FreeHGlobal (pt);

    三. 复杂结构体的传递

       1. 输出参数,结构体作为指针传出

    Cpp代码
    typedef struct  
    {  
        char name[20];  
        int age;  
        double scores[30];  
    }Student;  
      
    // Class中包含结构体数组类型  
    typedef struct  
    {  
        int number;  
        Student students[50];  
    }Class;  
      
    // 传入复杂结构体测试  
    JNAAPI int GetClass(Class *pClass,int len);  
    C#代码
    // 接口定义   
    [DllImport("jnalib.dll", EntryPoint = "GetClass")]  
    public static extern int GetClass(IntPtr pv,int len);  
      
    // 结构体定义  
    // Student  
    [StructLayout(LayoutKind.Sequential)]  
    public struct Student  
    {  
        [MarshalAs(UnmanagedType.ByValTStr,SizeConst=20)]  
        public string name;  
        public int age;  
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]  
        public double[] scores;  
    }  
      
    // Class  
    [StructLayout(LayoutKind.Sequential)]  
    public struct Class  
    {  
        public int number;  
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] // 指定数组尺寸   
        public Student[] students; // 结构体数组定义  
    }  
      
    // 调用复杂结构体测试  
    int size = Marshal.SizeOf(typeof(Class)) * 50;  
    IntPtr pBuff = Marshal.AllocHGlobal(size); // 直接分配50个元素的空间,比Marshal.copy方便多了  
    GetClass(pBuff, 50);  
      
    Class[] pClass = new Class[50];  
    for (int i = 0; i < 50; i++)  
    {  
        IntPtr ptr = new IntPtr(pBuff.ToInt64() + Marshal.SizeOf(typeof(Class)) * i);  
        pClass[i] = (Class)Marshal.PtrToStructure(ptr, typeof(Class));  
    }  
    Marshal.FreeHGlobal(pBuff); // 释放内存  

       2. 输入参数, 给复杂结构体赋值后作为输入参数传入

       对于比较大的结构体指针,无法直接应用结构体类型,转化成IntPtr类型, 此时需要将原生类型转化为指针,并给指针赋值

       调用方法: 

    Marshal.StructureToPtr(stu, ptr1, true) 

    转摘自

      C#调用C/C++动态库 封送结构体,结构体数组

  • 相关阅读:
    CentOS 安装 nginx 教程
    CentOS 安装 NETCore 教程
    Bootstrap Blazor 组件介绍 Table (三)列数据格式功能介绍
    Net Core 一个简单的封装,缓存表达式树去生成反射的调用
    c#缩放图片
    .net5创建sqlite数据库文件
    使用C#处理图片
    Python enumerate()函数
    在R语言中,使用类似Python原生字符串的方式处理路径
    利用BAT脚本生成空文件夹
  • 原文地址:https://www.cnblogs.com/HuangWj/p/5633675.html
Copyright © 2011-2022 走看看