Está en la página 1de 29

What lead me to write this application is when i wanted to access the MSAccess database using c sharp I

couldn't get any information material. All the material available on the net is partial to sql, and hence the
purpose we will develop this application in 2 phase First we will see how to make the database connection
to the MSAccess and see what the intricacies of it. And then we will finish with the application.
Enough of the talking and let us move towards the main topic. The connection to the database is rather
modified as compared with the ADO connection that we had earlier. The following figure shows the
sequence properly (i hope)
OleDbConnection--> OleDbCommand --> OleDbDataReader
now those who are familiar with ado will obiviously recognise the simillarity but for some clarification
and for those who are not well versed with ado here is little explanation.
OleDbConnection --> represents single connection to the database, and depending upon the capabilites of
the underlying database it gives you the power to manipulate the database. The point to remember here is
even though oledbconnection object goes out of scope it does not get closed. And therefore you will have
to explicitely call the close() method of the object.
OleDbCommand --> this is our normal command object as we had in ado. You can call sql stored
procedures and sql queries through this object.
OleDbDataReader --> Now this class is of paramount importance since it gives actual access to the
underlying dataset of the database. Once you call the ExecuteReader method of the OleDbCommand it
gets created the dotnet beta 2 sdk says not to create the object of this class directly.
Now you can see more about these main object in .net beta 2 documentation and here is the source code
of how to make the program access the database.
using System;
using System.Data.OleDb;

class OleDbTest{

public static void Main()


{
//create the database connection
OleDbConnection aConnection = new
OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\db1.mdb");

//create the command object and store the sql query


OleDbCommand aCommand = new OleDbCommand("select * from emp_test", aConnection);
try
{
aConnection.Open();

//create the datareader object to connect to table


OleDbDataReader aReader = aCommand.ExecuteReader();
Console.WriteLine("This is the returned data from emp_test table");

//Iterate throuth the database


while(aReader.Read())
{
Console.WriteLine(aReader.GetInt32(0).ToString());
}

//close the reader


aReader.Close();

//close the connection Its important.


aConnection.Close();
}
//Some usual exception handling
catch(OleDbException e)
{
Console.WriteLine("Error: {0}", e.Errors[0].Message);
}
}
}
The steps involved in running this application successfully
1.create a data base in msaccess called db1.mdb
2.make a table in it called emp_test
3.let it have fields like
emp_code int
emp_name text
emp_ext text
4.save the above code in the sample.cs file
5. make sure the database is on the c:\ and mdac2.6 or later is installed(available in the ms site)
6. compile and run.
Now lets talk about various details of what we have learned in the constructor of the oledbconnection
you have seen "provider=" stuff. there are following types of drivers which are compatible with
ado.net.
sqlolddb --> Microsoft OLE DB Provider for SQL Server,
msdaora --> Microsoft OLE DB Provider for Oracle,
Microsoft.Jet.OLEDB.4.0 --> OLE DB Provider for Microsoft Jet
you can choose any of then but they will demand different parameters to be passed to then for example
the jet.oledb.. needs the name of the mdb file and sqloledb need the name of the user and its password.
These all drivers are located in System.Data.OleDb namespace and hence you must include it, again
they are not compatible with oledb provider for odbc. i.e. you can't use these drivers and try to access
database thru you vb6.0 application so don't go finding the references of these files in c: :-)
Following guidelines are given by Microsoft while choosing the providers SQL Server:
.NET Data Provider Recommended for middle-tier applications using Microsoft SQL Server 7.0 or
Later.
Recommended for single-tier applications using Microsoft Data Engine (MSDE) or Microsoft SQL
Server 7.0 orlater.
Recommended over use of the OLE DB Provider for SQL Server (SQLOLEDB) with the OLE DB
.NET Data Provider.
For Microsoft SQL Server 6.5 and earlier, you must use the OLE DB Provider for SQL Server with the
OLE DB.NET Data Provider.
OLE DB .NET Data Provider Recommended for middle-tier applications using Microsoft SQL Server
6.5 or earlier, or Oracle.
For Microsoft SQL Server 7.0 or later, the SQL Server .NET Data Provider is recommended.
Recommended for single-tier applications using Microsoft Access databases.
Use of the OLE DB .NET Data Provider with a Microsoft Access database for a middle-tier application
is notrecommended.
Support for the OLE DB Provider for ODBC (MSDASQL) is disabled.
I think i will stop for now and will continue in the (may be) next session the details of the dotnet Please
let me know if code does not run, if it runs :-)
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.

