Automatisieren von Microsoft Access mit Visual C #

Zusammenfassung

In diesem Artikel wird veranschaulicht, wie Sie Microsoft Access mithilfe von Microsoft Visual C# 2005 oder Microsoft Visual C# .NET automatisieren. In den Themen und im Beispielcode wird gezeigt, wie Sie Folgendes tun:

  • Öffnen Sie eine Datenbank in Access.
  • Drucken oder Anzeigen einer Vorschau eines Access-Berichts
  • Anzeigen und Bearbeiten eines Access-Formulars
  • Vermeiden Sie Dialogfelder, wenn Sie eine kennwortgeschützte Datenbank öffnen oder wenn die Sicherheit auf Benutzerebene aktiviert ist.
  • Automatisieren Sie die Access-Runtime.

Automatisierung im Vergleich zu ADO.NET

Ein Entwickler kann mit einer Microsoft Access-Datenbank aus Visual C# 2005 oder Visual C# .NET arbeiten, indem er zwei separate Technologien verwendet: Automatisierung und Microsoft ADO.NET.

ADO.NET ist die bevorzugte Technologie, wenn Sie mit Datenobjekten wie Tabellen und Abfragen in einer Access-Datenbank arbeiten möchten. Verwenden Sie Automatisierung nur, wenn Sie anwendungsspezifische Features von Microsoft Access benötigen, z. B. die Möglichkeit, einen Access-Bericht zu drucken oder in der Vorschau anzuzeigen, ein Access-Formular anzuzeigen oder Access-Makros aufzurufen.

In diesem Artikel wird erläutert, wie Access automatisiert wird. In diesem Artikel wird ADO.NET nicht behandelt. Wenn Sie Informationen zu ADO.NET benötigen, klicken Sie auf die folgenden Artikelnummern, um die Artikel in der Microsoft Knowledge Base anzuzeigen:

  • 306636 Herstellen einer Verbindung mit einer Datenbank und Ausführen eines Befehls mithilfe von ADO 2005 und Visual C# 2005 oder mithilfe von ADO.NET und Visual C# .NET

  • 314145 Auffüllen eines DataSet-Objekts aus einer Datenbank mithilfe von Visual C# .NET

  • 307587 Aktualisieren einer Datenbank aus einem DataSet-Objekt mit Visual C# 2005 oder Visual C# .NET

Automatisierung ist eine COM-Technologie (Component Object Model). Die Automatisierung ermöglicht es Anwendungen, die in Sprachen wie Visual C# .NET geschrieben wurden, andere Anwendungen programmgesteuert zu steuern. Wenn Sie eine Microsoft Office-Anwendung automatisieren, führen Sie tatsächlich eine Instanz dieser Anwendung im Arbeitsspeicher aus und rufen dann das Objektmodell der Anwendung auf, um verschiedene Aufgaben in dieser Anwendung auszuführen. Mit Access und anderen Microsoft Office-Anwendungen können nahezu alle Aktionen, die Sie manuell über die Benutzeroberfläche ausführen können, auch programmgesteuert mithilfe der Automatisierung ausgeführt werden.

Access macht diese programmgesteuerte Funktionalität über ein Objektmodell verfügbar. Das Objektmodell ist eine Auflistung von Klassen und Methoden, die als Gegenstück zu den logischen Komponenten von Access dienen. Um über Visual C# .NET auf das Objektmodell zuzugreifen, können Sie einen Projektverweise auf die Typbibliothek festlegen.

Allgemeine Automatisierungsaufgaben

Öffnen einer Datenbank in Access

Wenn Sie Microsoft Access automatisieren, müssen Sie eine Datenbank öffnen, bevor Sie nützliche Aufgaben wie das Drucken von Berichten ausführen können. Zum Öffnen einer Datenbank in der Instanz von Access, die Sie automatisieren, verwenden Sie die OpenCurrentDatabase- oder OpenAccessProject-Methoden des Application-Objekts. Sie können jeweils nur eine Datenbank in Access öffnen lassen. Um mit einer anderen Datenbank zu arbeiten, können Sie die CloseCurrentDatabase-Methode verwenden, bevor Sie eine andere öffnen.

Sie können auch die System.Runtime.InteropServices.Marshal.BindToMoniker(<path to database>)-Methode verwenden, um eine Datenbank in einer Instanz von Access zu öffnen. Wenn die Datenbank bereits in einer Instanz von Access geöffnet ist, gibt BindToMoniker das Application -Objekt dieser Instanz zurück. Andernfalls startet BindToMoniker eine neue Instanz von Access und öffnet die angegebene Datenbank.

OpenCurrentDatabase ist die bevorzugte Methode zum Öffnen einer Datenbank, da Sie die Instanz von Access angeben, die Sie automatisieren. Sie können auch Argumente angeben, um zu steuern, wie die Datenbank geöffnet wird, z. B.:

Access.Application oAccess = null;

// Start a new instance of Access for Automation:
oAccess = new Access.ApplicationClass();

// Open a database in exclusive mode:
oAccess.OpenCurrentDatabase(
   "c:\\mydb.mdb", //filepath
   true //Exclusive
   );

Zum Anzeigen einer Vorschau oder zum Drucken eines Access-Berichts rufen Sie die OpenReport-Methode des DoCmd-Objekts auf. Wenn Sie OpenReport aufrufen, bestimmt eines der übergebenen Argumente, ob der Bericht auf dem Bildschirm in der Vorschau angezeigt wird oder ob er an den Drucker gesendet wird:

// Preview a report named Sales:
oAccess.DoCmd.OpenReport(
   "Sales", //ReportName
   Access.AcView.acViewPreview, //View
   System.Reflection.Missing.Value, //FilterName
   System.Reflection.Missing.Value //WhereCondition
   );

// Print a report named Sales:
oAccess.DoCmd.OpenReport(
   "Sales", //ReportName
   Access.AcView.acViewNormal, //View
   System.Reflection.Missing.Value, //FilterName
   System.Reflection.Missing.Value //WhereCondition
   );

Beachten Sie, dass das Argument Ansicht bestimmt, ob der Bericht in Access angezeigt oder an den Drucker gesendet wird. Das WhereCondition-Argument kann das Recordset des Berichts einschränken, wenn Sie eine gültige SQL WHERE-Klausel (ohne das Wort WHERE) verwenden. Beachten Sie, dass Sie System.Reflection.Missing.Value verwenden können, um optionale Objektparameter zu überspringen.

Wenn Sie eine Vorschau eines Berichts anzeigen, müssen Sie die Visible-Eigenschaft des Application-Objekts so festlegen, dass Access auf dem Bildschirm sichtbar ist. Auf diese Weise kann der Benutzer den Bericht im Access-Fenster anzeigen.

Es gibt eine andere Möglichkeit, einen Bericht oder andere Objekte in der Datenbank zu drucken. Verwenden Sie die PrintOut-Methode des DoCmd-Objekts. In diesem Beispiel wählen Sie im Datenbankfenster einen Bericht mit dem Namen "Employees" aus, und rufen dann PrintOut auf, um das ausgewählte Objekt zu drucken. Mit der PrintOut-Methode können Sie Argumente angeben, die dem Dialogfeld "Drucken" in Access entsprechen:

// Select the Employees report in the database window:
oAccess.DoCmd.SelectObject(
   Access.AcObjectType.acReport, //ObjectType
   "Employees", //ObjectName
   true //InDatabaseWindow
   );

// Print 2 copies of the selected object:
oAccess.DoCmd.PrintOut(
   Access.AcPrintRange.acPrintAll, //PrintRange
   System.Reflection.Missing.Value, //PageFrom
   System.Reflection.Missing.Value, //PageTo
   Access.AcPrintQuality.acHigh, //PrintQuality
   2, //Copies
   false //CollateCopies
   );

Oder Sie möchten in einigen Fällen sowohl die OpenReport- als auch die PrintOut-Methode verwenden, um einen Bericht zu drucken. Angenommen, Sie möchten mehrere Kopien des Mitarbeiterberichts drucken, jedoch nur für einen bestimmten Mitarbeiter. In diesem Beispiel wird zuerst OpenReport verwendet, um den Mitarbeiterbericht im Vorschaumodus zu öffnen, wobei das WhereCondition-Argument verwendet wird, um die Datensätze auf einen bestimmten Mitarbeiter zu beschränken. Anschließend wird PrintOut verwendet, um mehrere Kopien des aktiven Objekts zu drucken:

// Open the report in preview mode using a WhereCondition:
oAccess.DoCmd.OpenReport(
   "Employees", //ReportName
   Access.AcView.acViewPreview, //View
   System.Reflection.Missing.Value, //FilterName
   "[EmployeeID]=1" //WhereCondition
   );

// Print 2 copies of the active object: 
oAccess.DoCmd.PrintOut(
   Access.AcPrintRange.acPrintAll, //PrintRange
   System.Reflection.Missing.Value, //PageFrom
   System.Reflection.Missing.Value, //PageTo
   Access.AcPrintQuality.acHigh, //PrintQuality
   2, //Copies
   false //CollateCopies
   );

// Close the report preview window: 
oAccess.DoCmd.Close(
   Access.AcObjectType.acReport, //ObjectType
   "Employees", //ObjectName
   Access.AcCloseSave.acSaveNo //Save
   );

In Access 2002 wurde das Printer-Objekt eingeführt. Sie können dieses Objekt verwenden, um access-Druckereinstellungen einfacher anzupassen als in früheren Versionen von Access. Wenn Sie ein Beispiel für die Verwendung des Printer-Objekts in Access zum Drucken eines Berichts verwenden möchten, klicken Sie auf die artikelnummer unten, um den Artikel in der Microsoft Knowledge Base anzuzeigen:

284286 Zurücksetzen von Änderungen am Application.Printer-Objekt

Anzeigen und Bearbeiten eines Access-Formulars

Visual C# .NET verfügt über sehr leistungsstarke Formularfunktionen. Es kann jedoch vorkommen, dass der Benutzer ein Formular anzeigen soll, das zuvor in Access entwickelt wurde. Oder Sie haben in Ihrer Access-Datenbank ein Formular, das Kriterien für eine Abfrage oder einen Bericht bereitstellt, und Sie müssen dieses Formular öffnen, bevor Sie den Bericht in der Vorschau anzeigen oder drucken können. Zum Öffnen und Anzeigen eines Access-Formulars rufen Sie die OpenForm-Methode des DoCmd-Objekts auf:

// Show a form named Employees:
oAccess.DoCmd.OpenForm(
   "Employees", //FormName
   Access.AcFormView.acNormal, //View
   System.Reflection.Missing.Value, //FilterName
   System.Reflection.Missing.Value, //WhereCondition
   Access.AcFormOpenDataMode.acFormPropertySettings, //DataMode
   Access.AcWindowMode.acWindowNormal, //WindowMode
   System.Reflection.Missing.Value //OpenArgs
   );

Sie können jetzt die Steuerelemente im Formular bearbeiten.

Dialogfelder für Zugriffssicherheit

Wenn Sie Access automatisieren, werden Sie möglicherweise aufgefordert, einen Benutzernamen oder ein Kennwort oder beides einzugeben, wenn Sie versuchen, eine Datenbank zu öffnen. Wenn der Benutzer die falschen Informationen eingibt, tritt in Ihrem Code ein Fehler auf. Es kann vorkommen, dass Sie diese Dialogfelder vermeiden und stattdessen den Benutzernamen und das Kennwort programmgesteuert angeben möchten, damit Ihr Automatisierungscode unterbrechungslos ausgeführt wird.

Es gibt zwei Arten von Sicherheit in Microsoft Access: kennwortgeschützte Datenbanken und Sicherheit auf Benutzerebene über eine Arbeitsgruppendatei (System.mdw). Wenn Sie versuchen, eine kennwortgeschützte Datenbank zu öffnen, erhalten Sie ein Dialogfeld, in dem Sie zum Eingeben des Datenbankkennworts aufgefordert werden. Die Sicherheit auf Benutzerebene unterscheidet sich von einer kennwortgeschützten Datenbank. Wenn die Sicherheit auf Benutzerebene aktiviert ist, zeigt Access ein Anmeldedialogfeld an, in dem sowohl ein Benutzername als auch ein Kennwort angezeigt werden, bevor der Benutzer eine Datenbank in Access öffnen kann.

Vermeiden von Dialogfeldern für Datenbankkennwörter

Wenn Sie eine Datenbank öffnen, die mit einem Kennwort geschützt wurde, können Sie das Dialogfeld vermeiden, indem Sie das Kennwort für die OpenCurrentDatabase-Methode angeben:

// Open a password-protected database in shared mode:
// Note: The bstrPassword argument is case-sensitive
oAccess.OpenCurrentDatabase(
   "c:\\mydb.mdb", //filepath
   false, //Exclusive
   "MyPassword" //bstrPassword
   );

Hier ist ein Beispiel, in dem oAccess zuvor auf eine Instanz von Access festgelegt wurde, die keine Datenbank geöffnet hat. Dieser Code stellt das Kennwort für die Datenbank bereit, um ein Dialogfeld zu vermeiden:

string sDBPassword = "MyPassword"; //database password
DAO._DBEngine oDBEngine = oAccess.DBEngine;
DAO.Database oDB = oDBEngine.OpenDatabase("c:\\mydb.mdb",
   false, false, ";PWD=" + sDBPassword);
oAccess.OpenCurrentDatabase("c:\\mydb.mdb", false);
oDB.Close();
System.Runtime.InteropServices.Marshal.ReleaseComObject(oDB);
oDB = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(oDBEngine);
oDBEngine = null;

Die oDB.Close schließt die Datenbank in Access nicht. Es wird nur die DAO-Verbindung mit der Datenbank geschlossen, die über das DBEngine-Objekt hergestellt wurde. Die DAO-Verbindung ist nach der Verwendung der OpenCurrentDatabase-Methode nicht mehr erforderlich. Beachten Sie den Code zum Freigeben der oDB- und oDBEngine-Objekte. Sie müssen diese Objekte verwenden, damit Access nach Abschluss des Codes ordnungsgemäß beendet wird.

Vermeiden von Anmeldedialogfeldern für die Zugriffssicherheit

Wenn die Sicherheit auf Benutzerebene in Access aktiviert ist, wird der Benutzer in einem Anmeldedialogfeld aufgefordert, sowohl einen Benutzernamen als auch ein Kennwort einzugeben. Ein Benutzername und ein Kennwort können nicht mithilfe des Access-Objektmodells angegeben werden. Wenn Sie daher beim Automatisieren von Access das Anmeldedialogfeld vermeiden möchten, müssen Sie zuerst die Msaccess.exe Datei starten und die Befehlszeilenoptionen /user und /pwd angeben, um den Benutzernamen und das Kennwort anzugeben. Anschließend können Sie GetActiveObject oder BindToMoniker verwenden, um das Application-Objekt der ausgeführten Instanz von Access abzurufen, sodass Sie dann mit der Automatisierung fortfahren können.

Automatisieren der Access-Runtime

Die Microsoft Office Developer Edition enthält die Microsoft Office Developer Tools (MOD). Mithilfe von MOD können Access-Entwickler Access-Anwendungen erstellen und an Benutzer verteilen, die nicht über die Einzelhandelsversion von Access verfügen. Wenn der Benutzer die Access-Anwendung auf einem Computer installiert, der nicht über die Einzelhandelsversion von Access verfügt, wird eine Laufzeitversion von Access installiert. Die Access-Runtime wird installiert und wie die Einzelhandelsversion registriert. Die ausführbare Datei wird auch als Msaccess.exe bezeichnet. Die Access-Runtime ermöglicht es einer Access-Anwendung, auf einem Clientcomputer ausgeführt zu werden, aber die Access-Runtime erlaubt es einem Benutzer nicht, neue Anwendungen zu entwickeln oder den Entwurf vorhandener Anwendungen zu ändern.

Die Access-Runtime muss mit einer Datenbank gestartet werden. Aufgrund dieser Anforderung müssen Sie, wenn Sie die Access-Runtime automatisieren möchten, die Msaccess.exe starten und eine Datenbank angeben, die geöffnet werden soll. Nachdem Sie getActiveObject oder BindToMoniker zum Abrufen des Application-Objekts verwendet haben, können Sie die Access-Runtime automatisieren. Wenn Sie diesen Ansatz nicht verwenden, wenn Sie versuchen, die Access-Runtime zu automatisieren, erhalten Sie eine Fehlermeldung wie die folgende, wenn Sie versuchen, die Instanz zu instanziieren:

System.Runtime.InteropServices.COMException (0x80080005) Serverausführung fehlgeschlagen.

Erstellen des vollständigen Beispiels für Visual C# 2005 oder Visual C# .NET Project

Um das folgende Schritt-für-Schritt-Beispiel zu verwenden, stellen Sie sicher, dass die Northwind-Beispieldatenbank installiert ist. Standardmäßig installiert Microsoft Access 2000 die Beispieldatenbanken im folgenden Pfad:

C:\Programme\Microsoft Office\Office\Samples

Microsoft Access 2002 verwendet den folgenden Pfad:

C:\Programme\Microsoft Office\Office10\Beispiele

Microsoft Office Access 2003 verwendet den folgenden Pfad:

C:\Programme\Microsoft\Office\Office11\Samples

