Attaching to an already running Office application from your application using GetActiveObject or BindToMoniker

One common pattern of Office development is the Office Automation Executable—a console or windows forms application that starts up an Office application and talks to it.  Sometimes you won’t want to start a new instance of an Office application but will instead want to attach to an already running instance. To do this, you can use one of two methods provided by .NET.

System.Runtime.InteropServices.Marshal.GetActiveObject allows you to attach to a running instance of an Office application by passing a string identifier for the Office application called a program ID or ProgID. The ProgID for an Office application is in the format [AplicationName].Application. So for Excel it is “Excel.Application” and for Word it is “Word.Application”. GetActiveObject returns an object that must be cast to the correct application object from the application’s object model, so for our Excel example it must be cast to Excel’s Application object.

The second method is System.Runtime.InteropServices.Marshal.BindToMoniker which allows you to attach to a running instance of an Office document by passing the full path to an Office document that is currently open. BindToMoniker returns an object that must be cast to the document object from the application’s object model, so for our Excel example it must be cat to Excel’s Workbook object.

The code below shows a console application that uses both of these methods. It first uses GetActiveObject to get an already running Excel instance. If Excel isn’t running, a COMException is thrown and the code catches that exception and returns. Then, it creates a workbook, saves the workbook, stores the file name in a variable, and disconnects from the running Excel instance. Finally, the code uses BindToMoniker and the stored file name to reconnect to the running Excel instance and get the Workbook object associated with the file name. Once again, if the workbook specified by the file name is not open, a COMException is thrown and the code catches that exception and returns.

 using System;
 using Excel = Microsoft.Office.Interop.Excel;
 using System.Windows.Forms;
  
 namespace ConsoleApplication
 {
   class Program
   {
     static void Main(string[] args)
     {
       Excel.Application myExcelApp = null;
  
       try
       {
         myExcelApp =
           System.Runtime.InteropServices.Marshal.GetActiveObject(
           "Excel.Application") as Excel.Application;
       }
       catch (System.Runtime.InteropServices.COMException e)
       {
         MessageBox.Show(
           String.Format("Excel application was not running: {0}",
           e.Message));
         return;
       }
  
       if (myExcelApp != null)
       {
         MessageBox.Show(
           "Successfully attached to running instance of Excel.");
         myExcelApp.Visible = true;
         myExcelApp.StatusBar = "Hello World";
         Excel.Workbook myExcelWorkbook = 
           myExcelApp.Workbooks.Add(System.Type.Missing);
  
         // Save the workbook
         myExcelWorkbook.Save();
         string fileName = myExcelWorkbook.FullName;
  
       // Discard the application object
         myExcelApp = null;
  
         // Reconnect using the file name and BindToMoniker
         Excel.Workbook myExcelWorkbook2 = null;
         try
         {
           myExcelWorkbook2 = 
             System.Runtime.InteropServices.Marshal.BindToMoniker(
             fileName) as Excel.Workbook;
         }
         catch (System.Runtime.InteropServices.COMException e)
         {
           MessageBox.Show(String.Format(
             "File name {0} was not found running: {1}",
             fileName, e.Message));
           return;
         }
  
         if (myExcelWorkbook2 != null)
         {
           MessageBox.Show(String.Format(
             "Successfully bound to moniker {0}.", fileName));
           myExcelWorkbook2 = null;
         }
       }
     }
   }
 }

From the book “Visual Studio Tools for Office 2007”: