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

标签 c# marshalling com-interop unmanaged managed

我在将字符串从非托管代码传递到托管代码时遇到问题。 在我的非托管类 (unmanagedClass.cpp) 中,我有一个指向托管代码函数的指针:

TESTCALLBACK_FUNCTION testCbFunc;

TESTCALLBACK_FUNCTION 接受一个字符串并且不返回任何内容:

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

非托管类继承自只有一个方法的 ITest 接口(interface):

    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);

要从非托管代码调用测试函数,我使用这个

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

但是当调用 managedClass.cs 中的测试方法时,我总是收到 null 字符串。 为什么会这样?

提前致谢!

最佳答案

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

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

    [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));

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

请注意,当您声明回调接口(interface)而不是委托(delegate)时,所有这些问题是如何消失的。 COM 方式。

关于c# - 将字符串从非托管代码传递到托管代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15480317/

相关文章:

c# - 使用 Image 类在 c# 中丢失图像质量(减少颜色数量)

c# - Nunit判断当前正在执行的测试用例

c# - 如何将一个 COM 类实例作为参数传递给 C# 中的另一个 COM 方法?

c# - newtonsoft jobject.Value<DateTime>() 不起作用

java - Spring 网络服务 : easy way to un-marshall a bean to XML client side?

xml - Golang marshal 嵌套 xml 标签

c# - 将嵌套结构从 C# 编码到 C++

c# - 错误 : Word 2013 VSTO Cannot Handle Image in Header Formatted Behind or In Front of Text

c# - 将 C++ 字符串/wchar_t* 转换为 C# 字符串?

c# - 在 XNA 中处理纹理加载和跨多个类访问的最佳方法?