65.9K
CodeProject is changing. Read more.
Home

Hosting EXE Applications in a WPF Window Application

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (19 votes)

Oct 25, 2013

CPOL

1 min read

viewsIcon

385021

downloadIcon

9199

Introduce a simple way to embed an EXE into a WPF window application.

Introduction 

This article introduces a way to host an EXE in a WPF window. To make the code easy to reuse, it is set into a WPF user control and also implements the IDisposable interface. A test WPF window app is added as a test project.  

Background 

As a development request I needed to embed a wPython Python edit and compare tool, built by me, into a newly developed WPF application. With the magic power of search engines, I found an article in CodeProject on embedding an EXE into a WinForms program. It's needed to make several changes to become a new WPF control. I also added the IDisposable interface to improve the resource control ability. The links to the reference articles are listed here:

Using the code 

To use the control, we only need to specify the full path of the executable to be embedded and when to dispose it. 

appControl.ExeName = "notepad.exe";
this.Unloaded += new RoutedEventHandler((s, e) => { appControl.Dispose(); }); 

How does it works 

The embedded application is launched with its containing directory as a working directory.

try
{
  var procInfo = new System.Diagnostics.ProcessStartInfo(this.exeName);
  procInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(this.exeName);
  // Start the process
  _childp = System.Diagnostics.Process.Start(procInfo);

  // Wait for process to be created and enter idle condition
  _childp.WaitForInputIdle();

  // Get the main handle
  _appWin = _childp.MainWindowHandle;
}
catch (Exception ex)
{
  Debug.Print(ex.Message + "Error");
}  

Get the container WPF control's handle and set the embedded application's parent window to the container. Change the style for the embedded application. 

// Put it into this form
var helper = new WindowInteropHelper(Window.GetWindow(this.AppContainer));
SetParent(_appWin, helper.Handle);

// Remove border and whatnot
SetWindowLongA(_appWin, GWL_STYLE, WS_VISIBLE);

// Move the window to overlay it on this window
MoveWindow(_appWin, 0, 0, (int)this.ActualWidth, (int)this.ActualHeight, true); 

The embedded application is disposed when the container is disposed.

if (!_isdisposed)
{
  if (disposing)
  {
      if (_iscreated && _appWin != IntPtr.Zero && !_childp.HasExited)
      {
          // Stop the application
          _childp.Kill();

          // Clear internal handle
          _appWin = IntPtr.Zero;
      }
  }
  _isdisposed = true;
}  

Points of Interest 

Some of the embedded applications can't be closed as mentioned in the article: Hosting EXE Application in a WinForms project. So it is changed to use the Process.Kill() method to make sure the embedded application is closed.  

Also the signature of SetWindowLongA is changed a little as the previous one throws an error in the VS2012 compiler.  

History

  • 2013-10-25: Released.