之前,我有这样的代码在C++如何编组由C#委托返回一个对象返回它的值C++
class MyClass { ... };
typedef MyClass (*Callback)();
Callback theCB;
static void RegisterCallback(Callback cb) { theCB = cb; };
static void CallCallback() {
MyClass obj = theCB();
}
我使用痛饮但是为了简单(如果你不知道痛饮)我有这样的包装在C#
public class MyClassWrapper
{
public IntPtr ptrToNativeObj; // pointer to native MyClass object
public MyClassWrapper()
{
ptrToNativeObj = call to native code that creates
and returns a new instance of MyClass in C++
}
};
现在我想支持C#中的回拨机制,所以我将它设置这样的:
public MyClassWrapper MyFunction()
{
return new MyClassWrapper();
}
delegate MyClassWrapper CallbackDotNet();
static void main()
{
var fct = new CallbackDotNet(MyFunction);
P/Invoke call to native function RegisterCallback(fct);
then finally:
P/Invoke call to native function CallCallback();
}
我有所有这些代码安装程序正常工作。 CallCallback中的本机代码将正确调用MyFunction。
但现在我需要妥善处理返回的对象......而在C++中的回调是由价值回归所以这不会免费工作
MyFunction的返回一个C#参考:
static void CallCallback() {
MyClass obj = theCB();
}
如何编写对MyFunction返回的MyClassWrapper对象的“引用”,以便C++接收“by-value”MyClass对象?
我应该继续写一个自定义编组吗?
http://msdn.microsoft.com/en-us/library/zk0a8dea(v=vs.90).aspx
然后使用它像这里
[return: MarshalAs(UnmanagedType.CustomMarshaler,
MarshalType = "MyCustomMarshaler")]
delegate MyClassWrapper CallbackDotNet();
我看着自定义marshallers的文档,它是相当复杂的。 貌似实现有趣的方法如下:
IntPtr MarshalManagedToNative(Object ManagedObj);
,代码会像
IntPtr MarshalManagedToNative(Object ManagedObj)
{
MyClassWrapper val = ManagedObj as MyClassWrapper;
return val.ptrToNativeObj;
}
但是,这将返回一个MyClass的*回本地代码,而不是一个MyClass的值这C++代码期望!
static void CallCallback() {
MyClass obj = theCB();
}
编组人员是否足够聪明以取消引用指针?
是否有令人信服的理由,你不能有回调返回一个指针,并取消对它的引用在C++的一面呢? – cdhowie 2013-02-08 22:49:58
我不能控制C++代码,不幸的是... – 2013-02-08 23:07:23
不同的托管签名可以使用匿名medhod来完成,它将完成marrshaling。至于按值返回,您可以在内部声明一个具有固定大小字节数组的结构,并在非托管回调签名中使用该结构。然后在你的ananimus方法中,只需使用Marshall.Copy从存储在包装器中的指针填充该数组。你需要知道你的本地对象的大小(sizeof?)。 – user629926 2013-02-09 06:02:57