Laden...

C# - Komponente aus VBA ansprechen

Erstellt von Harown vor 17 Jahren Letzter Beitrag vor 16 Jahren 6.556 Views
Harown Themenstarter:in
19 Beiträge seit 2007
vor 17 Jahren
C# - Komponente aus VBA ansprechen

Hallo,

ich habe ein kleines Tool, das ich evtl. auch gerne in Access benutzen möchte. Ich hab mir dazu aus der dll eine tlb exportieren lassen und die als Verweis in die Access-Anwendung hinzugefügt.
Ich bin leider kein VBA-Hecht und weiß nun nicht recht, wie ich mein Objekt erzeugen soll. Mein Namespace ist MultiSelect, meine Klasse CheckedComboBox.

Habs so versucht:

Dim cCB As Object
Set cCB = CreateObject("MultiSelect.CheckedComboBox")

Dann sagt mir Access "Objekterstellung durch ActiveX net möglich".

Ach ja, im Intellisense sieht man auch nix ...

Danke im Voraus!

476 Beiträge seit 2004
vor 17 Jahren

hallo Harown,

hier findest du ein kleines Beispiel zu einer kleinen DLL die von VBA aus aufgerufen werden kann.

-yellow

Edit: Über COMWrapper, über Schnittstellen...

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de

3.728 Beiträge seit 2005
vor 17 Jahren
Com

Du solltest Deine .NET Komponenten nicht direkt für COM-Interop registrieren, sondern separate Wrapper-Assemblies erstellen.

Im Normalfall solltest Du statt CreateObject new verwenden. Also

Dim objSomething As Namespace.ClassName
Set objSomething=New Namespace.ClassName

Damit Du auch IntelliSense bekommst, musst Du eigene COM-Schnittstellen in C# schreiben. Diese Posts sollten Dir dabei weiterhelfen:
Warum ist Access so verhaßt?
COM Interface für die eigene Application

Harown Themenstarter:in
19 Beiträge seit 2007
vor 17 Jahren

Vielen Dank für eure Antworten!

Habe das mal mit dem COMWrapper-Projekt ausprobiert: tlb erzeugt und über Extras - Verweise hinzugefügt. Einwandfrei sichtbar im Intellisense sind dann auch der COMWrapper - Namespace und die YellowWrapper - Klasse. Nur leider kriege ich die gleiche Fehlermeldung unabhängig ob ich new oder createObject verwende:
Objekterstellung durch ActiveX nicht möglich


Dim blub As COMWrapper.YellowWrapper

'Set blub = CreateObject("COMWrapper.YellowWrapper")
Set blub = New COMWrapper.YellowWrapper

Hmm, was mach ich denn da falsch? Hab ich noch irgendwas vergessen?

476 Beiträge seit 2004
vor 17 Jahren

hmm...wir hatten schon mal ein Problem mit Excel '97... welche Version von Access setzt du ein?

-yellow

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de

Harown Themenstarter:in
19 Beiträge seit 2007
vor 17 Jahren

Vielleicht mach ich ja irgendwas Grundlegendes falsch. Ist es richtig, dass ich eine tlb importieren muss? Das Projekt lässt sich als dll erst gar nicht einbinden. Muss das so?

3.728 Beiträge seit 2005
vor 17 Jahren
Makrosicherheit

TLB ist ok. Die DLL ist ja eine .NET Assembly, mit der Access nix anfangen kann.

Access 2003 und 2007 sind standardmäßig ziemlich restriktiv Eingestellt, was VBA-Code (Oft auch als VBA-Makros bezeichnet) angeht. Der Aufruf einer, möglicherweise gefährlichen, externen ActiveX-Komponente wird vielleicht durch diese hohe Sicherheitsstufe verhindert.

Zum Test solltest Du die Maktosicherheit mal auf "Niedrig" stellen. Das geht im Menü "Extras" unter "Makros" und dann "Sicherheit".

Harown Themenstarter:in
19 Beiträge seit 2007
vor 17 Jahren

Hmm, funktioniert leider auch nicht. Hab's heute nochmal auf einem anderen Rechner mit der gleichen Access-Version probiert, ging aber auch nicht. Muss ich da vielleicht noch irgendwas registrieren? Hatte das versucht mit Regsvr32.exe, aber der sagte mir nur, dass er die Datei nicht laden konnte (sowohl .tlb als auch .dll). Pfad war definitiv richtig. Hmm ...

3.728 Beiträge seit 2005
vor 17 Jahren
Cas

Vielleicht liegt es an fehlenden CAS-Rechten.

Ist Deine .NET Assembly signiert?
In welcher CAS-Codegruppe ist die Assembly?
Welchen Berechtigungssatz erhält die Assembly?

Wenn Du jetzt nur "Bahnhof" verstehst, solltest Du Dir folgende Beiträge anschauen:
GetActiveObject("Outlook.Application") funktioniert nicht
problem mit Microsoft.Office.Interop.Outlook

.NET Assemblies kann man nicht RegSvr32.exe für COM registrieren. Man muss stattdessen das Tool REGASM.EXE aus dem .NET Framework Verzeichnis verwenden.

Harown Themenstarter:in
19 Beiträge seit 2007
vor 16 Jahren

Okay. Es lag an der fehlerhaften bzw. nichtvorhandenen Registrierung. Hatte die tlb fälschlicherweise mit TLBEXP.EXE erstellt. Mit REGASM.EXE hat's dann funktioniert.

Tausend Dank!

Harown Themenstarter:in
19 Beiträge seit 2007
vor 16 Jahren

Hmm, beim Versuch eine eigene DLL als Com-Komponente laufen zu lassen, bekomme ich folgende Fehlermeldung, wenn ich den Konstruktor aufrufen will:

"Funktionsmerkmal in Objektbibliothek nicht unterstützt"

Ich habe daraufhin stückweise sämtlichen Code der Klasse bis auf den (leeren) Konstruktor entfernt um die Ursache des Problems eingrenzen zu können, ohne Erfolg ...

Woran kann das liegen? Danke!

Harown Themenstarter:in
19 Beiträge seit 2007
vor 16 Jahren

Ah Momento, kann es daran liegen, dass ich eine von UserControl abgeleitete Klasse in einem Standardmodul instanzieren will?

3.728 Beiträge seit 2005
vor 16 Jahren
Konstruktor

Unter COM werden keine parametrisierten Konstruktoren unterstützt.

Auch von UserControl abgeleitete Klassen werden nicht funktionieren, da es in der COM-Welt keine Windows.Forms-Elemente gibt. Es gibt zwar ActiveX-Controls, die sind aber nicht kompatibel.

Wenn Du .NET-Assemblies in COM-Anwendungen verwenden willst, darfst Du nach außen (also public) nur Typen verwenden, die es in er COM-Welt gibt (Also solche, die eine COM-Schnittstelle haben). .NET UserControls lassen sich nicht auf VB/VBA-Formulare plazieren. Es gibt zwar im Internet diverse Anleitungen, wie man mit .NET ein ActiveX-Control schreiben kann, das ist aber keine stabile Angelegenheit und wird von Microsoft nicht supported.

Was man allerdings tun kann, ist eine Wrapper-Klasse dazwischenzuhängen. Man registriert nicht die eigentliche Klasse für COM-Interop, sondern nur den Wrapper, der vorzugsweise in einer separaten Assembly untergebracht sein sollte. So kann man bestimmte Funktionen der eigenen .NET-Anwendung für COM-Clients zugänglich machen.

Harown Themenstarter:in
19 Beiträge seit 2007
vor 16 Jahren

Dank dir, Rainbird,

damit hatt's funktioniert. Was ich jetzt nur noch nicht weiß, ist, wie ich ein Objekt, das von UserControl erbt, in ein Access-Formular hinzufüge, nachdem es dort instanziiert wurde. Geht das in VBA überhaupt zur Laufzeit?

Vielen Dank!

3.728 Beiträge seit 2005
vor 16 Jahren
UserControls

Access unterstützt zwar eingebettete OLE-Inhalten, aber diese werden vom .NET Framework nicht unterstützt. Es gibt also keine Möglichkeit, ein .NET Steuerelement auf direktem Weg auf einem Access-Formular zu plazieren.

Es gibt aber einen indirekten Weg, der realtiv gut funktioniert. Man schreibt in C# ein Formular ohne Rahmen. Darauf plaziert man das UserControl. Dann schreibt man eine COM-Wrapper-Klasse, die das Formular steuert und auch dessen Fensterhandle (hwnd) an Acces zurückgeben kann.
Auf der Access Seite erzeugt man über den COM-Wrapper eine Instanz des rahmenlosen Formulars und besorgt sicht über die Eigenschaft den Handle. Nun kann man mit der Win32.API-Funktion SetParent das .NET Fenster kapern und innerhalb eines Rechtecks oder einer GroupBox auf dem Access-Formular plazieren.

So kann man Access mit einem Trick, .NET Benutzeroberflächenelemente unterschieben.

Wenn möglich würde ich aber lieber Access in die Tonne treten und alles auf .NET migrieren.