zoukankan      html  css  js  c++  java
  • 如何通过P/Invoke返回Struct和String Array

    P/Invoke提供了方便的.NET和c++ dll交互接口,通过P/Invoke可以将native的对象转化成managed object,从而享受.NET带来的种种便利.

    但是,假如dll中返回的参数,不是形如int, double, bool这样可以直接转化为.NET类型的对象,又该如何使用P/Invoke呢?

    比如我有这样一个接口:

    Code

    getGroupList返回一个嵌套struct的结构体,如何在.NET中获取该对象呢?

    如果查阅MSDN,通常会得到这样的答案:

    声明一个带Attribute的结构体

    Code

    然后写一个如下的函数,试图通过对Attribute的修饰来达到获取返回的结构体的目的.

    Code

     假如你正在采用类似的方法解决问题,基本上你会得到一个Memory Corrupt的错误信息. 或许有人要说,结构体/String数组不应该作为返回值传递,而是应该放到参数中,由getGroupList来为参数赋值. 的确,有很多这样调用的例子,网上能搜到一大把,可惜的是,这样的方法只适用于定长的结构. 比如,不包括的struct,或者是定长的String数组. MSDN上有很多类似的例子,请看这里.

    既然MSDN上已经有成功的例子了,那我这里要说明的是什么呢? 注意struct groupList中,groups的个数是不确定的,它是一个指像group数组的指针. .NET在Marshal的时候自然不知道如何将这样的结构体转换成.NET Object. 但是,我们可以手动写一个转换:

    Code

    关于IntPtr,可以在网上找一些相关的信息,这里,只要把它想象成c++中的void*类型即可. 在Main中,我们读到了一个IntPtr类型的groupList,即指向dll返回结构体的指针. 然后,在parseGroupList中,我们一步一步地解析这个指针.

    struct groupList的第一个member是int count.所以,我们通过

    int groupCount = Marshal.ReadInt32(groupListPtr)  把它读出来

    第二个member是group*.那就可以用

    IntPtr groupPtr = Marshal.ReadIntPtr(groupListPtr, 4);

    读出来.注意这里4这个参数表示位移,我们之前已经读到一个int了,所以要位移4bytes.

    以此类推,如此我们可以把c++中的结构体,转换成.NET中的List<Group>类型. 全归功于Marshal的强大功能.

     

    总结

    以上的方法,可以读取任何的结构体,关于如何解析字符串数组,可以看code project上的经典文章

    http://www.codeproject.com/KB/cs/marshalarrayofstrings.aspx

    我就是看了这篇文章后受到启发,把它扩展应用到返回struct上的.

    最后还要提一下,通常情况下,还是把结构体放在返回值里,原因一,返回值要留给ErrorCode用;原因二,这样的写法通常会忘记释放内存(注意,groupList是在dll中用malloc分配的,还需要在同一个dll中free掉).一个更好的做法是设计一组GroupListAlloc/GroupListFree/int GetGroupList(GroupList*)的接口. 当然,解析的过程还是一样的. :)

     

  • 相关阅读:
    零基础学python-16.7 nonlocal介绍
    零基础学python-16.6 嵌套作用域
    零基础学python-16.5 模块间全局变量的修改以及其他访问全局变量的方法
    零基础学python-16.4 global作用域
    零基础学python-16.3 变量名解析:LEGB原则
    如何格式化日期和时间
    如何创建指定的日期和时间
    如何遍历Set对象
    如何遍历Map对象
    如何遍历List对象
  • 原文地址:https://www.cnblogs.com/magicdlf/p/PInvoke.html
Copyright © 2011-2022 走看看