Laden...

.NET Assembly aus Excel 2000 VBA heraus aufrufen

Erstellt von marco.b vor 16 Jahren Letzter Beitrag vor 16 Jahren 4.882 Views
M
marco.b Themenstarter:in
303 Beiträge seit 2006
vor 16 Jahren
.NET Assembly aus Excel 2000 VBA heraus aufrufen

Hi,

für einen Kunden muss ich eine .NET Bibliothek in Excel VBA einbinden. Anforderung war, dass die Assembly in VB.NET geschrieben wird. Ich hoffe es ist ok, wenn ich die Frage dennoch in diesem Forum stelle.
Ich muss dazu sagen, dass es das erste mal ist, dass ich eine COM-Komponente für Office erstelle.

Ich habe eine Klassenbibliothek erstellt und folgende Klasse eingefügt. Ich dachte folgende Angaben genügen, um sie COM-fähig zu machen:


Imports System.Runtime.InteropServices

<Assembly: System.Reflection.AssemblyKeyFileAttribute( _
           "d:\Strongkey.snk" _
           )> 
<ComClass(OfficeArchiveService.ClassId, OfficeArchiveService.InterfaceId, OfficeArchiveService.EventsId)> _
Public Class OfficeArchiveService
#Region "COM GUIDs"
    ' These  GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class.
    Public Const ClassId As String = "6DB79AF2-F661-44AC-8458-62B06BFDD9E4"
    Public Const InterfaceId As String = "EDED909C-9271-4670-BA32-109AE917B1D7"
    Public Const EventsId As String = "17C731B8-CE61-4B5F-B114-10F3E46153AC"
#End Region
    Public Sub New()

    End Sub

    (... Methoden ...)

Dann habe ich mit dem Tool RegAsm.exe die Assembly registriert und eine TLB-Bibliothek daraus erstellt.
In Excel 2000 VBA habe ich den Verweis auf meine Bibliothek hinzugefügt.
Mein Problem ist nun, dass ich nicht auf meinen obigen Typen zugreifen kann. In der Objektkatalog-Ansicht von VBA wird von meiner Bibliothek lediglich der Typ "<Global>" bereitgestellt, zumindest steht das in der dortigen Liste.

Was mache ich falsch?

M
marco.b Themenstarter:in
303 Beiträge seit 2006
vor 16 Jahren

Habe noch etwas herausgefunden:

Wenn ich im VBA Objektkatalog im Kontextmenü auf "Verborgene Elemente anzeigen" klicke, wird mein Typ ausgegraut und mit führendem Unterstrich dargestellt. Was hat das zu bedeuten?

3.728 Beiträge seit 2005
vor 16 Jahren
COM-Wrapper

Das Beispiel sieht seltsam aus. Ich würde das eher so machen:


Imports System.Runtime.InteropServices

' COM-Schnittstelle

<ComVisible(True)> _
<GuidAttribute("FAC3E52F-A480-48D9-7D89-13691EC3202D")> _
Public Interface IApplicationComWrapper

    <DispId(1)> _
    Sub DoSomething(ByVal testParam As String)

End Interface

' Wrapper-Klasse

<ProgId("MyApplication.ApplicationComWrapper")> _
<ComVisible(True)> _
<GuidAttribute("DAC3E52F-C480-48D9-8D89-23691EA32029")> _
<ClassInterfaceAttribute(ClassInterfaceType.AutoDispatch)> _
Public Class ApplicationComWrapper
    Implements IApplicationComWrapper

    Public Sub DoSomething(ByVal testParam As String) Implements IApplicationComWrapper.DoSomething
        '
        ' Hier eigentlichen Funktionscode einfügen!
        '
    End Sub

End Class

Indem Du eine explizite COM-Schnittstelle veröffentlichst, wird VBA auch Intellisense für Methoden und Eigenschaften anbieten. Durch die aktivierte Dispatch-Klassenschnittstelle kann die COM-Komponente auch von VBScript oder Javascript aus aufgerufen werden.

In Excel-VBA wird die Komponente folgendermaßen verwendet:


' Objektvariable anlegen (Schnittstelle verwenden und NICHT die Klasse!)
Dim objTest As MyApplication.IApplicationComWrapper

' Instanz erzeugen (Erst hier die Klasse angeben!)
Set objTest=new MyApplication.ApplicationComWrapper

' Funktion aufrufen
objTest.DoSomething "Hallo Welt"

1.274 Beiträge seit 2005
vor 16 Jahren

Hallo Rainbird,

warum das Interface angeben und nicht die Klasse, gibt es dafür einen technischen Grund oder ist es nur für ein einfacheres austauschen der Komponenten gedacht?

Lg
LastGentleman

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

M
marco.b Themenstarter:in
303 Beiträge seit 2006
vor 16 Jahren

Hi Rainbird,

danke für deine Antwort, die Klassen sind jetzt sichtbar und IntelliSense funktioniert in VB6. Wenn ich nun den den VBA Excel Code ausführen will, gibt es bei der Zeile mit dem Methodenaufruf aus meiner Klasse die Fehlermeldung "The format of the file 'TestDLL.dll' is invalid".
Kennst du diese Meldung?

3.728 Beiträge seit 2005
vor 16 Jahren
Intellisense

Original von LastGentleman
warum das Interface angeben und nicht die Klasse, gibt es dafür einen technischen Grund oder ist es nur für ein einfacheres austauschen der Komponenten gedacht?

Intellisense funktioniert in dieser Konfiguration nur mit der Schnittstelle, aber nicht mit der Klasse. Ich habe das dazu geschrieben, dass mir hinterher niemand kommt und sagt "In VB sehe ich gar keine Funktionen".

Wenn ClassInterfaceType nicht auf AutoDual eingestellt ist, wird die Klassenschnittstelle nicht für COM veröffentlicht. AutoDual wird von Microsoft aber ausdrücklich nicht empfohlen, das es zu Versionierungsproblemen führen kann. Deshalb muss ClassInterfaceType auf None oder AutoDispatch (Wenn man Unterstützung für Späte Bindung haben möchte; VBScript kann z.B. NUR über Dispatch zugreifen) eingestellt werden.
Da die Klassenschnittstelle nicht veröffentlicht wird, funktioniert für die Klasse dann in VBA/VB auch keine Intellisense (da ja keine Metadaten der Klasse verfügbar sind). Funktionieren würde ein Zugriff aber trotzdem. Aber wer will schon ohne Intellisense arbeiten?
Also werden für die Objektveriablen immer die Schnittstellen verwendet und nicht die Klassen.

3.728 Beiträge seit 2005
vor 16 Jahren

Original von marco.b
Wenn ich nun den den VBA Excel Code ausführen will, gibt es bei der Zeile mit dem Methodenaufruf aus meiner Klasse die Fehlermeldung "The format of the file 'TestDLL.dll' is invalid".

Hast Du die TLB-Datei im Excel-VBA-Projekt als Verweis eingefügt?

Verwendest Du komplexe Typen, eigene Klassen oder Arrays als Parameter oder Rückgabe-Werte einer Funktion?
Du darfst nur Typen verwenden, für die es in der COM-Welt eine Entsprechung gibt. Du kannst z.B. kein ADO.NET DataSet an eine COM-Anwendung zurückgeben, da es in der COM-Welt keine DataSets gibt.

COM unterstützt auch keine Überladungen und auch keine parametrisierten Konstruktoren. Auf deratige Sachen musst Du komplett verzeichten, wenn Du Klassen für COM veröffentlichst.

Hast Du verschiedene Sprachversionen (Englisches Excel auf Deutschem Windows, oder etwas ähnliches)?

Hast Du es schonmal auf einem anderen PC ausprobiert?

Ist SP1 für Visual Studio 2005 installiert?

M
marco.b Themenstarter:in
303 Beiträge seit 2006
vor 16 Jahren

Hi Rainbird,

nein das SP1 ist nicht installiert, nicht hier im Geschäft. Da wir im Geschäft ansonsten eher Java/PHP entwickeln, haben wir uns fürs Prototyping der Bibliothek für VB.NET 2005 Express entschieden, und meine private Visual Studio Pro will ich nicht unbedingt verwenden. Kann es vielleicht an VB Express liegen?

3.728 Beiträge seit 2005
vor 16 Jahren
Visual Studio

Ich hatte daheim bis vor kurzem auch nur Express und nie derartige Probleme. Deshalb denke ich nicht, dass es an der Edition liegt.

Es gab aber mal einen Bug in Visual Studio, welcher beim kompilieren COM-Wrapper erzeugt hat, die unter Office (also auch Excel) nicht aufrufbar waren. Dafür gab es einen Patch. Im SP1 sollte dieser Patch aber enthalten sein.

Irgendjemand hatte auch mal den Link zu einem einzelnen Patch hier im Forum gepostet, aber ich hab den Beitrag auf die Schnelle nicht gefunden.

M
marco.b Themenstarter:in
303 Beiträge seit 2006
vor 16 Jahren

Es geht einfach nicht - ich könnte aus der Haut fahren.
Also das SP1 habe ich installiert, ich benutze bei Rückgabewerten und Parametern keine exotischen Typen (nur String und Integer), nur intern verwende ich eigene .NET Typen.

Vielleicht liegt es an der Art, wie ich die TLB verfügbar mache?

  1. Ich kompiliere eine Klassenbibliothek unter VB.NET Express 2005 SP1
  2. Mit der Kommandozeile erstelle ich eine TLB mit "regasm datei.dll /tlb:datei.tlb /Codebase"
    Mit sn.exe habe ich zuvor einen Strongname generiert und die Assembly damit signiert
  3. Mit "gacutil /i datei.dll" registriere ich die Assembly im Global Assembly Cache

In Excel 2000 füge ich dann den Verweis auf die TLB hinzu. Dann kommt beim Ausführen eben die Fehlermeldung "invalid format".

3.728 Beiträge seit 2005
vor 16 Jahren
Gac

Warum legst Du die Datei in den GAC?

Wenn die Datei im GAC liegt, müssen alle Abhängigkeiten ebenfalls dort liegen. Lass die Datei lieber als private Assembly im Programmverzeichnis. Da weißt Du immer wo sie ist und die COM-Clients finden sie auch, da in der Registry ja der komplette Pfad abgelegt wird. GAC ist also in den meisten Fällen böse.

Versuchs mal ohne GAC. Nicht vergssen, alle Versionen Deiner DLL wieder aus dem GAC rauszunehmen.

M
marco.b Themenstarter:in
303 Beiträge seit 2006
vor 16 Jahren

Mein Problem ist immernoch nicht gelöst, aber wir haben nun eine neuere Office-Version installiert und da funktioniert es auf Anhieb perfekt. Also das Problem tritt nur mit Office 2000 auf. Nunja, insofern hat sich die Sache erledigt.

Danke für deine Hilfe, Rainbird.

3.728 Beiträge seit 2005
vor 16 Jahren
Office 2000

Vielleicht hilft das bei Office 2000: http://support.microsoft.com/kb/908002/en-us