代码之家  ›  专栏  ›  技术社区  ›  Odrade

C:一般将非托管数组转换为托管列表

  •  3
  • Odrade  · 技术社区  · 17 年前

    我正在处理一组通过动态分配的数组返回数据的本机函数。函数将引用指针作为输入,然后将其指向结果数组。

    例如:

    typedef struct result
    {
       //..Some Members..//
    }
    
    int extern WINAPI getInfo(result**);
    

    调用后,“result”指向以空结尾的result*数组。

    我要从此非托管数组创建托管列表。我可以这样做:

    struct Result
    {
       //..The Same Members..//
    }
    
    public static unsafe List<Result> getManagedResultList(Result** unmanagedArray)
    {
        List<Result> resultList = new List<Result>();
    
        while (*unmanagedArray != null)
        {
           resultList.Add(**unmanagedArray);
           ++unmanaged;
        }
        return result;
    }
    

    这项工作,它将是乏味和丑陋的重新实现每一种类型的结构,我将不得不处理(~35)。我想要一个对数组中结构类型通用的解决方案。为此,我尝试了:

    public static unsafe List<T> unmanagedArrToList<T>(T** unmanagedArray)
    { 
        List<T> result = new List<T>();
        while (*unmanagedArray != null)
        {
            result.Add((**unmanagedArray));
            ++unmanagedArray;
        }
        return result;
    }
    

    但这不会编译,因为您无法“获取托管类型(‘T’)的地址、大小或声明指针”。

    我还尝试在不使用不安全代码的情况下执行此操作,但遇到了marshal.copy()需要知道非托管数组大小的问题。我只能使用不安全的代码来确定这一点,因此在本例中使用marshal.copy()似乎没有什么好处。

    我错过了什么?有人能对这个问题提出一个通用的方法吗?

    2 回复  |  直到 17 年前
        1
  •  3
  •   Pavel Minaev    17 年前

    您可以合理地假设所有指针的大小和表示都是相同的(不确定C spec是否保证了这一点,但实际上您会发现确实如此)。所以你可以治疗你的 T** 作为 IntPtr* . 另外,我也不知道 Marshal.Copy 这对您有帮助,因为它只有内置类型的重载。所以:

    public static unsafe List<T> unmanagedArrToList<T>(IntPtr* p)
    { 
        List<T> result = new List<T>();
        for (; *p != null; ++p)
        {
            T item = (T)Marshal.PtrToStructure(*p, typeof(T));
            result.Add(item);
        }
        return result;
    }
    

    当然,你需要一个明确的演员表 国际乒乓球联合会 无论何时调用它,但至少没有其他代码重复。

        2
  •  0
  •   John Fisher    17 年前

    你说:

    marshal.copy()需要知道大小 非托管数组的。我只能 使用不安全代码确定

    你好像失踪了 Marshal.SizeOf() .

    从你在文章中提到的内容来看,这可能足以解决你的问题。(另外,函数的参数可能需要是object**,而不是t**。)