Home » Tipps & Tricks » COM/OLE/DDE » Andere Office-Anwendungen » Access mit OLE-Automation steuern

Access mit OLE-Automation steuern

Wie kann ich Access starten?

Verwendung der D5-Komponenten:

Wenn Sie das Delphi 5-Patch haben, können Sie die TAccessApplication-Komponente verwenden, um Access zu starten. Setzen Sie eine auf ein Formular, und wenn ihre AutoConnect-Eigenschaft true ist, wird Access automatisch gestartet, wenn Ihr Programm startet. Wenn die Eigenschaft false ist, rufen Sie

AccessApplication1.Connect;

auf, wenn Access gestartet werden soll. Um eine laufende Instanz von Access zu verwenden, sofern es eine gibt, setzen Sie die ConnectKind-Eigenschaft von TAccessApplication auf ckRunningOrNew oder auf ckRunningInstance, wenn Sie keine neue Instanz starten wollen, wenn Access nicht läuft.
Wenn Access einmal gestartet ist, können Sie andere Komponenten, wie TAccessReport, mit deren ConnectTo-Methode damit verbinden:

  AccessApplication1.Connect;
  AccessApplication1.Visible := True;
  AccessApplication1.OpenCurrentDatabase('C:OfficeSamplesNorthwind.mdb', True);
  AccessApplication1.DoCmd.OpenReport('Sales by Year', acViewDesign, EmptyParam,
  EmptyParam);
  AccessReport1.ConnectTo(AccessApplication1.Reports['Sales by Year']);
  AccessReport1.Caption := 'Annual sales - from bad to worse';

Beachten Sie, dass ein Workbook oder ein Worksheet geöffnet werden muss, bevor Sie damit verbinden können.
Wenn Sie nicht das Patch für Delphi 5 haben, ist das Starten von Access ein bisschen anders, weil es keine TAccessApplication-Komponente gibt. (Das liegt daran, dass Microsoft das Application-Objekt in der Typbibliothek als verborgen deklariert hat.) Jedoch können Sie ein Application-Objekt auf die gleiche Art wie in D4 (s. unten) erzeugen und dann die Access-Komponenten damit verbinden.

Access öffnen (frühe Bindung):

Bevor Sie diese Methode verwenden können, müssen Sie die Typbibliothek (MSAcc8.olb für Access 97) importiert haben.
Eine Art, Access zu starten, ist den Aufruf von GetActiveObject auszuprobieren (try-Abschnitt), um eine bereits laufende Access-Instanz zu erhalten, es sollte aber ein Aufruf von CoApplication.Create im except-Teil stehen. Aber except-Klauseln sind langsam und können bei Leuten, die gerne „Bei Exceptions anhalten“ aktiviert haben, Probleme innerhalb der IDE auslösen. Der folgende Code benötigt keine try-except-Konstruktion, weil die Verwendung von OleCheck bei GetActiveObject im Fall, dass Access nicht läuft, vermieden wird.

uses Windows, ComObj, ActiveX, Access_TLB;

  var
    Access: _Application;
    AppWasRunning: boolean; // tells you if you can close Access when you've finished
    Unknown: IUnknown;
    Result: HResult;
  begin
    AppWasRunning := False;

    {$IFDEF VER120}      // Delphi 4
    Result := GetActiveObject(CLASS_Application_, nil, Unknown);
    if (Result = MK_E_UNAVAILABLE) then
      Access := CoApplication_.Create

    {$ELSE}              // Delphi 5
    Result := GetActiveObject(CLASS_AccessApplication, nil, Unknown);
    if (Result = MK_E_UNAVAILABLE) then
      Access := CoAccessApplication.Create
    {$ENDIF}

    else begin
      { make sure no other error occurred during GetActiveObject }
      OleCheck(Result);
      OleCheck(Unknown.QueryInterface(_Application, Access));
      AppWasRunning := True;
    end;
    Access.Visible := True;
    ...

Ohne Verwendung der Typbibliothek:

Automation ist sehr viel schneller und einfacher, wenn Typbibliotheken (frühe Bindung) verwendet werden, deshalb sollten Sie es, wenn immer möglich, vermeiden, ohne sie zu arbeiten. Aber wenn es wirklich nicht anders geht, hier, wie vorzugehen ist:

        var
          Access: Variant;
        begin
          try
            Access := GetActiveOleObject('Access.Application');
          except
            Access := CreateOleObject('Access.Application');
          end;
          Access.Visible := True;

Wie kann ich Access schließen?

Eine Application-Variable Access vorausgesetzt:

  Access.Quit(acQuitSaveAll);
  Access := nil;

Der Parameter der Quit-Methode ist vom Typ TOleNum und sollte einer der Werte acQuitSaveNone, acQuitSaveAll oder acQuitPrompt sein. Wenn Sie die Typbibliothek nicht verwenden, können Sie diese so deklarieren:

  const
    acQuitPrompt = $00000000;
    acQuitSaveAll = $00000001;
    acQuitSaveNone = $00000002;

Wie kann ich eine Datenbank öffnen?

Eine Applictaion-Variable Access vorausgesetzt:

Access.OpenCurrentDatabase('C:My DocumentsBooks.mdb', True);

Der zweite Parameter gibt an, ob Sie die Datei im Exklusiv-Modus öffnen wollen.

Wie kann ich eine Datenbank schließen?

Eine Application-Variable Access vorausgesetzt:

Access.CloseCurrentDatabase;

Wie kann ich einen Report öffnen?

Eine Application-Variable Access vorausgesetzt:

Access.DoCmd.OpenReport('Titles by Author', acViewPreview, EmptyParam, EmptyParam);

Der Wert des zweiten Parameters sollte acViewDesign, acViewNormal oder acViewPreview sein. acViewNormal, der Standard-Wert, druckt den Report sofort. Wenn Sie die Typbibliothek nicht verwenden, können Sie die Werte so definieren:

  const
    acViewNormal = $00000000;
    acViewDesign = $00000001;
    acViewPreview = $00000002;

Der dritte Parameter steht für den Namen einer Abfrage (Query) in der aktuellen Datenbank. Der vierte Parameter steht für eine SQL-WHERE-Abfrage – der String muss gültiges SQL ohne das WHERE sein.

Wie kann ich alle Reports und Forms auflisten?

Wenn Sie einmal eine Datenbank geöffnet haben, können Sie die Eigenschaften Reports und Forms von Access-Application verwenden, um die geöffneten Reports und Forms aufzulisten:

  for i := 0 to Access.Reports.Count - 1 do
    Memo1.Lines.Add(Access.Reports[i].Name);
  for i := 0 to Access.Forms.Count - 1 do
    Memo1.Lines.Add(Access.Forms[i].Name);

Beachten Sie aber, dass diese Eigenschaften nur die geöffneten Reports und Forms einer Datenbank zurückgeben. Um die geschlossenen zu erhalten, müssen Sie DAO97.pas (oder DAO_TLB.pas für Delphi 4) verwenden und auf die Documents-Sammlung zugreifen:

uses DAO97;
var
  i: integer;
  Cont: Container;
begin
  Cont := Access.CurrentDB.Containers.Item['Reports'];
  for i := 0 to Cont.Documents.Count - 1 do
    Memo1.Lines.Add(Cont.Documents[i].Name);
  Cont := Access.CurrentDB.Containers.Item['Forms'];
  for i := 0 to Cont.Documents.Count - 1 do
    Memo1.Lines.Add(Cont.Documents[i].Name);