Automatización de Microsoft Access mediante Visual C #

Resumen

En este artículo se muestra cómo automatizar Microsoft Access mediante Microsoft Visual C# 2005 o Microsoft Visual C# .NET. Los temas y el código de ejemplo muestran cómo hacer lo siguiente:

  • Abra una base de datos en Access.
  • Imprimir o obtener una vista previa de un informe de Access.
  • Mostrar y editar un formulario de Access.
  • Evite cuadros de diálogo al abrir una base de datos protegida con contraseña o cuando la seguridad de nivel de usuario esté activada.
  • Automatice el entorno de ejecución de Access.

Automatización frente a ADO.NET

Un desarrollador puede trabajar con una base de datos de Microsoft Access desde Visual C# 2005 o Visual C# .NET mediante dos tecnologías independientes: Automation y Microsoft ADO.NET.

ADO.NET es la tecnología preferida si desea trabajar con objetos de datos, como tablas y consultas en una base de datos de Access. Use Automation solo si necesita características específicas de la aplicación de Microsoft Access, como la capacidad de imprimir o obtener una vista previa de un informe de Access, mostrar un formulario de Access o llamar a macros de Access.

En este artículo se describe cómo automatizar Access. En el artículo no se describen ADO.NET. Para obtener información sobre ADO.NET, haga clic en los números de artículo siguientes para ver los artículos de Microsoft Knowledge Base:

  • 306636 Conexión a una base de datos y ejecución de un comando mediante ADO 2005 y Visual C# 2005 o mediante ADO.NET y Visual C# .NET

  • 314145 Cómo rellenar un objeto DataSet desde una base de datos mediante Visual C# .NET

  • 307587 Actualización de una base de datos desde un objeto DataSet mediante Visual C# 2005 o Visual C# .NET

Automation es una tecnología de modelo de objetos componentes (COM). La automatización permite que las aplicaciones escritas en lenguajes como Visual C# .NET controlen mediante programación otras aplicaciones. Al automatizar una aplicación de Microsoft Office, realmente ejecuta una instancia de esa aplicación en memoria y, a continuación, llama al modelo de objetos de la aplicación para realizar varias tareas en esa aplicación. Con Access y otras aplicaciones de Microsoft Office, prácticamente todas las acciones que se pueden realizar manualmente a través de la interfaz de usuario también se pueden realizar mediante programación mediante Automation.

Access expone esta funcionalidad mediante programación a través de un modelo de objetos. El modelo de objetos es una colección de clases y métodos que sirven como homólogos de los componentes lógicos de Access. Para acceder al modelo de objetos desde Visual C# .NET, puede establecer una referencia de proyecto a la biblioteca de tipos.

Tareas comunes de Automatización

Abrir una base de datos en Access

Al automatizar Microsoft Access, debe abrir una base de datos para poder realizar tareas útiles, como la impresión de informes. Para abrir una base de datos en la instancia de Access que va a automatizar, use los métodos OpenCurrentDatabase o OpenAccessProject del objeto Application. Solo puede tener una base de datos abierta en Access a la vez. Para trabajar con otra base de datos, puede usar el método CloseCurrentDatabase antes de abrir otra.

También puede usar el método System.Runtime.InteropServices.Marshal.BindToMoniker(<path to database>) para abrir una base de datos en una instancia de Access. Si la base de datos ya está abierta en una instancia de Access, BindToMoniker devuelve el objeto Application de esa instancia. De lo contrario, BindToMoniker inicia una nueva instancia de Access y abre la base de datos especificada.

OpenCurrentDatabase es el método preferido para abrir una base de datos, ya que se especifica la instancia de Access que se va a automatizar. También puede proporcionar argumentos para controlar cómo se abre la base de datos, por ejemplo:

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
   );

Para obtener una vista previa o imprimir un informe de Access, llame al método OpenReport del objeto DoCmd. Al llamar a OpenReport, uno de los argumentos que se pasan determina si el informe está en vista previa en la pantalla o si se envía a la impresora:

// 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
   );

Observe que el argumento View determina si el informe se muestra en Access o si se envía a la impresora. El argumento WhereCondition puede limitar el conjunto de registros del informe, si usa una cláusula WHERE de SQL válida (sin la palabra WHERE). Observe que puede usar System.Reflection.Missing.Value para omitir los parámetros de objeto que sean opcionales.

Si va a obtener una vista previa de un informe, asegúrese de establecer la propiedad Visible del objeto Application para que Access esté visible en la pantalla. De este modo, el usuario puede ver el informe en la ventana Acceso.

Hay otra manera de imprimir un informe u otros objetos en la base de datos. Use el método PrintOut del objeto DoCmd. En este ejemplo, seleccione un informe denominado Empleados en la ventana Base de datos y, a continuación, llame a PrintOut para imprimir el objeto seleccionado. El método PrintOut permite proporcionar argumentos que corresponden al cuadro de diálogo Imprimir de Access:

// 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
   );

O bien, en algunos casos, es posible que desee usar los métodos OpenReport y PrintOut para imprimir un informe. Supongamos que desea imprimir varias copias del informe Empleados, pero solo para un empleado específico. En este ejemplo, primero se usa OpenReport para abrir el informe Empleados en modo de vista previa, usando el argumento WhereCondition para limitar los registros a un empleado específico. A continuación, PrintOut se usa para imprimir varias copias del objeto activo:

// 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
   );

Access 2002 introdujo el objeto Printer. Puede usar este objeto para personalizar la configuración de la impresora de Access más fácilmente que en versiones anteriores de Access. Para obtener un ejemplo del uso del objeto Printer en Access para imprimir un informe, haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:

284286 Cómo restablecer los cambios en el objeto Application.Printer

Mostrar y editar un formulario de acceso

Visual C# .NET tiene funcionalidades de formulario muy eficaces. Sin embargo, puede haber ocasiones en las que desee que el usuario vea un formulario que se desarrolló anteriormente en Access. O bien, puede que tenga un formulario en la base de datos de Access que proporcione criterios para una consulta o informe, y debe abrir ese formulario para poder obtener una vista previa o imprimir el informe. Para abrir y mostrar un formulario de Access, llame al método OpenForm del objeto DoCmd:

// 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
   );

Ahora puede editar los controles del formulario.

Cuadros de diálogo Seguridad de acceso

Al automatizar Access, es posible que se le pida que escriba un nombre de usuario o una contraseña, o ambos, al intentar abrir una base de datos. Si el usuario escribe la información incorrecta, se producirá un error en el código. Puede haber ocasiones en las que quiera evitar estos cuadros de diálogo y, en su lugar, proporcionar mediante programación el nombre de usuario y la contraseña para que el código de Automation se ejecute sin interrupciones.

Hay dos tipos de seguridad en Microsoft Access: bases de datos protegidas con contraseña y seguridad de nivel de usuario a través de un archivo de grupo de trabajo (System.mdw). Si intenta abrir una base de datos protegida con contraseña, recibirá un cuadro de diálogo que le pedirá la contraseña de la base de datos. La seguridad de nivel de usuario es diferente de una base de datos protegida con contraseña. Cuando se activa la seguridad de nivel de usuario, Access muestra un cuadro de diálogo de inicio de sesión que solicita un nombre de usuario y una contraseña antes de que el usuario pueda abrir cualquier base de datos en Access.

Evitar la contraseña de la base de datos cuadros de diálogo

Si va a abrir una base de datos protegida con una contraseña, puede evitar el cuadro de diálogo proporcionando la contraseña al método OpenCurrentDatabase:

// 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
   );

Este es un ejemplo, donde oAccess se ha establecido previamente en una instancia de Access que no tiene una base de datos abierta. Este código proporciona la contraseña a la base de datos para evitar un cuadro de diálogo:

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;

ODB.Close no cierra realmente la base de datos en Access. Solo cierra la conexión DAO a la base de datos que se realizó a través del objeto DBEngine. La conexión DAO ya no es necesaria después de usar el método OpenCurrentDatabase. Observe el código para liberar los objetos oDB y oDBEngine. Debe usar estos objetos para que Access salga correctamente una vez completado el código.

Evitar los cuadros de diálogo de inicio de sesión de seguridad de acceso

Si la seguridad de nivel de usuario está activada en Access, se le pedirá al usuario un cuadro de diálogo de inicio de sesión, solicitando un nombre de usuario y una contraseña. No se puede especificar un nombre de usuario y una contraseña mediante el modelo de objetos de Access. Por lo tanto, si desea evitar el cuadro de diálogo de inicio de sesión al automatizar Access, primero debe iniciar el archivo Msaccess.exe y proporcionar los modificadores de línea de comandos /user y /pwd para especificar el nombre de usuario y la contraseña. Después, puede usar GetActiveObject o BindToMoniker para recuperar el objeto Application de la instancia en ejecución de Access, de modo que pueda continuar con Automation.

Automatización del entorno de ejecución de acceso

Microsoft Office Developer Edition incluye Microsoft Office Developer Tools (MOD). Con MOD, los desarrolladores de Access pueden crear y distribuir aplicaciones de Access a los usuarios que no tengan la versión comercial de Access. Cuando el usuario instala la aplicación de Access en un equipo que no tiene la versión comercial de Access, se instala una versión en tiempo de ejecución de Access. Access Runtime está instalado y está registrado como la versión comercial. El ejecutable también se denomina Msaccess.exe. Access Runtime permite que una aplicación de Access se ejecute en un equipo cliente, pero Access Runtime no permite a un usuario desarrollar nuevas aplicaciones ni modificar el diseño de las aplicaciones existentes.

Access Runtime debe iniciarse con una base de datos. Debido a este requisito, si desea automatizar Access Runtime, debe iniciar el Msaccess.exe y especificar una base de datos para abrir. Después de usar GetActiveObject o BindToMoniker para recuperar el objeto Application, puede automatizar access runtime. Si no usa este enfoque al intentar automatizar Access Runtime, recibirá un mensaje de error como el siguiente al intentar crear una instancia de la instancia:

Error en la ejecución del servidor System.Runtime.InteropServices.COMException (0x80080005).

Creación del proyecto completo de Visual C# 2005 o Visual C# .NET

Para usar el ejemplo paso a paso siguiente, asegúrese de que la base de datos de ejemplo Northwind está instalada. De forma predeterminada, Microsoft Access 2000 instala las bases de datos de ejemplo en la siguiente ruta de acceso:

C:\Archivos de programa\Microsoft Office\Office\Samples

Microsoft Access 2002 usa la siguiente ruta de acceso:

C:\Archivos de programa\Microsoft Office\Office10\Samples

Microsoft Office Access 2003 usa la siguiente ruta de acceso:

C:\Archivos de programa\Microsoft\Office\Office11\Samples

