【问题标题】:'Cannot marshal 'return value': Invalid managed/unmanaged type combination.' while marshalling delegate with string array'无法封送'返回值':托管/非托管类型组合无效。'同时用字符串数组编组委托
【发布时间】:2017-10-19 07:41:01
【问题描述】:

我正在尝试将委托编组为函数指针。委托的返回类型是字符串数组,而函数指针的返回类型是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" };
    }
}

【问题讨论】:

  • 无法从 C 或 C++ 程序可靠地调用该函数。调用者无法知道返回的数组中有多少元素以及是否需要释放字符串和数组的存储空间。例外只是告诉您编组器也不知道。它不能知道。你必须重新考虑这一点。
  • 在这种情况下,我还有什么其他选择可以实现这一目标?
  • 为自己设定一个避免GetFunctionPointerForDelegate的目标。 C++/CLI 不需要它,因为 C++/CLI 代码可以调用 C++ 和 C# 函数并直接访问 C++ 和 C# 对象。因此,您需要一个具有正确调用签名的 C++/CLI 函数,这样您就可以获取指向它的指针并立即获得正确的类型(无需强制转换!)。在该函数中,您可以访问 C# 对象、调用委托,以及您需要做的任何事情。
  • 我不明白,您可以提供一个快速示例吗?

标签: c# c++ c++-cli


【解决方案1】:

这就是我最终解决它的方法......

//  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();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多