3

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

例如:

typedef struct result
{
   //..Some Members..//
}

int extern WINAPI getInfo(result**);

调用后,'result' 指向一个以 null 结尾的 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() 似乎没有任何好处。

我错过了什么?有人可以建议一个通用的方法来解决这个问题吗?

4

2 回答 2

3

您可以合理地假设所有指针的大小和表示形式都是相同的(不确定 C# 规范是否保证这一点,但在实践中您会发现确实如此)。所以你可以把你的T**as 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;
}

当然,IntPtr*无论何时调用它都需要显式转换,但至少没有代码重复。

于 2009-06-10T18:55:56.923 回答
0

你说:

Marshal.Copy() 需要知道非托管数组的大小。我只能使用不安全的代码来确定这一点

您似乎缺少Marshal.SizeOf()

从您在帖子中提到的内容来看,这可能足以解决您的问题。(此外,您的函数的参数可能需要是 Object** 而不是 T**。)

于 2009-06-10T18:12:37.120 回答