Dynamically creating an ActiveX on a WPF/Windows .Net app

  • Thread starter Thread starter Oriane
  • Start date Start date
O

Oriane

Hi there,

I have problems creating the Windows Media player ActiveX using this C# code
in a Windows Form project:

Type objType = Type.GetTypeFromProgID("AxWMPLib,
AxWindowsMediaPlayer");
oStibil = Activator.CreateInstance(obj);

Of course, I didn't reference the COM component in my .Net project, as I
want to achieve late binding. The objType is null.

Now this WMP ActiveX is installed (I have even tried on two different
machines), and when I use this very same code with another ActiveX class
name, it works. The class name is correct (I can see it if I add a reference
to this WMP COM component in .Net).

Now if the ActiveX is a "in process" ActiveX (a dll or ocx, like the WMP
one) I can't see where it is on my app (I mean on my Windows form). The
final goal would be for me to set the location of the ActiveX, but I can't
see how...

Can I add it to a Control ? To a Container ? Is there a X/Y property I can
set ?

Best regards
 
I just understand that the Ax... DLL is a COM wrapper generated by Visual
Studio when we add the WMP activeX with the designer.

Anyway my other question still remains: how can I set the position of a ocx
on a .Net Windows Form app, when the ActiveX is not referenced but
dynamically created ?

One other question: when the new release of an ActiveX is rolled out, does
its ClassId change ? Or its class name ?

Best regards
 
This works

using WMPLib;
..
//test to see if windows media is already running
private System.Int32 iHandle = Win32.FindWindow("WMPlayerApp", "Windows
Media Player");
//its not so start it
if (iHandle == 0)
{
// get Window handle
System.Diagnostics.Process retVal =
System.Diagnostics.Process.Start(@"C:\Program Files\Windows Media
Player\wmplayer.exe");
retVal.WaitForInputIdle();
}

Win32.SendMessage(iHandle, Win32.WM_COMMAND, 0x00004978, 0x00000000);

--

Regards,
Alvin Bruney [MVP ASP.NET]

[Shameless Author plug]
Download OWC Black Book, 2nd Edition
Exclusively on www.lulu.com/owc $15.00
Need a free copy of VSTS 2008 w/ MSDN Premium?
http://msmvps.com/blogs/alvin/Default.aspx
 
Hello Oriane,

Let's first look at what Visual Studio does for us when we add the WMP
ActiveX to a Winform from tool box, then I will explain my solution of late
binding for WMP.

******** VS Early Binding to Use WMP ActiveX Control ********

1. VS internally calls aximp.exe to generates a DLL named WMPLib.
This is a RCW of the wmv.dll component.
Its CLSID is {6BF52A50-394A-11D3-B153-00C04F79FAA6}, and the progID is
"WMPlayer.OCX"

2. VS internally calls aximp.exe to generates a DLL named AxWMPLib
The AxWMPLib is a completely ordinary .NET assembly (not a COM component,
this explains why Type.GetTypeFromProgID("AxWMPLib, AxWindowsMediaPlayer");
returns null). Its major class "AxWindowsMediaPlayer" inherits from the
abstract call System.Windows.Forms.AxHost. AxWindowsMediaPlayer wraps the
ActiveX control (WMPLib) and exposes them as a fully featured Windows Form
control, which allows us to use it easily in VS Form designer.

Below is the early binding code generated by the designer to use the
control:

this.axWindowsMediaPlayer1 = new AxWMPLib.AxWindowsMediaPlayer();
this.axWindowsMediaPlayer1.Enabled = true;
this.axWindowsMediaPlayer1.Location = new System.Drawing.Point(0, 0);
this.axWindowsMediaPlayer1.Name = "axWindowsMediaPlayer1";
this.axWindowsMediaPlayer1.OcxState =
((System.Windows.Forms.AxHost.State)(resources.GetObject("axWindowsMediaPlay
er1.OcxState")));
this.axWindowsMediaPlayer1.Size = new System.Drawing.Size(292, 273);
this.axWindowsMediaPlayer1.TabIndex = 0;

this.axWindowsMediaPlayer1.Location and this.axWindowsMediaPlayer1.Size
define the position and size of the control. The original ActiveX control
exposes the properties "Top", "Left", "Width", "Height". Our AxHost wraps
these property and exposes them as the Location and Size properties in
Winform.

***** My Solution of Late Binding to Use WMP ActiveX Control *****

Step1. Run this command on the wmv.dll file:
C:\WINDOWS\system32>aximp.exe wmp.dll /source
(aximp.exe is from framework sdk)
The command generates three files:
Generated Source: C:\WINDOWS\system32\AxWMPLib.cs
Generated Assembly: C:\WINDOWS\system32\WMPLib.dll
Generated Assembly: C:\WINDOWS\system32\AxWMPLib.dll

The source file AxWMPLib.cs is actually the source of AxWMPLib.dll wrapping
the ActiveX control (WMPLib). AxWMPLib.cs uses early binding to reference
the RCW dll (WMPLib.dll):
private WMPLib.IWMPPlayer4 ocx;

Step2. Add the source file AxWMPLib.cs to your .NET project. (please do not
add the rest DLLs. If AxWMPLib.dll and WMPLib.dll are already referenced by
your project, please remove them)
After adding the file, you will find the project cannot parse the
compilation for lack of the definition of WMPLib.IWMPPlayer4. In the next
step, we will convert all the early binding codes to late binding and
eliminate the errors.

Step3. Convert all the early binding codes in AxWMPLib.cs to late binding.

A. Change the line
private WMPLib.IWMPPlayer4 ocx;
to
private object ocs;

B. Change the code
this.ocx = ((WMPLib.IWMPPlayer4)(this.GetOcx()));
to
this.ocx = this.GetOcx();

C. Change all the occurrences of get/set ocx's properties to use late
binding:
For example, Change
this.ocx.URL = value;
to
ocx.GetType().InvokeMember("URL",
System.Reflection.BindingFlags.SetProperty, null, ocx, new object[]{ value
});

Step 4. Use the control in our winform:

AxWMPLib.AxWindowsMediaPlayer axWindowsMediaPlayer1 = new
AxWMPLib.AxWindowsMediaPlayer();
((System.ComponentModel.ISupportInitialize)(this.axWindowsMediaPlayer1)).Beg
inInit();
axWindowsMediaPlayer1.Enabled = true;
axWindowsMediaPlayer1.Location = new System.Drawing.Point(0, 0);
axWindowsMediaPlayer1.Name = "axWindowsMediaPlayer1";
axWindowsMediaPlayer1.OcxState =
((System.Windows.Forms.AxHost.State)(resources.GetObject("axWindowsMediaPlay
er1.OcxState")));
axWindowsMediaPlayer1.Size = new System.Drawing.Size(292, 273);
axWindowsMediaPlayer1.TabIndex = 0;
// add the control to the current form:
this.Controls.Add(this.axWindowsMediaPlayer1);
((System.ComponentModel.ISupportInitialize)(this.axWindowsMediaPlayer1)).End
Init();

********* ANSWER SOME "WHYs" and QUESTIONS ***********

1. Why don't I suggest creating an object of "WMPlayer.OCX"?
"WMPlayer.OCX" is the prog ID of the underlying ActiveX control. Creating
such an object can be a way to solve the problem:
Dim wmpApp As Object = CreateObject("WMPlayer.OCX")
However, it requires us to write more codes for attaching the ocx control
to Windows Form. Looking at the source code of AxHost, you may find this:

private void AttachWindow(IntPtr hwnd) {
Debug.WriteLineIf(AxHTraceSwitch.TraceVerbose, "attaching window for
"+this.ToString()+" "+hwnd.ToString());
if (!axState[fFakingWindow]) {
this.WindowAssignHandle(hwnd, axState[assignUniqueID]);
}
UpdateZOrder();

// Get the latest bounds set by the user.
Size setExtent = Size;
Debug.WriteLineIf(AxHTraceSwitch.TraceVerbose, "SetBounds " +
setExtent.ToString());

// Get the default bounds set by the ActiveX control.
UpdateBounds();
Size ocxExtent = GetExtent();
Debug.WriteLineIf(AxHTraceSwitch.TraceVerbose, "OcxBounds " +
ocxExtent.ToString());

Point location = Location;

// Choose the setBounds unless it is smaller than the default bounds.
if (setExtent.Width < ocxExtent.Width || setExtent.Height <
ocxExtent.Height)
Bounds = new Rectangle(location.X, location.Y, ocxExtent.Width,
ocxExtent.Height);
else {
Size newSize = SetExtent(setExtent.Width, setExtent.Height);
if (!newSize.Equals(setExtent)) {
Bounds = new Rectangle(location.X, location.Y, newSize.Width,
newSize.Height);
}
}

OnHandleCreated(EventArgs.Empty);
InformOfNewHandle();
}

This is the code that attaches the ActiveX control to the winform handle so
that it can be shown in our form. If you would like to re-write this piece
of code, it can be the second solution of this problem. However, in my
opinion, it is more convenient to reuse the existing implementation of
AxHost.

2. when the new release of an ActiveX is rolled out, does its ClassId
change ? Or its class name ?

The CLSID of WMP ActiveX control won't be changed:
{6BF52A50-394A-11D3-B153-00C04F79FAA6}

When a newer version of WMP is rolled out, it may add some interfaces and
have a newer prog ID version, e.g. WMPlayer.OCX.10, or WMPLib.IWMPPlayer6,
however, the old versions of the interfaces will be kept for backwards
compatibility.

In my above solution, it uses the CLSID to initialize the ActiveX control:
public AxWindowsMediaPlayer() :
base("6bf52a52-394a-11d3-b153-00c04f79faa6") {
}
Therefore, it will continue work in future.

3. how can I set the position of a ocx on a .Net Windows Form app, when the
ActiveX is not referenced but dynamically created ?
Please see my solution in the above section.

Oriane, please let me know whether my solution is helpful and my
explanation is clear or not. If you have any other questions or concerns,
please DON'T hesitate to tell me.

Regards,
Jialiang Ge ([email protected], remove 'online.')
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://support.microsoft.com/select/default.aspx?target=assistance&ln=en-us.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top