2017-04-14 7 views
3

Ich erstelle eine COM-Schnittstelle, die For Each in Visual Basic-Skripts und IEnumVariant in C++ verwenden soll. Der Fehler ist, dass ich nicht möchte, dass die C++ - Client-Anwendung mscorlib.tlb importieren muss.C# COM-Enumerable ohne Verweis auf MSCORLIB

Bisher meine Schnittstelle ist:

[ComVisible(true)] 
[InterfaceType(ComInterfaceType.InterfaceIsDual)] 
public interface ICars : System.Runtime.InteropServices.ComTypes.IEnumVARIANT 
{ 
    int Count { get; } 
} 

[ComVisible(true)] 
[ClassInterface(ClassInterfaceType.None)] 
public class Cars : ICars 
{ 
    int ICars.Count => throw new NotImplementedException(); 

    int IEnumVARIANT.Next(int celt, object[] rgVar, IntPtr pceltFetched) 
    { 
     throw new NotImplementedException(); 
    } 

    int IEnumVARIANT.Skip(int celt) 
    { 
     throw new NotImplementedException(); 
    } 

    int IEnumVARIANT.Reset() 
    { 
     throw new NotImplementedException(); 
    } 

    IEnumVARIANT IEnumVARIANT.Clone() 
    { 
     throw new NotImplementedException(); 
    } 
} 

TlbExp diesen Code ausspuckt:

// Generated .IDL file (by the OLE/COM Object Viewer) 
// 
// typelib filename: carsIEnumerator.tlb 

[ 
    uuid(3BBCEAA2-9498-48BF-8053-1CEFB3C1C86F), 
    version(1.0), 
    custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "ClassLibraryIEnumerator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null") 

] 
library ClassLibraryIEnumerator 
{ 
    // TLib :  // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D} 
importlib("mscorlib.tlb"); 
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046} 
importlib("stdole2.tlb"); 

// Forward declare all types defined in this typelib 
interface ICars; 

[ 
    odl, 
    uuid(ABD2A9E4-D5C5-3ED9-88AF-4C310BD5792D), 
    version(1.0), 
    dual, 
    oleautomation, 
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ClassLibraryIEnumerator.ICars")  

] 
interface ICars : IDispatch { 
    [id(0x60020000), propget] 
    HRESULT Count([out, retval] long* pRetVal); 
}; 

wie kann ich das verhindern?

Auch wenn ich nur meine benutzerdefinierte Schnittstelle und eine einzelne Klasse (ohne Verwendung von .NET-Typ) haben, ist die Referenz immer noch da.

Antwort

2

Die IEnumVARIANT Typ-Deklaration muss von irgendwo kommen. Es ist kein Standardtyp wie int, den jeder Compiler kennt. Wenn Sie die IDL selbst erstellen, verwenden Sie #import "oaidl.idl", um die Definition einzuschließen. Aber das kann in .NET nicht funktionieren, da der Typbibliotheksexport keine IDL verwendet. So kommt es von einem Ort, den der Exporteur kennt, mscorlib.tlb

Die Problemumgehung ist, einfach die Schnittstellendeklaration in Ihren eigenen Code zu setzen, anstatt den in mscorlib zu verwenden. Kopieren/Einfügen ist es aus dem Reference Source oder dies:

[Guid("00020404-0000-0000-C000-000000000046")] 
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] 
[ComImport] 
public interface IEnumVARIANT 
{ 
    [PreserveSig] 
    int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0), Out] object[] rgVar, IntPtr pceltFetched); 

    [PreserveSig] 
    int Skip(int celt); 

    [PreserveSig] 
    int Reset(); 

    IEnumVARIANT Clone(); 
} 

Und verwenden YourNamespace.IEnumVARIANT in Ihrer iCars Erklärung.


Deklarieren Sie Ihren eigenen enumerator Interface-Typen ist eine Lösung, als auch, hat IEnumVARIANT keine Preise gewinnen. Sie können die wackeligen Methoden, die niemand benutzt, fallen lassen und sie typsicher machen. Eine akzeptable Alternative, wenn Sie den Clientcode ebenfalls kontrollieren oder foreach in einer Skriptsprache nicht glücklich halten müssen. Bedenken Sie:

[ComVisible(true)] 
public interface ICarEnumerator { 
    ICar Next(); 
} 

Und ICarEnumerator GetCars() in der iCars Schnittstelle.


Zu guter Letzt, ziehen Sie in Erwägung, einen Iterator überhaupt nicht zu implementieren. macht es wie ein Array in dem Client-Code anschauen:

[ComVisible(true)] 
public interface ICars 
{ 
    int Count { get; } 
    ICar this[int index] { get; } 
} 
+0

Große Antwort, wie immer. Ich ging zu der zweiten Option, die Sie vorgeschlagen haben (d. H. Count + this [int index]). Wenn ich jedoch den ICarEnumerator implementiere, sollte ich dann in der Lage sein, ihn sowohl in C++ als auch in VBscript zu verwenden? – peval27

+0

Ja. Ein VBScript-Programmierer kann jedoch erwarten, dass 'For Each' funktioniert. –

+0

Ich habe den 'ICarEnumerator' implementiert und wenn ich 'For Each car in cars.GetCars()' 'VBscript sagt: Objekt unterstützt diese Eigenschaft oder Methode nicht. Irgendeine Idee? – peval27

Verwandte Themen