Search code examples
c#wpfexewindowsformshost

WindowsFormsHost in WPF Not Displaying Hosted Application


In my WPF, I have a grid that contains a WindowsFormsHost which will host an .exe. My .xaml code is:

<Window x:Class="PracticeWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PracticeWPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="800" Width="1300">
    <Grid x:Name="grid">

        <Button x:Name="BtnRun" Content="Run" 
                HorizontalAlignment="Left" Margin="10,10,0,0"
                VerticalAlignment="Top" Click="BtnRun_Click"/>

        <WindowsFormsHost x:Name="formshost" Margin="0,39,0,0"
            Height="720" Width="1280"/>

    </Grid>
</Window>

And my cs:

namespace PracticeWPF
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        [DllImport("user32.dll")]
        public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        private void BtnRun_Click(object sender, EventArgs e)
        {
            Process proc = Process.Start("notepad.exe"); 
            proc.WaitForInputIdle();

            while (proc.MainWindowHandle == IntPtr.Zero)
            {
                Thread.Sleep(100);
                proc.Refresh();
            }
            SetParent(proc.MainWindowHandle, formshost.Handle);
        }    
    }
}

Everything works when I'm using a WinForm but when I use the WindowsFormsHosting inside a WPF the .exe isn't visible. Any help would be greatly appreciated. Thank you.


Solution

  • At this link Docking Window inside another Window I think your answer. I matched it with your code

    xaml

    <Window x:Class="PracticeWPF.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  
            xmlns:local="clr-namespace:PracticeWPF"
            mc:Ignorable="d"
            Title="MainWindow" Height="800" Width="1300">
        <Grid x:Name="grid">
    
            <Button x:Name="BtnRun" Content="Run" 
                    HorizontalAlignment="Left" Margin="10,10,0,0"
                    VerticalAlignment="Top" Click="BtnRun_Click"/>
    
            <WindowsFormsHost x:Name="formshost" Margin="0,39,0,0"
                Height="720" Width="1280">
                 <wf:Button Text="by button" Visible="False"></wf:Button>
            </WindowsFormsHost>
        </Grid>
    </Window>
    

    and mainwindow.cs

    namespace PracticeWPF
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void BtnRun_Click(object sender, EventArgs e)
            {
                //Process proc = Process.Start("notepad.exe");
               //proc.WaitForInputIdle();
    
                //while (proc.MainWindowHandle == IntPtr.Zero)
                //{
                //    Thread.Sleep(100);
                //    proc.Refresh();
                //}
                this.Width = formshost.Width;
                this.Height = formshost.Height;
                dockIt();
            }
    
    
            [DllImport("user32.dll")]
            public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    
            private Process pDocked;
            private IntPtr hWndOriginalParent;
            private IntPtr hWndDocked;
    
            [DllImport("user32.dll", SetLastError = true)]
            public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    
    
            private void dockIt()
            {
                if (hWndDocked != IntPtr.Zero) //don't do anything if there's already a window docked.
                    return;
                IntPtr hWndParent = IntPtr.Zero;
    
                pDocked = Process.Start(@"notepad");
                while (hWndDocked == IntPtr.Zero)
                {
                    pDocked.WaitForInputIdle(1000); //wait for the window to be ready for input;
                    pDocked.Refresh();              //update process info
                    if (pDocked.HasExited)
                    {
                        return; //abort if the process finished before we got a handle.
                    }
                    hWndDocked = pDocked.MainWindowHandle;  //cache the window handle
                }
                //Windows API call to change the parent of the target window.
                //It returns the hWnd of the window's parent prior to this call.
                hWndOriginalParent = SetParent(hWndDocked, formshost.Handle);
    
                //Wire up the event to keep the window sized to match the control
                formshost.SizeChanged += new SizeChangedEventHandler(Panel1_Resize);
                //Perform an initial call to set the size.
                Panel1_Resize(new Object(), new EventArgs());
            }
    
            private void undockIt()
            {
                //Restores the application to it's original parent.
                SetParent(hWndDocked, hWndOriginalParent);
            }
    
            private void Panel1_Resize(object sender, EventArgs e)
            {
                //Change the docked windows size to match its parent's size. 
                MoveWindow(hWndDocked, 0, 0, (int)formshost.Width, (int)formshost.Height, true);
            }
        }
    }