C#COM可见.Net程序集与旧版C ++ COM DLL的结构

时间:2012-06-28 15:50:43

标签: .net com interop com-interop

我们有一个遗留的C ++ COM DLL,用于定义IDL中的结构 IDL的简化版包含:

typedef struct 
{
    int num;
} LegacyStruct;

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

我们现在需要定义一个实现ILegacyInterface的.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#程序集类。

编译时,会显示以下警告:
类型库导出器警告处理'CSClass.GetStruct(pVal)'。警告:非COM可见值类型'LegacyStruct'正在从当前正在导出的类型或其基本类型之一中引用。

由于LegacyStruct是非COM可见的,因此生成的程序集的.tlb没有暴露GetStruct()方法(即,使用oleview查看时)。
显然C ++ COM客户端不编译:
错误C2039:'GetStruct':不是'CSClass'的成员

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

2 个答案:

答案 0 :(得分:3)

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

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

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

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

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

答案 1 :(得分:1)

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

我一般发现.Net项目自动导入TLB的方式限制太多。解决此问题的一种方法是使用所有适当的ComInterface,Guid和CoClass属性在C#文件中重新声明IDL内容。

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