2

パラメータの 1 つとして char* を期待するアンマネージ C++ dll を呼び出しており、byte[] をそれにプッシュしたいと考えています。プロジェクトは VB.NET で書かれています。

これにはどのような種類のマーシャリングが機能しますか?

4

3 に答える 3

1

管理対象構造をパラメーターとして渡すために固定する必要がある場合は、次のコードを使用できます。

    // (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);
于 2008-11-05T08:25:56.753 に答える
0

私は .net の専門家ではありませんが、最近似たようなことをする必要がありました。

シリアル化の問題だけではなく、ガベージ コレクターが C++ ランドで使用されているときにバイト配列をクリーンアップするのを停止する必要もあります...

以下の C# のスニペットが役立ちます。

// byte[] (byteArray) を固定します  
GCHandle ハンドル = GCHandle.Alloc(byteArray, GCHandleType.Pinned);   
IntPtr アドレス = handle.AddrOfPinnedObject();  
// アドレス ポインタを使用して、C++ の処理を​​行います。

// 掃除
ハンドル.フリー();
于 2008-11-05T04:45:54.593 に答える
0

PInvoke 定義で、char* パラメータを byte[] として宣言するだけで、標準のマーシャラーが作業を処理します。

しかし、これは最善のアイデアかもしれませんし、そうでないかもしれません。C++ 関数は文字列を予期していますか、それともデータのバッファーを予期していますか (C/C++ コードでは、char が 1 バイトであるという事実に基づいて、バッファーに char* を使用することがよくあります)。

バッファの場合、byte[] は確かに正しいですが、文字列が必要な場合は、パラメータを文字列として (明示的に) 宣言し、Encoding.ASCII.GetString() を使用して変換すると、より明確になる可能性があります。 byte[] を文字列に変換します。

また、C++ 関数が文字列を想定していて、パラメータを byte[] として宣言することにした場合は、C/C++ が文字列の終わりを決定する方法であるため、バイト配列がゼロで終わっていることを確認してください。

于 2009-11-21T13:52:49.437 に答える