Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

WPF Interoperability


Embedding ActiveX Controls in WPF Applications

There must be thousands of ActiveX controls in existence, and they can be easily embedded in WPF applications. But that's not because of any hard work done by the WPF team. Ever since version 1.0, Windows Forms has had a bunch of plumbing built-in for interoperability with ActiveX controls. Rather than duplicating all of that plumbing natively inside WPF, the team decided to simply depend on Windows Forms for this scenario. WPF gets the functionality "for free" just by working well with Windows Forms.

Using Windows Forms as an intermediate layer between ActiveX and WPF might sound suboptimal, but the development experience is just about as pleasant as can be expected. To demonstrate how to embed an ActiveX control in a WPF application, we'll use the Microsoft Terminal Services Control that ships with Windows. This control contains basically all the functionality of Remote Desktop, but controllable via a few simple APIs.

The first step for using an ActiveX control is to get a managed and Windows Forms-compatible definition of the relevant types. This can be done in two ways:

  • Run the ActiveX Importer (AXIMP.EXE) on the ActiveX DLL. This utility is included in the .NET Framework component of the Windows SDK.
  • In any Windows Forms project in Visual Studio, add the component to the Toolbox using the COM Components tab from the dialog shown by the Tools, Choose Toolbox Items menu item. Then drag the control from the Toolbox onto any Form. This process causes Visual Studio to invoke the ActiveX Importer behind the scenes.

No matter which approach you use, two DLLs get generated. You should add references to these in your WPF-based project (along with System.Windows.Forms.dll and WindowsFormsIntegration.dll). One is an Interop Assembly that contains "raw" managed definitions of the unmanaged interfaces, classes, enums, and structures defined in the type library contained inside the ActiveX DLL. The other is an assembly that contains a Windows Forms control corresponding to each ActiveX class. The first DLL is named with the library name from the original type library, and the second DLL is named the same but with an Ax prefix.

The Microsoft Terminal Services Control, the original ActiveX DLL is called mstscax.dll and is found in Windows' system32 directory. (In the Choose Toolbox Items dialog, it shows up as "Microsoft Terminal Services Control.") Running the ActiveX Importer generates MSTSCLib.dll and AxMSTSCLib.dll.

With the four relevant two assemblies added to a project (MSTSCLib.dll, AxMSTSCLib.dll, System.Windows.Forms.dll, and WindowsFormsIntegration.dll), Listings Ten and Eleven contain the XAML and C# code to host the control and get the resulting application shown in Figure 11.

[Click image to view at full size]
Figure 11: Hosting the Terminal Services ActiveX Control in a WPF Window.

There's nothing special about the XAML in Listing Ten; it simply contains a DockPanel with a TextBox and Button for choosing a server and connecting to it.

<Window x:Class=.Window1"
xmlns=://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=://schemas.microsoft.com/winfx/2006/xaml"
Title=the Terminal Services ActiveX Control">
<DockPanel Name=" Margin="">
  <StackPanel Margin=",0,0,10" DockPanel.Dock=" Orientation=">
   <TextBox x:Name=" Width="" Margin=",0,10,0"/>
   <Button x:Name=" Click=_Click">Connect</Button>
  </StackPanel>
</DockPanel>
</Window>
Listing Ten

In Listing Eleven, a WindowsFormsHost is added to the DockPanel, and the Windows Forms representation of the ActiveX control is added to the WindowsFormsHost. This control is called AxMsTscAxNotSafeForScripting. (In versions of Windows prior to Windows Vista, it has the somewhat simpler name of AxMsTscAx.) The interaction with the AxMsTscAxNotSafeForScripting control is quite simple. Its Server property can be set to a simple string, and you can connect to the server by calling Connect.

using System;
using System.Windows;
using System.Windows.Forms.Integration;

namespace HostingActiveX
{ 
 public partial class Window1 : Window
 { 
  AxMSTSCLib.AxMsTscAxNotSafeForScripting termServ;
  public Window1()
  { 
   InitializeComponent();

   // Create the host and the ActiveX control
   WindowsFormsHost host = new WindowsFormsHost();
   termServ = new AxMSTSCLib.AxMsTscAxNotSafeForScripting();
   // Add ActiveX control to host, and the host to the WPF panel
   host.Child = termServ;
   panel.Children.Add(host);
  } 
  void connectButton_Click(object sender, RoutedEventArgs e)
  { 
   termServ.Server = serverBox.Text;
   termServ.Connect();
  } 
 } 
} 
</Window>
Listing Eleven

Of course, the instantiation of the WindowsFormsHost and the AxMsTscAxNotSafeForScripting control can be done directly in XAML, replacing the highlighted code in Listing Eleven. This is shown in Listing Twelve. You could go a step further and use data binding to replace the first line in connectButton_Click, but you would still need the event handler for calling the Connect method.

<Window x:Class=.Window1"
xmlns=://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ax="clr-namespace:AxMSTSCLib;assembly=AxMSTSCLib"
      Title=the Terminal Services ActiveX Control">
<DockPanel Name=" Margin="">
  <StackPanel Margin=",0,0,10" DockPanel.Dock=" Orientation=">
   <TextBox x:Name=" Margin=",0,10,0"/>
   <Button x:Name=" Click=_Click">Connect</Button>
  </StackPanel>
  <WindowsFormsHost>
   <ax:AxMsTscAxNotSafeForScripting x:Name="termServ"/>
  </WindowsFormsHost>
</DockPanel>
</Window>
Listing Twelve


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.