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++动态库 封送结构体,结构体数组

  • 相关阅读:
    LeetCode 264. Ugly Number II
    LeetCode 231. Power of Two
    LeetCode 263. Ugly Number
    LeetCode 136. Single Number
    LeetCode 69. Sqrt(x)
    LeetCode 66. Plus One
    LeetCode 70. Climbing Stairs
    LeetCode 628. Maximum Product of Three Numbers
    Leetcode 13. Roman to Integer
    大二暑假周进度报告03
  • 原文地址:https://www.cnblogs.com/HuangWj/p/5633675.html
Copyright © 2011-2022 走看看