Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
How can I embed a non-native application (application installed in windows 7)in a windows form using c#.

I am able to get what i have so far to work sometimes when i start with debugging and the application opens within the form. But when i start without debugging, the application always opens outside of the form. I don't understand why this happens.

Is what I am trying to accomplish possible? Based on other forum answers, it seems it might not be

Thank you

What I have tried:

C#
public partial class Form1 : Form { Process process = new Process();

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

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    public Form1()
    {
        InitializeComponent();
        // panel1.Container.Add(process);
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardInput = true;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = false;
         string path = Path.Combine(Path.GetFullPath(@"C:\Program Files (x86)\Plan-G v3.2.0"), "Plan-G3.exe");
         process = Process.Start(path);

         Debug.WriteLine(process.MainWindowHandle);
         while (process.MainWindowHandle == IntPtr.Zero)
        {
             Thread.Sleep(1000); // Don't hog the CPU
            process.Refresh(); // You need this since `MainWindowHandle` is cached


        }

        Form1.SetForegroundWindow(process.MainWindowHandle);
        SetForegroundWindow(process.MainWindowHandle);

        SetParent(process.MainWindowHandle, panel1.Handle);

        MoveWindow(process.MainWindowHandle, 0, 0, panel1.Width - 90, panel1.Height, true);


    }
}


I have also tried this:
C#
public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();
        [DllImport("user32.dll")]
        static extern bool AttachThreadInput(uint idAttach, uint idAttachTo,
   bool fAttach);

        [DllImport("user32.dll", SetLastError = true)]
        static extern bool BringWindowToTop(IntPtr hWnd);

        [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

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

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
        Process process = new Process();
        private static void ForceForegroundWindow(IntPtr hWnd)

        {

            uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);

            uint appThread = GetCurrentThreadId();

            const int SW_SHOW = 5;

            if (foreThread != appThread)

            {

                AttachThreadInput(foreThread, appThread, true);

                BringWindowToTop(hWnd);

                ShowWindow(hWnd, SW_SHOW);

                AttachThreadInput(foreThread, appThread, false);

            }

            else

            {

                BringWindowToTop(hWnd);

                ShowWindow(hWnd, SW_SHOW);

            }

        }
        public Form1()
        {
            InitializeComponent();

            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.UseShellExecute = false;
            string path = Path.Combine(Path.GetFullPath(@"C:\Program Files (x86)\Plan-G v3.2.0"), "Plan-G3.exe");
            process = Process.Start(path);

            Debug.WriteLine(process.MainWindowHandle);
            while (process.MainWindowHandle == IntPtr.Zero)
            {
                Thread.Sleep(1000); // Don't hog the CPU
                process.Refresh(); // You need this since `MainWindowHandle` is cached


            }

            //Form1.SetForegroundWindow(process.MainWindowHandle);
            ForceForegroundWindow(process.MainWindowHandle);

            SetParent(process.MainWindowHandle, this.Handle);

            MoveWindow(process.MainWindowHandle, 0, 0, this.Width - 90, this.Height, true);
             


        }
    }


I have also looked at all other solutions proposed in CodeProject and elsewhere including:
Bring Process to the front[^]
Hosting EXE Applications in a WinForm project[^]
c# - Docking Window inside another Window - Stack Overflow[^]
How to embed (dock) Third party EXE into Panel/form in C# .net[^]
Posted
Updated 26-Oct-18 4:50am
v2
Comments
Maciej Los 26-Oct-18 2:16am    
Why? It has no sense!
anupama lite iyer 26-Oct-18 2:31am    
I need to show it as part of my form

1 solution

You're going to have to explain what you mean by a "non-windows application exe".

There are problems with doing this. First, the app you launch may not support this and may render incorrectly.

Next, the app will not know it's inside your application window. It will behave just like your application is now the desktop window. Users can move it off-screen, minimize it, maximize it, resize it, ... whatever.

Also, when you launch the application, you have to wait for the window handle to be created before you try to get it's window handle. Your code seems to be written to do that, but it's not going to work in all cases. More importantly, the window handle may now exist, but is its message pump running? Maybe not. When you start throwing messages at the window handle, the message pump to process them may not be there yet, so your messages get ignored.

A better solution is to scrap the polling for MainWindowHandle and just call process.WaitForInputIdle(). That way you know the message pump is running.

Also, you can get rid of the two calls to SetForegroundWindow. You shouldn't need them at all.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900