我有一个问题,从非托管代码传递字符串到托管。在我的非托管类(unmanagedClass.cpp)我有一个指针从托管代码函数:
TESTCALLBACK_FUNCTION testCbFunc;
TESTCALLBACK_FUNCTION接受一个字符串,不返回任何值:
typedef void (*TESTCALLBACK_FUNCTION )(char* msg);
非托管类继承自只有一个方法的ITest接口:
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);
}
从非托管代码调用Test函数,我使用这个
(*testCbFunc)("Func Uragan33::Execute has been started!");
但是当managedClass.cs的测试方法被调用时,我总是收到null字符串。为什么会这样呢?
提前感谢!
调用约定不匹配。c++代码中的typedef用默认的调用约定(__cdecl)声明了一个函数指针。但是托管代码中委托的默认值是__stdcall。
您将需要一个属性来告诉pinvoke编组程序。让它看起来像这样:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TestDelegate(string info);
删除函数声明中的[MarshalAs]。修复c++代码中的类型定义可能更好,如果可以的话,使所有内容保持一致是首选的解决方案:
typedef void (__stdcall * TESTCALLBACK_FUNCTION )(char* msg);
无关,这是一个你需要修复的错误:
unmanaged.put_TestCallBack(new TestDelegate(this.Test));
您创建的委托对象对垃圾收集器不可见。它将在下一次GC中收集,当本机代码进行回调时,您的代码将崩溃。您必须将委托对象存储在某个地方,以便GC始终看到引用。或者作为类中的字段,附加要求类对象需要保持足够长的存活时间,或者作为静态变量。
请注意,当您声明回调接口而不是委托时,所有这些问题都消失了。COM方式