2013-02-08 70 views
1

之前,我有这样的代码在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(); 
} 

编组人员是否足够聪明以取消引用指针?

+0

是否有令人信服的理由,你不能有回调返回一个指针,并取消对它的引用在C++的一面呢? – cdhowie 2013-02-08 22:49:58

+0

我不能控制C++代码,不幸的是... – 2013-02-08 23:07:23

+0

不同的托管签名可以使用匿名medhod来完成,它将完成marrshaling。至于按值返回,您可以在内部声明一个具有固定大小字节数组的结构,并在非托管回调签名中使用该结构。然后在你的ananimus方法中,只需使用Marshall.Copy从存储在包装器中的指针填充该数组。你需要知道你的本地对象的大小(sizeof?)。 – user629926 2013-02-09 06:02:57

回答

1

谢谢大家的意见

看起来自定义封送拆收器是要走的路!

我做了一个简单的测试用例,一切正常。它按预期工作。 这里是如果你有兴趣的封送:

public class MyCustomMarshaler : ICustomMarshaler 
{ 
    public static ICustomMarshaler GetInstance(String cookie) 
    { 
     return new MyCustomMarshaler(); 
    } 
    public IntPtr MarshalManagedToNative(Object ManagedObj) 
    { 
     MyClassWrapper val = ManagedObj as MyClassWrapper; 
     return val.ptrToNativeObj; 
    } 
    ... 
} 

[return: MarshalAs(UnmanagedType.CustomMarshaler,MarshalType = "MyCustomMarshaler")] 
public delegate MyClassWrapper CallbackDotNet(); 

有了这个封送时,C++调用C#回调函数MarshalManagedToNative上被调用的是C#回调回报,这使得转换的C#的引用(MyClassWrapper)到一个指向C++类MyClass的指针。

这似乎足够了,然后P/Invoke将负责将此MyClass *解引用到MyClass值。

这是并不难,因为我以为......