Delphi TControls are hwnds, too

Borland devcon starts Tuesday, so with that in mind I figured what can be more fun than putting WPF inside a Delphi application?  Turns out this is both really easy and really difficult.  The easy part is that hwnds are hwnds are hwnds, so Delphi hwnds get along just fine with WPF HwndSource.  There's more than one way to do this in Delphi, but the quickest and easiest was grabbed the Delphi form's handle and pass it to HwndSource:

   dialog_global := TForm1.Create(nil);
  Result := dialog_global.Handle;

(An alternate and more elegant approach would have been to create a subclass of TControl that overrides CreateWnd, and create the HwndSource from there.  But if you don't need to manipulate the HwndSource as a TControl, what I did works fine)

The hard part was, Delphi doesn't yet support .Net 2.0, which WPF requires.  I'm sure Borland will fix that in a future version, although for now it definitely makes life harder!  But I wasn't to be denied, so I decided to use the unmanaged version of Delphi ("Delphi for Win32" as opposed to "Delphi for the .Net Framework"), together with a separate assembly written in a language that supports .Net 2.0.  The easiest way to make this happen was using a Delphi DLL together with a managed .exe, because I couldn't figure out a way to write a DLL that unmanaged Delphi would be willing to call.  (I tried writing a dll in managed C++ with unmanaged entry points, but Delphi identified the dll as managed code and refused to touch it because of the CLR version)  My Delphi dll exported two functions -- one that returns the form's hwnd, and a second that displayed the form.  All the managed code .exe has to do is call the first export, pass that hwnd to HwndSource, and then call the second export.

The Delphi part looked like this:

 var
  dialog_global: TForm1;

function Setup(): HWND; stdcall;
begin
  dialog_global := TForm1.Create(nil);
  Result := dialog_global.Handle;
end;

function ShowIt(child:HWND): Integer; stdcall;
begin
  dialog_global.ShowModal();
  Result := 0;
end;

exports
  Setup, ShowIt;

And the managed code? 

 HWND dialog = Setup();
HWND clock = ManagedCode::GetHwnd(dialog, 263, 72, 186, 183);
ShowIt(clock);

Where GetHwnd creates an HwndSource and instantiates the WPF content of your choice.  Not bad for a Sunday afternoon!