More VSTO 2.0 Managed Controls

So you've (hypothetically) installed VSTO 2.0, you create a new Excel project, and you drag and drop a managed windows forms button onto the Excel worksheet.

How does this magic work? The first clue is seen in the formula bar. You might see this text:

=EMBED("WinForms.Control.Host","")

When you drag and drop a managed control onto Excel, we actually embed an ActiveX control that then hosts the WinForms control. The ProgID of this control is WinForms.Control.Host which shows in the formula bar.

There are a lot of reasons we embed this “WinForms.Control.Host“ ActiveX control instead of embedding the WinForm control directly. The main reason is security. We don't want to load a managed control at all into the document unless the VSTO 2.0 security model allows it. As you probably know, the VSTO 2.0 (and 1.0) security model is “No code runs by default.“ There has to be stronger evidence than local-machine evidence (e.g. the fact that the document and assemblies are on your local machine is not enough). The actual managed control that is created and displayed in the document is created in the same AppDomain as the customization and is therefore subject to the same security policy applied to the customization.

If security doesn't allow the managed control to load, we have to put something in the document where the control should be so that the next time the document opens, there will still be a place for the control to be sited should security settings change to allow the control to run. So if the managed control isn't allowed to run, our ActiveX control stays in the document and displays a blank space for where the managed control would go if it was allowed to run. 

A second reason we don't embed the WinForm control directly is because we wanted to support registration free controls. To embed a WinForms control directly, we would have had to create a COM-callable wrapper for it and register that COM callable wrapper in the registry. The .NET way is not to have to go touch the registry when you install a solution. Having the “WinForms.Control.Host“ ActiveX control means we only have to register that control in the registry once, and then you can use any managed controls you want in Office solutions without having to touch the registry again.

Another clue to the architecture of managed control hosting comes when you write this code in the button click event handler:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

   Dim b As System.Windows.Forms.Button = Button1
MsgBox(b.Parent.GetType().ToString())

End Sub

Note that I am casting the Button1 object to System.Windows.Forms.Button. This is because I want to look at the parent property provided by the primary interface, not the parent property provided by the extender interface. For more on this, see my previous blog on the subject: https://blogs.msdn.com/eric_carter/archive/2004/05/19/135563.aspx

When I run the customization and click on the button, I get the following dialog box:

---------------------------
ExcelApplication61
---------------------------
Microsoft.VisualStudio.OfficeTools.Controls.VSTOContainerControl
---------------------------
OK
---------------------------

OK--what's going on here? You would expect the parent to be the ActiveX control, yet it looks like there is another object here. The VSTOContainerControl is a control that is parented by the WinForms.Control.Host ActiveX control and always serves as the parent to the actual control (in this case Windows.Forms.Button) being put in the document.

Why this additional layer? 

The VSTOContainerControl derives from UserControl and provides a safe surface on which to place any arbitrary WinForms control. There are several reasons why this layer is required. Among the most important are:

1) Most of the WinForms controls aren't attributed with the COMVisibleAttribute set to true. This means they can't be directly talked to by our COM based ActiveX control (Winforms.Control.Host). The VSTOContainerControl is marked with the COMVisibleAttribute set to true which allows the ActiveX control to talk to it and it in turn talks to the control being hosted, in this case the Button.

2) There are certain WinForms controls that always expect to be parented by a Form or UserControl. They don't react well to being parented directly by an ActiveX control. UserControl (which the VSTOContainerControl derives from) has been tested extensively when parented directly by an ActiveX control. So for further stability and compatibility, we always add this addition UserControl layer when hosting a control.

This architecture ensures reliable and stable hosting of WinForms controls within Office documents.

Now, when you re-read my previous article on Extender & Primary you will understand the last paragraph in more detail: if you talk to the regular Button1 class we provide (Microsoft.Office.Tools.Excel.Controls.Button)and set it's Left property, you are changing the position of the WinForms.Control.Host ActiveX control in the document since you are talking to the Extender interface's Left by default. If you cast the control we provide to a System.Windows.Forms.Button and set the left, you are now setting the left position of the Button relative to the VSTOContainerControl which you will never want to do.