2013-03-18 132 views
4

我有一个从非托管代码传递字符串到托管的问题。 在我的非托管类(unmanagedClass.cpp)我有一个指针从托管代码的功能:从非托管代码传递字符串到托管

TESTCALLBACK_FUNCTION testCbFunc; 

TESTCALLBACK_FUNCTION接受一个字符串,并没有返回值:从ITest接口

typedef void (*TESTCALLBACK_FUNCTION)(char* msg); 

非托管类inherites其中只有一种方法:

STDMETHOD(put_TestCallBack) (THIS_ 
        LPVOID FnAddress  
      ) PURE; 

在managedClass.cs中,我编写了此代码:

public class ManagedClass 
{ 
    ITest unmanaged = new unmanagedClass(); 
    public delegate void TestDelegate(string info); 
    ManagedClass() 
    { 
     unmanaged.put_TestCallBack(new TestDelegate(this.Test)); 
    } 
    void Test(string info) 
    { 
      MessageBox.Show(info); 
    } 
} 

[ComImport, Guid("<my guid here>")] 
public class unmanagedClass 
{ 
} 

[ComImport, System.Security.SuppressUnmanagedCodeSecurity, 
Guid("<my guid here>"), 
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface ITest 
{ 
    [PreserveSig] 
    int put_TestCallBack([MarshalAs(UnmanagedType.FunctionPtr), In] Capture.TestDelegate func); 

}

要调用从非托管代码测试FUNC我用这个

(*testCbFunc)("Func Uragan33::Execute has been started!"); 

但是,当从managedClass.cs测试方法被称为我总是收到字符串。 为什么会发生?

提前致谢!

回答

5

您在调用约定时不匹配。 C++代码中的typedef使用默认的调用约定(__cdecl)声明了一个函数指针。但托管代码中委托的默认值是__stdcall。

您将需要一个属性来告诉pinvoke编组否则。让它看起来像这样:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    public delegate void TestDelegate(string info); 

删除函数声明中的[MarshalAs]。固定在你的C++代码的类型定义可能是可取的,如果可以的话,显然让一切保持一致是首选的解决方案:

typedef void (__stdcall * TESTCALLBACK_FUNCTION)(char* msg); 

无关的,这你需要一个bug修复:

unmanaged.put_TestCallBack(new TestDelegate(this.Test)); 

您创建的委托对象对垃圾收集器不可见。如果将在下一个GC上收集,当本机代码进行回调时,您的代码将崩溃。您必须将委托对象存储在某处,以便GC始终可以看到参考。既可以作为类中的字段,也可以附加要求类对象需要保持足够长的时间或静态变量。

请注意,当您声明回调接口而不是委托时,所有这些问题都会消失。 COM方式。

+0

非常感谢你! – Alekstim 2013-03-19 08:27:43

相关问题