How can I run another application within a panel of my C# program?

126,602

Solution 1

I don't know if this is still the recommended thing to use but the "Object Linking and Embedding" framework allows you to embed certain objects/controls directly into your application. This will probably only work for certain applications, I'm not sure if Notepad is one of them. For really simple things like notepad, you'll probably have an easier time just working with the text box controls provided by whatever medium you're using (e.g. WinForms).

Here's a link to OLE info to get started:

http://en.wikipedia.org/wiki/Object_Linking_and_Embedding

Solution 2

Using the win32 API it is possible to "eat" another application. Basically you get the top window for that application and set it's parent to be the handle of the panel you want to place it in. If you don't want the MDI style effect you also have to adjust the window style to make it maximised and remove the title bar.

Here is some simple sample code where I have a form with a button and a panel:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Process p = Process.Start("notepad.exe");
            Thread.Sleep(500); // Allow the process to open it's window
            SetParent(p.MainWindowHandle, panel1.Handle);
        }

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

I just saw another example where they called WaitForInputIdle instead of sleeping. So the code would be like this:

Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);

The Code Project has a good article one the whole process: Hosting EXE Applications in a WinForm project

Solution 3

Another interesting solution to luch an exeternal application with a WinForm container is the follow:

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


private void Form1_Load(object sender, EventArgs e)
{
    ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
    psi.WindowStyle = ProcessWindowStyle.Minimized;
    Process p = Process.Start(psi);
    Thread.Sleep(500);
    SetParent(p.MainWindowHandle, panel1.Handle);
    CenterToScreen();
    psi.WindowStyle = ProcessWindowStyle.Normal;
}

The step to ProcessWindowStyle.Minimized from ProcessWindowStyle.Normal remove the annoying delay.

enter image description here

Solution 4

  • Adding some solution in Answer..**

This code has helped me to dock some executable in windows form. like NotePad, Excel, word, Acrobat reader n many more...

But it wont work for some applications. As sometimes when you start process of some application.... wait for idle time... and the try to get its mainWindowHandle.... till the time the main window handle becomes null.....

so I have done one trick to solve this

If you get main window handle as null... then search all the runnning processes on sytem and find you process ... then get the main hadle of the process and the set panel as its parent.

        ProcessStartInfo info = new ProcessStartInfo();
        info.FileName = "xxxxxxxxxxxx.exe";
        info.Arguments = "yyyyyyyyyy";
        info.UseShellExecute = true;
        info.CreateNoWindow = true;
        info.WindowStyle = ProcessWindowStyle.Maximized;
        info.RedirectStandardInput = false;
        info.RedirectStandardOutput = false;
        info.RedirectStandardError = false;

        System.Diagnostics.Process p = System.Diagnostics.Process.Start(info); 

        p.WaitForInputIdle();
        Thread.Sleep(3000);

        Process[] p1 ;
    if(p.MainWindowHandle == null)
    {
        List<String> arrString = new List<String>();
        foreach (Process p1 in Process.GetProcesses())
        {
            // Console.WriteLine(p1.MainWindowHandle);
            arrString.Add(Convert.ToString(p1.ProcessName));
        }
        p1 = Process.GetProcessesByName("xxxxxxxxxxxx");
        //p.WaitForInputIdle();
        Thread.Sleep(5000);
      SetParent(p1[0].MainWindowHandle, this.panel2.Handle);

    }
    else
    {
     SetParent(p.MainWindowHandle, this.panel2.Handle);
     }

Solution 5

I notice that all the prior answers use older Win32 User library functions to accomplish this. I think this will work in most cases, but will work less reliably over time.

Now, not having done this, I can't tell you how well it will work, but I do know that a current Windows technology might be a better solution: the Desktop Windows Manager API.

DWM is the same technology that lets you see live thumbnail previews of apps using the taskbar and task switcher UI. I believe it is closely related to Remote Terminal services.

I think that a probable problem that might happen when you force an app to be a child of a parent window that is not the desktop window is that some application developers will make assumptions about the device context (DC), pointer (mouse) position, screen widths, etc., which may cause erratic or problematic behavior when it is "embedded" in the main window.

I suspect that you can largely eliminate these problems by relying on DWM to help you manage the translations necessary to have an application's windows reliably be presented and interacted with inside another application's container window.

The documentation assumes C++ programming, but I found one person who has produced what he claims is an open source C# wrapper library: https://bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper. The post is old, and the source is not on a big repository like GitHub, bitbucket, or sourceforge, so I don't know how current it is.

Share:
126,602

Related videos on Youtube

Alex
Author by

Alex

Updated on July 05, 2022

Comments

  • Alex
    Alex almost 2 years

    I've been reading lots on how to trigger an application from inside a C# program (Process.Start()), but I haven t been able to find any information on how to have this new application run within a panel of my C# program. For example, I'd like a button click to open a notepad.exe WITHIN my application, not externally.

  • hrh
    hrh over 12 years
    Super helpful! the link didn't show the dll imports for their functions so i thought id share them here [DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll")] static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll")] static extern bool MoveWindow(IntPtr Handle, int x, int y, int w, int h, bool repaint);
  • user21479
    user21479 about 9 years
    When I use this with IE or Chrome, top portion of the browser shows up as black. Is there a way to change this to transparent so that it shows my main window's color?
  • Fernando Vieira
    Fernando Vieira about 8 years
    Notepad was just an example for testing purposes!
  • Chris Rogers
    Chris Rogers over 7 years
    @PaulSonier - even when the short answer is completely wrong? ;-) The short answer is Yes
  • dudeNumber4
    dudeNumber4 over 7 years
    The referenced article/code flat doesn't work for me (maybe because I'm using WPF?). Must use this: stackoverflow.com/questions/5836176/…. Also, for pinvoke imports, pinvoke.net is always useful.
  • Sam Hobbs
    Sam Hobbs over 6 years
    Yes, experienced Windows programmers use WaitForInputIdle. Windows programmers should always look twice or more at code that uses Sleep.
  • Vinicius Gonçalves
    Vinicius Gonçalves about 6 years
    In the real world we often have to adapt something that was not made for that.
  • Lodewijk
    Lodewijk almost 6 years
    don't sleep to wait for events that don't execute in guaranteed expected time on a realtime platform
  • camino
    camino over 5 years
    if you want to maximize the window: [DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); social.msdn.microsoft.com/Forums/vstudio/en-US/…
  • Kiran Desai
    Kiran Desai about 5 years
    This solution is working well for notepad exe, but when I'm trying to use excel exe then excel is opened outside of panel. How to restrict that?
  • Louis Go
    Louis Go almost 4 years
    @KiranDesai I tried the solution and code project article but both of them don't work on Win7 and Win10 2004. May I ask what's your environment to make it work?