Click here to Skip to main content
13,344,273 members (52,608 online)
Click here to Skip to main content
Add your own
alternative version


33 bookmarked
Posted 25 Nov 2009

Hosting an Excel Application in an MDI Form

, 8 Dec 2009
Rate this:
Please Sign up or sign in to vote.
How to use WebBrowser, a form, and an MDI parent to open Excel files


Warning: Microsoft took out the ability to host Excel in a WebBrowser in IE10. This article was written before that happened.

Excel Interop can be a nice thing for anyone wanting to embed Excel into their applications. In particular, using an MDI parent to host multiple instances of Excel Workbooks. You may say why would I need that? The answer is this: you have developed an application that contains many different kinds of opened windows and/or web browsers that, in essence, automate all UNC paths, URL navigating, and opening of windows without cluttering the desktop. This is really nice for customers that would rather do their job than keeping track of a zillion windows and UNCs or URLs.


First off, I don't want to lead anyone to believe that hosting Excel workbooks in a web browser is easy. There are lots of problems, some of which will be discussed here. First off, thanks goes to this CodeProject article which started me off into thinking about how to enhance what was there. Thanks bsargos for all of your excellent work. This project only adds to what you've already done. Note there is a new problem with this work as indicated by Problem 4 in the comments section below. I've had to abandon this idea because of the problems, but will continue to work on it as time permits. The bottom line is that working with a COM object such as Excel leaves us blind because we can't see the code and can't determine why simple things such as clicking a menuitem in the excel toolbar doesn't work. If you can lend to our understanding of the Excel internals, please comment.

Using the Code

From the article above, most of the methods are intact; however, there were some additional changes, refactoring etc., to move this project a bit further down the road. One of them was to add to the list of Excel menu items (needing removal) that just plain don't work when hosted in a web browser.

Problem 1

The need to remove things in the Excel menu that just don't work when a workbook is hosted in a WebBrowser. I can find no documentation anywhere regarding why these commands just don't work from the Excel toolbar when Excel is hosted in a .NET WebBrowser or even an AxWebBrowser. The string removeList contains the names of commands that don't work.

