0

So I've started fiddling around with VSB to, generally be better. I really want to learn, but I feel either the information I can find is outdated, or the code just doesn't work for me, for whatever reason. But, to the problem:

I want to be able to: Be able to click on a tab inside my VSB project, once that tab is clicked, there's a panel. Inside that panel, I want for example notepad to open, maximized to the panel window, docked and not able to move it (notepad).

I would like to do the same for other programs as well. My current code is the basic that opens notepad in a new window. I've only just begun poking at VSB so my knowledge is very limited.

I was able to do this in VSB (No C#) but not for C3

Current Code:

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

namespace Software_Solution_C__Project__v._10._0._0
{
    public partial class Form1 : Form
    { 
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            AboutBox1 myForm = new AboutBox1();
            myForm.ShowDialog();
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Process.Start("mspaint.exe");
        }
    }
}

I tried to google, I tried different solutions I found, tried to find my way around, but it either crashed or gave endless error messages rendering me unable to do it.

Edit: I've also tried the following code:

namespace Software_Solution_C__Project__v._10._0._0
{
    public partial class Form1 : Form
    { 
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            AboutBox1 myForm = new AboutBox1();
            myForm.ShowDialog();
        }

        private const int WM_SYSCOMMAND = 274; private const int SC_MAXIMIZE = 61488;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]

        public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Process proc;
            proc = Process.Start("Notepad.exe");
            proc.WaitForInputIdle();
            SetParent(proc.MainWindowHandle, panel1.Handle);
            //SendMessage(proc.MainWindowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
        }
    }
}

The problem here is, notepad does open in the panel, but not stretched / docked to fit window, and if I move the window, another instance of notepad opens. And if I close notepad, it just reopens again.

Stefan Wuebbe
  • 2,109
  • 5
  • 17
  • 28
