Opening Office Files From A Windows Form Application

A common scenario when you have a Windows form application is one in which you need to automate Office to work with or open files.

However, there are a few important details you need to about the file you are opening:

1) Is it there
2) Is it already open somewhere
3) If it is already open and can I grab the instance

To do this you must:

1) Check to see if the file exists.
2) If the file is open to grab the instance it is opened with. This can be done with BindToMoniker().
3) If the file is not open, open it and then grab an instance to it.

Here is the code:

using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using System.Diagnostics;

private Excel.Workbook openFile(string fn)
{
    // bind to the path… if the document is not open
    // then the Marshal will open an new instance of Excel or
    // open in the current active instance of Excel
    Excel.Workbook wb = (Excel.Workbook)Marshal.BindToMoniker(fn);
    if (wb == null)
    {
        // we need to start a new instance of Excel
        // with the filename passed to it
        Process p = new Process();
        p.StartInfo.FileName = "excel.exe";
        p.StartInfo.Arguments = fn; // send the filename to excel
        p.Start(); // start an instance of Excel first
        p.WaitForInputIdle();  // wait for the process to be ready
        // now bind to minker again to connect to the instance
        // of the file that we just opened
        wb = (Excel.Workbook)Marshal.BindToMoniker(fn);
    }

    // show the application – just in case
    wb.Application.Visible = true;
    // verify the window is shown
    wb.Windows[1].Visible = true;
    // if minimized – restore the window
    if (wb.Application.WindowState == Excel.XlWindowState.xlMinimized)
        wb.Application.WindowState = Excel.XlWindowState.xlNormal;
    // set the applcation to the foreground
    SetForegroundWindow(wb.Application.Hwnd);
    // then activate the workbook
    wb.Activate();
    return wb; // done
}

The code simply looks uses the Marshal BindToMoniker function to access the “object” that currently maintains the file – if it is in memory. If it is not found, we kick off a new process with that filename as a parameter passed to Excel. Excel will open the document and then we are able to use BindToMoniker again to get access to that workbook object. The code at the end does a lot of work to verify that Excel is visible and activated.

Finally to use all this:

private void openAnExcelFile()
{
    string fn = @"c:\users\davidcr\desktop\test.xlsx";
    if (File.Exists(fn))
    {
        Excel.Workbook wb = openFile(fn);
        MessageBox.Show(wb.Name + " has been opened.");
    }
}

Leave a Reply