パラメータの 1 つとして char* を期待するアンマネージ C++ dll を呼び出しており、byte[] をそれにプッシュしたいと考えています。プロジェクトは VB.NET で書かれています。
これにはどのような種類のマーシャリングが機能しますか?
パラメータの 1 つとして char* を期待するアンマネージ C++ dll を呼び出しており、byte[] をそれにプッシュしたいと考えています。プロジェクトは VB.NET で書かれています。
これにはどのような種類のマーシャリングが機能しますか?
管理対象構造をパラメーターとして渡すために固定する必要がある場合は、次のコードを使用できます。
// (c) 2007 Marc Clifton
/// <summary>
/// A helper class for pinning a managed structure so that it is suitable for
/// unmanaged calls. A pinned object will not be collected and will not be moved
/// by the GC until explicitly freed.
/// </summary>
internal class PinnedObject<T> : IDisposable where T : struct
{
protected T managedObject;
protected GCHandle handle;
protected IntPtr ptr;
protected bool disposed;
public T ManangedObject
{
get
{
return (T)handle.Target;
}
set
{
Marshal.StructureToPtr(value, ptr, false);
}
}
public IntPtr Pointer
{
get { return ptr; }
}
public int Size
{
get { return Marshal.SizeOf(managedObject); }
}
public PinnedObject()
{
managedObject = new T();
handle = GCHandle.Alloc(managedObject, GCHandleType.Pinned);
ptr = handle.AddrOfPinnedObject();
}
~PinnedObject()
{
Dispose();
}
public void Dispose()
{
if (!disposed)
{
if (handle.IsAllocated)
handle.Free();
ptr = IntPtr.Zero;
disposed = true;
}
}
}
}
その後、PinnedObject.Pointerを使用してアンマネージコードを呼び出すことができます。extern宣言では、そのパラメーターのタイプとしてIntPtrを使用します。
PinnedObject<BatteryQueryInformation> pinBatteryQueryInfo = new PinnedObject<BatteryQueryInformation>();
pinBatteryQueryInfo.ManangedObject = _structBatteryQueryInfo;
Unmanaged.Method(pinBatteryQueryInfo.Pointer);
私は .net の専門家ではありませんが、最近似たようなことをする必要がありました。
シリアル化の問題だけではなく、ガベージ コレクターが C++ ランドで使用されているときにバイト配列をクリーンアップするのを停止する必要もあります...
以下の C# のスニペットが役立ちます。
// byte[] (byteArray) を固定します GCHandle ハンドル = GCHandle.Alloc(byteArray, GCHandleType.Pinned); IntPtr アドレス = handle.AddrOfPinnedObject(); // アドレス ポインタを使用して、C++ の処理を行います。 // 掃除 ハンドル.フリー();
PInvoke 定義で、char* パラメータを byte[] として宣言するだけで、標準のマーシャラーが作業を処理します。
しかし、これは最善のアイデアかもしれませんし、そうでないかもしれません。C++ 関数は文字列を予期していますか、それともデータのバッファーを予期していますか (C/C++ コードでは、char が 1 バイトであるという事実に基づいて、バッファーに char* を使用することがよくあります)。
バッファの場合、byte[] は確かに正しいですが、文字列が必要な場合は、パラメータを文字列として (明示的に) 宣言し、Encoding.ASCII.GetString() を使用して変換すると、より明確になる可能性があります。 byte[] を文字列に変換します。
また、C++ 関数が文字列を想定していて、パラメータを byte[] として宣言することにした場合は、C/C++ が文字列の終わりを決定する方法であるため、バイト配列がゼロで終わっていることを確認してください。