•Show and edit an Access form.

•Avoid dialog boxes when you open a password-protected database or when user-level security is turned
on.

•Automate the Access Runtime.


# FillReportGrid("Select FName,LName,SSN,City,State,Agi,CreatedDate,ReturnDate From
ClientInfo"); //is Working.....
# FillReportGrid("Select FName,LName,SSN,StreetAddr,Zip,City,State From ClientInfo1");
# /* is not working From C#.....but working in Access...
#
# ClientInfo Table :
#
# Field Name Datatype
# FName Text
# LName Text
# SSN Number
# StreetAddr Text
# Zip Number
# City Text
# State Text
# Agi Number
# CreatedDate Date/Time
# ReturnDate Date/Time
#
# ClientInfo1 Query:
# SELECT * FROM ClientInfo WHERE LName Like '*f*';
# */
# public void FillReportGrid(String query)
# {
# try
# {
# DBConnect.ConnectDataBase();
# OleDbCommand cmdGetUsers = new System.Data.OleDb.OleDbCommand();
# cmdGetUsers.Connection = DBConnect.accessConn;
# dataGridReport.Rows.Clear();
# if (SelectClauseBuilder().Length > 0)
# {
# cmdGetUsers.CommandText = query;
# OleDbDataReader readerData = cmdGetUsers.ExecuteReader();
# int rowNo = 0;
#
# if (readerData.HasRows)
# {
# while (readerData.Read())
# {
# dataGridReport.Rows.Add();
#
# for (int colNo = 0; colNo < readerData.VisibleFieldCount; colNo++)
# {
# if (dataGridReport.Rows[rowNo].Cells[colNo].Visible)
# {
# dataGridReport.Rows[rowNo].Cells[colNo].Value =
readerData[colNo].ToString();
# }
# }
#
# rowNo++;
# }
# }
#
# readerData.Close();
# }
#
# DBConnect.DisConnectDataBase();
# }
# catch (Exception e)
# {
# System.Console.WriteLine(e.StackTrace.ToString());
# }
# }
#
# public class DBConnect
# {
# public static System.Data.OleDb.OleDbConnection accessConn;
#
# public DBConnect()
# {
# }
#
# public static void ConnectDataBase()
# {
# accessConn = new System.Data.OleDb.OleDbConnection();
# accessConn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
+ System.Windows.Forms.Application.StartupPath + "\\Report.mdb";
# try
# {
# accessConn.Open();
# }
# catch (System.Data.OleDb.OleDbException e)
# {
# MessageBox.Show(String.Format("Database Error: {0}", e.Message), "WinTree
Application");
# }
# catch (System.Exception e)
# {
# MessageBox.Show(String.Format("Error: {0}", e.Message), "WinTree
Application");
# }
# }
#
# public static OleDbDataReader executeQuery(string str)
# {
# OleDbCommand command = new OleDbCommand();
# command.Connection = accessConn;
# command.CommandText = str;
# return command.ExecuteReader();
# }
#
# public static void executeNonQuery(string str)
# {
# try
# {
# OleDbCommand command = new OleDbCommand();
# command.Connection = accessConn;
# command.CommandText = str;
# command.ExecuteNonQuery();
# }
# catch (Exception ex)
# {
# MessageBox.Show(ex.ToString());
# }
# }
#
# public static void DisConnectDataBase()
# {
# if (accessConn != null)
# {
# accessConn.Close();
# }
# }
# }

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.

•Show and edit an Access form.

•Avoid dialog boxes when you open a password-protected database or when user-level security is turned
on.

•Automate the Access Runtime.

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
When you automate an application such as a Microsoft Office application, the calls to the properties and
methods of the Office application's objects must be connected in some way to those objects. The process of
connecting property and method calls to the objects that implement those properties and methods is
commonly called binding. In Visual C#, the two types of binding that are available are early binding and
late binding. The type of binding you choose can affect many aspects of your program, including
performance, flexibility, and maintainability.

This article explains and compares early and late binding for Visual C# Automation clients and provides
code samples that demonstrate both types of binding.

Late binding
In contrast to early binding, late binding waits until run time to bind property and method calls to their
objects. To do this, the target object must implement a special COM interface: IDispatch. The
IDispatch::GetIDsOfNames method allows Visual C# to interrogate an object about what methods and
properties it supports and the IDispatch::Invoke method then allows Visual C# to call those methods and
properties. Late binding in this fashion has the advantage of removing some of the version dependencies
that are inherent with early binding. However, it has the disadvantages of removing compile-time checks on
the integrity of automation code, as well as not providing Intellisense features that can provide clues to
correct calls to methods and properties.

To use late binding in Visual C#, use the System.Type.InvokeMember method. This method calls
IDispatch::GetIDsOfNames and IDispatch::Invoke to bind to the Automation server's methods and
properties.

Create an Automation client that uses late binding


Start Microsoft Visual Studio .NET. On the File menu, click New and then click Project. Select
Windows Application from the Visual C# Projects types. Form1 is created by default.
On the View menu, select Toolbox to display the Toolbox, and add a button to Form1.
Double-click Button1. The code window for the Form appears.
In the code window, replace the following code
private void button1_Click(object sender, System.EventArgs e)
{
}
with:
private void button1_Click(object sender, System.EventArgs e)
{
object objApp_Late;
object objBook_Late;
object objBooks_Late;
object objSheets_Late;
object objSheet_Late;
object objRange_Late;
object[] Parameters;

try
{
// Get the class type and instantiate Excel.
Type objClassType;
objClassType = Type.GetTypeFromProgID("Excel.Application");
objApp_Late = Activator.CreateInstance(objClassType);

//Get the workbooks collection.


objBooks_Late = objApp_Late.GetType().InvokeMember( "Workbooks",
BindingFlags.GetProperty, null, objApp_Late, null );

//Add a new workbook.


objBook_Late = objBooks_Late.GetType().InvokeMember( "Add",
BindingFlags.InvokeMethod, null, objBooks_Late, null );

//Get the worksheets collection.


objSheets_Late = objBook_Late.GetType().InvokeMember( "Worksheets",
BindingFlags.GetProperty, null, objBook_Late, null );

//Get the first worksheet.


Parameters = new Object[1];
Parameters[0] = 1;
objSheet_Late = objSheets_Late.GetType().InvokeMember( "Item",
BindingFlags.GetProperty, null, objSheets_Late, Parameters );

//Get a range object that contains cell A1.


Parameters = new Object[2];
Parameters[0] = "A1";
Parameters[1] = Missing.Value;
objRange_Late = objSheet_Late.GetType().InvokeMember( "Range",
BindingFlags.GetProperty, null, objSheet_Late, Parameters );

//Write "Hello, World!" in cell A1.


Parameters = new Object[1];
Parameters[0] = "Hello, World!";
objRange_Late.GetType().InvokeMember( "Value",
BindingFlags.SetProperty,
null, objRange_Late, Parameters );

//Return control of Excel to the user.


Parameters = new Object[1];
Parameters[0] = true;
objApp_Late.GetType().InvokeMember( "Visible",
BindingFlags.SetProperty,
null, objApp_Late, Parameters );
objApp_Late.GetType().InvokeMember( "UserControl",
BindingFlags.SetProperty,
null, objApp_Late, Parameters );
}
catch( Exception theException )
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat( errorMessage, theException.Message );
errorMessage = String.Concat( errorMessage, " Line: " );
errorMessage = String.Concat( errorMessage, theException.Source );

MessageBox.Show( errorMessage, "Error" );


}
}
Scroll to the top of the code window. Add the following line to the end of the list of using directives:
using System.Reflection;

Common Automation Tasks


Open a Database in Access
When you automate Microsoft Access, you must open a database before you can perform
useful tasks, such as printing reports. To open a database in the instance of Access you are
automating, you use the OpenCurrentDatabase or OpenAccessProject methods of the
Application object. You can have only one database opened in Access at a time. To work
with a different database, you can use the CloseCurrentDatabase method before opening
another.

You may also use the System.Runtime.InteropServices.Marshal.BindToMoniker(<path


to database>) method to open a database in an instance of Access. If the database is
already open in an instance of Access, BindToMoniker returns the Application object of
that instance. Otherwise, BindToMoniker starts a new instance of Access and opens the
specified database. OpenCurrentDatabase is the preferred method to open a database,
because you specify the instance of Access that you are automating. You can also provide
arguments to control how the database is opened, for example:

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

