Interop COM(-isch)接口封送会在简单调用时导致AccessViotlationException

时间:2013-10-19 10:30:54

标签: c# com interop marshalling

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

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

然后C ++测试应用程序在IUnknown(部分)接口上调用AddRef,它返回2 - 正如预期的那样。请注意,我的托管接口定义(counter-part)不是从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)。

我尝试过很多东西(很多东西,我甚至都记不起来),目前我不知道如何解决这个问题,或者问题可能是什么。

非常感谢任何帮助。感谢名单!

编辑:要求获得有关未知的详细信息:

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

1 个答案:

答案 0 :(得分:1)

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

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

[PreserveSig]
int CountClasses();

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