C#&アンマネージDLL 普通の配列の引渡し

また,C#内のfloat配列をドカンと
アンマネージDLLに渡す必要が出てきて

もちろん,C#内のすべてのオブジェクトは,マネージ管理
ガーベジコレクションが勝手気ままに,オブジェクトのアドレスを,変えてくれまする

これじゃぁ~,アンマネージDLL側は安心して,データの受取ができない...

ってことで,まず思いついたのが
Marshal.AllocCoTaskMem()を使用して,固定アドレスなバッファを作成して,こいつに配列の中身を全コピーの上で
アンマネージDLLを呼び出しちゃえ!ってやつ

ソースはこちら

[DllImport("hogehoge.dll")]
private static extern int dll_TestFunc(int frameno, IntPtr ary, int aryCount);

public int TestFunc(int frameno, ref float[] ary)
{
    int len = ary.Length;
    IntPtr p = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(float)) * len);
    Marshal.Copy(ary,      0, p, len);
    int re = dll_TestFunc(frameno, p, len);
    Marshal.FreeCoTaskMem(p);
    return re;
}
でも,これだと,メモリリソース倍必要だし
コピーのオーバーヘッドも,ちと嫌な感じだし?

配列から直接IntPtr(しかも,マネージメモリ管理から外れるように,fixedしてくれないとまずい)
取り出せないのかねぇ~?

だったんですが,

GCHandle構造体
を使えば良いそうな.

ハンドルを取得するときに,ピン止め(GCHandleType.Pinned)するのがミソ
これで,マネージメモリ管理から外れまする

ソースはこちら
[DllImport("hogehoge.dll")]
private static extern int dll_TestFunc(int frameno, IntPtr ary, int aryCount);
public int TestFunc(int frameno, ref float[] ary)
{
    int len = ary.Length;
    GCHandle gcH = GCHandle.Alloc(ary, GCHandleType.Pinned);
    int re = dll_TestFunc(frameno,    gcH.AddrOfPinnedObject(), len);
    gcH.Free();

    return re;
}
これで,だいぶすっきりしましたわん 😉

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください