C++/Cx 将委托传递给本机 C++ 抛出异常

C++/Cx passing delegates to native c++ exception thrown

我有一个 C++/Cx 库,我需要将 C# 的回调函数作为指向它的指针传递给它。

委托在WinRt层声明如下:

public delegate void del(int, enumType, uint, string, int);

C#

void callbackFunction(
            int a,
            enumType b,   //this is public enum class
            uint c,
            String d,
            int e)
{
     tb.Text() = d;
}

Wrc_Component.wrc w = new Wrc_Component.wrc();

del d = new d(callbackFunction);
IntPtr p = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(d);

w.func(p.ToInt32(), "string");

再次在 WinRt 层定义 func():

void wrc::func(int ptrToCallback, Platform::String^ str){
    void*p = (void*)ptrToCallBack;
    callBackFunction cb = (callBackFunction)p;
    cb(0,enumType(0),0,"aaaa",0);             //here is exception thrown
}

当然代码简化了一点。 抛出以下异常的行在代码中标记为:

An exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in App1.exe but was not handled in user code

Additional information: Windows Runtime delegates may not be used for PInvoke interop.

我还想提一下,如果我调用以相同方式检索的函数但更简单,它不会抛出任何异常。

是什么导致了这个异常?这是因为用户定义的枚举类型吗?

编辑

而且,如果我需要将它进一步向下传递给 C++ 本机库怎么办,据我所知,我无法从 WinRt 中的委托检索指向函数的指针。

您没有将委托函数作为本机指针传递。您将它们作为委托类型传递。在你的 C# 中试试这个:

void callbackFunction(
            int a,
            enumType b,   //this is public enum class
            uint c,
            String d,
            int e)
{
     tb.Text() = d;
}

Wrc_Component.wrc w = new Wrc_Component.wrc();

del d = new del(callbackFunction);

w.func(d, "string");

对于您的 WinRT 更改为:

void wrc::func(del^ myDel, Platform::String^ str){
    if(myDel)
        myDel->Invoke(0, enumType(0),0,"aaaa",0);
}

我相信我涵盖了所有内容,但我有一个关于此主题的完整博客 post:http://www.robwirving.com/2014/07/21/calling-c-methods-c-winrt-components/

如 robwirving 所述,您不能仅将函数指针作为委托传递给 Windows 运行时组件。

Windows 运行时委托不同于 .NET 委托。要将处理程序从 .NET 传递到 Windows 运行时,您需要有一个 Windows 运行时包装器。在你的情况下,你可以通过委托 del.

    del handler = new del((a, b, c, d, e) =>
    {
       // to change the UI element in a handler, you may need to consider using the CoreDispatcher.
       tb.Text = d;
    });

    w.func(handler, "string");

我设法修复了那个异常...

这个异常的原因是在Windows运行时声明的委托不能在C#中使用,因此声明并使用C#委托解决了问题。

此外,对于问题中的构造(当然除了委托),我能够在我使用的所有三个层中传递和存储函数指针。

但是,如果有人发现此实现中可能存在的危险,请与我们分享以获得更好的代码!

感谢@Jeffrey Chen 和@robwirving 提供的其他回答。