1

我们有一个传统的 C++ COM DLL,它在 IDL 中定义了一个结构。
IDL 的简化版本包含:

typedef struct 
{
    int num;
} LegacyStruct;

interface ILegacyInterface : IUnknown
{
    HRESULT GetStruct( [in,out] LegacyStruct* pVal );
}

我们现在需要定义一个实现 ILGacyInterface 的 .Net C# COM 可见程序集。

在 C# 项目中,我们添加对旧 COM DLL 的引用并定义实现此接口的类:

[ComVisible( true )]
public class CSClass : ILegacyInterface
{
    public void GetStruct( ref LegacyStruct pVal )
    {
        ....
    }
}

目标是在 C++ COM 客户端程序中使用这个 COM 公开的 C# 程序集类。该程序应该能够使用旧版 COM DLL 和实现 ILegacyInterface 的新 C# 程序集类。

编译时,显示以下警告:
Type library exporter warning processing 'CSClass.GetStruct(pVal)'。警告:非 COM 可见值类型“LegacyStruct”被当前导出的类型或其基类型之一引用。

由于 LegacyStruct 是非 COM 可见的,因此生成的程序集的 .tlb 没有公开 GetStruct() 方法(即,当使用 oleview 查看时)。
显然 C++ COM 客户端无法编译:
错误 C2039: 'GetStruct' : is not a member of 'CSClass'

有没有办法确保在旧版 C++ COM DLL 中定义的 LegacyStruct 在 C# COM 可见 .Net 程序集的方法中使用时正确公开?

4

2 回答 2

3

要解决此问题,需要以下 2 项:

  1. 旧版 COM IDL 必须包含正在定义的结构的 uuid。tcarvin 在上面提到了这一点。除了 uuid 之外,结构标记名称必须与结构名称相同。将标签留在外面是不够的,即即使 uuid 存在。这是新的结构定义:

    typedef [uuid(XXX-YYY-ZZZ-AAA-BBB)]
    结构 LegacyStruct
    {
    int num;
    } LegacyStruct;

    没有与结构关联的 uuid 将在生成的 .Net 程序集中包含其定义的副本以及自动生成的 uuid。就同​​名的 COM 而言,这显然是一个完全不同的结构。

  2. 将旧 COM DLL 添加为对 C# 项目的引用时,将“嵌入互操作类型”属性设置为 False 很重要。这也将确保遗留 COM DLL 的定义,例如结构等,不包含在生成的 .Net 程序集中。

于 2012-06-29T14:38:25.217 回答
1

我意识到这并没有严格回答您关于为什么会发生这种情况的问题,但是我遇到了与 tlbimp 类似的问题,并且我学会了避免它。

我通常发现 .Net 项目自动导入 TLB 的方式过于严格。解决此问题的一种方法是使用所有适当的 ComInterface、Guid 和 CoClass 属性在 C# 文件中重新声明 IDL 内容。

tlbimp+reflector 也是为这些声明生成骨架的好方法。如果您查看 tlbimp 的反编译结果,您可以看到您期望在 .Net 声明中缺少哪些属性,这可能有助于您弄清楚发生了什么。

于 2012-06-28T16:09:06.973 回答