When you try to use System.Runtime.InteropServices.Marshal.GetActiveObject from Microsoft Visual C# .NET to automate a Microsoft Office application,
you may receive the following error message, even though the Office application
is running:
An unhandled exception of type
'System.Runtime.InteropServices.COMException' occurred in
mscorlib.dll
Although the Office application is running, it may not be
registered in the Running Object Table (ROT). A running instance of an Office
application must be registered in the ROT before GetActiveObject can be used to attach to it.
When an Office application
starts, it does not immediately register its running objects. This optimizes
the application startup process. Instead of registering at startup, an Office
application registers its running objects in the ROT after it loses focus.
Therefore, if you attempt to use GetActiveObject to attach to a running instance of an Office application before
the application has lost focus, you may receive an error message.
Using code, you can change focus from the Office
application to your own application (or to some other application) to allow it
to register itself in the ROT. Additionally, if your code is starting the
executable (.exe) file for the Office application, you may need to wait for the
Office application to finish loading before you attempt to attach to the
running instance. A code sample is provided as a workaround in the "More
Information" section.
In most situations, developers who want to automate an
Office application should create a new instance of the Office application.
However, you may prefer to automate an Office application that is already
running, such as if the user previously started the Office application or if
you start the .exe file for the Office application by using code so that you
can specify command-line switches for the application. In order to automate the
running Office application, you must use GetActiveObject.
On the File menu, click New, and then click Project. Under Project Types, click Visual C# Projects, and then click Windows Application under Templates. Form1 is created by default.
Add a reference to Microsoft Word Object Library. To do this, follow these steps:
On the Project menu, click Add Reference.
On the COM tab, locate Microsoft Word Object Library, and
then click Select.
Note Microsoft Office 2003 includes Primary Interop Assemblies (PIAs). Microsoft 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/
)
INFO: Microsoft Office XP PIAs Are
Available for Download
Click OK in the Add References dialog box to accept your selections.
On the View menu, click Toolbox to display the toolbox, and then add a button to Form1.
Double-click Button1. The code window for the form appears.
Create an instance of the application by using the System.Diagnostics.Process.Start method.
Give the focus to your Visual C# form.
Try to use GetActiveObject while accounting for the load time of the Office
application.
The following revised code illustrates this workaround:
private void button1_Click(object sender, System.EventArgs e)
{
int iSection = 0, iTries = 0;
Word.Application oWord;
// Start Word, giving it focus.
System.Diagnostics.Process.Start("C:\\Program Files\\Microsoft Office\\Office10\\winword.exe");
// Move focus back to this form. (This ensures the Office
// application registers itself in the ROT, allowing
// GetObject to find it.)
this.Activate();
tryAgain:
try
{
// Attempt to use GetObject to reference the running
// Office application.
iSection = 1; // Attempting GetObject.
oWord = (Word.Application) System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
iSection = 0; // Resume normal error handling.
// Automate Word.
MessageBox.Show(oWord.Name + ": able to GetObject after " +
(iTries + 1) + " tries.");
oWord.ActiveDocument.Content.Text = "Hello!";
// You are finished with Automation, so release your reference.
oWord = null;
// Exit procedure.
return;
}
catch (Exception err)
{
if (iSection == 1)
{
//GetObject may have failed because the
//Shell function is asynchronous; enough time has not elapsed
//for GetObject to find the running Office application. Wait
//1/2 seconds and retry the GetObject. If you try 20 times
//and GetObject still fails, assume some other reason
//for GetObject failing and exit the procedure.
iTries++;
if (iTries < 20)
{
System.Threading.Thread.Sleep(500); // Wait 1/2 seconds.
this.Activate();
goto tryAgain; //resume code at the GetObject line
}
else
MessageBox.Show("GetObject still failing. Process ended.");
}
else
{
//iSection = 0 so use normal error handling:
MessageBox.Show(err.Message);
}
}
}