This past week I’ve been working on a sample illustrating how to host OpenSpan within WPF. Specifically, I’ve been working on using our re-parenting control to host external applications within the Prism application block from Microsoft.
For my first attempt at using the re-parenting control, I created a WPF user control with this XAML:
<UserControl x:Class="StockTraderRI.Modules.Research.GoogleFinanceView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:os="clr-namespace:OpenSpan.Controls.Reparenting.TabbedReparentContainer;assembly=OpenSpan.Controls" Height="Auto" Width="Auto"> <DockPanel LastChildFill="True"> <TextBlock Text="{Binding TickerSymbol}" Style="{StaticResource CurrentSymbolTitle}" DockPanel.Dock="Top" /> <WindowsFormsHost Name="_WindowsFormsHost"> <os:TabbedReparentContainer Load="OnReparentContainerLoad" Disposed="OnReparentContainerDisposed" /> </WindowsFormsHost> </DockPanel></UserControl>
As you can see I declaratively added the TabbedReparentContainer within the WindowsFormHost. In the load event handler I created and started the adapter:
private void OnReparentContainerLoad(object sender, EventArgs e){ _Google = new GoogleFinanceAdapter(); _Google.HomePage.Created += OnGoogleHomePageCreated; _Google.Start();}
The setup was very easy so I was feeling pretty confident until I ran the project and received this exception: “Unable to start message form.”
I was puzzled since I knew that the exception occurs when we cannot start the windows form we use internally for inter-process communication. What could be stopping us from starting the windows form? To find out, I downloaded the latest version of Reflector and started debugging. If you haven’t used it, the latest version of Reflector let’s you debug decompiled .NET assemblies within Visual Studio. With Reflector it was pretty easy to see that we were stuck in System.Windows.Forms.NativeWindow:
public virtual void CreateHandle(CreateParams cp){ System.Windows.Forms.IntSecurity.CreateAnyWindow.Demand(); if (((cp.Style & 0x40000000) != 0x40000000) || (cp.Parent == IntPtr.Zero)) { System.Windows.Forms.IntSecurity.TopLevelWindow.Demand(); } lock (this) { this.CheckReleased(); WindowClass class2 = WindowClass.Create(cp.ClassName, cp.ClassStyle); lock (createWindowSyncObject) // <== STUCK { // ... } }}
So there you have it. When .NET is creating a window on one thread, you cannot start another thread and create a window on it at the same time. I’m not really sure why this restriction exists as there isn’t anything inside of the lock that looks particularly unsafe. Nevertheless, because of this, you cannot start adapters synchronously within the Load event, at least in Beta 2.
I’m continuing to work on this sample and will keep posting other interesting things I find over the next few days.
Comments on this entry are closed.