この質問に関連するカスタム マーシャラーを作成しようとすると ( P/Invoke from C to C# without know size of array )、理解できないものに出くわしました。これは私が書いた初めてのカスタム マーシャラーなので、私の無知のために明らかな何かが欠けていることは間違いありません。
ここに私のC#コードがあります:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace CustomMarshaler
{
public class MyCustomMarshaler : ICustomMarshaler
{
static MyCustomMarshaler static_instance;
public IntPtr MarshalManagedToNative(object managedObj)
{
if (managedObj == null)
return IntPtr.Zero;
if (!(managedObj is int[]))
throw new MarshalDirectiveException("VariableLengthArrayMarshaler must be used on an int array.");
int[] arr = (int[])managedObj;
int size = sizeof(int) + arr.Length * sizeof(int);
IntPtr pNativeData = Marshal.AllocHGlobal(size);
Marshal.WriteInt32(pNativeData, arr.Length);
Marshal.Copy(arr, 0, pNativeData + sizeof(int), arr.Length);
return pNativeData;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
int len = Marshal.ReadInt32(pNativeData);
int[] arr = new int[len];
Marshal.Copy(pNativeData + sizeof(int), arr, 0, len);
return arr;
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
}
public void CleanUpManagedData(object managedObj)
{
}
public int GetNativeDataSize()
{
return -1;
}
public static ICustomMarshaler GetInstance(string cookie)
{
if (static_instance == null)
{
return static_instance = new MyCustomMarshaler();
}
return static_instance;
}
}
class Program
{
[DllImport(@"MyLib.dll")]
private static extern void Foo(
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyCustomMarshaler))]
int[] arr
);
static void Main(string[] args)
{
int[] colorTable = new int[] { 1, 2, 3, 6, 12 };
Foo(colorTable);
foreach (int value in colorTable)
Console.WriteLine(value);
}
}
}
反対側には、たまたま Delphi で書かれた簡単なネイティブ DLL があります。
library MyLib;
procedure Foo(P: PInteger); stdcall;
var
i, len: Integer;
begin
len := P^;
Writeln(len);
for i := 1 to len do begin
inc(P);
Writeln(P^);
inc(P^);
end;
end;
exports
Foo;
begin
end.
アイデアは、配列が DLL に渡され、DLL が長さフィールドと配列の値を出力するというものです。また、ネイティブ コードは、配列の各値を 1 ずつ増やします。
したがって、次の出力が表示されることを期待しています。
5 1 2 3 6 12 2 3 4 7 13
しかし残念ながら、次の出力が表示されます。
5 1 2 3 6 12 1 2 3 6 12
MarshalNativeToManaged
デバッガーの下で、それが実行中であり、それが返す値がインクリメントされていることがわかります。しかし、これらのインクリメントされた値は、 に渡されるオブジェクトには戻りませんFoo
。
これを修正するにはどうすればよいですか?