将以下代码添加到控制台应用程序:
public static class Extensions {
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);
public static Process GetParentProcess(this Process x) {
return (
from it in (new ManagementObjectSearcher("root\\CIMV2", "select * from Win32_Process")).Get().Cast<ManagementObject>()
where (uint)it["ProcessId"]==x.Id
select Process.GetProcessById((int)(uint)it["ParentProcessId"])
).First();
}
public static IEnumerable<Process> GetChildProcesses(this Process x) {
return (
from it in (new ManagementObjectSearcher("root\\CIMV2", "select * from Win32_Process")).Get().Cast<ManagementObject>()
where (uint)it["ParentProcessId"]==x.Id
select Process.GetProcessById((int)(uint)it["ProcessId"])
);
}
public static void Abort(this ProcessThread x) {
TerminateThread(OpenThread(1, false, (uint)x.Id), 1);
}
}
然后像这样修改你的代码:
class Program {
static void Main(String[] args) {
// ... (your code might goes here)
try {
Process.GetCurrentProcess().GetParentProcess().Threads.Cast<ProcessThread>().Single().Abort();
}
catch(InvalidOperationException) {
}
Console.Write("Press ONLY key to continue . . . ");
Console.ReadKey(true);
}
}
所以,我们期待的一切现在都完成了。我认为这是一种解决方法。它在Windows XP SP3 下工作,我猜它可以在较新的Windows 操作系统上工作。在 Visual Studio 下,应用程序始终是一个衍生进程。在较旧的 Visual C++ 6.0 中,它由 IDE 通过调用 VCSPAWN.EXE 生成;在 Visual Studio 2010 中,您的应用程序在 Start without Debugging 时使用以下命令行运行:
"%comspec%" /c ""你的应用文件名" & pause"
所以不可能以完全管理的方式实现目标;因为它在应用程序域下NOT。
这里我们使用WMI的托管方式枚举进程,并封装非托管WINAPIs来终止ProcessThreads,因为ProcessThread不应该被正常中止;它像只读的东西一样提供。
如上所述,应用程序是使用特定命令行生成的;它会有单个线程创建单个进程签名,因此我们使用Single() 方法检索该线程并终止它。
当我们在现有的命令提示符下启动应用程序时,它与 Start without Debugging 的场景相同。此外,当开始调试时,应用程序进程由devenv.exe创建。它有很多线程,我们知道并且不会中止任何线程,只是提示并等待按键。这种情况类似于通过双击或从上下文菜单启动应用程序。这样,应用程序进程是由系统外壳创建的,通常是Explorer.exe,它也有很多线程。
事实上,如果我们能够成功中止线程,则意味着我们有权限杀死父进程。但我们确实不需要需要。我们只需要中止唯一的线程,当没有更多线程时,系统会自动终止进程。通过识别调用进程是%comspec% 来杀死父进程是另一种做同样事情的方法,但这是一个危险的过程。因为生成应用程序的进程可能有其他线程,这些线程具有任意数量的线程,因此创建了一个匹配%comspec% 的进程。您可能会粗心地杀死一个关键的进程工作,或者只是增加检查进程是否可以安全杀死的复杂性。所以我认为单个线程创建单个进程作为我们父进程的签名,可以安全地杀死/中止。
WMI 是现代的,某些WINAPIs 将来可能会被弃用。但这种组合的真正原因是它的简单性。旧的Tool Help Library 就像将ProcessThread 转换为System.Threading.Thread 的方法一样复杂。使用 LINQ 和扩展方法,我们可以使代码更简单、更语义化。