Print or Preview an Access Report


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:

// 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 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 (http://support.microsoft.com/kb/284286/ ) How to reset changes to the


Application.Printer object

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

You can now edit the controls on the form.

Back to the top

Access Security Dialog Boxes


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 user-
level 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 user-
level 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 (http://support.microsoft.com/kb/305542/ ) Understanding the role of workgroup


information files in Access security

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 (http://support.microsoft.com/kb/235422/ ) How to open a password-protected


database through Automation in Access 2000

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 (http://support.microsoft.com/kb/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 (http://support.microsoft.com/kb/209207/ ) How to use command-line switches in


Microsoft Access

Back to the top

Automating Access Runtime


The Microsoft Office Developer Edition includes the Microsoft Office Developer Tools
(MOD). Using MOD, Access developers can create and distribute Access applications to users
who do not have the retail version of Access. When the user installs the Access application on
a computer that does not have the retail version of Access, a Runtime version of Access is
installed. The Access Runtime is installed and is registered like the retail version. The
executable is also called Msaccess.exe. The Access Runtime allows an Access application to
run on a client computer, but the Access Runtime does not permit a user to develop new
applications or modify the design of existing applications.

The Access Runtime must be started with a database. Because of this requirement, if you
want to automate the Access Runtime, you must start the Msaccess.exe and specify a
database to open. After you use GetActiveObject or BindToMoniker to retrieve the
Application object, you can then automate the Access Runtime. If you do not use this
approach when you try to automate the Access Runtime, you will receive an error message
such as the following when you try to instantiate the instance:

System.Runtime.InteropServices.COMException (0x80080005)
Server execution failed.

For more information click the article number below to view the article in the Microsoft
Knowledge Base:

295179 (http://support.microsoft.com/kb/295179/ ) Using automation causes a Run-Time


Error when only the Microsoft Access Runtime is installed on a computer

Back to the top

Create the Complete Sample Visual C# 2005 or Visual C# .NET Project


To use the following step-by-step sample, make sure the Northwind sample database is
installed. By default, Microsoft Access 2000 installs the sample databases in the following
path:

C:\Program Files\Microsoft Office\Office\Samples

Microsoft Access 2002 uses the following path:

C:\Program Files\Microsoft Office\Office10\Samples

Microsoft Office Access 2003 uses the following path:

C:\Program Files\Microsoft Office\Office11\Samples

To make sure that the Northwind sample database is installed on Access 2002 or on Access
2003, click Sample Databases on the Help menu, and then click Northwind Sample
Database.

1. Close any instances of Access that are currently running.

2. Start Microsoft Visual Studio .NET.

3. On the File menu, click New, and then click Project. Select Windows Application
from the Visual C# Project types. By default, Form1 is created.

Note You must change the code in Visual Studio 2005. By default, Visual C# adds one
form to the project when you create a Windows Forms project. The form is named
Form1. The two files that represent the form are named Form1.cs and
Form1.designer.cs. You write the code in Form1.cs. The Form1.designer.cs file is where
the Windows Forms Designer writes the code that implements all the actions that you
performed by dragging and dropping controls from the Toolbox.

For more information about the Windows Forms Designer in Visual C# 2005, visit the
following Microsoft Developer Network (MSDN) Web site:

http://msdn2.microsoft.com/en-us/library/ms173077.aspx
(http://msdn2.microsoft.com/en-us/library/ms173077.aspx)

4. Add a reference to Microsoft Access Object Library. To do this, follow these steps:
1. On the Project menu, click Add Reference.

2. On the COM tab, locate Microsoft Access Object Library, and then click
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 (http://support.microsoft.com/kb/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 (http://support.microsoft.com/kb/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.private void Form1_Load(object sender, System.EventArgs e)
11.{
12.
13.}
14.
15.private void button1_Click(object sender, System.EventArgs e)
16.{
17.
18.}

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

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

19.Add the following code to the Using directives in Form1.cs:


20.using System.Runtime.InteropServices;
21.using System.Diagnostics;
22.using System.Reflection;

23.Press F5 to build and to run the program. Form1 is displayed.

24.Click Print report, and then click Go!. The Print_Report procedure prints a report from
the Northwind database.

25.Click Preview report, and then click Go!. The Preview_Report procedure previews a
report from the Northwind database. Close the Access instance when you are ready to
continue.

26.Click Show form, and then click Go!. The Show_Form procedure displays the
Customer Labels dialog box form from the Northwind database. It also sets the option
group on the form to "Specific Country" and selects "USA" from the list. Close the
Access instance when you are ready to continue.

27.Click Print report (Security), and then click Go!. The Print_Report_Security
procedure shows you how to automate Access and how to avoid the logon dialog box if
user-level security is turned on. In this example, assume the default logon by passing
the user Admin with a blank password. The code then prints a report in the Northwind
database.

28.Click Preview report (Runtime), and then click Go!. The Preview_Report_Runtime
procedure shows you how to automate the Access Runtime to preview a report in the
Northwind database. If the retail version of Access is installed, the procedure will still
work correctly. Close the instance of Access when you are ready to continue.
Binding for Office automation servers with Visual C#
.NET

SUMMARY
When you automate an application such as a Microsoft Office application, the calls to the properties and methods of the
Office application's objects must be connected in some way to those objects. The process of connecting property and method calls
to the objects that implement those properties and methods is commonly called binding. In Visual C#, the two types of binding
that are available are early binding and late binding. The type of binding you choose can affect many aspects of your program,
including performance, flexibility, and maintainability.

This article explains and compares early and late binding for Visual C# Automation clients and provides code samples that
demonstrate both types of binding.

Early binding
With early binding, Visual C# uses type information that is available about the Office Application in question to bind directly
to the methods or properties it needs to use. The compiler can perform type and syntax checks to ensure that the correct number
and type of parameters are passed to the method or property, and that the returned value will be of the expected type. Because less
work is required at run time to make a call to a property or method, early binding is sometimes faster; however, although early
binding may be faster, performance differences when compared to late binding are often negligible.

Early binding does have the minor disadvantage that it can introduce possible version compatibility issues. For example, suppose
that an Automation server such as Microsoft Excel 2002 introduces a new method or property that was unavailable in Excel 2000,
or makes a change to an existing property or method. These changes may alter the binary layout of the object and cause problems
with a Visual C# application that uses the Excel 2002 type information to automate Excel 2000. To avoid this problem with early
binding, it is generally recommended that you use the type information for the earliest version of the Office Application that you
wish to support when you develop and test your Automation client.

The following steps demonstrate how to build an Automation client that uses early binding. Note that, as the steps illustrate, early
binding requires you to reference the type library for the Automation client.
Create an Automation client that uses early binding

Start Microsoft Visual Studio .NET. On the File menu, click New and then click Project.
Select Windows Application from the Visual C# Projects types. Form1 is created by
default.
Add a reference to the Microsoft Excel Object Library. To do this, follow these steps:

1. On the Project menu, click Add Reference.

2. On the COM tab, locate theMicrosoft Excel Object Library and click Select.

Note Office 2003 includes Primary Interop Assemblies (PIAs). Office XP does not
include PIAs, but they can be downloaded. For additional information about
Office XP PIAs, click the following article number to view the article in the
Microsoft Knowledge Base:

328912 (http://support.microsoft.com/kb/328912/ ) Microsoft Office XP primary


interop assemblies (PIAs) are available for download

3. Click OK in the Add References dialog box to accept your selections. If you
receive a prompt to generate wrappers for the libraries that you selected, click
Yes.
2. On the View menu, select Toolbox to display the Toolbox, and add a button to Form1.

3. Double-click Button1. The code window for the Form appears.

4. In the code window, replace the following code


5. private void button1_Click(object sender, System.EventArgs e)
6. {
7. }

with:

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


{
Excel.Application objApp;
Excel._Workbook objBook;
Excel.Workbooks objBooks;
Excel.Sheets objSheets;
Excel._Worksheet objSheet;
Excel.Range range;

try
{
// Instantiate Excel and start a new workbook.
objApp = new Excel.Application();
objBooks = objApp.Workbooks;
objBook = objBooks.Add( Missing.Value );
objSheets = objBook.Worksheets;
objSheet = (Excel._Worksheet)objSheets.get_Item(1);

range = objSheet.get_Range("A1", Missing.Value);

range.set_Value(Missing.Value, "Hello, World!" );

//Return control of Excel to the user.


objApp.Visible = true;
objApp.UserControl = true;
}
catch( Exception theException )
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat( errorMessage,
theException.Message );
errorMessage = String.Concat( errorMessage, " Line: " );
errorMessage = String.Concat( errorMessage,
theException.Source );

MessageBox.Show( errorMessage, "Error" );


}
}

8. Scroll to the top of the code window. Add the following line to the end of the list of
using directives:
9. using System.Reflection;
10.using Excel = Microsoft.Office.Interop.Excel;

Late binding

In contrast to early binding, late binding waits until run time to bind property and method
calls to their objects. To do this, the target object must implement a special COM interface:
IDispatch. The IDispatch::GetIDsOfNames method allows Visual C# to interrogate an
object about what methods and properties it supports and the IDispatch::Invoke method
then allows Visual C# to call those methods and properties. Late binding in this fashion has
the advantage of removing some of the version dependencies that are inherent with early
binding. However, it has the disadvantages of removing compile-time checks on the integrity
of automation code, as well as not providing Intellisense features that can provide clues to
correct calls to methods and properties.

To use late binding in Visual C#, use the System.Type.InvokeMember method. This
method calls IDispatch::GetIDsOfNames and IDispatch::Invoke to bind to the
Automation server's methods and properties.
Create an Automation client that uses late binding

Start Microsoft Visual Studio .NET. On the File menu, click New and then click Project.
Select Windows Application from the Visual C# Projects types. Form1 is created by
default.
On the View menu, select Toolbox to display the Toolbox, and add a button to Form1.

Double-click Button1. The code window for the Form appears.

In the code window, replace the following code

1. private void button1_Click(object sender, System.EventArgs e)


2. {
3. }

with:

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


{
object objApp_Late;
object objBook_Late;
object objBooks_Late;
object objSheets_Late;
object objSheet_Late;
object objRange_Late;
object[] Parameters;

try
{
// Get the class type and instantiate Excel.
Type objClassType;
objClassType = Type.GetTypeFromProgID("Excel.Application");
objApp_Late = Activator.CreateInstance(objClassType);

//Get the workbooks collection.


objBooks_Late = objApp_Late.GetType().InvokeMember( "Workbooks",
BindingFlags.GetProperty, null, objApp_Late, null );

//Add a new workbook.


objBook_Late = objBooks_Late.GetType().InvokeMember( "Add",
BindingFlags.InvokeMethod, null, objBooks_Late, null );

//Get the worksheets collection.


objSheets_Late =
objBook_Late.GetType().InvokeMember( "Worksheets",
BindingFlags.GetProperty, null, objBook_Late, null );

//Get the first worksheet.


Parameters = new Object[1];
Parameters[0] = 1;
objSheet_Late = objSheets_Late.GetType().InvokeMember( "Item",
BindingFlags.GetProperty, null, objSheets_Late,
Parameters );

//Get a range object that contains cell A1.


Parameters = new Object[2];
Parameters[0] = "A1";
Parameters[1] = Missing.Value;
objRange_Late = objSheet_Late.GetType().InvokeMember( "Range",
BindingFlags.GetProperty, null, objSheet_Late, Parameters
);

//Write "Hello, World!" in cell A1.


Parameters = new Object[1];
Parameters[0] = "Hello, World!";
objRange_Late.GetType().InvokeMember( "Value",
BindingFlags.SetProperty,
null, objRange_Late, Parameters );

//Return control of Excel to the user.


Parameters = new Object[1];
Parameters[0] = true;
objApp_Late.GetType().InvokeMember( "Visible",
BindingFlags.SetProperty,
null, objApp_Late, Parameters );
objApp_Late.GetType().InvokeMember( "UserControl",
BindingFlags.SetProperty,
null, objApp_Late, Parameters );
}
catch( Exception theException )
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat( errorMessage,
theException.Message );
errorMessage = String.Concat( errorMessage, " Line: " );
errorMessage = String.Concat( errorMessage,
theException.Source );

MessageBox.Show( errorMessage, "Error" );


}
}

4. Scroll to the top of the code window. Add the following line to the end of the list of
using directives:
5. using System.Reflection;

También podría gustarte