Wie erstelle ich eine moduldefinierte Funktion in einer COM Type Library?

8

Die von VBA verwendete VBE7.dll-Typbibliothek hat die folgende MIDL für das Conversion -Modul:

%Vor%

Wo ich besonders interessiert bin, wie VBA die Funktion HRESULT zurückgibt CDec (die letzte Funktion in der MIDL oben), so dass innerhalb VBA, hat die Funktion CDec eine Unterschrift von

%Vor%

Es scheint wie VBA die TLB-Definition HRESULT zurückschattet. Um also die Theorie zu testen, möchte ich meinen eigenen TLB erstellen, der eine HRESULT zurückgebende Funktion innerhalb eines% definiert. co_de%, und dann sehen, wie VBA diese Funktion behandelt.

Ich glaube nicht, dass dies in C # oder VB.NET gemacht werden kann, und als ich versuchte, eine Funktion in einem Standardmodul in VB6 zu definieren, war das Modul in der DLL nicht sichtbar.

Ist das mit C ++ möglich? Welche Art von Projekt muss ich erstellen? Gibt es etwas Besonderes, was ich tun muss? Muss ich vielleicht die MIDL von Hand bearbeiten?

Hinweis: Ich beziehe diese Frage nicht explizit als module , da ich versuche, einen TLB aus C # zu interpretieren. Um zu testen, wie der VBA-Host einen TLB interpretiert, möchte ich einen geeigneten TLB in jeder Sprache erstellen, die ihn unterstützt. Ich habe Visual Studio 6, 2003, 2013 und 2015 zu meiner Verfügung.

    
ThunderFrame 13.06.2017, 00:32
quelle

1 Antwort

5

Wichtig in der CDec-Deklaration sind die [out] und [retval] Attribute kombiniert. Tools, die es verstehen (wie VB / VBA) werden in der Lage sein, Aufrufe an diese Methode in vereinfachter Weise zu kompilieren, was die Fehlerbehandlung maskiert, also

%Vor%

ist äquivalent zu

%Vor%

äquivalent bedeutet hier nicht, dass es in binärer Form gleichwertig ist, sondern nur die Werkzeuge, die verstehen, dass die Syntax in Ordnung ist, wenn sie den ersten Ausdruck verwenden (und das endgültige binäre Ziel kompilieren) der Zweite. Es bedeutet auch, dass, wenn ein Fehler (HRESULT-Fehler) vorliegt, das Tool einen Fehler nach Belieben auslösen sollte (VB / VBA wird dies tun).

Das ist einfach " syntaktischer Zucker ".

Sie können das mit MIDL schreiben, aber auch mit .NET: Erstellen Sie einfach eine Standard-Klassenbibliothek mit Visual Studio und fügen Sie diese Beispiel-c # -Klasse hinzu:

%Vor%

Kompilieren Sie das und führen Sie das regasm-Tool aus, um es mit einem Befehl wie dem folgenden zu registrieren:

%Vor%

Dadurch wird die Klasse als COM-Objekt registriert und eine C:\mypath\ClassLibrary1\bin\Debug\classlibrary1.tlb type-Bibliotheksdatei erstellt.

Starten Sie jetzt Excel (Sie können einen beliebigen mit COM-Automatisierung kompatiblen Client verwenden) und fügen Sie einen Verweis auf die ClassLibrary1 hinzu (Entwicklermodus, VBA-Editor, Tools / Referenz). Wenn Sie es nicht sehen, laufen Sie möglicherweise mit einer anderen Bitness. Es ist möglich, COM für die 32-64-Kommunikation zu verwenden, aber stellen Sie erst jetzt sicher, dass Ihr Client mit der gleichen Bitness läuft, wie Ihr ClassLibrary1.dll kompiliert wurde.

Sobald Sie die Referenz haben, fügen Sie etwas VB-Code, wie folgt hinzu.

%Vor%

Wie Sie sehen werden, zeigt VB intellisense die Methode, die wir erwarten, wie in C #, und es funktioniert gut.

Versuchen wir nun, es aus C ++ zu verwenden: Erstellen Sie ein Konsolenprojekt (stellen Sie erneut sicher, dass die Bitheit kompatibel ist), und fügen Sie diesen Code hinzu:

%Vor%

Dies funktioniert auch gut und der Code ähnelt VB. Beachten Sie, dass ich Visual Studio magische #import-Anweisung verwendet habe, die super cool ist, weil es viele Details von COM-Automatisierung plumbing (genau wie VB / VBA), einschließlich bstr und Variante smart Klassen.

Lassen Sie uns auf den Test -Aufruf klicken und eine Goto-Definition (F12) machen, das sehen wir:

%Vor%

haha! Dies ist im Grunde, was VB / VBA auch unterdeckt. Wir können sehen, wie die Ausnahmebehandlung durchgeführt wird. Wenn Sie F12 in _Class1Ptr ausführen, sehen Sie Folgendes (vereinfacht):

%Vor%

Hier sind wir. Wie Sie sehen können, ist die Test -Methode, die von C # in ihrer binären Form generiert wird, von der [out, retval] -Form wie erwartet. Der Rest ist alles Zucker und Wrapper. Die meisten COM-Interfacemethoden sind auf binärer Ebene mit [out, retval] entworfen, da Compiler kein gemeinsames kompatibles Binärformat für die Rückgabe von Funktionen unterstützen.

Was VBE7 definiert, ist ein Dispatch-Interface , wieder eine Form von syntaktischem Zucker zum Definieren von Schnittstellen auf der COM-Raw- / Binär-IUnknown-Schnittstelle. Das einzige Geheimnis ist, warum CDec anders als andere Methoden in VBE7 definiert ist. Ich habe keine Antwort dafür.

Nun speziell zum Schlüsselwort module in IDL ist IDL nur ein Werkzeug für abstrakte Definitionen (Funktionen, Konstanten, Klassen usw.), das optional Artefakte (.H, .C, .TLB usw.) gezielt ausgibt für eine bestimmte Sprache (C / C ++ usw.) oder für bestimmte Clients.

Es kommt vor, dass VB / VBA TLBs Konstanten und Methoden unterstützt. Es interpretiert Konstanten als das, was sie sind, und funktioniert in Modulen als DLL-Exporte vom DLL-Namen des Moduls.

Wenn Sie also diese my.idl -Datei irgendwo auf Ihrer Festplatte erstellen:

%Vor%

Sie können einen TLB daraus wie folgt kompilieren:

%Vor%

Es wird eine my.tlb -Datei erstellt, auf die Sie in VB / VBA verweisen können. Jetzt von VB / VBA, haben Sie eine neue Funktion verfügbar (intellisense wird daran arbeiten) namens GetCurrentThreadId . Es funktioniert, weil Windows 'kernel32.dll eine Funktion GetCurrentThreadId exportiert.

Sie können DLL-Exporte nur aus C / C ++ - Projekten (und aus anderen Sprachen / Tools wie Delphi), aber nicht von VB / VBA, nicht von .NET.

Tatsächlich gibt es einige Tricks, um Exporte in .NET zu erstellen, aber es ist nicht wirklich Standard: Ist es möglich, Funktionen aus einer C # DLL wie in VS C ++ zu exportieren?

    
Simon Mourier 16.06.2017, 06:45
quelle