Добавьте следующий код в консольное приложение:
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 ваше приложение запускается со следующей командной строкой, когда Запуск без отладки :
"% comspec%" / c "" имя файла вашего приложения«& пауза»
Таким образом, невозможно достичь цели полностью управляемыми способами ;потому что это было НЕ в домене приложения.
Здесь мы используем управляемый способ WMI
для перечисления процессов и инкапсулируем неуправляемые WINAPI
s для завершения ProcessThread
s, потому что ProcessThread
не должен обычно прерываться;он предоставляется как что-то только для чтения.
Как упоминалось выше, приложение было порождено определенной командной строкой; будет иметь один поток, создающий сигнатуру одного процесса, поэтому мы использовали метод Single()
, чтобы получить этот поток и завершить его.
Когда мы запускаем приложение в существующей командной строке, это тот же сценарий, что и Запуск без отладки .Более того, когда Start Debugging , процесс приложения создается devenv.exe
.В нем много потоков, мы знаем это и не будем прерывать ни одного потока, просто приглашаем и ждем нажатия клавиши.Эта ситуация аналогична запуску приложения двойным щелчком мыши или из контекстного меню .Таким образом, процесс приложения создается системной оболочкой, обычно Explorer.exe
, и также имеет много потоков.
Фактически, если мы можем успешно прервать поток, это означает, что у нас есть разрешения на уничтожение родительского процесса.Но нам НЕ нужно.Нам просто нужно прервать единственный поток, процесс автоматически завершается системой, когда у него больше нет потоков.Убить родительский процесс, указав, что вызывающим процессом является %comspec%
, - это еще один способ сделать то же самое, но это опасная процедура.Поскольку процесс, порождающий приложение, может иметь другие потоки, у которых есть любое количество потоков, создайте соответствующий процесс %comspec%
.Вы можете убить критическую работу процесса небрежно или просто усложнить проверку безопасности процесса.Поэтому я рассматриваю , когда один поток создает один процесс в качестве сигнатуры нашего родительского процесса, который можно безопасно уничтожать / прерывать.
WMI
современно, некоторые из WINAPI
могут устареть в будущем.Но настоящая причина этой композиции в ее простоте.Старый Tool Help Library
такой сложный, как способы конвертации ProcessThread
в System.Threading.Thread
.С помощью LINQ и методов расширения мы можем сделать код более простым и более семантическим.