Notice: This website is an unofficial Microsoft Knowledge Base (hereinafter KB) archive and is intended to provide a reliable access to deleted content from Microsoft KB. All KB articles are owned by Microsoft Corporation. Read full disclaimer for more details.

PRB: Visual C# .NET Error Attaching to Running Instance of Office Application


View products that this article applies to.

Symptoms

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

Additional information: Operation unavailable

↑ Back to the top


Cause

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.

↑ Back to the top


Resolution

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.

↑ Back to the top


Status

This behavior is by design.

↑ Back to the top


More information

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.

Steps to Reproduce the Behavior

  1. Start Microsoft Visual Studio .NET.
  2. 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.
  3. Add a reference to Microsoft Word Object Library. To do this, follow these steps:
    1. On the Project menu, click Add Reference.
    2. 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 INFO: Microsoft Office XP PIAs Are Available for Download
    3. Click OK in the Add References dialog box to accept your selections.
  4. On the View menu, click Toolbox to display the toolbox, and then add a button to Form1.
  5. Double-click Button1. The code window for the form appears.
  6. Add the following code to the top of Form1.cs:
    using Word = Microsoft.Office.Interop.Word;
    					
  7. 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)
    {
    	Word.Application oWord;
    
    	System.Diagnostics.Process.Start("C:\\Program Files\\Microsoft Office\\Office10\\Winword.exe");
    	oWord = (Word.Application) System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
    	MessageBox.Show(oWord.Name);
    	oWord = null;
    }
    					
  8. Make sure that the location of the Winword.exe file is correct in the code sample.
  9. Quit Microsoft Word if it is already running.
  10. On the Debug menu, click Start.

↑ Back to the top


Workaround

To work around the problem, follow these steps:
  1. Create an instance of the application by using the System.Diagnostics.Process.Start method.
  2. Give the focus to your Visual C# form.
  3. 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);
		}
	}

}
				

↑ Back to the top


References

For more information, visit the following Microsoft Developer Network (MSDN) Web site:
Microsoft Office Development with Visual Studio
http://msdn2.microsoft.com/en-us/library/aa188489(office.10).aspx

↑ Back to the top


Keywords: kbpia, kbautomation, kbprb, KB316125

↑ Back to the top

Article Info
Article ID : 316125
Revision : 13
Created on : 6/29/2007
Published on : 6/29/2007
Exists online : False
Views : 630