Naeksu
  • 11
  • 1
  • 1
    [Unhook Window into its original State](https://stackoverflow.com/a/65847818/7444103) -- Read the notes about [Is it legal to have a cross-process parent/child or owner/owned window relationship](https://devblogs.microsoft.com/oldnewthing/20130412-00/?p=4683) – Jimi Nov 25 '22 at 11:20
  • 2
    When you wrote _"I was able to do this in VSB (No C#) but not for C3"_ What is "VSB" and what is "C3" – Stefan Wuebbe Nov 25 '22 at 14:21
  • I don't quite understand what you mean. Do you want to use the panel to open the notepad file in the form? If so, are you trying to open a full notepad file, or read the information in the notepad file? Can you elaborate a little more with your VSB? – wenbingeng-MSFT Nov 28 '22 at 09:19
  • @wenbingeng-MSFT I want to open just a clean notepad for example, (this will apply to other .exe I want to open) within that form. So, I have a form, and then a panel. Within that panel, I want the exe to be open, maximized, not able to drag to make it bigger or smaller. If that makes sense? – Naeksu Dec 02 '22 at 11:32
  • found another SO answer that may be relevant https://stackoverflow.com/questions/758494/how-can-i-run-another-application-within-a-panel-of-my-c-sharp-program?noredirect=1&lq=1 – eri0o May 25 '23 at 12:02

1 Answers1

2

After layers of hard work, I've built a "panel1" in "form1" to realize this function. You can refer to the following code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
 
namespace WindowsFormsApp4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// Embed external exe
        /// </summary>
        public class EmbeddedExeTool
        {
            [DllImport("User32.dll", EntryPoint = "SetParent")]
            private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
 
            [DllImport("user32.dll", EntryPoint = "ShowWindow")]
            private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
 
            [DllImport("user32.dll", SetLastError = true)]
            private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
 
            [DllImport("user32.dll")]
            private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
            [DllImport("user32.dll")]
            private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
            IntPtr WindowHandle = IntPtr.Zero;
            private const int WS_THICKFRAME = 262144;
            private const int WS_BORDER = 8388608;
            private const int GWL_STYLE = -16;
            private const int WS_CAPTION = 0xC00000;
            private Process proApp = null;
            private Control ContainerControl = null;
 
            private const int WS_VISIBLE = 0x10000000;
            [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
            private static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
            [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
            private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong);
 
            private IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
            {
                if (IntPtr.Size == 4)
                {
                    return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
                }
                return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
            }
            /// <summary>
            /// Load an external exe program into the program container
            /// </summary>
            /// <param name="control">To display the container control of the exe</param>
            /// <param name="exepath">The full absolute path of the exe</param>
            public void LoadEXE(Control control, string exepath)
            {
                ContainerControl = control;
                control.SizeChanged += Control_SizeChanged;
                ProcessStartInfo info = new ProcessStartInfo(exepath);
                info.WindowStyle = ProcessWindowStyle.Minimized;
                info.UseShellExecute = false;
                info.CreateNoWindow = false;
                proApp = Process.Start(info);
                Application.Idle += Application_Idle;
                EmbedProcess(proApp, control);
                
            }
            /// <summary>
            /// Load an external exe program into the program container
            /// </summary>
            /// <param name="form">The form to display the exe</param>
            /// <param name="exepath">The full absolute path of the exe</param>
            public void LoadEXE(Form form, string exepath)
            {
                ContainerControl = form;
                form.SizeChanged += Control_SizeChanged;
                proApp = new Process();
                proApp.StartInfo.UseShellExecute = false;
                proApp.StartInfo.CreateNoWindow = false;
                proApp.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
                proApp.StartInfo.FileName = exepath;
                proApp.StartInfo.Arguments = Process.GetCurrentProcess().Id.ToString();
                proApp.Start();
                Application.Idle += Application_Idle;
                EmbedProcess(proApp, form);
            }
            /// <summary>
            /// Make sure the application embeds this container
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Application_Idle(object sender, EventArgs e)
            {
                if (this.proApp == null || this.proApp.HasExited)
                {
                    this.proApp = null;
                    Application.Idle -= Application_Idle;
                    return;
                }
                if (proApp.MainWindowHandle == IntPtr.Zero) return;
                Application.Idle -= Application_Idle;
                EmbedProcess(proApp, ContainerControl);
            }
            /// <summary>
            /// Embed the specified program into the specified control
            /// </summary>
            private void EmbedProcess(Process app, Control control)
            {
                // Get the main handle
                if (app == null || app.MainWindowHandle == IntPtr.Zero || control == null) return;
                try
                {
                    // Put it into this form
                    SetParent(app.MainWindowHandle, control.Handle);
                    // Remove border and whatnot               
                    SetWindowLong(new HandleRef(this, app.MainWindowHandle), GWL_STYLE, WS_VISIBLE);
                    ShowWindow(app.MainWindowHandle, (int)ProcessWindowStyle.Maximized);
                    MoveWindow(app.MainWindowHandle, 0, 0, control.Width, control.Height, true);
                }
                catch (Exception ex3)
                {
                    Console.WriteLine(ex3.Message);
                }
            }
 
 
            /// <summary>
            /// Embed container resize event
            /// </summary>
            private void Control_SizeChanged(object sender, EventArgs e)
            {
                if (proApp == null)
                {
                    return;
                }
 
                if (proApp.MainWindowHandle != IntPtr.Zero && ContainerControl != null)
                {
                    MoveWindow(proApp.MainWindowHandle, 0, 0, ContainerControl.Width, ContainerControl.Height, true);
                }
            }
        }
 
 
        private void Form1_Load(object sender, EventArgs e)
        {
            EmbeddedExeTool exetool = new EmbeddedExeTool();
            
            exetool.LoadEXE(panel1, "notepad.exe");  //The specific path to embed the external exe
        }
        /// <summary>
        /// The dock of the panel needs to be set to full
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void panel1_Paint(object sender, PaintEventArgs e)
        {
 
 
        }
    }
}

If you have any questions, we can discuss them together.

wenbingeng-MSFT
  • 1,546
  • 1
  • 1
  • 8