How to do this:
1. build a ProcessInfo that's going to define how your "external app" window appears.
2. use Process.Start with the ProcessInfo to get a handle to an instance of the external app.
3. give the started Process a little time to "settle in."
4. set the Parent Window ... your Panel or other WinForms ContainerControl ... of the Process handle.
5. move the external app window to the place you want it inside your WinForm ContainerControl.
Example code: a WinForm named 'FormWithNotePad with a Panel on it named 'pnlForNotePad:
[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", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
public Process NotePadProcess { set; get; }
private void FormWithNotePad_Load(object sender, EventArgs e)
{
ProcessStartInfo info = new ProcessStartInfo();
info.UseShellExecute = true;
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Normal;
info.RedirectStandardInput = false;
info.RedirectStandardOutput = false;
info.RedirectStandardError = false;
info.FileName = "notepad.exe";
NotePadProcess = Process.Start(info);
if (NotePadProcess == null) return;
NotePadProcess.WaitForInputIdle();
SetParent(NotePadProcess.MainWindowHandle, pnlForNotePad.Handle);
MoveWindow(NotePadProcess.MainWindowHandle, 0, 0, pnlForNotePad.Width, pnlForNotePad.Height, true);
}
Now, let's consider the issue of Focus in WinForms:
1. as you may know, for every Control there is a 'TabStop Property, and a 'TabOrder value; that governs the order in which a given Control on a Form gets Focus, both when you use the tab-key to move Focus from control to control, and at app start-up ... most of the time.
The control on the Form with current active Focus is returned by the 'ActiveControl property.
Take some time (if you haven't already) to familiarize yourself with 'TabStop and 'TabOrder properties, and the 'ActiveControl property.
2. however, some Controls on a Form get "preference" for taking Focus; TextBox and RichTextBox seem to get this "preference" in my experience.
So, what to with your externa app running in some ContainerControl ... and Focus:
1. set the Form 'KeyPreview Property to 'true.
2. wire-up an EventHandler to the Form 'KeyDown Event
3. plan for how you want other Controls on the Form to get key-strokes: if you have a TextBox on your Form, you almost certainly want the user to be able to type in it.
Example:
private void FocusBackOnTheExternalApp_Click(object sender, EventArgs e)
{
pnlForNotePad.Focus();
}
private void FormWithNotePad_KeyDown(object sender, KeyEventArgs e)
{
if (ActiveControl == null
|| pnlForNotePad == this.ActiveControl
&& ! (ActiveControl is TextBoxBase))
{
SetForegroundWindow(NotePadProcess.MainWindowHandle);
SendKeys.SendWait(e.KeyCode.ToString());
e.Handled = true;
}
}
private void FormWithNotePad_Click(object sender, EventArgs e)
{
ActiveControl = null;
}
In the KeyDown EventHandler shown above, we don't let the external app get the keystrokes if the active control on the form is a TextBox, or RichTextBox ... both inherit from 'TextBoxBase.
Of course, you could configure your Panel, or other ContainerControl, to have another Control on it you would use for some purpose in relationship to the external app.
Other ideas:
1. consider using a Form as the Container ?
2. consider keeping a local copy of the keystrokes sent to the external app ?
3. of course, you can use other Controls on the Form, like a TextBox, as a source of whatever characters you want to send to the external app: just remember that for the external app to receive input via 'SendKeys its Windows handle must be set to 'topmost via the 'SetForegroundWindow API call.