我在将字符串从非托管代码传递到托管时遇到问题。 在我的非托管类( 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 func,我使用此
(*testCbFunc)("Func Uragan33::Execute has been started!");
但是当调用managedClass.cs的Test方法时,我总是收到 null 字符串。 为什么会这样?
提前感谢!
答案 0 :(得分:5)
您在调用约定上存在不匹配。 C ++代码中的typedef声明了一个带有默认调用约定的函数指针,即__cdecl。但是托管代码中委托的默认值是__stdcall。
否则你将需要一个属性告诉pinvoke marshaller。看起来像这样:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TestDelegate(string info);
将[MarshalAs]放入函数声明中。在您的C ++代码中修复typedef可能更为可取,如果可以的话,明确地使所有内容保持一致是首选解决方案:
typedef void (__stdcall * TESTCALLBACK_FUNCTION )(char* msg);
无关,这是一个你需要解决的错误:
unmanaged.put_TestCallBack(new TestDelegate(this.Test));
您创建的委托对象对垃圾收集器不可见。如果将在下一个GC上收集,则当本机代码进行回调时,您的代码将崩溃。您必须将委托对象存储在某处,以便GC始终看到引用。无论是作为类中的字段,还是要求类对象需要保持足够长的时间,还是静态变量。
注意当您声明回调接口而不是委托时,所有这些问题都会消失。 COM方式。