请问C#如何添加子进程并在任务管理中有显示,参考Edge的多进程例子:
这里这个Edge应用下有多个子进程,请问如何在C#中添加类似的进程并在任务管理器中显示出来。
Winform无法实现,需要借用win api。
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndParent);
private Process childProcess;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, System.EventArgs e)
{
// 启动一个新的子进程
childProcess = new Process();
childProcess.StartInfo.FileName = "cmd.exe";
childProcess.StartInfo.UseShellExecute = false;
childProcess.StartInfo.CreateNoWindow = true; // 不显示CMD窗口
// 启动进程
childProcess.Start();
// 等待进程启动完成
//childProcess.WaitForInputIdle();
// 将子进程附加到当前WinForms进程
SetParent(childProcess.MainWindowHandle, this.Handle);
}
有没有完整的解决方案代码?你上面那个MultiThreads(32位)就是多进程的吧???
请将解决方案代码发我邮箱,谢谢:
lzhdim@163.com
@lzhdim: 我就说你这个id怎么那么熟悉,我看过你很多篇文章!
试过SetParent
,但是是在Winform里的,能嵌入到主窗体的Panel里,但是设置父子进程无效,所以来问问。。。
@echo_lovely: ChatGPT那个打不开,哈哈。。。
@lzhdim: 嵌入到主窗体Panel里的,我问GPT了,它回复我比较麻烦,我没有做测试
@lzhdim:
这是GPT回复我的代码,它尝试将记事本附加到winform:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public partial class MainForm : Form
{
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndParent);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int Width, int Height, uint uFlags);
const int SW_SHOWNORMAL = 1;
private Process childProcess;
public MainForm()
{
InitializeComponent();
}
private void btnStartProcess_Click(object sender, EventArgs e)
{
// 启动一个新的子进程
childProcess = new Process();
childProcess.StartInfo.FileName = "notepad.exe";
childProcess.StartInfo.UseShellExecute = true; // 使用Shell执行
childProcess.StartInfo.CreateNoWindow = false; // 显示Notepad窗口
// 启动进程
childProcess.Start();
// 等待Notepad进程启动完成并获取窗口句柄
childProcess.WaitForInputIdle(); // 这里需要等待Notepad进程准备好
// 获取Notepad的主窗口句柄
IntPtr notepadHandle = childProcess.MainWindowHandle;
// 设置父窗口
SetParent(notepadHandle, this.Handle);
// 将Notepad窗口大小调整以适应父窗口
SetWindowPos(notepadHandle, IntPtr.Zero, 0, 0, this.Width, this.Height, 0);
// 显示Notepad窗口
ShowWindow(notepadHandle, SW_SHOWNORMAL);
}
}
我记得楼主你搞过很多这种windows api的项目啊,应该比较熟悉,我班门弄斧了
@echo_lovely: 周一好啊。。。我用的Windows 11 24H2,Windows 10下能用的那个API函数SetParent在24H2下不兼容了,无法实现多进程。。。
嵌入窗体不是找pid,而是找窗体句柄。
如果你process里可以找到MainWindowHandle的,那个就是主窗体句柄
主意窗体必须可见才有这个,窗体不可见。你需要遍历所有顶级窗体,EnumWindows 然后通过GetWindowThreadProcessId去比对这个顶级窗体隶属于pid下(有时候还需要查询pid的层级,因为有时候这个顶级窗体可能属于某个exe的子进程里)
代码我就不贴全了,只贴核心的
public static IntPtr FindMainWindowByPid(int pid)
{
IntPtr r = IntPtr.Zero;
EnumWindows((hWnd, param) =>
{
GetWindowThreadProcessId(hWnd, out uint windowPid);
if ((int)windowPid == pid && IsMainWindow(hWnd))
{
r = hWnd;
return false;
}
else if (isChirldProcess(pid, windowPid.ToString()) && IsMainWindow(hWnd))
{
r = hWnd;
return false;
}
return true;
}, IntPtr.Zero);
return r;
}
另外补充说明,如果进程不是你自己启动的。windows下未公开接收孤儿进程的手段。
我大体猜一下,通常想这么做是希望关闭的时候一起关闭。标准做法是使用job任务,把主进程和你嵌入的进程使用job关联到一起。
非标准做法就是自己在closing的时候,强行给对方发送关闭消息
我这写的一个从指定进程下找指定窗体的:
/*** 进程工具类 Austin Liu 刘恒辉 Project Manager and Software Designer E-Mail: lzhdim@163.com Blog: http://lzhdim.cnblogs.com Date: 2024-01-15 15:18:00 ***/ namespace Lzhdim.LPF.Utility { using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; /// <summary> /// 进程工具类 /// </summary> public class ProcessUtil { #region Windows 32 API private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr lParam); [DllImport("user32.dll")] private static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowProc lpEnumFunc, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowTextLength(IntPtr hWnd); #endregion Windows 32 API /// <summary> /// 根据进程名查找底下的某个窗体 /// </summary> /// <param name="processName">进程名</param> /// <param name="windowTitle">窗体名</param> /// <returns>该窗体的句柄</returns> public static IntPtr FindWindowHandleFormProcess(string processName, string windowTitle) { IntPtr intPtr = IntPtr.Zero; bool bIsFind = false; Process[] processes = Process.GetProcessesByName(processName); // 替换为实际进程名 foreach (Process process in processes) { EnumChildWindows(process.MainWindowHandle, (hWnd, param) => { int length = GetWindowTextLength(hWnd); if (length > 0) { StringBuilder sb = new StringBuilder(length); GetWindowText(hWnd, sb, length + 1); if (sb.ToString() == windowTitle) { intPtr = hWnd; bIsFind = true; return true; } } return true; }, IntPtr.Zero); if (bIsFind) break; } return intPtr; } } }