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 提供的其他回答。
我有一个 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 提供的其他回答。