2012-07-25 24 views
5

Hy vọng rằng câu hỏi là rõ ràng nhưng để pad nó ra cho rõ ràng:Làm thế nào để lộ một enum định nghĩa trong một thư viện COM qua interop như kiểu trả về của aC# chức năng

Tôi có một dll VB6 định nghĩa một enum mà Tôi đang tham khảo trong dll C# của tôi. C# dll định nghĩa một CCW theo cách chính xác với một giao diện idispatch khai báo một hàm trả về kiểu là enum.

Khi chạy regasm tôi nhận được cảnh báo rằng enum không hiển thị COM và do đó chức năng không được xuất. Kể từ khi nó được định nghĩa trong thư viện VB6 của tôi tôi đã có thể nghĩ rằng nó đã được COM có thể nhìn thấy kể từ khi nó được định nghĩa trong một dll COM.

Tôi nhận ra mình có thể ngừng làm phiền và sử dụng int để vượt qua enum và chỉ thực hiện kết thúc, nhưng nó thật sự bực mình và tôi muốn biết liệu có tồn tại hay không.

Theo yêu cầu ở đây là một số mẫu mã:

VB6 dll định nghĩa một enum

Public Enum myEnum 
    first = 0 
    second = 1 
End Enum 

này được nhập khẩu qua interop vào C# và nếu bạn xem các siêu dữ liệu nó trông giống như

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

Sau đó, giao diện CCW được xác định

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

Regasm phàn nàn rằng myEnum không hiển thị. Tôi phải đồng ý với nó vì chế độ xem siêu dữ liệu không có thuộc tính hiển thị com. Kỳ lạ nếu tôi sử dụng các loại khác định nghĩa trong VB dll cho các đối số của chức năng tôi nhận được không có khiếu nại, nó chỉ xuất hiện để được enum và tôi đoán đó là bởi vì tôi thực sự phơi bày việc thực hiện interopped của VB6 enum và không phải là thực tế enum. Vì vậy, tôi nghĩ rằng tôi hiểu vấn đề, những gì tôi muốn biết là nếu có một cách để có được điều này làm việc bằng cách sử dụng enums mà không liên quan đến hack bất kỳ mã trung gian hoặc tự động tạo ra.

+0

VB6 có phải là dll COM không? Vui lòng cho chúng tôi biết một số mã để hiểu vấn đề. –

Trả lời

2

Có vẻ như giải pháp là đặt thuộc tính "Các loại nhúng Interop" thành False cho COM lắp ráp trong dự án C#.

Để kiểm tra này, tôi đã tạo ra một dll VB COM như StackOverflow.ExampleCom với đoạn mã sau vào nó

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 

Sau đó, tôi tạo ra một dự án C# lớp và nhập thư viện StackOverflow COM này. Đoạn mã sau trong C# sau đó tạo một đối tượng COM để hiển thị lại kiểu liệt kê được xác định trong mã VB tạo ra tình huống tương tự được mô tả bởi 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; } } 
    } 
} 

Nếu chúng ta xây dựng này sau đó cố gắng để tạo ra một typelib từ lắp ráp này sử dụng regasm /tlb:EnumDemo.tlb bin\Debug\EnumDemo.dll sau đó tôi nhận được một cảnh báo về việc sử dụng phi COM kiểu giá trị có thể nhìn thấy.Tuy nhiên một khi tham chiếu đến VB COM dll có "Embed Interop Types" đặt sai, cảnh báo biến mất và kiểm tra typelib được tạo với OleView cho thấy kiểu đang được sử dụng và importlib đã được thêm vào để tham khảo dll gốc.

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

Công việc tuyệt vời. Tôi thực sự không muốn quay trở lại những rắc rối của các tập tin interop vận chuyển vì điều này tạo ra tất cả các loại vấn đề khác mà đã biến mất khi chúng tôi bắt đầu nhúng các loại interop. Tôi đoán do đó tôi có thể sẽ phải nghỉ mát để đúc enums để loại thích hợp của họ trước khi trở về và đối phó với nó trong khách hàng. – Akuma

1

Bạn nói đúng. Problem là khi bạn nhập enums vào mã của bạn, cho phép bạn sử dụng những enums trong mã của bạn - bên trong hội đồng của bạn. Bạn sẽ không thể sử dụng chúng trực tiếp. Bạn cần phải xác định các liệt kê trong .NET và làm cho chúng ComVisible.They sẽ được hiển thị dưới dạng EnumType_myEnum thay vì chỉ myEnum (xem this)

+0

Đây là một cái gì đó có thể được thực hiện bằng cách sử dụng C++/MIDL. Bạn sử dụng importlib để đưa các kiểu từ một thư viện vào thư viện kiểu của riêng bạn. Sau đó, bạn có thể khai báo các phương thức trả về các kiểu enum từ thư viện khác và mọi thứ hoạt động. Tuy nhiên tôi không thể thấy bất kỳ lớp thuộc tính InteropServices nào trông giống như chúng sẽ giúp tuyên bố rằng một kiểu đến từ một typelib khác. Một câu đố hay. – patthoyts