2

ICustomMarshalerを実装する独自のマーシャラーを使用して、ネイティブ(管理されていない)dllC関数を操作しています。

関数MarshalNativeToManagedで、dll側からの正しい結果が表示されます。問題は、MarshalNativeToManagedが返すオブジェクトが「使用」されていないことです。(In、Out)パラメーターを指定して呼び出している関数のオブジェクトは変更されません。

(これは、前にここで説明した「C#:PInvoke呼び出し後にデータを含まないカスタムマーシャラーを持つオブジェクト」とまったく同じ問題のようです) C#:PInvoke呼び出し後にデータを含まないカスタムマーシャラーを持つオブジェクト

単純なクラス:

    [StructLayout(LayoutKind.Sequential)]
    class CMA { 
        public int a; 
        char b;
        public char get_b() { return b; }
    }

関数のシグネチャは次のようになります。

[DllImport("first.dll", EntryPoint = "hack")]
    public static extern int hack([In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
                                            MarshalTypeRef=typeof(ZMarshal))] CMA cma);

メインのどこかで私はそれをこのように呼んでいます:

int retcode = hack(cma);

MarshalNativeToManagedで、dll関数呼び出しからの正しい結果が表示されます。

    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        // everything is fine with pNativeData;
        // but let us even say I ignore it
        // and return the object in the following way:
        CMA cma = new CMA();
        cma.a = 999;
        return cma; // this will be lost. I mean cma object in the main will not be changed
    }

私はここで何が間違っているのですか?簡単なメモ:「他の方法」ではなく、CustomMarshalerを使用して処理する方法を知りたいです:)

4

2 に答える 2

2

わかりました、今何が起こっているかを知っているようです。

秘訣は、オブジェクトを処理している間、実際にはポインターを処理していることです (C# がその事実を隠そうとしても)、次のように段階的に次のように処理します。2) MarshalManagedToNative(void* pCMA) // C# は、ここでハックに渡したポインターを渡します 3) Void* MarshalNativeToManaged(void *_some_PTR_to_memory_visible_to_managed_and_unmanaged_area) そして、この関数が返すこの Void* ptr を .NET がどうするかという質問があります。ref を使用しない場合、ハック (cma) でオブジェクトを変更する方法はありません。このポインターはどこでも使用されていません。関数は無効である可能性があります。

    public class ZMarshal : System.Runtime.InteropServices.ICustomMarshaler
{
    static ZMarshal static_instance;
    object oo;
    public IntPtr MarshalManagedToNative(object o)
    {
        if (!(o is CMA))
           throw new System.Runtime.InteropServices.MarshalDirectiveException("Blabala");
        oo = o;

その後、MarshalNativeToManaged で

    public object MarshalNativeToManaged(IntPtr pNativeData)
    {

        // some code that deals with the pNativeData really
        // but for our example only let us say we simply ignore what we just got
        // from the unmanaged world and simply change our object

        ((CMA)oo).a = 999;
        return oo; // this will not be lost now :)

この hack(ref CMA); のように ref を使用するとします。// 前の回答のおかげで ところで、この場合は hack(CMA**pp) であり、.NET は MarshalNativeToManaged *pp = oo; から返されるポインターを使用します。

肝心なのは、ポインタを保持してそれが指しているメモリの値を変更するか、(ref を使用して) ポインタをポインタに渡し (はい、古き良き ** 本当に)、ポインタ自体の値を変更する必要があるということです。

于 2012-05-25T14:45:30.670 に答える
1

C#言語では、引数をrefまたはoutとして宣言して、新しい値を返すことができるようにする必要があります。修理:

[DllImport("first.dll", EntryPoint = "hack")]
public static extern int hack(
    [In, Out]
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ZMarshal))]
    ref CMA cma);
于 2012-05-25T00:27:15.523 に答える