Microsoft KB Archive/316125

From BetaArchive Wiki

Article ID: 316125

Article Last Modified on 6/29/2007



APPLIES TO

  • Microsoft Visual C# .NET 2003 Standard Edition
  • Microsoft Visual C# .NET 2002 Standard Edition
  • Microsoft Office Access 2003
  • Microsoft Access 2002 Standard Edition
  • Microsoft Office Excel 2003
  • Microsoft Excel 2002 Standard Edition
  • Microsoft Office PowerPoint 2003
  • Microsoft PowerPoint 2002 Standard Edition
  • Microsoft Office Word 2003
  • Microsoft Word 2002 Standard Edition



This article was previously published under Q316125

For a Microsoft Visual Basic .NET version of this article, see 308409.

For a Microsoft Visual Basic 6.0 and Visual C++ 6.0 version of this article, see 238610.

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

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.

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.

STATUS

This behavior is by design.

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.


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

}
                

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


Keywords: kbautomation kbprb kbpia KB316125