How to host an console exe with UI in winform
I am working on a project with some specific requirement: I need to create a program which can monitor and runs exe inside of it using c#. However, an approach of using Console program to actually host anoth开发者_如何学运维er exe seems to be no end. So i used WinForm.
I have been looking and found some quite good solution, which host an UI Application inside the WinForm. But in my case, the exe has no UI, but it is capable of create an UI (OpenGL), so it is not applicable for those solutions. Is there any way to host this kind of exe inside of the WinForm? Which i can run many of it simultaneously?
Thanks
Hosting a process within another one makes no sens. If you want to launch an exe from another one, you can use System.thread.Process
and if those process need to interact with each other, well, WCF is made just for that.
Thank you for all your suggestion. However, i did find out another way around to grab the correct Window which created by my console exe, and put it into the correct winform. This is quite a cheat though. This idea is originally comes from the Window Tabifier from codeproject: http://www.codeproject.com/KB/cs/WindowTabifier.aspx . As my exe does not have the corresponding UI for the process.WaitForInputIdle, i do a cheat on Thread.Sleep(2000) to skip the starting time, and grab the created Window of the console based on the name of it.
Library import:
public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private extern static bool EnumThreadWindows(int threadId, EnumWindowsProc callback, IntPtr lParam);
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
private extern static int GetWindowText(IntPtr hWnd, StringBuilder text, int maxCount);
Some methods to find the correct opened window
public IntPtr FindWindowInProcess(Process process, Func<string, bool> compareTitle)
{
IntPtr windowHandle = IntPtr.Zero;
foreach (ProcessThread t in process.Threads)
{
windowHandle = FindWindowInThread(t.Id, compareTitle);
if (windowHandle != IntPtr.Zero)
{
break;
}
}
return windowHandle;
}
private IntPtr FindWindowInThread(int threadId, Func<string, bool> compareTitle)
{
IntPtr windowHandle = IntPtr.Zero;
EnumThreadWindows(threadId, (hWnd, lParam) =>
{
StringBuilder text = new StringBuilder(200);
GetWindowText(hWnd, text, 200);
if (compareTitle(text.ToString()))
{
windowHandle = hWnd;
return false;
}
else
{
windowHandle = FindChildWindow(hWnd, compareTitle);
if (windowHandle != IntPtr.Zero)
{
return false;
}
}
return true;
}, IntPtr.Zero);
return windowHandle;
}
private IntPtr FindChildWindow(IntPtr hWnd, Func<string, bool> compareTitle)
{
IntPtr windowHandle = IntPtr.Zero;
EnumChildWindows(hWnd, (hChildWnd, lParam) =>
{
StringBuilder text = new StringBuilder(200);
GetWindowText(hChildWnd, text, 200);
if (compareTitle(text.ToString()))
{
windowHandle = hWnd;
return false;
}
return true;
}, IntPtr.Zero);
return windowHandle;
}
Last, start the processes:
String fileName = "myexe.exe";
String dir = Path.GetDirectoryName(fileName);
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = fileName;
process.StartInfo.WorkingDirectory = dir;
process.Start();
// Wait for process to be created and enter idle condition
Thread.Sleep(5000);
IntPtr appWin = FindWindowInProcess(process, s => s.StartsWith("Built on"));
// Put it into this form
SetParent(appWin, this.Handle);
// Remove border and whatnot
SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE);
// Move the window to overlay it on this window
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
See Is it possible to log message to cmd.exe in C#/.Net? for information how to create/attach to a console.
Also, look at e.g. Poderosa for an open source terminal emulator that you might be able to embed.
精彩评论