2017-10-19 1 views
0

デリゲートを関数ポインタにマーシャリングしようとしています。デリゲートの戻り値の型は文字列の配列で、関数ポインタの戻り値の型はchar **'値を整列化できません:無効な管理対象/非管理対象型の組み合わせです。'文字列配列のデリゲートを整列化しています。

以下のコードは無効な管理対象/非管理型の組み合わせの例外をスローします。これをどうすれば解決できますか?

// unmanaged code 

typedef char** (*MyFuncPtr)(void); 

class __declspec(dllexport) MyUnmanagedClass{ 
private: 
    MyFuncPtr mFunPtr 
public: 

    MyUnmanagedClass(MyFuncPtr funPtr) 
    { 
     mFunPtr = funPtr; 
    } 

    char* Func1() 
    { 
     // callback 
     mFunPtr(); 

     return "something"; 
    } 
}; 

// managed wrapper (CLI) 

public delegate cli::array<String^>^ MyDelegate(); 

public class MyCliClass{ 
private: 
    MyDelegate mDel; 
public: 

    MyCliClass(MyDelegate del) 
    { 
     mDel = del; 
    } 

    String^ Func2() 
    { 
     MyFuncPtr funPtr = static_cast<MyFuncPtr>(Marshal::GetFunctionPointerForDelegate(mDel).ToPointer()); 

     MyUnmanagedClass* muc = new MyUnmanagedClass(funPtr); 
     char* retValPtr = muc->Func1(); 

     return context->marshal_as<String^>(retValPtr); 
    } 
}; 

// managed client (C#) 
class Program 
{ 
    static void Main(string[] args) 
    { 
     MyCliClass mcc = new MyCliClass(Func3); 
     mcc.Func2(); 
    } 

    static string[] Func3() 
    { 
     return new[] { "Some 1", "Some 2" }; 
    } 
} 
+0

です。呼び出し元は、返された配列内の要素数と、文字列と配列の記憶領域を解放する必要があるかどうかを知ることはできません。例外は、単にマーシャルがどちらも知らないことを伝えます。それは分からない。あなたはこれを再考する必要があります。 –

+0

その場合、これを達成するために他にどのような選択肢が必要ですか? –

+0

自分自身に 'GetFunctionPointerForDelegate'を避けるという目標を設定します。 C++/CLIコードでは、C++関数とC#関数の両方を呼び出し、C++オブジェクトとC#オブジェクトの両方に直接アクセスできるため、C++/CLIではその必要はありません。だからあなたが必要とするのは、正しい呼び出しシグネチャを持つC++/CLI関数です。ポインタを取り、すぐに正しい型(キャストなし)を得ることができます。その関数の中で、C#オブジェクトにアクセスし、代理人を呼び出すことができます。 –

答えて

0

これは、関数は、CまたはC++のプログラムから確実に呼び出すことは不可能です...私は最終的にそれを解決する方法

// unmanaged code 
class __declspec(dllexport) NativeInterface 
{ 
public: 
    vector<string> NativeInterfaceFunc() = 0; 
}; 

class __declspec(dllexport) UnmanagedClass{ 
private: 
    NativeInterface* mNativeInterface 
public: 

    UnmanagedClass(NativeInterface* nativeInterface) 
    { 
     mNativeInterface = nativeInterface; 
    } 

    string UnmanagedClassFunc() 
    { 
     vector<string> values = mNativeInterface->NativeInterfaceFunc(); 

     ostringstream oss; 

     copy(values.begin(), values.end(), ostream_iterator<string>(oss, ",")); 

     return oss.str(); 
    } 
}; 

// managed wrapper (CLI) 
class NativeClass : NativeInterface 
{ 
public: 
    NativeInterface(ManagedInterface^ managedInterface) 
    { 
     mManagedInterface = managedInterface   
    }; 

    vector<string> NativeInterfaceFunc() 
    { 
     IEnumerable<String^> managedReturn = mManagedInterface->ManagedInterfaceFunc(); 

     vector<string> nativeReturn; 

     marshal_context^ context = new marshal_context(); 

     for each(String^ manRet in managedReturn) 
     { 
      nativeReturn.push_back(context->marshal_as<const char*>(manRet)) 
     } 

     delete context; 

     return nativeReturn; 
    }; 
private: 
    gcroot<ManagedInterface^> mManagedInterface; 
}; 

public ref class CliClass{ 
public: 

    CliClass(ManagedInterface^ managedInterface) 
    { 
     mNativeInterface = new NativeClass(managedInterface); 

     mUnmanagedClass = new UnmanagedClass(mNativeInterface); 
    } 

    ~CliClass() 
    { 
     delete mUnmanagedClass; 
     delete mNativeInterface; 
    } 

    String^ CliFunc() 
    { 
     string nativeReturn = mUnmanagedClass->UnmanagedClassFunc(); 

     return gcnew String(nativeReturn.c_str()); 
    } 
private: 
    UnmanagedClass mUnmanagedClass; 
    NativeInterface mNativeInterface; 
}; 

// managed interface (C#) 
interface ManagedInterface 
{ 
    IEnumerable<string> ManagedInterfaceFunc(); 
} 

// managed interface implementation(C#) 
public class ManagedClass : ManagedInterface 
{ 
    public IEnumerable<string> ManagedInterfaceFunc() 
    { 
     return new List<string> { "Some 1", "Some 2" }; 
    } 
} 

// managed client (C#) 
class Program 
{ 
    static void Main(string[] args) 
    { 
     MyCliClass mcc = new MyCliClass(new ManagedClass()); 

     Console.WriteLine(mcc.CliFunc()); 

     mcc.Dispose(); 
    } 
} 
関連する問題