2012-07-25 18 views
5

Mam nadzieję, że pytanie jest jasne, ale pad to dla jasności:Jak narazić enum zdefiniowane w bibliotece COM poprzez współdziałanie jako typ zwracanej aC# funkcji

Mam dll VB6, który definiuje enum że Odwołuję się w moim C# dll. C# dll definiuje CCW w prawidłowy sposób za pomocą interfejsu idispatch, który deklaruje funkcję, której typem powrotu jest enum.

Po uruchomieniu regresji pojawia się ostrzeżenie, że wyliczenie nie jest widoczne w COM, więc funkcja nie jest eksportowana. Ponieważ jest on zdefiniowany w mojej bibliotece VB6, pomyślałbym, że jest już widoczny w COM, ponieważ jest zdefiniowany w bibliotece dll COM.

Zdaję sobie sprawę, że mogę przestać się bawić i używać int do przekazywania enum i po prostu rzucać oba końce, ale to jest właściwe frustrujące i chciałbym wiedzieć, czy istnieje sposób.

Zgodnie z wnioskiem o to niektóre przykładowy kod:

dll VB6 definiuje enum

Public Enum myEnum 
    first = 0 
    second = 1 
End Enum 

To jest importowane poprzez współdziałanie w języku C# i jeśli przeglądać metadane wygląda coś takiego

[Guid("EnumGUID")] 
public enum myEnum 
{ 
    first = 0, 
    second = 1   
} 

Następnie interfejs CCW jest zdefiniowany

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

Regasm skarży się, że myEum nie jest widoczny. Muszę się z tym zgodzić, ponieważ widok metadanych nie ma widocznego atrybutu. O dziwo jeśli używam innych typów definiuje w bibliotece DLL VB argumenty funkcji nie otrzymuję skarg, to po prostu wydaje się być enum i domyślam się, że to dlatego, że faktycznie wystawiam interopped implementację wyliczenia VB6, a nie rzeczywiste wyliczenie.

Więc myślę, że rozumiem problem, chciałbym wiedzieć, czy istnieje sposób, aby to działało przy użyciu wyliczeń, które nie wymagają hakowania pośredniego lub generowanego automatycznie kodu.

+0

Czy dll VB6 jest dll COM? Pokaż nam kod, aby zrozumieć problem. –

Odpowiedz

2

Wygląda na to, że rozwiązaniem jest ustawienie właściwości "Embed Interop Types" na False for zaimportowany zestaw COM w projekcie C#.

Aby to sprawdzić stworzyłem dll VB COM jako StackOverflow.ExampleCom z następującego kodu w nim

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 

Potem stworzył projekt klasy C# i importowane tej biblioteki StackOverflow COM. Poniższy kod w C# tworzy następnie obiekt COM, który ponownie eksponuje wyliczony typ zdefiniowany w kodzie VB, tworząc taką samą sytuację opisaną przez 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; } } 
    } 
} 

Jeśli budujemy ten następnie spróbuj utworzyć TypeLib z tego zgromadzenia z wykorzystaniem regasm /tlb:EnumDemo.tlb bin\Debug\EnumDemo.dll potem dostać ostrzeżenie o wykorzystaniu typów widoczne wartości non-COM.Jednak gdy odniesienie do biblioteki dll VB COM ma "Emop typu interop" ustawioną na false, ostrzeżenie znika, a sprawdzenie wygenerowanego typelib za pomocą OleView pokazuje, że typ jest używany, a importlib został dodany w odniesieniu do oryginalnej biblioteki 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); 
    }; 
    ... 
+0

Doskonała robota. Naprawdę nie chcę wracać do kłopotów z wysyłaniem plików interop, ponieważ tworzy to różnego rodzaju inne problemy, które minęły, gdy zaczęliśmy osadzać typy interopów. Sądzę więc, że najprawdopodobniej będę musiał uciekać się do wyrzucania wyliczeń do ich odpowiedniego typu, zanim zwrócą je i zajmą się tym w kliencie. – Akuma

1

Masz rację. Problem jest po zaimportowaniu wyliczeń do kodu, co pozwala na użycie wyliczeń wewnątrz kodu - wewnątrz zespołu. Nie można ich użyć bezpośrednio. Musisz zdefiniować wyliczenia w .NET i uczynić je ComVisible. Zostaną ujawnione jako EnumType_myEnum zamiast tylko myEnum (patrz this)

+0

Jest to coś, co można zrobić za pomocą C++/MIDL. Za pomocą importlib można przenieść typy z jednej biblioteki do własnej biblioteki typów. Następnie możesz zadeklarować metody, które zwracają typy enum z drugiej biblioteki i wszystko działa. Jednak nie widzę żadnych klas atrybutów InteropServices, które wyglądają tak, jakby pomogły w deklarowaniu, że typ pochodził z innego typelibu. Dobra łamigłówka. – patthoyts