How to expose an enum defined in a COM library via interop as the return type of a c# function

c#, com-interop, enums

Solution

It looks like the solution is to set the "Embed Interop Types" property to False for the imported COM assembly in the C# project.

To test this I created a VB COM dll as `StackOverflow.ExampleCom` with the following code in it

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

Then I created a C# class project and imported this StackOverflow COM library. The following code in C# then creates a COM object that re-exposes the enumerated type defined in the VB code creating the same situation described by the 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; } }
    }
}

If we build this then try to create a typelib from this assembly using `regasm /tlb:EnumDemo.tlb bin\Debug\EnumDemo.dll` then I get a warning about the use of non-COM visible value types. However once the reference to the VB COM dll has the "Embed Interop Types" set false, the warning disappears and checking the generated typelib with OleView shows that the type is being used and `importlib` has been added to reference the original 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);
    };
    ...

Problem

Hopefully the question is clear but to pad it out for clarity: I have a VB6 dll that defines an enum that I am referencing in my C# dll. The C# dll defines a CCW in the correct way with an idispatch interface that declares a function who's return type is the enum. When running regasm I get a warning that the enum is not COM visible and so the function is not exported. Since it's defined in my VB6 library I would have thought it is already COM visible since it's defined in a COM dll. I realise I can stop messing about and use an int to pass the enum and just do casting either end but it's proper frustrating and I would like to know if a way exists. As requested here is some sample code: VB6 dll defines an enum ``` Public Enum myEnum first = 0 second = 1 End Enum ``` This gets imported through interop into the C# and if you view the metadata it looks something like this ``` [Guid("EnumGUID")] public enum myEnum { first = 0, second = 1 } ``` Then the CCW interface is defined ``` [ComVisible(true)] [Guid("InterfaceGuid")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IMyCCWInterface { [DispId(1)] myEnum myFunction(); } ``` Regasm complains that myEnum is not com visible. I have to agree with it since the metadata view doesn't have the com visible attribute. Strangely if I use other types defines in the VB dll for arguments of the function I get no complaints, it just appears to be the enum and I'm guessing it's because I'm actually exposing the interopped implementation of the VB6 enum and not the actual enum. So I think I understand the issue, what I would like to know is if there's a way to get this working using enums that doesn't involve hacking any intermediate or auto generated code.

Original source