Click here to Skip to main content
Click here to Skip to main content

Win32 process suspend/resume tool

By , 3 Oct 2002
 

Why pause and resume processes?

Anyone using the Windows NT product line (Windows 2000 and Windows XP) must have used the task manager utility. This utility, activated by pressing CTRL+SHIFT+ESC, brings up a list of the active processes and allows you several actions for controlling them: starting new processes, stopping processes and setting their priority. When you have some process that is taking a lot of resources (normally CPU time), you can easily assign it the lowest priority and the system will take care of assigning only the remaining resources or the "idle time" on the machine.

Well, a feature I always missed from Windows and present on other operating systems is the ability of pausing and resuming a process. Some daily situations you could face where this feature would be useful (actually, the ones I use it for):

  • You have a time-consuming operation, e.g. a big build, and want to pause it for doing something quickly and resuming it after doing this
  • You have some P2P software or download running and want to pause and resume it without reconnecting and want to browse some pages quickly
  • A program starts a disk trashing operation and you want to send and e-mail
  • A program starts working in a way it shouldn't for just a moment and you want to attach a debugger to it
  • You have a buggy process running and want to kill it fast

How it is done

The main problem is: there is no SuspendProcess API function. And there is no documented or safe way of doing this.

The only simple way of doing this is via SuspendThread/ResumeThread. This pair of API functions allows you to suspend and resume a thread. More than that, for the sake of safety, they maintain an internal "suspend count'. Each time you call SuspendThread, it increments this counter. ResumeThread, on the other hand, decreases this counter. If this was not done this way, the caller of SuspendThread would have no way of knowing how to restore the original state of the thread. Calling ResumeThread after calling SuspendThread effectively restores the original thread's state.

Knowing this, it is very straightforward suspending a process: it is just a matter of listing all the threads on a process, opening a handle for each of them and calling SuspendThread. The resuming is done the same way.

The ToolHelp32 API has functions for easily listing threads and processes on a system. Actually, there are two functions that do this on my code that were shamelessly borrowed from MSDN samples.

So, I wrote this little command line utility (I have an idea for integrating it with the task manager, but I have not the time for doing it right now).

How to use it

I suggest you to put the executable anywhere on the PATH. The Windows directory would be fine. Always compile this program without DLL dependencies on the CRT, so the program will start faster. You could be starting this program under very adverse conditions, so looking for a MSVCRT*.DLL and loading it could make a huge difference in the startup time.

As with most command line tools, it is meant to be used from the command prompt, by clicking on the "Command Prompt" shortcut or opening Start/Run and executing cmd.exe. The usage for the program is very simple:

pausep PID [/r]

If you type only pausep without arguments, the program will display its usage and a list of running processes and their PID. If you type pausep PID, the program will call SuspendThread on all the process's threads. This will suspend the threads or increment their suspend count. If you pass the "/r" argument, the program will do the opposite action, i.e., resuming the thread. Note that if you pausep the same process 3 times without resuming, you will need to use pausep /r it for 3 times too.

The risks with this approach

Not all programs are well written. Not all programs are made to be suspended, specially the multithreaded ones. Programs that implement timeouts may behave abnormally if you pause and resume them. When you pause and resume threads in an arbitrary order, like with this utility, you can create deadlocks.

So, only use this program when you know what you are doing.

The standard disclaimer

As I said before, this is not the safest tool in the world. Use it at your own risk: if you use it, you can loose data, profit, have hardware problems, cause radioactive contamination and start a world war. But, for me, it works fine and never had a problem.

Well, the code in this article is free for you to use any way you want. If you improve it, drop me a note, so I can keep the code in sync. If you make money with this code, you are a genius! You deserve the money. Just remember to send me a "thank you" and give me some tips. I will not reject any money you send me too.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Daniel Turini
CEO
Brazil Brazil
I develop software since I was 11. In the past 20 years, I developed software and used very different machines and languages, since Z80 based ones (ZX81, MSX) to mainframe computers. I still have passion for ASM, though no use for it anymore.
Professionally, I developed systems for managing very large databases, mainly on Sybase and SQL Server. Most of the solutions I write are for the financial market, focused on credit systems.
To date, I learned about 20 computer languages. As the moment, I'm in love with C# and the .NET framework, although I only can say I’m very proficient at C#, VB.NET(I’m not proud of this), T/SQL, C++ and libraries like ATL and STL.
I hate doing user interfaces, whether Web based or not, and I’m quite good at doing server side work and reusable components.
I’m the technical architect and one of the authors of Crivo, the most successful automated credit and risk assessment system available in Brazil.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
SuggestionEasier ApproachmemberMember 803644620-Apr-12 22:31 
You can also use the undocumented functions NtSuspendProcess and NtResumeProcess in ntdll.dll. The process handle must have been opened with the PROCESS_SUSPEND_RESUME access right.
 
