3

動的に割り当てられた配列を介してデータを返す一連のネイティブ関数を扱っています。関数は参照ポインターを入力として取り、それを結果の配列にポイントします。

例えば:

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

int extern WINAPI getInfo(result**);

呼び出しの後、'result' は null で終わる結果* の配列を指します。

このアンマネージド アレイからマネージド リストを作成したいと考えています。私は次のことができます:

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**したがって、として扱うことができます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()が不足しているようです。

投稿で言及したことから、問題を解決するにはそれで十分かもしれません。(また、関数のパラメーターは、T** ではなく Object** である必要がある場合もあります。)

于 2009-06-10T18:12:37.120 に答える