Para asegurarse de que la base de datos de ejemplo Northwind está instalada en Access 2002 o en Access 2003, haga clic en Bases de datos de ejemplo en el menú Ayuda y, a continuación, haga clic en Base de datos de ejemplo northwind.

  1. Cierre todas las instancias de Access que se estén ejecutando actualmente.

  2. Inicie Microsoft Visual Studio .NET.

  3. En el menú Archivo, haga clic en Nuevo y, a continuación, haga clic en Proyecto. Seleccione Aplicación windows en Los tipos de proyecto de Visual C#. De forma predeterminada, se crea Form1.

    Nota Debe cambiar el código en Visual Studio 2005. De forma predeterminada, Visual C# agrega un formulario al proyecto al crear un proyecto de Windows Forms. El formulario se denomina Form1. Los dos archivos que representan el formulario se denominan Form1.cs y Form1.designer.cs. El código se escribe en Form1.cs. El archivo Form1.designer.cs es donde el diseñador de Windows Forms escribe el código que implementa todas las acciones que ha realizado arrastrando y quitando controles desde el cuadro de herramientas.

    Para obtener más información sobre el Diseñador de Windows Forms en Visual C# 2005, visite el siguiente sitio web de Microsoft Developer Network (MSDN):https://msdn.microsoft.com/en-us/library/ms173077.aspx

  4. Agregue una referencia a la biblioteca de objetos de Microsoft Access. Para ello, siga estos pasos:

    1. On the Project menu, click Add Reference.
    2. En la pestaña COM, busque Biblioteca de objetos de Microsoft Access y, a continuación, haga clic en Seleccionar.

    Nota En Visual Studio 2005. no es necesario hacer clic en Seleccionar.

    Nota Microsoft Office 2003 incluye ensamblados de interoperabilidad primarios (PIA). Microsoft Office XP no incluye los PIA, pero se pueden descargar.

  5. En el cuadro de diálogo Agregar referencias, haga clic en Aceptar para aceptar las selecciones.

    Nota Si hace referencia a la biblioteca de objetos de Access 10.0 y recibe errores al intentar agregar la referencia.

  6. En el menú Ver, haga clic en Cuadro de herramientas para mostrar el cuadro de herramientas.

  7. Agregue cinco controles de botón de radio y un control de botón a Form1.

  8. Seleccione todos los controles de botón de radio y, a continuación, establezca la propiedad Size en 150,24.

  9. Agregue controladores de eventos para el evento Form Load y para el evento Click del control Button:

    1. En la vista de diseño de Form1.cs, haga doble clic en Form1.

      El controlador del evento Load del formulario se crea y se muestra en Form1.cs.

    2. En el menú Ver, haga clic en Diseñador para cambiar a la vista de diseño.

    3. Haga doble clic en Button1.

      El controlador del evento Click del botón se crea y se muestra en Form1.cs.

  10. En Form1.cs, reemplace el código siguiente.

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

    con:

          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. Agregue el código siguiente a las directivas Using en Form1.cs:

    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Reflection; 
    
  12. Presione F5 para compilar y ejecutar el programa. Se muestra Form1.

  13. Haga clic en Imprimir informe y, a continuación, haga clic en Go!. El procedimiento Print_Report imprime un informe de la base de datos Northwind.

  14. Haga clic en Vista previa del informe y, a continuación, haga clic en Go!. El procedimiento Preview_Report obtiene una vista previa de un informe de la base de datos Northwind. Cierre la instancia de Access cuando esté listo para continuar.

  15. Haga clic en Mostrar formulario y, a continuación, haga clic en Go!. El procedimiento Show_Form muestra el formulario de cuadro de diálogo Etiquetas de cliente de la base de datos Northwind. También establece el grupo de opciones del formulario en "País específico" y selecciona "USA" en la lista. Cierre la instancia de Access cuando esté listo para continuar.

  16. Haga clic en Imprimir informe (seguridad) y, a continuación, haga clic en Go!. El procedimiento Print_Report_Security muestra cómo automatizar Access y cómo evitar el cuadro de diálogo de inicio de sesión si la seguridad de nivel de usuario está activada. En este ejemplo, suponga que el inicio de sesión predeterminado pasa el usuario Administración con una contraseña en blanco. A continuación, el código imprime un informe en la base de datos Northwind.

  17. Haga clic en Vista previa del informe (tiempo de ejecución) y, a continuación, haga clic en Go!. El procedimiento Preview_Report_Runtime muestra cómo automatizar Access Runtime para obtener una vista previa de un informe en la base de datos Northwind. Si se instala la versión comercial de Access, el procedimiento seguirá funcionando correctamente. Cierre la instancia de Access cuando esté listo para continuar.

Referencias

Para obtener más información, visite el siguiente sitio web de MSDN: Desarrollo de Microsoft Office con Visual Studio https://msdn.microsoft.com/en-us/library/aa188489(office.10).aspxPara obtener más información, haga clic en los números de artículo siguientes para verlos en Microsoft Knowledge Base:

317109 aplicación de Office no se cierra después de la automatización del cliente de Visual Studio .NET

316126 Uso de Visual C# para automatizar una instancia en ejecución de un programa de Office