Hosting Licensed ActiveX Controls in WPF

by bryanpjohnston

Recently we had a need to host some ActiveX controls inside a WPF window. Hosting controls in a .NET Windows Forms app is pretty straight-forward, basically register the control, add it to your toolbox in Visual Studio, then drag-n-drop the control on your form. Hosting the control in a WPF window is possible by the use of a WindowsFormsHost. Here is a walkthrough for hosting an ActiveX control in WPF from MSDN.

However we found that some of our controls gave licensing errors which crashed the application. These were our own custom controls that contained licensed third party controls. Everything seemed to work when the controls were called from a VB executable, but when hosting them in WPF, the controls crashed if the developer license wasn’t installed on the computer.

After reading up on Visual Basic Licensing, it seemed that our parent ActiveX control should pass the necessary license information to the third party control at runtime. I took a step back and created a Windows Forms test project. I created a custom test .ocx that contained a licensed third party control and placed it on a Windows Form. I ran my sample project on a test machine and SUCCESS, the control displayed fine – no licensing issues. A quick look at the designer code of my form shows some extra initialization that we were missing in WPF:

#regionWindows Form Designer generated code

///<summary>
/// Required method for Designer support – do not modify
/// the contents of this method with the code editor.
///</summary>

private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.axUC_Bryan1 = new AxBryanTestUC.AxUC_Bryan();
((System.ComponentModel.ISupportInitialize)(this.axUC_Bryan1)).BeginInit();
this.SuspendLayout();
//
// axUC_Bryan1
//
this.axUC_Bryan1.Enabled = true;
this.axUC_Bryan1.Location = new System.Drawing.Point(35, 34);
this.axUC_Bryan1.Name = “axUC_Bryan1”;
this.axUC_Bryan1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject(“axUC_Bryan1.OcxState”)));
this.axUC_Bryan1.Size = new System.Drawing.Size(545, 329);
this.axUC_Bryan1.TabIndex = 0;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(672, 412);
this.Controls.Add(this.axUC_Bryan1);
this.Name = “Form1”;
this.Text = “Form1”;
((System.ComponentModel.ISupportInitialize)(this.axUC_Bryan1)).EndInit();
this.ResumeLayout(false);
}
#endregion

private AxBryanTestUC.AxUC_Bryan axUC_Bryan1;

To properly initialize the control, you need to call .BeginInit(), set the OcxState, then call.EndInit(). The first and last part sound easy enough, but how do we set the OcxState. When the ActiveX control was added to the Windows Form, Visual Studio added the OcxState as a resource to the form. So open Form1.res in an xml editor, copy the <data>…</data> element that references your <controlName>.OcxState, and add it to your WPF Resources.resx file. In the excerpt below, originally data name=”axUC_Bryan1.OcxState”, but I changed the name to _myCustomControl to match the name of my class member (and because the designer complained it wasn’t a valid identifier).

  <data name=_myCustomControl” mimetype=application/x-microsoft.net.object.binary.base64>
<value>
AAEAAAD/////AQAAAABBBAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBBBBBBERhdGEHAgIAAAAJAwAAAA8DAAAAbQAAAAIB
AAAAAQAABAAQAAAAbWZlY3BkZWRoaG9iYWFuZwAAAABIAAAAk7IAAEgAAAADAAgAC/JXRyAAAABfAGUA
eAB0AGUAbgB0AHgAVDgAAAMACAAK8ldH4P///18AZQB4AHQAZQBuAHQAeQABIgAACw==
    </value>
</data>

Resources.resx – designer view

Copying the resource above is necessary because the AxHost.OcxState class contains the necessary licensing information that gets passed to your control. Even if your control doesn’t require a license, if it contains a licensed third party control, it will need to be initialized properly. So once you have added the appropriate serialized AxHost.OcxState resources to your WPF project, you can create and initialize your control like so:

private void LoadUserControl(object sender, RoutedEventArgs e)
{_myCustomControl = new AxBryanTestUC.AxUC_Bryan();

((System.ComponentModel.ISupportInitialize)(_myCustomControl)).BeginInit();

_myCustomControl.OcxState = ((System.Windows.Forms.AxHost.State)(Properties.Resources._myCustomControl));

((System.ComponentModel.ISupportInitialize)(_myCustomControl)).EndInit();

_myCustomControl.Show();

contentHost.Child = _myCustomControl;
}

Advertisements