2009-06-10 104 views
3

我正在处理一组通过动态分配数组返回数据的本机函数。这些函数将引用指针作为输入,然后将其指向结果数组。c#:通常将非托管阵列转换为托管列表

例如:

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

int extern WINAPI getInfo(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

你可以做一个合理的假设,所有指针的是大小和代表性是相同的(不知道C#规格保证了这一点,但实际上你会发现它是这种情况)。所以你可以把你的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; 
} 

当然,你需要一个显式的IntPtr*当你调用该方法,但至少没有重复代码,否则。

0

你说:

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

看来你错过了Marshal.SizeOf()

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

+0

Marshal.Copy需要知道源数组中有多少元素,但我不知道在编译时由于数组是由本机代码动态分配的。我不知道任何方式来确定非托管阵列中的元素数量,而不使用不安全的代码。 – Odrade 2009-06-10 18:22:26