【问题标题】:Returned managed object method not called from C++ in COM interop在 COM 互操作中未从 C++ 调用返回的托管对象方法
【发布时间】:2013-10-29 01:23:17
【问题描述】:

这是我的previous post 的后续跟进。阅读该帖子以了解上下文。请注意,它不是严格的 COM 互操作 - 但 C++ 接口与 COM 兼容。

我试图在 C# 中实现这个 C++ 接口

class IPluginFactory : public FUnknown
{
    virtual tresult PLUGIN_API createInstance (FIDString cid, FIDString iid, void** obj) = 0;
};

我的 C# 代码如下所示:

[ComImport]
[Guid(Interfaces.IPluginFactory)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPluginFactory
{
    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    Int32 CreateInstance([In] ref Guid classId, [In] ref Guid interfaceId, [MarshalAs(UnmanagedType.IUnknown), In, Out] ref object instance);
}

实现将一个新的对象实例分配给“instance”参数并返回 0 (S_OK)。我什至投射到预期的(托管)界面。

instance = (IPluginBase)new PluginBase();
return 0;

返回的对象由这个 C++ 接口表示:

class IPluginBase: public FUnknown
{
public:
    virtual tresult PLUGIN_API initialize (FUnknown* context) = 0;
    virtual tresult PLUGIN_API terminate () = 0;
};

在我的 C# 实现中看起来像这样:

[ComImport]
[Guid(Interfaces.IPluginBase)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPluginBase
{
    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    Int32 Initialize([MarshalAs(UnmanagedType.IUnknown), In] object context);

    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    Int32 Terminate();
}

在我编写的非托管 C++ 测试应用程序中,我可以成功调用 createInstance 并接收代码用作 IPluginBase* 的非空指针。

当我尝试在此 IPluginBase* 指针上调用“初始化”方法时,问题就出现了。它永远不会到达托管代码(没有命中断点 - 其他断点工作正常)并且返回代码是 0x80004003。看起来包装器在这里做了一些拦截......

我的问题是:CreateInstance 的托管表示的声明是否正确? 我在这里想念什么? (这应该是普通的互操作,不是吗?)

也欢迎对声明“样式”提出其他建议。 谢谢,马克。

编辑:问题似乎出在 createInstance 方法上。我无法获取 iid 参数要求的返回接口。

[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
Int32 CreateInstance([In] ref Guid classId, [In] ref Guid interfaceId, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1), In, Out] ref object instance);

我还尝试将 UnmanagedType.Interface 与 IidParameterIndex 结合使用,但两者都会导致 IUnknown 被封送回来。如果我重新查询 IPluginBase 接口,则 IPluginBase::initialize 方法有效(托管代码命中中的断点)。

【问题讨论】:

  • 那是 E_POINTER,“无效指针”。对你传递的参数不满意,不要传递 null。很难猜测“上下文”可能是什么。请联系此代码的作者以获得支持。
  • 为什么不能传递 NULL 作为参数值?我可以使用“AllowNull”属性吗? ;-) “上下文”是 IUnknown*。代码的作者是我——即 C++ 接口定义是我试图在 .NET 中与之互操作的第 3 方标准。

标签: c# .net interface com com-interop


【解决方案1】:

编辑:问题似乎出在 createInstance 方法上。我是 无法获取 iid 要求的返回接口 参数。

在这里指定 IidParameterIndex 没有帮助。 createInstance 的实现应如下所示:

public int createInstance(ref Guid classId, ref Guid riid, ref IntPtr instance)
{
    if (instance != IntPtr.Zero)
        return E_POINTER;

    // substitute your actual object creation code for CreateObject
    object obj = CreateObject(classId) 

    // return the correct interface
    IntPtr unk = Marshal.GetIUnknownForObject(obj);
    try
    {
        return Marshal.QueryInterface(unk, ref riid, out instance);
    }
    finally
    {
        Marshal.Release(unk);
    }
}

【讨论】:

  • 啊,开枪!有没有办法让这个对象作为返回(输出)类型工作?您的解决方案确实有效。谢谢!
  • 我不知道更好的方法,最近刚刚处理了similar problem
猜你喜欢
  • 2012-01-26
  • 1970-01-01
  • 2013-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多