Um sicherzustellen, dass die Northwind-Beispieldatenbank in Access 2002 oder Access 2003 installiert ist, klicken Sie im Menü "Hilfe" auf "Beispieldatenbanken" und dann auf "Northwind-Beispieldatenbank".

  1. Schließen Sie alle Instanzen von Access, die derzeit ausgeführt werden.

  2. Starten Sie Microsoft Visual Studio .NET.

  3. Klicken Sie im Menü Datei auf Neu, und klicken Sie dann auf Projekt. Wählen Sie "Windows-Anwendung" aus den Visual C#-Projekttypen aus. Standardmäßig wird Form1 erstellt.

    Hinweis Sie müssen den Code in Visual Studio 2005 ändern. Visual C# fügt dem Projekt standardmäßig ein Formular hinzu, wenn Sie ein Windows Forms Projekt erstellen. Das Formular heißt "Form1". Die beiden Dateien, die das Formular darstellen, heißen "Form1.cs" und "Form1.designer.cs". Sie schreiben den Code in Form1.cs. In der Datei "Form1.designer.cs" schreibt der Windows Forms-Designer den Code, der alle Aktionen implementiert, die Sie durch Ziehen und Ablegen von Steuerelementen aus der Toolbox ausgeführt haben.

    Weitere Informationen zum Windows Forms-Designer in Visual C# 2005 finden Sie auf der folgenden Microsoft Developer Network (MSDN)-Website:https://msdn.microsoft.com/en-us/library/ms173077.aspx

  4. Fügen Sie einen Verweis auf die Microsoft Access-Objektbibliothek hinzu. Gehen Sie dazu wie folgt vor:

    1. On the Project menu, click Add Reference.
    2. Suchen Sie auf der Registerkarte COM nach der Microsoft Access-Objektbibliothek, und klicken Sie dann auf "Auswählen".

    Hinweis In Visual Studio 2005. Sie müssen nicht auf "Auswählen" klicken.

    Hinweis Microsoft Office 2003 enthält primäre Interopassemblys (PRIMARY Interop Assemblies, PIAs). Microsoft Office XP enthält keine PIAs, sie können jedoch heruntergeladen werden.

  5. Klicken Sie im Dialogfeld "Verweise hinzufügen" auf "OK", um Ihre Auswahl zu übernehmen.

    Hinweis Wenn Sie auf die Access 10.0-Objektbibliothek verweisen und beim Versuch, den Verweis hinzuzufügen, Fehler erhalten.

  6. Klicken Sie im Menü "Ansicht" auf "Toolbox", um die Toolbox anzuzeigen.

  7. Fügen Sie Formular1 fünf Optionsfeld-Steuerelemente und ein Schaltflächensteuerelement hinzu.

  8. Wählen Sie alle Optionsfeldsteuerelemente aus, und legen Sie dann die Size-Eigenschaft auf 150,24 fest.

  9. Fügen Sie Ereignishandler für das Formularladeereignis und für das Click-Ereignis des Schaltflächen-Steuerelements hinzu:

    1. Doppelklicken Sie in der Entwurfsansicht für "Form1.cs" auf "Form1".

      Der Handler für das Load-Ereignis des Formulars wird erstellt und in Form1.cs angezeigt.

    2. Klicken Sie im Menü "Ansicht" auf "Designer", um zur Entwurfsansicht zu wechseln.

    3. Doppelklicken Sie auf Schaltfläche1.

      Der Handler für das Click-Ereignis der Schaltfläche wird erstellt und in Form1.cs angezeigt.

  10. Ersetzen Sie in Form1.cs den folgenden Code

    private void Form1_Load(object sender, System.EventArgs e)
    {
    
    }
    
    private void button1_Click(object sender, System.EventArgs e)
    {
    
    } 
    

    mit:

          private string msAction = null;
          // Commonly-used variable for optional arguments:
          private object moMissing = System.Reflection.Missing.Value;
    
    private void Form1_Load(object sender, System.EventArgs e)
          {
             radioButton1.Text = "Print report";
             radioButton2.Text = "Preview report";
             radioButton3.Text = "Show form";
             radioButton4.Text = "Print report (Security)";
             radioButton5.Text = "Preview report (Runtime)";
             button1.Text = "Go!";
             radioButton1.Click += new EventHandler(RadioButtons_Click);
             radioButton2.Click += new EventHandler(RadioButtons_Click);
             radioButton3.Click += new EventHandler(RadioButtons_Click);
             radioButton4.Click += new EventHandler(RadioButtons_Click);
             radioButton5.Click += new EventHandler(RadioButtons_Click);
          }
    
    private void RadioButtons_Click(object sender, System.EventArgs e)
          {
             RadioButton radioBtn = (RadioButton) sender;
             msAction = radioBtn.Text;
          }
    
    private void button1_Click(object sender, System.EventArgs e)
          {
             // Calls the associated procedure to automate Access, based
             // on the selected radio button on the form.
             switch(msAction)
             {
                case "Print report": Print_Report();
                   break;
                case "Preview report": Preview_Report();
                   break;
                case "Show form": Show_Form();
                   break;
                case "Print report (Security)": Print_Report_Security();
                   break;
                case "Preview report (Runtime)": Preview_Report_Runtime();
                   break;
             }
          }
    
    private void NAR(object o)
          {
             // Releases the Automation object.
             try // use try..catch in case o is not set
             {
                Marshal.ReleaseComObject(o);
             }
             catch{}
          }
    
    private Access.Application ShellGetDB(string sDBPath, string sCmdLine,
             ProcessWindowStyle enuWindowStyle, int iSleepTime)
          {
             //Launches a new instance of Access with a database (sDBPath)
             //using System.Diagnostics.Process.Start. Then, returns the
             //Application object via calling: BindToMoniker(sDBPath). Returns
             //the Application object of the new instance of Access, assuming that
             //sDBPath is not already opened in another instance of Access. To
             //ensure the Application object of the new instance is returned, make
             //sure sDBPath is not already opened in another instance of Access
             //before calling this function.
             // 
             //Example:
             //Access.Application oAccess = null;
             //oAccess = ShellGetDB("c:\\mydb.mdb", null,
             //  ProcessWindowStyle.Minimized, 1000);
    
    Access.Application oAccess = null;
             string sAccPath = null; //path to msaccess.exe
             Process p = null;
    
    // Enable exception handler:
             try
             {
                // Obtain the path to msaccess.exe:
                sAccPath = GetOfficeAppPath("Access.Application", "msaccess.exe");
                if (sAccPath == null)
    
    {
                   MessageBox.Show("Can't determine path to msaccess.exe");
                   return null;
                }
    
    // Make sure specified database (sDBPath) exists:
                if(!System.IO.File.Exists(sDBPath))
                {
                   MessageBox.Show("Can't find the file '" + sDBPath + "'");
                   return null;
                }
    
    // Start a new instance of Access passing sDBPath and sCmdLine:
                if(sCmdLine == null)
                   sCmdLine = @"""" + sDBPath + @"""";
                else
                   sCmdLine = @"""" + sDBPath + @"""" + " " + sCmdLine;
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = sAccPath;
                startInfo.Arguments = sCmdLine;
                startInfo.WindowStyle = enuWindowStyle;
                p = Process.Start(startInfo);
                p.WaitForInputIdle(60000); //max 1 minute wait for idle input state
    
    // Move focus back to this form. This ensures that Access
                // registers itself in the ROT:
                this.Activate();
    
    // Pause before trying to get Application object:
                System.Threading.Thread.Sleep(iSleepTime);
    
    // Obtain Application object of the instance of Access
                // that has the database open:
                oAccess = (Access.Application) Marshal.BindToMoniker(sDBPath);
                return oAccess;
             }
             catch(Exception e)
             {
                MessageBox.Show(e.Message);
                // Try to quit Access due to an unexpected error:
                try // use try..catch in case oAccess is not set
                {
                   oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch{}
                NAR(oAccess);
                oAccess = null;
                return null;
             }
          }
    
    private Access.Application ShellGetApp(string sCmdLine,
             ProcessWindowStyle enuWindowStyle)
          {
             //Launches a new instance of Access using System.Diagnostics.
             //Process.Start then returns the Application object via calling:
             //GetActiveObject("Access.Application"). If an instance of
             //Access is already running before calling this function,
             //the function may return the Application object of a
             //previously running instance of Access. If this is not
             //desired, then make sure Access is not running before
             //calling this function, or use the ShellGetDB()
             //function instead. Approach based on Q316125.
             // 
             //Examples:
             //Access.Application oAccess = null;
             //oAccess = ShellGetApp("/nostartup",
             //  ProcessWindowStyle.Minimized);
             // 
             //-or-
             // 
             //Access.Application oAccess = null;
             //string sUser = "Admin";
             //string sPwd = "mypassword";
             //oAccess = ShellGetApp("/nostartup /user " + sUser + "/pwd " + sPwd,
             //  ProcessWindowStyle.Minimized);
    
    Access.Application oAccess = null;
             string sAccPath = null; //path to msaccess.exe
             Process p = null;
             int iMaxTries = 20; //max GetActiveObject attempts before failing
             int iTries = 0; //GetActiveObject attempts made
    
    // Enable exception handler:
             try
             {
                // Obtain the path to msaccess.exe:
                sAccPath = GetOfficeAppPath("Access.Application", "msaccess.exe");
                if(sAccPath == null)
                {
                   MessageBox.Show("Can't determine path to msaccess.exe");
                   return null;
                }
    
    // Start a new instance of Access passing sCmdLine:
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = sAccPath;
                startInfo.Arguments = sCmdLine;
                startInfo.WindowStyle = enuWindowStyle;
                p = Process.Start(startInfo);
                p.WaitForInputIdle(60000); //max 1 minute wait for idle input state
    
    // Move focus back to this form. This ensures that Access
                // registers itself in the ROT:
                this.Activate();
    
    tryGetActiveObject:
                // Enable exception handler:
                try
                {   
                   // Attempt to use GetActiveObject to reference a running
                   // instance of Access:
                   oAccess = (Access.Application)
                      Marshal.GetActiveObject("Access.Application");
                }
                catch
                {
                   //GetActiveObject may have failed because enough time has not
                   //elapsed to find the running Office application. Wait 1/2
                   //second and retry the GetActiveObject. If you try iMaxTries
                   //times and GetActiveObject still fails, assume some other
                   //reason for GetActiveObject failing and exit the procedure.
                   iTries++;
                   if(iTries < iMaxTries)
                   {
                      System.Threading.Thread.Sleep(500); //wait 1/2 second
                      this.Activate();
                      goto tryGetActiveObject;
                   }
                   MessageBox.Show("Unable to GetActiveObject after " +
                      iTries + " tries.");
                   return null;
                }
    
    // Return the Access Application object:
                return oAccess;
             }
             catch(Exception e)
             {
                MessageBox.Show(e.Message);
                // Try to quit Access due to an unexpected error:
                try // use try..catch in case oAccess is not set
                {
                   oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch{}
                NAR(oAccess);
                oAccess = null;
                return null;
             }
          }
    
    private string GetOfficeAppPath(string sProgId, string sEXE)
          {
             //Returns path of the Office application. e.g.
             //GetOfficeAppPath("Access.Application", "msaccess.exe") returns
             //full path to Microsoft Access. Approach based on Q240794.
             //Returns null if path not found in registry.
    
    // Enable exception handler:
             try
             {
                Microsoft.Win32.RegistryKey oReg = 
                   Microsoft.Win32.Registry.LocalMachine;
                Microsoft.Win32.RegistryKey oKey = null;
                string sCLSID = null;
                string sPath = null;
                int iPos = 0;
    
    // First, get the clsid from the progid from the registry key
                // HKEY_LOCAL_MACHINE\Software\Classes\<PROGID>\CLSID:
                oKey = oReg.OpenSubKey(@"Software\Classes\" + sProgId + @"\CLSID");
                sCLSID = oKey.GetValue("").ToString();
                oKey.Close();
    
    // Now that we have the CLSID, locate the server path at
                // HKEY_LOCAL_MACHINE\Software\Classes\CLSID\ 
                // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx}\LocalServer32:
                oKey = oReg.OpenSubKey(@"Software\Classes\CLSID\" + sCLSID +
                   @"\LocalServer32");
                sPath = oKey.GetValue("").ToString();
                oKey.Close();
    
    // Remove any characters beyond the exe name:
                iPos = sPath.ToUpper().IndexOf(sEXE.ToUpper()); // 0-based position
                sPath = sPath.Substring(0, iPos + sEXE.Length);
                return sPath.Trim();
             }
             catch
             {
                return null;
             }
          }
    
    private void Print_Report()
          {
             // Prints the "Summary of Sales by Year" report in Northwind.mdb.
    
    Access.Application oAccess = null;
             string sDBPath = null; //path to Northwind.mdb
             string sReport = null; //name of report to print
    
    // Enable exception handler:
             try
             {
                sReport = "Summary of Sales by Year";
    
    // Start a new instance of Access for Automation:
                oAccess = new Access.ApplicationClass();
    
    // Determine the path to Northwind.mdb:
                sDBPath = oAccess.SysCmd(Access.AcSysCmdAction.acSysCmdAccessDir,
                   moMissing, moMissing).ToString();
                sDBPath = sDBPath + @"Samples\Northwind.mdb";
    
    // Open Northwind.mdb in shared mode:
                oAccess.OpenCurrentDatabase(sDBPath, false, "");
                // If using Access 10.0 object library, use this instead:
                //oAccess.OpenCurrentDatabase(sDBPath, false, null);
    
    // Select the report name in the database window and give focus
                // to the database window:
                oAccess.DoCmd.SelectObject(Access.AcObjectType.acReport, sReport, true);
    
    // Print the report:
                oAccess.DoCmd.OpenReport(sReport,
                   Access.AcView.acViewNormal, moMissing, moMissing, 
                   Access.AcWindowMode.acWindowNormal, moMissing);
                // If using Access 10.0 object library, use this instead:
                //oAccess.DoCmd.OpenReport(sReport,
                //  Access.AcView.acViewNormal, moMissing, moMissing,
                //  Access.AcWindowMode.acWindowNormal, moMissing);
             }
             catch(Exception e)
             {
                MessageBox.Show(e.Message);
             }
             finally
             {
                // Release any Access objects and quit Access:
                try // use try..catch in case oAccess is not set
                {
                   oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch{}
                NAR(oAccess);
                oAccess = null;
             }
          }
    
    private void Preview_Report()
          {
             // Previews the "Summary of Sales by Year" report in Northwind.mdb.
    
    Access.Application oAccess = null;
             Access.Form oForm = null;
             string sDBPath = null; //path to Northwind.mdb
             string sReport = null; //name of report to preview
    
    // Enable exception handler:
             try
             {
                sReport = "Summary of Sales by Year";
    
    // Start a new instance of Access for Automation:
                oAccess = new Access.ApplicationClass();
    
    // Make sure Access is visible:
                if(!oAccess.Visible) oAccess.Visible = true;
    
    // Determine the path to Northwind.mdb:
                sDBPath = oAccess.SysCmd(Access.AcSysCmdAction.acSysCmdAccessDir,
                   moMissing, moMissing).ToString();
                sDBPath = sDBPath + @"Samples\Northwind.mdb";
    
    // Open Northwind.mdb in shared mode:
                oAccess.OpenCurrentDatabase(sDBPath, false, "");
                // If using Access 10.0 object library, use this instead:
                //oAccess.OpenCurrentDatabase(sDBPath, false, null);
    
    // Close any forms that Northwind may have opened:
                while(oAccess.Forms.Count > 0)
                {   
                   oForm = oAccess.Forms[0];
                   oAccess.DoCmd.Close(Access.AcObjectType.acForm,
                      oForm.Name, Access.AcCloseSave.acSaveNo);
                   NAR(oForm);
                   oForm = null;
                }
    
    // Select the report name in the database window and give focus
                // to the database window:
                oAccess.DoCmd.SelectObject(Access.AcObjectType.acReport, sReport, true);
    
    // Maximize the Access window:
                oAccess.RunCommand(Access.AcCommand.acCmdAppMaximize);
    
    // Preview the report:
                oAccess.DoCmd.OpenReport(sReport,
                   Access.AcView.acViewPreview, moMissing, moMissing, 
                   Access.AcWindowMode.acWindowNormal, moMissing);
                // If using Access 10.0 object library, use this instead:
                //oAccess.DoCmd.OpenReport(sReport,
                //  Access.AcView.acViewPreview, moMissing, moMissing,
                //  Access.AcWindowMode.acWindowNormal, moMissing);
    
    // Maximize the report window:
                oAccess.DoCmd.Maximize();
    
    // Hide Access menu bar:
                oAccess.CommandBars["Menu Bar"].Enabled = false;
                // Also hide NorthWindCustomMenuBar if it is available:
                try
                {
                   oAccess.CommandBars["NorthwindCustomMenuBar"].Enabled = false;
                }
                catch{}
    
    // Hide Report's Print Preview menu bar:
                oAccess.CommandBars["Print Preview"].Enabled = false;
    
    // Hide Report's right-click popup menu:
                oAccess.CommandBars["Print Preview Popup"].Enabled = false;
    
    // Release Application object and allow Access to be closed by user:
                if(!oAccess.UserControl) oAccess.UserControl = true;
                NAR(oAccess);
                oAccess = null;
             }
             catch(Exception e)
             {
                MessageBox.Show(e.Message);
                // Release any Access objects and quit Access due to error:
                NAR(oForm);
                oForm = null;
                try // use try..catch in case oAccess is not set
                {
                   oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch{}
                NAR(oAccess);
                oAccess = null;
             }
          }
    
    private void Show_Form()
          {
             // Shows the "Customer Labels Dialog" form in Northwind.mdb
             // and manipulates controls on the form.
    
    Access.Application oAccess = null;
             Access.Form oForm = null;
             Access.Controls oCtls = null;
             Access.Control oCtl = null;
             string sDBPath = null; //path to Northwind.mdb
             string sForm = null; //name of form to show
    
    // Enable exception handler:
             try
             {
                sForm = "Customer Labels Dialog";
    
    // Start a new instance of Access for Automation:
                oAccess = new Access.ApplicationClass();
    
    // Make sure Access is visible:
                if(!oAccess.Visible) oAccess.Visible = true;
    
    // Determine the path to Northwind.mdb:
                sDBPath = oAccess.SysCmd(Access.AcSysCmdAction.acSysCmdAccessDir,
                   moMissing, moMissing).ToString();
                sDBPath = sDBPath + @"Samples\Northwind.mdb";
    
    // Open Northwind.mdb in shared mode:
                oAccess.OpenCurrentDatabase(sDBPath, false, "");
                // If using Access 10.0 object library, use this instead:
                //oAccess.OpenCurrentDatabase(sDBPath, false, null);
    
    // Close any forms that Northwind may have opened:
                while(oAccess.Forms.Count > 0)
                {   
                   oForm = oAccess.Forms[0];
                   oAccess.DoCmd.Close(Access.AcObjectType.acForm,
                      oForm.Name, Access.AcCloseSave.acSaveNo);
                   NAR(oForm);
                   oForm = null;
                }
    
    // Select the form name in the database window and give focus
                // to the database window:
                oAccess.DoCmd.SelectObject(Access.AcObjectType.acForm, sForm, true);
    
    // Show the form:
                oAccess.DoCmd.OpenForm(sForm, Access.AcFormView.acNormal, moMissing,
                   moMissing, Access.AcFormOpenDataMode.acFormPropertySettings,
                   Access.AcWindowMode.acWindowNormal, moMissing);
    
    // Use Controls collection to edit the form:
    
    oForm = oAccess.Forms[sForm];
                oCtls = oForm.Controls;
    
    // Set PrintLabelsFor option group to Specific Country:
    
    oCtl = (Access.Control)oCtls["PrintLabelsFor"];
                object[] Parameters = new Object[1];
                Parameters[0] = 2; //second option in option group
                oCtl.GetType().InvokeMember("Value", BindingFlags.SetProperty,
                   null, oCtl, Parameters);
                NAR(oCtl);
                oCtl = null;
    
    // Put USA in the SelectCountry combo box:
                oCtl = (Access.Control)oCtls["SelectCountry"];
                Parameters[0] = true;
                oCtl.GetType().InvokeMember("Enabled", BindingFlags.SetProperty,
                   null, oCtl, Parameters);
                oCtl.GetType().InvokeMember("SetFocus", BindingFlags.InvokeMethod,
                   null, oCtl, null);
                Parameters[0] = "USA";
                oCtl.GetType().InvokeMember("Value", BindingFlags.SetProperty,
                   null, oCtl, Parameters);
                NAR(oCtl);
                oCtl = null;
    
    // Hide the Database Window:
                oAccess.DoCmd.SelectObject(Access.AcObjectType.acForm, sForm, true);
                oAccess.RunCommand(Access.AcCommand.acCmdWindowHide);
    
    // Set focus back to the form:
                oForm.SetFocus();
    
    // Release Controls and Form objects:       
                NAR(oCtls);
                oCtls = null;
                NAR(oForm);
                oForm = null;
    
    // Release Application object and allow Access to be closed by user:
                if(!oAccess.UserControl) oAccess.UserControl = true;
                NAR(oAccess);
                oAccess = null;
             }
             catch(Exception e)
             {
                MessageBox.Show(e.Message);
                // Release any Access objects and quit Access due to error:
                NAR(oCtl);
                oCtl = null;
                NAR(oCtls);
                oCtls = null;
                NAR(oForm);
                oForm = null;
                try // use try..catch in case oAccess is not set
                {
                   oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch{}
                NAR(oAccess);
                oAccess = null;
             }
          }
    
    private void Print_Report_Security()
          {
             //Shows how to automate Access when user-level
             //security is enabled and you wish to avoid the logon
             //dialog asking for user name and password. In this
             //example we're assuming default security so we simply
             //pass the Admin user with a blank password to print the
             //"Summary of Sales by Year" report in Northwind.mdb.
    
    Access.Application oAccess = null;
             string sDBPath = null; //path to Northwind.mdb
             string sUser = null; //user name for Access security
             string sPwd = null; //user password for Access security
             string sReport = null; //name of report to print
    
    // Enable exception handler:
             try
             {
                sReport = "Summary of Sales by Year";
    
    // Determine the path to Northwind.mdb:
                sDBPath = GetOfficeAppPath("Access.Application", "msaccess.exe");
                if(sDBPath == null)
                {
                   MessageBox.Show("Can't determine path to msaccess.exe");
                   return;
                }
                sDBPath = sDBPath.Substring(0, sDBPath.Length - "msaccess.exe".Length)
                   + @"Samples\Northwind.mdb";
                if(!System.IO.File.Exists(sDBPath))
                {
                   MessageBox.Show("Can't find the file '" + sDBPath + "'");
                   return;
                }
    
    // Specify the user name and password for the Access workgroup
                // information file, which is used to implement Access security.
                // Note: If you are not using the system.mdw in the default
                // location, you may include the /wrkgrp command-line switch to
                // point to a different workgroup information file.
                sUser = "Admin";
                sPwd = "";
    
    // Start a new instance of Access with user name and password:
                oAccess = ShellGetDB(sDBPath, "/user " + sUser + " /pwd " + sPwd,
                   ProcessWindowStyle.Minimized, 1000);
                //or
                //oAccess = ShellGetApp(@"""" + sDBPath + @"""" + 
                //  " /user " + sUser + " /pwd " + sPwd,
                //  ProcessWindowStyle.Minimized);
    
    // Select the report name in the database window and give focus
                // to the database window:
                oAccess.DoCmd.SelectObject(Access.AcObjectType.acReport, sReport, true);
    
    // Print the report:
                oAccess.DoCmd.OpenReport(sReport,
                   Access.AcView.acViewNormal, moMissing, moMissing,
                   Access.AcWindowMode.acWindowNormal, moMissing );
                // If using Access 10.0 object library, use this instead:                       
                //oAccess.DoCmd.OpenReport(sReport,
                //  Access.AcView.acViewNormal, moMissing, moMissing,
                //  Access.AcWindowMode.acWindowNormal, moMissing);
             }
             catch(Exception e)
             {   
                MessageBox.Show(e.Message);
             }
             finally
             {
                // Release any Access objects and quit Access:
                try // use try..catch in case oAccess is not set
                {
                   oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch{}
                NAR(oAccess);
                oAccess = null;
             }
          }
    
    private void Preview_Report_Runtime()
          {
             //Shows how to automate the Access Runtime to preview
             //the "Summary of Sales by Year" report in Northwind.mdb.
    
    Access.Application oAccess = null;
             Access.Form oForm = null;
             string sDBPath = null; //path to Northwind.mdb
             string sReport = null; //name of report to preview
    
    // Enable exception handler:
             try
             {
                sReport = "Summary of Sales by Year";
    
    // Determine the path to Northwind.mdb:
                sDBPath = GetOfficeAppPath("Access.Application", "msaccess.exe");
                if(sDBPath == null)
                {
                   MessageBox.Show("Can't determine path to msaccess.exe");
                   return;
                }
    
    sDBPath = sDBPath.Substring(0, sDBPath.Length - "msaccess.exe".Length)
                   + @"Samples\Northwind.mdb";
                if(!System.IO.File.Exists(sDBPath))
                {
                   MessageBox.Show("Can't find the file '" + sDBPath + "'");
                   return;
                }
    
    // Start a new instance of Access with a database. If the
                // retail version of Access is not installed, and only the
                // Access Runtime is installed, launches a new instance
                // of the Access Runtime (/runtime switch is optional):
                oAccess = ShellGetDB(sDBPath, "/runtime",
                   ProcessWindowStyle.Minimized, 1000);
                //or
                //oAccess = ShellGetApp(@"""" + sDBPath + @"""" + " /runtime",
                //  ProcessWindowStyle.Minimized);
    
    // Make sure Access is visible:
                if(!oAccess.Visible) oAccess.Visible = true;
    
    // Close any forms that Northwind may have opened:
                while(oAccess.Forms.Count > 0)
                {   
                   oForm = oAccess.Forms[0];
                   oAccess.DoCmd.Close(Access.AcObjectType.acForm,
                      oForm.Name, Access.AcCloseSave.acSaveNo);
                   NAR(oForm);
                   oForm = null;
                }
    
    // Select the report name in the database window and give focus
                // to the database window:
                oAccess.DoCmd.SelectObject(Access.AcObjectType.acReport, sReport, true);
    
    // Maximize the Access window:
                oAccess.RunCommand(Access.AcCommand.acCmdAppMaximize);
    
    // Preview the report:
                oAccess.DoCmd.OpenReport(sReport,
                   Access.AcView.acViewPreview, moMissing, moMissing,
                   Access.AcWindowMode.acWindowNormal, moMissing );
                // If using Access 10.0 object library, use this instead:
                //oAccess.DoCmd.OpenReport(sReport,
                //  Access.AcView.acViewPreview, moMissing, moMissing,
                //  Access.AcWindowMode.acWindowNormal, moMissing);
    
    // Maximize the report window:
                oAccess.DoCmd.Maximize();
    
    // Hide Access menu bar:
                oAccess.CommandBars["Menu Bar"].Enabled = false;
                // Also hide NorthWindCustomMenuBar if it is available:
                try
                {
                   oAccess.CommandBars["NorthwindCustomMenuBar"].Enabled = false;
                }
                catch{}
    
    // Release Application object and allow Access to be closed by user:
                if(!oAccess.UserControl) oAccess.UserControl = true;
                NAR(oAccess);
                oAccess =  null;
             }
             catch(Exception e)
             {
                MessageBox.Show(e.Message);
                // Release any Access objects and quit Access due to error:
                NAR(oForm);
                oForm = null;
                try // use try..catch in case oAccess is not set
                {
                   oAccess.Quit(Access.AcQuitOption.acQuitSaveNone);
                }
                catch{}
                NAR(oAccess);
                oAccess = null;
             }
          }
    
    
  11. Fügen Sie den Using-Direktiven in Form1.cs den folgenden Code hinzu:

    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Reflection; 
    
  12. Drücken Sie F5, um das Programm zu erstellen und auszuführen. Form1 wird angezeigt.

  13. Klicken Sie auf "Bericht drucken" und dann auf "Los!". Die Print_Report Prozedur druckt einen Bericht aus der Northwind-Datenbank.

  14. Klicken Sie auf "Vorschaubericht" und dann auf "Gehe zu!". Die Preview_Report Prozedur enthält eine Vorschau eines Berichts aus der Northwind-Datenbank. Schließen Sie die Access-Instanz, wenn Sie bereit sind, den Vorgang fortzusetzen.

  15. Klicken Sie auf "Formular anzeigen" und dann auf "Los!". Das Show_Form-Verfahren zeigt das Dialogfeld "Kundenbezeichnungen" aus der Northwind-Datenbank an. Außerdem wird die Optionsgruppe im Formular auf "Bestimmtes Land" festgelegt und in der Liste "USA" ausgewählt. Schließen Sie die Access-Instanz, wenn Sie bereit sind, den Vorgang fortzusetzen.

  16. Klicken Sie auf "Bericht drucken" (Sicherheit) und dann auf "Los!". Das Print_Report_Security-Verfahren zeigt Ihnen, wie Sie Access automatisieren und das Anmeldedialogfeld vermeiden, wenn die Sicherheit auf Benutzerebene aktiviert ist. Nehmen Sie in diesem Beispiel die Standardanmeldung an, indem Sie dem Benutzer Admin mit einem leeren Kennwort übergeben. Der Code druckt dann einen Bericht in der Northwind-Datenbank.

  17. Klicken Sie auf "Vorschaubericht (Laufzeit)", und klicken Sie dann auf "Gehe zu!". Das Preview_Report_Runtime-Verfahren zeigt Ihnen, wie Sie die Access-Runtime automatisieren, um eine Vorschau eines Berichts in der Northwind-Datenbank anzuzeigen. Wenn die Einzelhandelsversion von Access installiert ist, funktioniert das Verfahren weiterhin ordnungsgemäß. Schließen Sie die Instanz von Access, wenn Sie bereit sind, den Vorgang fortzusetzen.

References

Weitere Informationen finden Sie auf der folgenden MSDN-Website: Microsoft Office Development with Visual Studio https://msdn.microsoft.com/en-us/library/aa188489(office.10).aspxFor more information, click the following article numbers to view the articles in the Microsoft Knowledge Base:

317109 Office-Anwendung wird nach der Automatisierung über den .NET-Client von Visual Studio nicht beendet

316126 Verwendung von Visual C# zum Automatisieren einer ausgeführten Instanz eines Office-Programms