【问题标题】:Unmanaged c++ DLL to get struct from c#非托管 c++ DLL 从 c# 获取结构
【发布时间】:2018-12-18 13:07:08
【问题描述】:

是否可以从 c++ DLL 调用 c# 中的方法?

我有很好的沟通 c# -> C++ ,但我希望能够发起呼叫 C++ -> c# 来轮询一些数据

我的代码看起来像这样......

host.h

/*
define the exporter for the C API
*/
#ifdef DLL_EXPORT
#define DLL_EXPORT __declspec(dllexport) 
#else
#define DLL_EXPORT __declspec(dllimport) 
#endif
class myClass
{
public:
    myCLass(){
        //do some initialising
    }
    ~myCLass(){
        //do some tidying
    }

    int getInt(int target) {
        switch (target)
        { 
        case 0:
            return someIntValue; 
        case 1:
            return someOtherIntValue;
        default:
            return 0;
        }
    }

   std::string getString(int target) {
        switch (target)
        { 
        case 0:
            return someStringValue;
        case 1:
            return someOtherStringValue;
        default:
            return "";
        }
    }
}

extern "C" {
    DLL_EXPORT  myClass* myClassConstructor();
    DLL_EXPORT void DestroySpatialser(const myClass* _pContext);
    DLL_EXPORT int getInt(myClass* _pContext, int target);
    DLL_EXPORT void getString(myClass* _pContext, int target, __out BSTR* returnStr);

}

host.cpp

extern "C" {


    myClass* myClassConstructor()
    {
        return new myClass();
    }

    void myClassDestructor(const myClass* _pContext)
    {
        if (_pContext != nullptr)
        {
            _pContext->~myClass();
            delete _pContext;
        }
    }

    //example
    int getInt(myClass* _pContext, int target)
    {
        if (_pContext == nullptr)
        {
            return K_ERR_INT;
        }
        return _pContext->getInt(target);
    }

    void getString(myClass* _pContext, int target, __out BSTR* returnStr)
    {
        std::string str;
        if (_pContext == nullptr)
        {
            str = K_ERR_CHAR;
        }
        else {
            str = _pContext->getString(target);
        }
        const std::string stdStr = str;
        _bstr_t bstrStr = stdStr.c_str();
        *returnStr = bstrStr.copy();
    }
}

csharp.cs

    private const string dllname = "myhost";

    [DllImport(dllname)]
    private static extern IntPtr myClassConstructor();

    [DllImport(dllname)]
    private static extern void myClassDestructor(IntPtr _pContext);

    [DllImport(dllname)]
    private static extern int getInt(IntPtr _pContext, int target);

    [DllImport(dllname)]
    private static extern float getFloat(IntPtr _pContext, int target);

    [DllImport(dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    extern static void getString(IntPtr _pContext, int target, [MarshalAs(UnmanagedType.BStr)] out String str);

    private static IntPtr _pContext;

    public static IntPtr Create()
    {
        _pContext = myClassConstructor();
        Debug.Log("_pContextcreated");
        return _pContext;
    }

    public static void Destroy()
    {
        myClassDestructor(_pContext );
    }

    private static int _getInt(int target)
    {
        return getInt(_pContext , target);
    }

    private static string _getString(int target)
    {
        String str;
        getString(_pContext , target, out str);
        return str;
    }

这一切都很好。

我想添加从 .cs 应用程序(它将是 3 个浮点数的结构)中获取值的功能,该应用程序应该从 myClass 的实例中调用。

我不想在 c# 端启动这个(我知道怎么做)。

有什么建议吗?

编辑

我实施了此处找到的解决方案 https://forum.unity.com/threads/communicating-c-with-c.89930/#post-586885

有两个变化(请参阅下面的 cmets 了解原因)

public int whatever = 0;
public delegate int myCallbackDelegate( int n, int m );
private myCallbackDelegate myCallback; // <-- add this line

[DllImport ("DLLImport_CProj")]
private static extern int TakesCallback( myCallbackDelegate fp, int n, int m );

void Awake()
{   
myCallback = new myCallbackDelegate( this.myCallback ) // <-- add this
int resp = TakesCallback(myCallback, 10, 20 ); // <-- change to this 
Debug.Log( resp );
}

【问题讨论】:

  • 感谢 Hans,您的建议与我在 forum.unity.com/threads/communicating-c-with-c.89930/… 找到的解决方案类似,这也是我最终使用的解决方案。
  • Hmya,论坛,不良代码的避难所和垃圾场。它有一个非常讨厌的错误,它不能满足// Ensure it doesn't get garbage collected 的要求。您无法通过简单的测试发现该错误。
  • 谢谢(再次) - 您能否详细说明您的链接解决方案如何确保这一点?
  • 它将委托对象存储在一个变量中,以便 GC 始终可以看到它。

标签: c# c++


【解决方案1】:

嗯,我能想到的一种方法是将 JSON 字符串作为 char 数组从 C++ 传递到 C#,然后在 C# 上解析它并获取数据。这是两种语言都熟悉的一种交流方式。 此外,您需要将回调从 C# 传递到 C++ 以允许执行此操作,如 this question 中所述。 让我知道这是否有帮助:)

【讨论】:

  • 感谢您的想法,但我不想在 c# 上启动此操作 - 我在我的问题中添加了一个限定条件以明确
  • @garrilla 是的,我意识到我评论了错误的流程。我现在正在编辑我的答案:)
  • 再次感谢@Oren_c,但您提供的附加信息是针对托管解决方案的。根据我的问题标题,我想保持不受管理。
【解决方案2】:

使您的 C# 类型为 COMVisible,这意味着您将能够从支持 COM 的 C++ 代码中调用它们,例如,使用 ATL

【讨论】:

  • 感谢您的努力,我希望保持不受管理并保持在现有模式内。不过有兴趣了解这些事情。
猜你喜欢
  • 1970-01-01
  • 2013-01-07
  • 2013-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-05
  • 2010-10-14
相关资源
最近更新 更多