1

我正在尝试为原生 C++ 插件标准编写托管互操作库。这个本机 C++ 库使用与 COM 兼容的接口设计。但是,它不会做任何类注册的事情。与 COM 一样,所有接口都派生自 IUnknown(称为 FUnknown,但无论如何都是相同的 3 个方法)。

我编写了一个简单的 C++ 控制台应用程序,它加载我的托管测试插件并通过导出的方法检索初始(根)接口(对象工厂模式 - 很像 com)。我使用第 3 方 DllExport 代码属性实现 - 这似乎工作正常。C++ 测试应用使用 LoadLibrary/GetProcAddress 并成功检索对接口的引用。我可以在我的托管导出函数中设置一个断点,它会按预期命中。

然后 C++ 测试应用程序在 IUnknown(部分)接口上调用 AddRef 并返回 2 - 正如预期的那样。请注意,我的托管接口定义(对应部分)不是从 IUnknown 派生的 - 或包含这些方法。我想说这意味着托管编组魔法已经介入并提供了CCW。

然后 C++ 测试应用程序在工厂接口上调用一个简单的方法 - 一个只返回一个 int32 的方法 - 并且也到达托管实现(断点被命中),但是当该方法返回时,它会抛出一个 AccessViolationException - 在托管的某处 -无管理的过渡。

class IPluginFactory : public FUnknown
{
public:
    // removed other methods before and after this one

    virtual int32 PLUGIN_API countClasses () = 0;       
};

int32 是一个#define 并且 PLUGIN_API 被定义为 __stdcall - 据我所知,它与 COM 兼容。

我定义的该接口的托管表示如下:

[ComImport]
[Guid("same guid as in C++ file")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPluginFactory
{
    [return: MarshalAs(UnmanagedType.I4)]
    Int32 CountClasses();
}

此方法的托管实现仅返回一个硬编码数字 (1)。

我已经尝试了很多事情(太多了,我什至都记不清了),目前不知道如何解决这个问题,或者问题可能是什么。

任何帮助深表感谢。谢谢!

编辑:请求有关 FUnknown 的详细信息:

class FUnknown
{
public:
    virtual tresult PLUGIN_API queryInterface (const TUID iid, void** obj) = 0;
    virtual uint32 PLUGIN_API addRef () = 0;
    virtual uint32 PLUGIN_API release () = 0;
};
4

1 回答 1

1

我们看不到 FUnknown 的样子。它必须与 IUnknown 相同才能允许互操作工作。CLR 将自动调用 AddRef、Release 和 QueryInterface。FUnknown 中恰好有三个方法非常重要,如果 FUnknown 或多或少,那么当您的 C# 代码调用 CountClasses() 时,您最终会调用完全错误的方法。确实是触发 AVE 的好方法。

我们可以看到的一个问题是 CountClasses 与 COM 不兼容,方法必须返回一个 Int32,即 HRESULT。错误代码(非零值)会自动触发 C# 程序中的异常。支持不兼容的方法签名,您必须使用属性。像这样:

[PreserveSig]
int CountClasses();

否则,这个错误不足以解释 AVE。接口不匹配是您更可能的克星。在这种情况下,您需要一个 C++/CLI 包装器。

于 2013-10-19T12:55:49.657 回答