The function prototypes are (according to ReactOS):
 
NTSTATUS NTAPI NtResumeProcess(IN HANDLE ProcessHandle)
NTSTATUS NTAPI NtSuspendProcess(IN HANDLE ProcessHandle)

GeneralThank Youmemberkazemtnt10-May-11 2:11 
thank you for it
Generalanother apimemberMember 248805611-Jan-10 21:26 
You can use NtSuspendProcess and NtResumeProcess APIs too.(in ntdll.dll)
They're undocumented but useful. : )
GeneralThank you!memberPaganBBD15-Apr-08 3:48 
Very elegant.
You saved me Smile | :)
QuestionHow to query for a process's statememberopen_mind_core27-Mar-08 8:02 
This tool is cool.
But let's say that I want to just query if a process is suspended, how can do that without calling SuspendThread/ResumeThread?
GeneralJust wanted to saymemberBrowner87!19-Nov-07 14:29 
Just wanted to say you're a genius! I've been trying forever to do this in VB6 and it seems to be impossible. I used the code to hack an irritating program that resists having it's process ended (it auto-restatrs) but can't detect a suspend! I used this code with a VB app that calls your app with the processes PID as an argument and the program suspends! Thought I'd post the code in case anyone wants it! Thanx again!
 
Make sure you add a .RES file with pausep.exe in it in a 'folder' called EXES and make it resource number 101
[Put in a module]
Option Explicit
 
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal Handle As Long) As Long
Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
Private Declare Function EnumProcesses Lib "PSAPI.DLL" (ByRef lpidProcess As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
Private Declare Function GetModuleFileNameExA Lib "PSAPI.DLL" (ByVal hProcess As Long, ByVal hModule As Long, ByVal ModuleName As String, ByVal nSize As Long) As Long
Private Declare Function EnumProcessModules Lib "PSAPI.DLL" (ByVal hProcess As Long, ByRef lphModule As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByVal lpBuffer As Long, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal lpDst As Long, ByVal lpSrc As Long, ByVal ByteLen As Long)
 
Private Declare Function SetThreadAffinityMask Lib "kernel32.dll" (ByVal hThread As Long, ByVal dwThreadAffinityMask As Long) As Long
 
Private Declare Function GetProcessAffinityMask Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpProcessAffinityMask As Long, ByRef SystemAffinityMask As Long) As Boolean
 
Private Declare Function GetCurrentProcess Lib "kernel32.dll" () As Long
Private Declare Function SetProcessAffinityMask Lib "kernel32.dll" (ByVal hProcess As Long, ByRef dwProcessAffinityMask As Long) As Long
 
Private Const PROCESS_QUERY_INFORMATION As Long = 1024
Private Const PROCESS_VM_READ As Long = 16
Private Const MAX_PATH As Long = 260
 
Public Function GetProcessByName(ByVal EXEName As String) As Long
Dim cb As Long
Dim cbNeeded As Long
Dim NumElements As Long
Dim ProcessIDs() As Long
Dim cbNeeded2 As Long
Dim NumElements2 As Long
Dim Modules(1 To 200) As Long
Dim ModuleName As String
Dim hProcess As Long
Dim i As Long
Dim PIDs() As Long
ReDim PIDs(0)
cb = 8
cbNeeded = 192 '96
Do While cb <= cbNeeded
cb = cb * 2
ReDim ProcessIDs(cb / 4) As Long
EnumProcesses ProcessIDs(1), cb, cbNeeded
Loop 'While ProcessIDs(1) <> 0
NumElements = cbNeeded / 4
For i = 1 To NumElements
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, ProcessIDs(i))
If hProcess <> 0 Then
If EnumProcessModules(hProcess, Modules(1), 200, cbNeeded2) <> 0 Then
ModuleName = Space(MAX_PATH)
'Debug.Print Left$(ModuleName, GetModuleFileNameExA(hProcess, Modules(1), ModuleName, 500))
If (InStr(1, Left$(ModuleName, GetModuleFileNameExA(hProcess, Modules(1), ModuleName, 500)), EXEName, vbTextCompare) > 0) Then
ReDim Preserve PIDs(UBound(PIDs) + 1)
PIDs(UBound(PIDs)) = hProcess 'ProcessIDs(i)
GetProcessByName = ProcessIDs(i) 'hProcess
Exit Function
End If
End If
End If
CloseHandle hProcess
Next
GetProcessByName = PIDs(UBound(PIDs))
End Function
 

Private Sub Main()
Dim PID As Long
PID = GetProcessByName("xxxxxxxxxx.exe")
If Len(Dir(App.Path & "\pausep.exe")) <= 0 Then
Dim k As Long, e() As Byte
e = LoadResData(101, "EXES")
k = FreeFile
Open App.Path & "\pausep.exe" For Binary Access Write Lock Read As k
Put k, , e
Close k
End If
Shell App.Path & "\pausep.exe " & PID
Do
On Error Resume Next
Kill App.Path & "\pausep.exe"
DoEvents
Loop Until Len(Dir(App.Path & "\pausep.exe")) <= 0
MsgBox "Done!"
End Sub

 
I have not failed 1000 times, I have successfully identified 1000 ways that will not work! Poke tongue | ;-P
 

-- modified at 20:35 Monday 19th November, 2007
GeneralMemory Leakmemberkeremsback17-Nov-06 4:36 
CloseHandle causes memoryleak according to MSDN:
 
The snapshot returned is a copy of the current state of the system.
 
To close a snapshot, call the CloseToolhelp32Snapshot function.
 
Do not call the CloseHandle function to close the snapshot call. That generates a memory leak.

GeneralProcess checkpointingmemberReal_Jeezy5-Nov-06 4:49 
I'm looking for a program that can make a memory-dump of a process and is able to reload the dumpfile later so basically the process resumes from the save point
 
Kinda like when you put the PC in hibernation mode
But on a single process scale.
 
Anyone know of such programs existence?
 
Thanks
GeneralI like it...memberSlsa749-Oct-05 9:09 
This is what I´ve been looking for!
 
I am working with a program called SaTScan which sometimes takes ages to complete a certain calculation. Plus it slows down the computer a lot. Now this little tool of yours suspends and resumes it without problems.
 
Thanks a lot. Johannes
GeneralToolHelpmemberB.Alas3-May-05 8:27 
Very simple clear and nicely written example.
 
But I still can't find out how to suspend a thread without ToolHelp since WinNT4 doesn't support it. Psapi has no thread enumeration so Im pretty stuck here Smile | :) .

GeneralHelp!!!memberjean_ni7-Apr-04 6:50 
I'm presently working on a small application and I'm really stuck Dead | X| .
 
The app takes a frame sent by my webcam, do something on it (in that case, add a VRML object to the scene) and proceed to the next frame. I can communicate with the app using keyevent(ie. 'esc' quit the application, 'm' put som info on stdout, etc) in the main loop. However, I'd need to pause and resume that mainloop when some event occurs (ie after typing 't' to translate a volume, the user must enter how long is the translation...).
 
Any ideas?
 
I'm using C++ Visual Studio .NET 2003
 
Jean_niConfused | :confused: Confused | :confused: Confused | :confused:
GeneralRe: Help!!!memberMsftone26-Jan-06 23:11 
What does this have to do with this topic?
 
Confused | :confused:
 
---
maximum 500 characters
QuestionHow to suspend/resume process on Win95?membertigra_woo12-Feb-04 15:17 
I want to suspend/resume process on Win95, how to do?
AnswerRe: How to suspend/resume process on Win95?memberDaniel Turini13-Feb-04 0:53 
Sorry, I can't help you, as I don't code on Win95 since, erm, mmm... 95. Wow, it has been 9 years already! Smile | :)
At least MSDN says that you can do OpenProcess, SuspendThread and ResumeThread on Win95, so I suspect that the problem is happening with my process listing code. Try to pass a known PID and see if it works...

 
Perl combines all the worst aspects of C and Lisp: a billion different sublanguages in one monolithic executable. It combines the power of C with the readability of PostScript. -- Jamie Zawinski
GeneralRe: How to suspend/resume process on Win95?membertigra_woo23-Feb-04 14:53 
OpenThread API unsupported on Win95
GeneralRe: How to suspend/resume process on Win95?membermurray skuce20-Jun-04 4:57 
There is a piece of software that, unlike Windows Taskmaster, does allow you to both see and suspend/resume processes. At least I think it has the same functionality you describe - I am myself no programmer.
 
It is called Process Explorer, copyright Mark Russinovich, from Sysinternals.com
 
It's been a great help to me in tracking down and suspending virus activitiy.

AnswerRe: How to suspend/resume process on Win95?memberMember 803644620-Apr-12 22:37 
It is not possible at all since this feature is included in Windows NT, only.
Generalaccess deniedmemberxuchangchang3-Feb-04 14:33 
While I want to suspend a thread in VC++,but return error code 0x00000005(Access denide),who know why?? thanks!
GeneralWREY was kinda rightmemberHockey23-Oct-02 22:31 
You need a simple app wizard gui.
 
Its like watching TV in black and white otherwise... Smile | :)
 

 
"An expert is someone who has made all the mistakes in his or her field" - Niels Bohr
GeneralRe: WREY was kinda rightmember*42*8-Nov-11 14:11 
If you want to quote people be respectfull and quote them right. Niels Bohr never mentioned "her" he wrote about "a man" ... You don't like it as he said it - don't quote him Frown | :-( .
GeneralRisky, but useful too I guesseditorNishant S4-Oct-02 23:06 
Handy for using on your own programs while debugging. Very risky to use it on other programs. Unsure | :~
 
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

GeneralDoesn't do much.memberWREY29-Sep-02 11:20 
This sample is just a "Start".
 
All it does is produce a list of the various Processes currently running on your machine, which you could obtain anyway by using Task Manager.
 
It lacks an interface (e.g. checkboxes) by which the user could select which Processes he/she may want to suspend or resume.
 
I tried running it several times from Start->Run to see if I could cause it to suspend or resume Processes, and all I got, was a very quick flicker of the program indicating it had completed execution. IOW, I didn't have a chance to test for those other options.
 
If you are running VC++ 6.0, you will have to create your own Console Application project for this sample, because it was written for VC++ .NET, and the sample didn't come with a ".dsp" file.
 
If you were thinking of borrowing features from this sample to import into your own application, I cannot attest for its ability to do anything else, because I didn't get to see those features. The ONLY thing I know it does, is list Processes. That's it!
 
I did see code in there for it to suspend and resume Processes, (though I couldn't test them) but for everything else, meaning, any user interface, and the assigning of priorities to Processes (if that's something you might want to do after you've suspended one or several of them, etc.), you're on your own.
 
Lastly, if your Process name has more than two parts (e.g. System Idle Process), it will only report two (e.g. System Process).
 
Frown | :(
 
William
GeneralRe: Doesn't do much.memberDaniel Turini29-Sep-02 12:27 
It's a command line tool.
As such, you must run it from the command prompt.
Type cmd.exe at Start->Run and open a command prompt. Then use it from there.
 
But even if you use it PASSING THE PID from Start->Run it should pause a process.
 
It's a pitty people are so used to GUI applications that don't know how to use command line utilities anymore... Cry | :((
 
I'll provide a soon .dsp for VC 6.0 users. I didn't because I thought most VC6.0 users would use the Project Converter Tool[^]
 
"In an organization, each person rises to the level of his own incompetence." Peter's Principle
GeneralRe: Doesn't do much.sitebuilderUwe Keim29-Sep-02 13:41 
Daniel Turini wrote:
It's a pitty people are so used to GUI applications that don't know how to use command line utilities anymore...
 
Right, those youngsters are so unflexible Smile | :)
 
Soon, the knowledge of command prompts will be lost forever, when the last man knowing it passes away Big Grin | :-D
 
--
Scanned MSDN Mag ad with YOUR name: www.magerquark.de/misc/CodeProject.html
See me: www.magerquark.de
GeneralRe: Doesn't do much.memberWREY29-Sep-02 13:53 
I did recognize it was a Command Line tool, which is why I went to Start->Run and entered the full path of where the executable module was located, and ran it from there. That is how I got to see the flash of the list of Processes it displayed.
 
I was more fortunate in seeing the entire list without it disappearing on me when I ran it from the VC++ IDE.
 
But just to be fair and as thorough as possible, I did go back to Start->Run and following the pathname of where the executable module was located, I did append the PID of a utility that was currently running on my system, and received an error message from the system about not being able to locate the component.
 
When I removed the PID and ran just the pathname again, I could see the quick display of the list before it vanished. So I did try that effort as well.
 
Typing 'cmd.exe' to run a command line tool doesn't buy me anything more that what I am able to accomplish from Start->Run. AAMOF, it's preferable to run an application from Start->Run if that's all you want to do (which in this case was all I wanted to do).
 
Yes, I'll admit I am one of those people who prefer having a GUI with which to interface than having to revert back to the method we all had to deal with back there in the dark ages BEFORE GUI came along. GUI showed us there was a nicer and more convenient way of interfacing with the computer. (Pity those who refuse to come out of the darkness into the light.) For the extra effort going GUI requires, I don't mind it at all; I'll do it any day. It's either the lazy or the ignorant ones who continually bash GUI.
 
Hmmm | :|
 
"Accept nothing short of perfection." The C++ Programming Language: 3rd Edition. Bjarne Stroustrup.
 
William

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 4 Oct 2002
Article Copyright 2002 by Daniel Turini
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid