我有一个Win Forms应用程序,我在其中从一个不同的.exe文件开始一个进程,然后将它的Handle属性设置为我的Win Form应用程序中的一个面板。这样可以在Win Forms应用程序中运行其他应用程序。
以下是我如何实现这一目标:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hwc, IntPtr hwp);
string exepath = "myProgram.exe";
ProcessStartInfo p = new ProcessStartInfo(exepath);
process = Process.Start(p);
Thread.Sleep(500); //sleep to allow program to start up properly
SetParent(process.MainWindowHandle, pictureBox1.Handle); //then set the handle to give the effect of being run inside the win forms app
现在我知道我可以在FormClosed事件中调用process.Kill(),这会在关闭此窗体时终止进程,但是如果我的Win Form应用程序被强制退出,我将如何杀死该进程?这甚至可能吗?
由于进程的句柄设置为Win Form应用程序中的面板,因此它不会出现在任务栏上,但如果未调用process.Kill(),它仍将继续运行当Win Form强行关闭时会发生。这意味着每次我必须通过任务管理器将其关闭,这很痛苦。
如果无法做到这一点,我不会费心将把手设置到面板上,我将在新窗口中打开它。
由于
答案 0 :(得分:1)
尝试使用此代码,我使用了很长时间:
public partial class Launcher : Form
{
/// <summary>Collection of process. </summary>
private Dictionary<IntPtr, Process> _processCollection = new Dictionary<IntPtr, Process>();
#region DLL Import
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
#endregion
/// <summary>Default constructor. </summary>
public Launcher()
{
InitializeComponent();
try {
FormClosing += Launcher_FormClosing;
StartInstances();
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
/// <summary>Starts the instances. </summary>
private void StartInstances()
{
var path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
var numberOfInstances = Int32.Parse(ConfigurationManager.AppSettings["NumerOfInstances"]);
for (int i = 0; i < numberOfInstances; i++) {
StartInstance(i, path);
}
}
/// <summary>Starts an instance. </summary>
private void StartInstance(int instanceId, string path)
{
Process proc = Process.Start(path + "\\foo.exe", instanceId.ToString());
IntPtr handlerDocked = IntPtr.Zero;
Panel panel = new Panel();
panel.Size = new Size(flwPanel.Width / 3, flwPanel.Height / 2);
flwPanel.Controls.Add(panel);
do {
try {
proc.WaitForInputIdle(1000); //wait for the window to be ready for input;
proc.Refresh(); //update process info
if (proc.HasExited) {
return; //abort if the process finished before we got a handle.
}
handlerDocked = proc.MainWindowHandle; //cache the window handle
}
catch {
Thread.Sleep(500);
}
} while (handlerDocked == IntPtr.Zero);
//hWndOriginalParent = SetParent(hWndDocked, panel1.Handle);
SetParent(handlerDocked, panel.Handle);
var docked = new DockedElement(handlerDocked, panel);
panel.SizeChanged += new EventHandler(Panel_Resize);
Panel_Resize(docked, new EventArgs());
_processCollection.Add(handlerDocked, proc);
}
private void Panel_Resize(object sender, EventArgs e)
{
var docked = (DockedElement)sender;
//Change the docked windows size to match its parent's size.
MoveWindow(docked.Handle, 0, 0, docked.Container.Width, docked.Container.Height, true);
}
/// <summary>Finallize instances. </summary>
public void FinallizeInstances()
{
foreach (var docked in _processCollection) {
docked.Value.Close();
}
_processCollection.Clear();
}
private void Launcher_FormClosing(object sender, FormClosingEventArgs e)
{
FinallizeInstances();
}
protected override void Dispose(bool disposing)
{
FinallizeInstances();
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
}
答案 1 :(得分:0)
为确保您的子进程在应用程序关闭后(正常或有力)正确擦除,您可以使用Job Objects。
作业对象允许将进程组作为一个单元进行管理。工作 对象是可控制的,可安全的,可控制的可共享对象 与它们相关的进程的属性。执行的操作 在作业对象上影响与作业对象关联的所有进程。 示例包括强制执行工作集大小和过程等限制 优先级或终止与作业相关的所有进程。
StackOverflow上有一个类似的问题,在C#中有详细的实现:Working example of CreateJobObject/SetInformationJobObject pinvoke in .net?