private void removeExcelButtons() {
        //None of these work in a hosted excel instance via a webbrowser 
        //So we'll get rid of them
        string removeList = "New Open Mail Recipient Print Preview";
        foreach (Office.CommandBarControl control in _StandardCommandBar.Controls){
            string name = control.get_accName(Missing.Value);
            if (removeList.Contains(name)) {
    catch (Exception iox) {
          "REX1001-An error occurred in RemoveExcelButtons"); 

Points of Interest

One of the tricks one learns regarding Excel automation within a WebBrowser is that there are two parts to this:

  1. The WebBrowser's work which is 100% independent of any Excel automation, and
  2. Learning how to take the work performed by the WebBrowser and gain addressability to the Excel object using Excel Interop.

When a WebBrowser navigates to a file that it knows to be an Excel file, it does all the work of opening the file via the logic contained within the WebBrowser. The .NET WebBrowser is just a wrapper for IE8, which is a COM object. In fact, many developers use the COM object instead of the .NET WebBrowser as it exposes a lot more functionality. It is more difficult to use as a result and the chief reason this tip sticks with the .NET WebBrowser.

The IE8 engine knows how to handle different document types, and does a great job of it, but the .NET side is oblivious to the work done by the asynchronous unmanaged side of the IE8 engine. That is, until the .NET side gains visibility to the resultant Excel object contained in the WebBrowser after it has completed the navigation to that file. In the method below, addressability happens on NavigateComplete, and in particular, in the call to initExcelObjects().

private void AttachApplication() {
    try {
        if(_ExcelFileName==null||_ExcelFileName.Length==0) return;
        // Creation of the workbook object
        // Get addressability to the Excel object via interop.
        // Get rid of buttons that don't work 
    } catch (Exception iox){
        MessageBox.Show(iox.Message,"EXW1001-Error in Excel Wrapper");

Let's examine the initExcelObjects() method below. The first line of code is the beginning of what is called "Excel Interop". The value of _Workbook is set prior to entry to this method upon the NavaigateComplete supporting code. It is merely an instance/pointer to the current workbook item. The workbook item has a property Application which gets us started. Notice the cast to one of the Excel Interop types. This is how we move from the COM side to the .NET side. Once we have the application layer ready, we now have the entire "world" of Excel opened up to .NET. The reason the code goes after the CommandBars is because of the second set of "problems" you'll encounter when hosting Excel objects in a .NET WebBrowser.

Problem 2

You have to explicitly set the toolbar position. If you don't do this, you won't get a toolbar.

private void initExcelObjects() {
     // Create the Excel.Application object using interop
     // Get .NET visibility
     _XlApplication = (Excel.Application)_Workbook.Application;
     // Creation of the standard toolbar NOTE there are many tool bars which
     // you can iterate through to see. But Standard is the big Kahuna
     _StandardCommandBar = _XlApplication.CommandBars["Standard"];
     //This is the fix for Problem 2 above
     _StandardCommandBar.Position = Office.MsoBarPosition.msoBarTop;
     _StandardCommandBar.Visible = _ToolBarVisible;    

Problem 3

Exiting the form containing the WebBrowser opened to an Excel workbook leaves Excel running along with the workbook left in a bad state. Bsargos' article includes this fix in the form Dispose() method.

It is worth pointing out the importance of this code. If it's not done, you will be faced with the absolutely maddening problem of half-baked closes of Excel. This shows up trying to reopen the same workbook and getting some ridiculous Excel message saying it's already open, of which you can only recover by taking down the Excel process. When this happens, you have lost control of that workbook. In fact, upon attempts to reopen the same workbook, you will get a request to attach a debugger (for runtime debugging). If you attach the debugger and attempt to see what's going on, you'll only see a bunch of machine code in the disassembly and a vague callstack pointing to Excel internal calls, which almost no one but MSFT engineers have any knowledge of. Bottom line, this code is essential in cleaning up after using Excel from the .NET side.

protected override void Dispose(bool disposing) {
  if(disposing&&(components!=null)) {
 try {
      // Quit Excel and clean up.
      if(_Workbook!=null) {
      if(_XlApplication!=null) {
  } catch (Exception iox){
        MessageBox.Show(iox.Message(),"BAD NEWS in dispose");

The thing to note in the code above is the workbook close as well as the application quit. Both are important to bringing this all down, but even more important is Marshal.ReleaseComObject. Your code must "cross the COM" divide and tell COM to clean up. Finally, the GC collect , seems to help, but is questionable to me because CLR documentation says that no matter what you attempt to do with the Garbage Collector, it always has a mind of its own. I advise leaving the code as-is because without it, you are only half-baked, and everyone knows how irritating it is to be that way.

I hope this helps you to avoid weeks of learning curves (which lead me to this article) with COM and Excel Interop. Feel free to add to it, subtract and comment. In the future, for the MDIParent, I'll be adding other "normal" functions you would expect from running Excel directly.


  • 08 December, 2009 - Added missing DLLS and disclaimer on "How difficult this is". Excel has a mind of its own which runs at COM layer, a totally invisible realm for the managed side. Many times, the Excel application will hang or menu items just won't respond.
  • 25 November, 2009 - Edited
  • 24 November, 2009 - Initial post


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Mr. Javaman
Software Developer (Senior)
United States United States
Mr Javaman

You may also be interested in...


Comments and Discussions

GeneralBetter Solution Pin
xzz019529-Jan-10 5:06
memberxzz019529-Jan-10 5:06 
QuestionGetActiveWorkbook always returns null? Pin
mahyari197023-Jan-10 5:40
membermahyari197023-Jan-10 5:40 
AnswerRe: GetActiveWorkbook always returns null? Pin
xzz019529-Jan-10 4:58
memberxzz019529-Jan-10 4:58 
GeneralThe Garbage Collection Zombie Stomp Pin
TheRaven15-Dec-09 2:33
memberTheRaven15-Dec-09 2:33 
GeneralRe: The Garbage Collection Zombie Stomp Pin
xzz01957-Jan-10 11:00
memberxzz01957-Jan-10 11:00 
GeneralProblem 4: MDI childform activate to FormWindowState.Maximum in with Excel Spreadsheet/Workbook [modified] Pin
xzz019526-Nov-09 8:46
memberxzz019526-Nov-09 8:46 
GeneralRe: Problem 4: MDI childform activate to FormWindowState.Maximum in with Excel Spreadsheet/Workbook Pin
xzz019527-Nov-09 10:13
memberxzz019527-Nov-09 10:13 
GeneralRe: Problem 4: MDI childform activate to FormWindowState.Maximum in with Excel Spreadsheet/Workbook Pin
xzz019530-Nov-09 7:23
memberxzz019530-Nov-09 7:23 
GeneralDisposing of Excel Pin
bilo8125-Nov-09 23:29
memberbilo8125-Nov-09 23:29 
GeneralRe: Disposing of Excel [modified] Pin
xzz019526-Nov-09 8:36
memberxzz019526-Nov-09 8:36 
GeneralRe: Disposing of Excel Pin
bilo8127-Nov-09 12:08
memberbilo8127-Nov-09 12:08 
I'm happy my post was helpful a little.

You can check out this post:[^]

The bottom line is, citing the article I found, "to create a "job object" for your main application. Then configure the job object to kill-process upon close. If the application dies, the OS will take care of cleaning up your processes."; in our case the process to clean up is Excel of course.

Now I'm not sure the code there is reliable at all since using IntPtr and unmanaged memory allocation requires always a great deal of attention and I just had a quick look at it.

For example, there is for sure an allocation of unmanaged memory which is not cleaned up in my opinion, and the leak is caused by the following line in the constructor of the class Job:

IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);

Basically, every call to Marshal.AllocHGlobal should be eventually followed by a call
Marshal.FreeHGlobal(extendedInfoPtr );

in my understanding, so I'm not sure the code you find there is actually error-free.
It is for sure a good start to investigate further...
You may want to check out this brilliant codeproject article which explain in details how to deals with unmanaged resources and their deallocation using the Dispose pattern:

IDisposable: What Your Mother Never Told You About Resource Deallocation[^]

General:: DLLs In Project Pin
DIEGO FELDNER25-Nov-09 6:55
memberDIEGO FELDNER25-Nov-09 6:55 
GeneralRe: :: DLLs In Project Pin
xzz019525-Nov-09 7:46
memberxzz019525-Nov-09 7:46 
GeneralRe: :: DLLs In Project Pin
Jigs Shah3-Dec-09 22:52
memberJigs Shah3-Dec-09 22:52 
GeneralRe: :: DLLs In Project Pin
xzz01958-Dec-09 5:11
memberxzz01958-Dec-09 5:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.180111.1 | Last Updated 8 Dec 2009
Article Copyright 2009 by Mr. Javaman
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid