如何在C#中暂停整个过程(就像我点击暂停时的Process Explorer一样)。
我正在使用Process.Start启动Process,并且在某个事件中,我想暂停该过程以便能够对其“快照”进行一些调查。
答案 0 :(得分:33)
这是我的建议:
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200)
}
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("kernel32", CharSet = CharSet.Auto,SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
private static void SuspendProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
SuspendThread(pOpenThread);
CloseHandle(pOpenThread);
}
}
public static void ResumeProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
var suspendCount = 0;
do
{
suspendCount = ResumeThread(pOpenThread);
} while (suspendCount > 0);
CloseHandle(pOpenThread);
}
}
答案 1 :(得分:11)
感谢Magnus
在包含Flags之后,我将代码修改为我项目中的扩展方法。我现在可以使用
var process = Process.GetProcessById(param.PId);
process.Suspend();
以下是可能感兴趣的人的代码。
public static class ProcessExtension
{
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
public static void Suspend(this Process process)
{
foreach (ProcessThread thread in process.Threads)
{
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
SuspendThread(pOpenThread);
}
}
public static void Resume(this Process process)
{
foreach (ProcessThread thread in process.Threads)
{
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
ResumeThread(pOpenThread);
}
}
}
我已经完成了一个实用程序,我通常用它来暂停/终止/列出进程。完整来源是on Git
答案 2 :(得分:3)
使用Win32 p / invoke的详细解决方案可以在CodeProject上找到。
答案 3 :(得分:2)
所以真的,其他答案显示的是暂停线程的过程,没有办法真正暂停进程(即在一次通话中)....
一个不同的解决方案是实际调试您正在启动的目标进程,请参阅Mike Stall's blog以获取有关如何从托管上下文实现此目的的一些建议。
如果您实现了调试器,您将能够扫描内存或您想要的其他快照。
但是,我想指出,从技术上讲,现在有办法真正做到这一点。即使你执行debugbreak一个目标调试对象进程,你的系统上的另一个进程可能会注入一个线程,并且无论目标进程的状态如何,都会给它一些执行代码的能力(甚至让我们说它是否因为访问冲突而遇到了断点) ),如果你所有的线程被挂起到超高挂起计数,当前处于主进程线程的断点和任何其他这样的假定冻结状态,系统仍然可以将另一个线程注入该进程并执行一些指令。您也可能会遇到修改或替换所有入口点kernel usually calls等等的麻烦,但您现在已进入粘性臂的MALWARE竞赛;)...
在任何情况下,使用托管接口进行调试似乎“比p / invoke”更多的本地API调用更容易,这将很难模拟你可能真正想做的事情......使用debug api的;)
答案 4 :(得分:1)
有关win32基础知识,请参阅此CodeProject文章:http://www.codeproject.com/KB/threads/pausep.aspx。此示例代码使用了SDK中的ToolHelp32库,因此我建议将此示例代码转换为非托管C ++ / CLI库,其中包含简单的接口,如“SuspendProcess(uint processID)。”
Process.Start将返回一个Process对象,您可以从中获取进程ID,然后根据上述内容将其传递给新库。
戴夫
答案 5 :(得分:0)
[DllImport("ntdll.dll", PreserveSig = false)]
public static extern void NtSuspendProcess(IntPtr processHandle);
static IntPtr handle;
string p = "";
foreach (Process item in Process.GetProcesses())
{
if (item.ProcessName == "GammaVPN")
{
p = item.ProcessName;
handle = item.Handle;
NtSuspendProcess(handle);
}
}
Console.WriteLine(p);
Console.WriteLine("done");