Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!

Mobiles Hauptmenü

VBA Projekt als Klassenbibliothek

Begonnen von Milvus, Oktober 23, 2018, 16:33:17

⏪ vorheriges - nächstes ⏩

markusxy

Zitat von: Lachtaube am November 17, 2018, 09:55:43Ausnahmen sind komplexe oder zeitkritische Methoden, die sich in VBA nur schwierig realisieren lassen.  Dafür verwende ich vorzugsweise klassische DLLs, die allerhöchstens als externe Abhängigkeit die auf allen Windows-Rechnern installierte msvcrt.dll aufweisen.

Ich möchte das Thema noch mal aufgreifen und mal etwas mit DLL experimentieren.
Ich frage mich ob besser c++ oder Delphi/Pascal, oder ??
Womit machst du sie?
Kann wer grundsätzliche Tipps zu möglichen Plattformvorteilen nennen - wenn es um VBA im Hintergrund geht.
Vor Jahren habe ich mit C bereits erste Erfahrung gemacht - hätte also C++ genommen.

LG Markus

PhilS

#46
Zitat von: markus888 am November 28, 2018, 10:16:25
Ich möchte das Thema noch mal aufgreifen und mal etwas mit DLL experimentieren.
Ich frage mich ob besser c++ oder Delphi/Pascal, oder ??
Die erste Frage sollte sein: COM oder WinAPI?

Wenn du nur einzelne Funktionen aus einer DLL aufrufen willst, dann ist WinAPI (Declare...) ausreichend und bringt den geringsten Overhead bei der Distribution einer solchen Anwendung mit sich.

Komplexere Objekte aus einer DLL kann man (theoretisch!) auf diesem Weg auch nutzen, aber die extrem gesteigerte Komplexität der Anbindung aus VBA verbietet diesen Ansatz faktisch. In diesem Fall ist eine COM-DLL das Mittel der Wahl.

Mit C++ und Delphi kannst du beide Ansätze implementieren. Delphi/Pascal ist mit VB(A)-Vorkenntnissen aus meiner Sicht wesentlich einfacher zu erlernen als C++. Das ist aber primär eine Frage der individuellen Vorkenntnisse und Vorlieben.

Wenn du in Richtung COM gehen willst, ist aus meiner Sicht eine .Net-DLL die erste Wahl. Mit VB.net hast du eine Sprache, die nah bei VBA liegt. Wenn du C-Nähe bevorzugst, hast du C# zur Auswahl. - Beides erfordert aus meiner Sicht und begrenzten Erfahrung mit C++ wesentlich weniger Einarbeitung als die o.g. Alternativen.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

markusxy

Phillip,
es geht vorerst nur um Funktionen mit Standard Aufrufkonvention.
Da geht es zuerst mal um Performance - auch für die Einbindung als UDF in Abfragen.
VBA Code kann ja noch so gut programmieren - die langsame Ausführung (im Vergleich zu c) ist ja zum Weinen.
Com dll wäre dann ein nächster Schritt.

Lachtaube

#48
@Markus,

im Prinzip kann jede Programmiersprache verwendet werden, die 32-Bit DLLs für Windows mit der Calling Convention StdCall erzeugen kann.

Der Aufwand, in C++ allgemein verwendbare DLLs zu schreiben (wenn man von Klassen und Templates Gebrauch macht), ist sehr hoch und IMHO deshalb nicht unbedingt empfehlenswert.

Wenn man ohne Install-Routinen leben will, sollte man beim Entwickeln in C darauf achten, möglichst ohne externe Abhängigkeiten anderer Bibliotheken auszukommen. Ausnahmen stellt die msvcrt.dll dar, die auf jedem Windows vorhanden ist. Nimmst Du aber z.B. das neueste Visual Studio, so muss i.d.R. immer die verwendete Runtime der C-Bibliothek mit vertrieben werden - statischen Linken bläht eine DLL doch sehr stark auf.

Ich verwende häufig den GCC oder hin und wieder auch CLang (einen qualitativen Unterschied zwischen beiden Compilern habe ich nicht unbedingt bemerkt) unter MSYS2 zum Kompilieren. Als Editor setze ich GNU-Emacs ein, der entsprechend eingerichtet, allen PiPaPo für eine C-Entwicklungsumgebung bietet, was man so benötigt. Unter C/C++ Development Environment for Emacs gibt es Tipps zur Konfiguration. Wenn Du Versuche mit GCC starten willst, sind die beiden Artikel Building Windows DLLs with MinGW und Advanced MinGW DLL Topics vielleicht hilfreich.

Pascal ist vom Sprachumfang her nicht ganz so mächtig wie C - dafür aber im Umgang mit Datentypen etwas sicherer und der Code ist leichter verständlich.

Auch FreeBASIC stellt eine interessante Alternative (nicht nur für DLLs - Objektorientierung ist möglich) dar, ohne eine neue Programmiersprache erlernen zu müssen, weil man hier, wie auch unter C und Pascal konstante Datenstrukturen bereits im Code anlegen kann. Es hat auch ein hervorragendes Manual, das ständig auf dem Laufenden gehalten wird. Aktuelle Versionen stellt Dein Landsmann Stefan Wurzinger unter http://office.mv-lacken.at/jenkins/ zur Verfügung.

Wenn man nicht mit Zeigern und Strukturen hantieren will, ist eine das Dot-Net unterstützende Programmiersprache sicherlich auch geeignet. Mir persönlich ist das jedoch zu sehr aufgebläht.
Grüße von der (⌒▽⌒)

markusxy

Zitat von: Lachtaube am November 28, 2018, 11:47:42Wenn man nicht mit Zeigern un Strukturen hantieren will

Wow, danke für die vielen Infos.
Und nein, auf die Zeiger möchte ich nicht verzichten.  :)

Milvus

Zitat von: PhilS am November 28, 2018, 10:47:05

Wenn du in Richtung COM gehen willst, ist aus meiner Sicht eine .Net-DLL die erste Wahl. Mit VB.net hast du eine Sprache, die nah bei VBA liegt.

Besten Dank,
habe mir bereits ein Buch besorgt, da gehts im Wesentlichen um ADO.Net. Wenn ich das so lese, vergeht mir die Lust an Access Recordsets.
Wie auch immer, kannst Du evtl. ein Buch empfehlen, das fix das Werkzeug von V-Studio einführt?

Ich würde dann einfach mal ein paar Experimente mit der Com machen. Erste cls hab ich ja schon. Die arbeiten aber mit Verweisen u.A. auf Excel. Da Office ja aber installiert ist, müsste das Einbinden in .Net ja auch nöglich sein, import nennt man das dort glaube ich.

Josef P.

#51
Hallo!

Ein Hinweis aus eigener Erfahrung:
Wenn du an die .net-COM-Klassen Referenzen von Access-/Excel-Objekten übergibst, achte auf das saubere Aufräumen. COM und .net passen nämlich bezüglich Freigeben der Referenz und dem Zerstören der Instanzen gar nicht so gut zusammen. In .net gibt der GC (Garbage collector) z. B. Speicher nicht sofort frei, wenn man es nicht expizit anweist.

Ich hatte bei einem COM-Add-In für den VBA-Editor anfangs Probleme, bis ich den GC soweit hatte, dass alles freigegeben wird und es zu keiner "hängengebliebenen" Access-Anwendung kommt.
Diese Probleme gibt es nur, wenn in VBA erzeugte Instanzen in der .net-COM verwendet werden. Instanzen aus .net-COM-Klassen in VBA verwenden ist kein Problem.


Vieleicht etwas OT (passt auch teilweise zu deinem anderen Thread), aber ich schreib mal meine Meinung zu dem ganzen Vorhaben und den damit aufkommenden Problemen.

Mir kommt vor, für dich gibt es derzeit nur einen Lösungsansatz für deine Problemstellung: alle aktuellen Access-Anwendung als Komponenten zu betrachten, die dann wie Microservies zusammenspielen sollen. Ich trau mich zu behaupten, dass du mit Access damit auf Dauer keine Freude haben wirst und vielleicht sogar Schiffbruch erleiden wirst.

Es ist vieles machbar. Aber nicht alles was machbar ist, muss sinnvoll sein. Access ist für mich ein RAD (Rapid Application Development)-System und keine Entwicklungsumgebung für Komponenten-Modelle.

Mit .net zu programmieren ist für mich schöner als in VBA, da man OOP nutzen kann. Es ist auch nett, wenn man eine .net-COM-dll in Access verwenden kann. (Funktioniert übrigens auch per Late binding der dll inkl.  Early binding der Typen für Intellisense ohne Eintrag in der Registry.)
Trotzdem nutze ich die Einbindung von .net-COM nur sehr selten, da es eine zusätzliche Abhängigkeit erzeugt.
Den intensiveren Gebrauch von .net-COM in VBA würde ich nur dann verwenden, wenn Access nur als Prototyp dient und die Anwendung später als .net-Anwendung laufen soll. In so einem Szeanrio wäre es Zeitverschwendung Logik in VBA zu schreiben, wenn man sie später in .net benötigt.

Weiters habe ich den Eindruck, dass du dich noch nicht intensiv mit einer Quellcodeverwaltung auseinander gesetzt hast. Damit wäre das Problem des wiederholt vorkommenden Codes auch behoben, da dann zwar der Code mehrmals verwendet wird, aber trotzdem nur an einer Stelle gewartet werden muss. Es mag dir am Anfang vielleicht umständlich vorkommen, in jeder Anwendung den Code eingebaut zu haben und die wiederverwendbaren Klassen nicht aus eine Bibliothek zu nutzen. In meiner (doch schon etwas längeren ;)) Praxis mit Access finde ich diese Variante - für fix in der Anwendung benötigter Klassen - passender für Access.



mfg
Josef

Milvus

Zitat von: Josef P. am November 30, 2018, 20:54:26
Weiters habe ich den Eindruck, dass du dich noch nicht intensiv mit einer Quellcodeverwaltung auseinander gesetzt hast. Damit wäre das Problem des wiederholt vorkommenden Codes auch behoben, da dann zwar der Code mehrmals verwendet wird, aber trotzdem nur an einer Stelle gewartet werden muss.

Danke, Einschätzung nicht ganz korrekt. Ich neige sehr stark zum Zentralisieren und Standardisieren und setzte mich sogar explizit damit auseinader. Hab ich im Forum hier und da schon mal erwähnt: Ich habe das Teil geerbt und die Situation ist da und ist wie sie ist. Nachträglich da was zusammen zu führen... keine Chance! Setze mich jetzt seit nem Halben Jahr mit der Lösung auseinander und bin zu dem Schluss gekommen:

Beste Lösung ist, dort wo eine gleichsinnige Funktionalität läuft, diese in Klassenmodulen übertragen und nachträglich verwalten.

Noch mal die Situation:

Es laufen ein Dutzend Frontends. Ein Dutzen Backends. Jedes FE hat Code für sich, der bei gleichen Funktionen zu 70% Deckungsgleich ist. Damit eine Funktion läuft, muss sie 5-20 andere Funktionen benutzen, die wuer über die Modulwelt verteilt sind. Das sind nur die Funktionen.

Datenmodell: Kaum aufgelöst, Tabellen mit > 50 Felden, Referentielle Integrität: Netagiv! Formulare: 100 Controls sind nix. Ein Formular arbeitet nicht für sich alleine, ist abhängig von anderen...

Meine erste Aussage war: Neu aufbauen!
Meine zweite Aussage war: Neu aufbauen!
Meine jeztzige Aussage ist: Neu aufbauen!

Wurliwurm

Zitat von: Milvus am Dezember 03, 2018, 06:41:35
Ich habe das Teil geerbt und die Situation ist da und ist wie sie ist. Nachträglich da was zusammen zu führen... keine Chance!

Liest sich wie der Klassiker: "Ein big ball of mud" und ein armer Mensch, der sich darum kümmern soll. Ich würde an Deiner Stelle da keine Arbeit mehr reinstecken. Access-VBA ist keine Wunderwaffe für Unternehmensanwendungen! Anstelle dessen Einarbeitung in Plattformen für verteilte Anwendungen. Josef hat es im vorigen Post schon gut beschrieben.

https://de.wikipedia.org/wiki/Big_Ball_of_Mud

Beaker s.a.

@Milvus
ZitatMeine erste Aussage war: Neu aufbauen!
Meine zweite Aussage war: Neu aufbauen!
Meine jetzige Aussage ist: Neu aufbauen!
Falls du Hilfe brauchst bei der Argumentation gegenüber dem
Auftraggeber; - meine Meinung: neu aufbauen!
gruss ekkehard
Alles, was geschieht, geschieht. - Alles, was während seines Geschehens etwas anderes geschehen lässt, lässt etwas anderes geschehen. - Alles, was sich selbst im Zuge seines Geschehens erneut geschehen lässt, geschieht erneut. - Allerdings tut es das nicht unbedingt in chronologischer Reihenfolge.
(Douglas Adams, Mostly Harmless)

markusxy

Zitat von: PhilS am November 28, 2018, 10:47:05
Mit C++ und Delphi kannst du beide Ansätze implementieren.

Ich hab jetzt meine ersten Gehversuche mit c und mit Delphi gemacht.
Bleibe jetzt aber vorerst bei Delphi. Hauptsächlich weil die Standard-Datentypen größtenteil mit den in VBA übereinstimmen
und daher viele Funktionen dazu mitgebracht werden. Grade beim Datum.
Bis auf den BSTR ist alles integriert. Wenn ich aus der DLL Arrays oder String zurückgeben muss, dann erzeuge ich eine Variable in VBA und übergebe diese per Referenz an die dll. In der DLL erzeuge ich dann den String oder das Array, dann sorgt VBA am Schluss automatisch für die Freigabe des Speichers.

Zitat von: PhilSKomplexere Objekte aus einer DLL kann man (theoretisch!) auf diesem Weg auch nutzen, aber die extrem gesteigerte Komplexität der Anbindung aus VBA verbietet diesen Ansatz faktisch. In diesem Fall ist eine COM-DLL das Mittel der Wahl.

Das nächste sind jetzt die COM DLL. Aber ich fürchte es geht mir wie dem Milvus und mir vergeht die Lust an VBA.  :(
Phillip, wie hast du das gemeint - komplexere Objekte nutzen.
ist es denn theoretisch möglich in einer DLL Objekte im Speicher zu halten und gezielt wieder freizugeben, oder ist da in jedem Fall eine COM Dll notwendig.

PhilS

Zitat von: markus888 am Dezember 07, 2018, 20:18:20
Phillip, wie hast du das gemeint - komplexere Objekte nutzen.
ist es denn theoretisch möglich in einer DLL Objekte im Speicher zu halten und gezielt wieder freizugeben, oder ist da in jedem Fall eine COM Dll notwendig.
COM ist ein Standard für die Erstellung/Aktivierung der Objekte, die Ermittlung deren (COM-)Interfaces und deren sauberer Entsorgung aus dem Speicher. VBA baut auf COM auf und somit bildet eine Instanz einer Objektvariable in VBA ein COM-Objekt ab.

Was aber eine DLL intern "bei sich zuhause" macht, ist allein deren Entwickler überlassen. Du kannst also in der DLL ein Objekt erstellen und über eine konventionelle (non-COM) API einen "Zeiger" (oder sonstigen Identifikator) des Objektes nach außen reichen. Wenn du in VBA diesen "Zeiger" speicherst und ihn dann an weitere API-Funktionen übergibst, kann die DLL das in Methodenaufrufe auf dem bestehenden Objekt übersetzen.

Folglich ist es nicht nur theoretisch, sondern auch praktisch (die GDI+ ist ein Beispiel) möglich, ohne COM mit Objekten zu arbeiten.
Es ist nur deutlich komplizierter in der Entwicklung.
Darüber hinaus hast du dir automatisch konzeptionell schon ein halbes Memory-Leak gebaut. Nur der Entwickler kennt den Zusammenhang zwischen dem Objekt-"Zeiger" und dem gezielten Freigeben des Objektes. Es gibt keinen definierten, allgemeingültigen Prozess für die Entsorgung obsoleter Objekte.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

markusxy

Zitat von: PhilS am Dezember 09, 2018, 11:30:01
Es gibt keinen definierten, allgemeingültigen Prozess für die Entsorgung obsoleter Objekte.

Davon wäre ich ausgegangen.
Werde jetzt mal com mit Delphi testen.

oliver3370

Hallo zusammen,
ich habe sehr interessiert Euren Gesprächsverlauf beobachtet. Ich möchte dazu folgenden Tip geben:

Exportiert man die Klasse in ACCDA/ACCDE entsteht eine CLS Datei: Hier ist der VB_Exposed Parameter sichtbar und kann per Textedit geändert werden.

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "Test_Klasse"
Attribute VB_GlobalNameSpace = True
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True   
Option Compare Database

Public Sub s_test(ByVal zeile As String)
    MsgBox "Jawoll dat klappt" & vbCrLf & zeile & vbCrLf & Application.CurrentProject.FullName
End Sub

Danach kann die Klasse importiert werden und die DB als ACCDE gespeichert werden. Dann den Verweis über durchsuchen im Verweise Dialog.
Danach kann man eine Hauptanwendung wie folgt schreiben:

Option Explicit
Private Kl_test As Test_Klasse
Sub test()
Set Kl_test = Test_Klasse      'late Binding wichtig
Call Kl_test.s_test("Huhu")    'Hier der Zugriff !
End Sub

Ich habe die Dateien in ein Paket gepackt. So ging es bei mir. Late Binding ist wichtig. Mit Early Binding und "New" geht es nicht, hatte ich herausgefunden.
mit netten Grüßen
Oliver

PhilS

Zitat von: oliver3370 am Dezember 10, 2019, 11:06:44
Ich habe die Dateien in ein Paket gepackt. So ging es bei mir. Late Binding ist wichtig. Mit Early Binding und "New" geht es nicht, hatte ich herausgefunden.
Private Kl_test As Test_Klasse ist aber kein Late Binding! Du bindest ja bereits bei der Deklaration an den konkreten Typ.

Eine Instanzierung mit New sollte ebenfalls funktionieren, wenn du die Attribute wie folgt setzt:
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True   
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor