Access und Excel sind Geschwister im Office-Paket, und aus VBA heraus kannst du Excel komplett fernsteuern: Mappen erzeugen, Zellen füllen, formatieren, ganze Recordsets in Sekunden exportieren. Diese Technik heißt Automation — ein Programm steuert ein anderes über dessen Objektmodell.
Das ist mächtig, hat aber eine Falle: Wer Excel nicht sauber beendet, hinterlässt unsichtbare Geisterprozesse im Speicher. Diese Lektion zeigt beides — den vollen Zugriff und das saubere Aufräumen.
Die Grundidee der Automation
Excel stellt ein Objektmodell bereit: An der Spitze steht die
Excel.Application, darunter Workbooks (Arbeitsmappen), darunter Worksheets
(Tabellenblätter), darunter Range/Cells (Zellen). Von Access aus greifst du auf
dieses Modell zu, als wärst du in Excels eigenem VBA.
Early Binding vs. Late Binding
Es gibt zwei Wege, an das Excel-Objekt zu kommen.
Late Binding — ohne Verweis, über CreateObject. Der Datentyp ist Object,
die Bindung passiert erst zur Laufzeit:
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
Early Binding — mit gesetztem Verweis. Im VBE unter Extras → Verweise die Microsoft Excel xx.x Object Library aktivieren, dann typisiert deklarieren:
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
| Late Binding | Early Binding | |
|---|---|---|
| Verweis nötig | nein | ja |
| IntelliSense | nein | ja |
Konstanten wie xlUp | selbst definieren | eingebaut |
| Versionssicher beim Verteilen | robuster | kann brechen |
Empfehlung: Entwickle mit Early Binding (wegen IntelliSense und Konstanten) und stelle für die Auslieferung auf Late Binding um, wenn deine Nutzer unterschiedliche Excel-Versionen haben. Bei Late Binding musst du Konstanten wie
xlUp(= -4162) selbst als Zahl schreiben.
Mappe öffnen und Zellen schreiben
Ein vollständiges Beispiel mit Late Binding. Beachte xlApp.Visible = True —
damit siehst du Excel überhaupt; ohne läuft es unsichtbar im Hintergrund.
Public Sub ExcelBefuellen()
Dim xlApp As Object
Dim wb As Object
Dim ws As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True ' Excel-Fenster anzeigen
Set wb = xlApp.Workbooks.Add ' neue leere Mappe
Set ws = wb.Worksheets(1) ' erstes Tabellenblatt
' Zellen schreiben
ws.Range("A1").Value = "Artikel"
ws.Range("B1").Value = "Preis"
ws.Cells(2, 1).Value = "Schraube" ' Zeile 2, Spalte 1
ws.Cells(2, 2).Value = 0.05
' Zelle lesen
Debug.Print ws.Range("B2").Value ' 0,05
' Überschrift fett
ws.Range("A1:B1").Font.Bold = True
' Speichern
wb.SaveAs "C:\Export\Artikel.xlsx"
End Sub
Range("A1") adressierst du wie in Excel, Cells(Zeile, Spalte) mit Zahlen — das
ist praktisch in Schleifen.
Ein ganzes Recordset in Excel kippen
Zeile für Zelle für Zelle zu schreiben ist langsam. Für Datenmengen gibt es
CopyFromRecordset: eine einzige Zeile kopiert ein komplettes Recordset in einen
Rutsch nach Excel.
Public Sub RecordsetNachExcel()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim xlApp As Object, wb As Object, ws As Object
Dim i As Long
Set db = CurrentDb
Set rs = db.OpenRecordset( _
"SELECT Kundenname, Ort, Umsatz FROM tblKunden", dbOpenSnapshot)
Set xlApp = CreateObject("Excel.Application")
Set wb = xlApp.Workbooks.Add
Set ws = wb.Worksheets(1)
' Spaltenüberschriften aus den Feldnamen
For i = 0 To rs.Fields.Count - 1
ws.Cells(1, i + 1).Value = rs.Fields(i).Name
Next i
ws.Range("A1").Resize(1, rs.Fields.Count).Font.Bold = True
' Daten ab Zeile 2 in einem Rutsch
ws.Range("A2").CopyFromRecordset rs
ws.Columns.AutoFit
xlApp.Visible = True
' Aufräumen
rs.Close
Set rs = Nothing
Set db = Nothing
Set ws = Nothing
Set wb = Nothing
Set xlApp = Nothing
End Sub
CopyFromRecordset schreibt nur die Daten, keine Überschriften — die setzt du wie
oben selbst aus rs.Fields.
Sauber beenden — der Geisterprozess
Das ist der wichtigste Teil. Wenn du Excel unsichtbar startest und die
Objektvariable einfach aus dem Gültigkeitsbereich fallen lässt, bleibt EXCEL.EXE
oft im Task-Manager hängen — ein Geisterprozess. Er belegt Speicher und
blockiert später die Datei.
Die Regel: erst Quit, dann jede Objektvariable auf Nothing setzen — von innen
nach außen.
Public Sub ExcelSauberBeenden()
Dim xlApp As Object, wb As Object, ws As Object
Set xlApp = CreateObject("Excel.Application")
Set wb = xlApp.Workbooks.Add
Set ws = wb.Worksheets(1)
ws.Range("A1").Value = "Fertig"
wb.SaveAs "C:\Export\Test.xlsx"
' In umgekehrter Reihenfolge abbauen
wb.Close SaveChanges:=False
xlApp.Quit ' Excel beenden
Set ws = Nothing
Set wb = Nothing
Set xlApp = Nothing ' Referenz freigeben -> Prozess verschwindet
End Sub
Falle: Sogenannte „unqualifizierte" Zugriffe wie
Cells(1, 1)stattws.Cells(1, 1)erzeugen versteckte Referenzen auf dieApplicationund verhindern das Beenden. Qualifiziere jeden Zugriff mitws.,wb.oderxlApp., sonst hilft auchQuitnichts.
Robuster mit Fehlerbehandlung
Damit kein Geisterprozess zurückbleibt, wenn zwischendrin etwas schiefgeht, gehört das Aufräumen in einen Fehlerbehandler:
Public Sub ExcelMitFehlerschutz()
Dim xlApp As Object, wb As Object
On Error GoTo Aufraeumen
Set xlApp = CreateObject("Excel.Application")
Set wb = xlApp.Workbooks.Add
wb.Worksheets(1).Range("A1").Value = "Hallo"
wb.SaveAs "C:\Export\Robust.xlsx"
Aufraeumen:
If Err.Number <> 0 Then MsgBox "Fehler: " & Err.Description
On Error Resume Next
If Not wb Is Nothing Then wb.Close SaveChanges:=False
If Not xlApp Is Nothing Then xlApp.Quit
Set wb = Nothing
Set xlApp = Nothing
End Sub
Die einfache Alternative: TransferSpreadsheet
Wenn du nur Daten aus einer Tabelle oder Abfrage nach Excel exportieren willst,
ohne zu formatieren, brauchst du gar keine Automation. DoCmd.TransferSpreadsheet
erledigt das in einer Zeile:
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, _
"tblKunden", "C:\Export\Kunden.xlsx", True
Der letzte Parameter True schreibt die Feldnamen als Überschriftszeile. Nimm
TransferSpreadsheet für schnelle Datendumps und die volle Automation nur, wenn du
Formatierung, Formeln oder mehrere Blätter brauchst.
Zusammengefasst
- Automation steuert Excel über sein Objektmodell:
Application → Workbook → Worksheet → Range. - Early Binding (Verweis) gibt IntelliSense; Late Binding (
CreateObject) ist versionssicherer. CopyFromRecordsetkippt ein ganzes Recordset in einem Rutsch nach Excel.- Immer
Quitund danach alle Objekte aufNothingsetzen — sonst bleibt ein Geisterprozess; jeden Zugriff qualifizieren. - Für einfache Exporte reicht
DoCmd.TransferSpreadsheetganz ohne Automation.