如何通过interop公开COM库中定义的枚举作为ac#函数的返回类型

Aku*_*uma 5 c# enums com-interop

希望问题很清楚,但为了清楚起见,请将其填写清楚:

我有一个VB6 dll定义了我在C#dll中引用的枚举.C#dll以正确的方式定义CCW,其中idispatch接口声明了一个函数,其返回类型是枚举.

运行regasm时,我收到一个警告,表明枚举不是COM可见,因此不会导出该函数.因为它是在我的VB6库中定义的,所以我认为它已经是COM可见的,因为它是在COM dll中定义的.

我意识到我可以停止搞乱并使用一个int传递枚举,只是做任何一个结束,但它是适当的令人沮丧,我想知道一种方式是否存在.

根据要求,这里有一些示例代码:

VB6 dll定义了一个枚举

Public Enum myEnum
    first = 0
    second = 1
End Enum
Run Code Online (Sandbox Code Playgroud)

这通过interop导入到C#中,如果您查看元数据,它看起来像这样

[Guid("EnumGUID")]
public enum myEnum
{
    first = 0,
    second = 1        
}
Run Code Online (Sandbox Code Playgroud)

然后定义CCW接口

[ComVisible(true)]
[Guid("InterfaceGuid")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyCCWInterface
{
    [DispId(1)]
    myEnum myFunction();
}
Run Code Online (Sandbox Code Playgroud)

Regasm抱怨myEnum不可见.我必须同意它,因为元数据视图没有com visible属性.奇怪的是,如果我在VB dll中使用其他类型定义函数的参数我没有抱怨,它似乎是枚举,我猜它是因为我实际上暴露了VB6枚举的交错实现而不是实际的枚举.

所以我想我理解这个问题,我想知道的是,如果有一种方法可以使用不涉及黑客攻击任何中间或自动生成的代码的枚举.

pat*_*yts 3

看来解决方案是将 C# 项目中导入的 COM 程序集的“Embed Interop Types”属性设置为 False。

为了测试这一点,我创建了一个 VB COM dll,其中StackOverflow.ExampleCom包含以下代码

Public Enum EThing
    eThingOne = 1
    eThingTwo = 2
End Enum
Private mThing As EThing
Private Sub Class_Initialize()
    mThing = eThingOne
End Sub
Public Property Let Thing(newVal As EThing)
    mThing = newVal
End Property
Public Property Get Thing() As EThing
    Thing = mThing
End Property
Run Code Online (Sandbox Code Playgroud)

然后我创建了一个 C# 类项目并导入了这个 StackOverflow COM 库。然后,以下 C# 代码创建一个 COM 对象,该对象重新公开 VB 代码中定义的枚举类型,创建与 OP 描述的相同情况。

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using StackOverflow;

namespace EnumDemo
{
    [ComVisible(true)]
    [Guid("c30d35fe-2c7f-448b-98be-bd9be567ce70")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IEnumDemo
    {
        [DispId(1)]
        EThing Thing
        {
            get;set;
        }
    }

    [ComVisible(true)]
    [Guid("af328c82-08e3-403e-a248-8c46e27b48f3")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("StackOverflow.EnumDemo")]
    public class EnumDemo
    {
        private EThing mThing = EThing.eThingOne;
        public EThing Thing { get { return mThing; } set { mThing = value; } }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我们构建它,然后尝试使用此程序集创建类型库,regasm /tlb:EnumDemo.tlb bin\Debug\EnumDemo.dll那么我会收到有关使用非 COM 可见值类型的警告。然而,一旦对 VB COM dll 的引用将“嵌入互操作类型”设置为 false,警告就会消失,并且使用 OleView 检查生成的类型库表明该类型正在被使用,并且importlib已被添加以引用原始 dll。

library EnumDemo
{
    // TLib :     // TLib :  : {D482D5CB-EE6C-455A-A28A-D26A5AC579D5}
    importlib("StackOverflow.dll");
    // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    ...
    interface IEnumDemo : IDispatch {
        [id(0x00000001), propget]
        HRESULT Thing([out, retval] EThing* pRetVal);
        [id(0x00000001), propput]
        HRESULT Thing([in] EThing pRetVal);
    };
    ...
Run Code Online (Sandbox Code Playgroud)