How To Automate Microsoft Access by Using Visual C
How To Automate Microsoft Access by Using Visual C
Visual C#
Email
Print
This article demonstrates how to automate Microsoft Access by using Microsoft Visual C#
2005 or Microsoft Visual C# .NET. The topics and the sample code show you how to do the
following:
Open a database in Access.
Print or preview an Access report.
Avoid dialog boxes when you open a password-protected database or when user-level
security is turned on.
307587 How to update a database from a DataSet object by using Visual C# 2005 or Visual
C# .NET
Automation is a Component Object Model (COM) technology. Automation allows
applications that are written in languages such as Visual C# .NET to programmatically control
other applications. When you automate a Microsoft Office application, you actually run an
instance of that application in memory, and then call on the application's object model to
perform various tasks in that application. With Access and other Microsoft Office
applications, virtually all of the actions that you can perform manually through the user
interface can also be performed programmatically by using Automation.
Access exposes this programmatic functionality through an object model. The object model is
a collection of classes and methods that serve as counterparts to the logical components of
Access. To access the object model from Visual C# .NET, you can set a project reference to
the type library. To learn more about this process, or to learn more about object model
documentation for Office, click the article number below to view the article in the Microsoft
Knowledge Base:
222101 How to find and use Office object model documentation
back to the top
To preview or to print an Access report, you call the OpenReport method of the DoCmd
object. When you call OpenReport, one of the arguments that you pass determines whether
the report is previewed on the screen, or whether it is sent to the printer:
// 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
);
Notice that the View argument determines whether the report is displayed in Access or
whether it is sent to the printer. The WhereCondition argument can limit the report's recordset,
if you use a valid SQL WHERE clause (without the word WHERE.) Notice that you can use
System.Reflection.Missing.Value to skip any object parameters that are optional.
If you are previewing a report, be sure to set the Visible property of the Application object so
that Access is visible on the screen. In this way, the user can view the report in the Access
window.
There is another way to print a report or other objects in the database. Use the PrintOut
method of the DoCmd object. In this example, you select a report named Employees in the
Database window, and then you call PrintOut to print the selected object. The PrintOut
method allows you to provide arguments that correspond to the Print dialog box in 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
);
Or, in some cases, you may want to use both the OpenReport and the PrintOut methods to
print a report. Suppose you want to print multiple copies of the Employees report but only for
a specific employee. This example first uses OpenReport to open the Employees report in
preview mode, using the WhereCondition argument to limit the records to a specific
employee. Then, PrintOut is used to print multiple copies of the active object:
Access 2002 introduced the Printer object. You can use this object to customize Access printer
settings more easily than in earlier versions of Access. For an example of using the Printer
object in Access to print a report, click the article number below to view the article in the
Microsoft Knowledge Base:
284286 How to reset changes to the Application.Printer object
back to the top
Show and Edit an Access Form
Visual C# .NET has very powerful form capabilities. However, there may be times when you
want the user to view a form that was previously developed in Access. Or, you may have a
form in your Access database that provides criteria for a query or report, and you must open
that form before you can preview or print the report. To open and show an Access form, you
call the OpenForm method of the DoCmd object:
// 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
);
When you automate Access, you may be prompted to enter a user name or a password, or
both, when you try to open a database. If the user enters the wrong information, an error will
occur in your code. There may be times when you want to avoid these dialog boxes and
instead to programmatically provide the user name and password so that your Automation
code runs uninterrupted.
There are two types of security in Microsoft Access: password-protected databases and userlevel security through a workgroup file (System.mdw). If you are trying to open a database
that is password protected, you will receive a dialog box prompting for the database
password. User-level security is different from a password-protected database. When userlevel security is activated, Access displays a logon dialog box prompting for both a user name
and password before the user can open any database in Access. For more information about
Access security and the workgroup information file, click the article number below to view
the article in the Microsoft Knowledge Base:
305542 Understanding the role of workgroup information files in Access security
back to the top
Avoiding Database Password Dialog Boxes
If you are opening a database that has been protected with a password, you can avoid the
dialog box by providing the password to the OpenCurrentDatabase method:
// 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
);
Here is an example, where oAccess has been previously set to an instance of Access that does
not have a database open. This code provides the password to the database to avoid a dialog
box:
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;
The oDB.Close does not actually close the database in Access. It only closes the DAO
connection to the database that was made through the DBEngine object. The DAO connection
is no longer necessary after the OpenCurrentDatabase method is used. Notice the code to
release the oDB and oDBEngine objects. You must use these objects so that Access quits
correctly after the code is completed.
For more information, click the article number below to view the article in the Microsoft
Knowledge Base:
235422 How to open a password-protected database through Automation in Access 2000
back to the top
Avoiding Access Security Logon Dialog Boxes
If user-level security is turned on in Access, the user is prompted with a logon dialog box,
prompting for both a user name and a password. A user name and a password cannot be
specified using the Access object model. Therefore, if you want to avoid the logon dialog box
when you automate Access, you must first start the Msaccess.exe file and provide the /user
and /pwd command-line switches to specify the user name and password. Afterward, you can
use GetActiveObject or BindToMoniker to retrieve the Application object of the running
instance of Access, so that you can then proceed with Automation. For an example of how to
do this, click the article number below to view the article in the Microsoft Knowledge Base:
192919 How to automate a secured access database using Visual Basic
For more information about starting Access with command-line switches, click the article
number below to view the article in the Microsoft Knowledge Base:
209207 How to use command-line switches in Microsoft Access
back to the top
Select.
Note In Visual Studio 2005. you do not have to click Select.
Note Microsoft Office 2003 includes Primary Interop Assemblies (PIAs).
Microsoft Office XP does not include PIAs, but they can be downloaded. For
more information about Office XP PIAs, click the following article number to
view the article in the Microsoft Knowledge Base:
328912 Microsoft Office XP primary interop assemblies (PIAs) are available
for download
3. In the Add References dialog box, click OK to accept your selections.
Note If you are referencing the Access 10.0 object library and you receive
errors when you try to add the reference, click the article number below to
view the article in the Microsoft Knowledge Base::
317157 PRB: Errors when you reference the Access 10.0 type library with
Visual Studio .NET
5. On the View menu, click Toolbox to display the toolbox.
6. Add five radio button controls and one button control to Form1.
7. Select all of the radio button controls, and then set the Size property to 150,24.
8. Add event handlers for the Form Load event and for the Click event of the Button
control:
1. In design view for Form1.cs, double-click Form1.
The handler for the Form's Load event is created and displayed in Form1.cs.
2. On the View menu, click Designer to switch to design view.
3. Double-click Button1.
The handler for the button's Click event is created and displayed in Form1.cs.
9. In Form1.cs, replace the following code
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
with:
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);
}
e)
try
{
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;
}
sCmdLine:
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
input state
running
tryGetActiveObject:
// Enable exception handler:
try
{
// Attempt to use GetActiveObject to reference a
// instance of Access:
oAccess = (Access.Application)
Marshal.GetActiveObject("Access.Application");
}
catch
{
//GetActiveObject may have failed because enough time
has not
1/2
iMaxTries
other
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;
}
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;
}
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();
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
}
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;
}
= false;
false;
oAccess.DoCmd.Close(Access.AcObjectType.acForm,
oForm.Name, Access.AcCloseSave.acSaveNo);
NAR(oForm);
oForm = null;
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;
}
security.
default
switch to
password:
+ sPwd,
focus
}
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;
}
the
/runtime",
//
ProcessWindowStyle.Minimized);
}
// Select the report name in the database window and give
focus
}
catch{}
REFERENCES
For more information, visit the following MSDN Web site:
Microsoft Office Development with Visual Studio
http://msdn2.microsoft.com/en-us/library/aa188489(office.10).aspx
For more information, click the following article numbers to view the articles in the Microsoft
Knowledge Base:
317157 PRB: Errors when you reference the Access 10.0 type library with Visual Studio .NET
317109 Office application does not quit after automation from Visual Studio .NET client
316126 How to use Visual C# to automate a running instance of an Office program
316125 PRB: Visual C# .NET error attaching to running instance of Office application
244695 BUG: Error message 2046 calling OpenForm or OpenReport with Access automation
302902 Binding for Office automation servers with Visual C# .NET
302295 How to obtain the window handle for an Office automation server by using Visual
C# .NET
306683 How to run Office macros by using automation from Visual C# .NET
Properties
Article ID: 317114 - Last Review: 01/17/2007 08:45:10 - Revision: 8.7
Applies to
Microsoft Visual C# 2005 Express Edition
Microsoft Visual C# .NET 2003 Standard Edition
Keywords:
kbpia kbhowtomaster KB317114
Feedback