将字符串从非托管代码传递到托管代码

本文关键字:托管代码 非托管代码 字符串 | 更新日期: 2023-09-27 18:04:25

我有一个问题,从非托管代码传递字符串到托管。在我的非托管类(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方式