|
基本的にその認識で問題ないと私は思います。
で、元々の本題である構造体配列をマーシャリングして
そのアンマネージポインタを得る方法について記載します。
実際に速度は計測していませんが、感覚的に早そうな順です。
1.unsafeを有効にしてマネージ構造体配列の先頭ポインタを得る方法
ILレベルでは2と同等かもしれませんが、最もわかりやすい書き方だと思います。
bool AddPoints(List<MyPoint> points)
{
unsafe
{
fixed (MyPoint* p = points.ToArray())
{
MyData data = new MyData();
data.Count = points.Count;
data.Points = (IntPtr)p;
int result = MyAddPoints(data);
return result == 0;
}
}
}
2.Marshal.UnsafeAddrOfPinnedArrayElementを使用する方法
VB.NETでも使用できるので私が最もよく使用する方法です。
bool AddPoints(List<MyPoint> points)
{
MyPoint[] arr = points.ToArray();
GCHandle h = GCHandle.Alloc(arr, GCHandleType.Pinned);
try
{
MyData data = new MyData();
data.Count = points.Count;
data.Points = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0);
int result = MyAddPoints(data);
return result == 0;
}
finally
{
h.Free();
}
}
3.APIでメモリをコピーする方法
状況によっては使います。
[DllImport("KERNEL32")]
private static extern int RtlMoveMemory(IntPtr dst, MyPoint[] src, int size);
bool AddPoints(List<MyPoint> points)
{
int elemSize = Marshal.SizeOf(typeof(MyPoint));
MyData data = new MyData();
data.Count = points.Count;
data.Points = Marshal.AllocCoTaskMem(elemSize * data.Count);
try
{
RtlMoveMemory(data.Points, points.ToArray(), elemSize * data.Count);
int result = MyAddPoints(data);
return result == 0;
}
finally
{
Marshal.FreeCoTaskMem(data.Points);
}
}
4.Marshal.Copyでメモリをコピーする方法
これを使う場合、最初からマネージ側の型をMarshal.Copyしやすい感じで実装すると思います。
bool AddPoints(List<MyPoint> points)
{
int elemSize = Marshal.SizeOf(typeof(MyPoint));
MyData data = new MyData();
data.Count = points.Count;
data.Points = Marshal.AllocCoTaskMem(elemSize * data.Count);
try
{
int[] arr = new int[data.Count * 2];
for (int i = 0; i < points.Count; i++)
{
arr[i * 2 + 0] = points[i].X;
arr[i * 2 + 1] = points[i].Y;
}
Marshal.Copy(arr, 0, data.Points, arr.Length);
int result = MyAddPoints(data);
return result == 0;
}
finally
{
Marshal.FreeCoTaskMem(data.Points);
}
}
ワンライナー派なら以下のような書き方でも良いかもしれません。
var arr = Array.ConvertAll(points.ToArray(), new Converter<MyPoint, long>(
delegate(MyPoint point) {
return point.X + point.Y * ((long)UInt32.MaxValue + 1);
}));
Marshal.Copy(arr, 0, data.Points, arr.Length);
5.型を動的に生成する方法
サンプルを書こうと思いましたが、めんどくさくなったのでやめました。
参考になるサイトを見つけたのでリンクを載せておきます。
http://sayurin.blogspot.jp/2008/11/ptrtostructurearray.html
|