views:

143

answers:

4

Say I have got a program that hogs the processor and/or hard disk to the point that it makes it nearly impossible to do anything else on that computer. Now I don't want to kill that program because what it does is useful (it's a batch job that really is that CPU or disk heavy, e.g. it could ZIP a few gigabytes of data files) but for a short time I need to do something else on that computer. Is there any way an external program could do to freeze that performance killer for a while?

It's like the old DOS option to switch between programs without actually having multitasking.

Assume that the hypothetical program in question is a 3rd party product for which I don't have the source code and there is no way to tell it to pause.

I know I can change the program's priority class e.g. in TaskManager but that's not enough, I want to freeze it.

I am talking about Windows XP as the OS and would like to program a solution with Delphi. I have got all rights on the machine, so I could start something as administrator, replace files and I could also install a service if that is necessary.

+8  A: 

You can freeze it with Process Explorer: Right-click on your program and select Suspend.

Here is some sample code for programmatic freezing from http://www.c-plusplus.de/forum/viewtopic-var-p-is-1460293.html, edited and omitted error checking for brevity:

#include <windows.h>

_NtSuspendProcess NtSuspendProcess =
    (_NtSuspendProcess) GetProcAddress( GetModuleHandle( "ntdll" ),
                                        "NtSuspendProcess" ); 
HANDLE ProcessHandle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid);
NtSuspendProcess( ProcessHandle );
Peter G.
Ah yes, but what API call is it using? SuspendThread on all of the process' threads? http://msdn.microsoft.com/en-us/library/ms686345(v=VS.85).aspx
Stijn Sanders
Knowing Russinovich and his knowledge of the Kernel it probably uses NtSuspendProcess directly.
Runner
Here the text in English http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
belisarius
@Runner Thanks, added some sample code for NtSuspendProcess, @belisarius Thanks, edited my link to point to English version.
Peter G.
+4  A: 

If you want to do it programatically you can use the approach described here.

What is does, is enumerating all the threads in a process and then suspending them. There is no SuspendProcess API, so this is a simulation of such a call.

Beware that this can potentionally have some bad side effects. It depend on the process and how it is written.

I don't know of any other way to do it in the Win32/64 API world. If you go lower to the kernel land and use the NT* APIs you have "NtSuspendProcess" API available. But this is undocumented so it can change with any version of windows or even with any service pack (not very likely though).

The declaration of "NtSuspendProcess" can be found in the JEDI ports of the windows APIs.

Runner
+1  A: 
  function OpenThread(dwDesiredAccess:DWORD;InheritHandle:Boolean;dwThreadID:DWORD):THandle;stdcall;external 'kernel32.dll';

 function ResumeProcess(PID:DWORD):Boolean;
var
tid,snap:THandle;
TE32:TThreadEntry32;
begin
Result:=False;
snap:=CreateToolHelp32SnapShot(TH32CS_SNAPTHREAD,0);
TE32.dwSize:=SizeOf(TThreadEntry32);
Thread32First(snap,TE32);
repeat
if TE32.th32OwnerProcessID=PID then
begin
tid:=OpenThread($0002,FALSE,TE32.th32ThreadID);
ResumeThread(tid);
Result:=TRUE;
CloseHandle(tid);
end;
until
Thread32Next(snap,TE32)=false;
CloseHandle(snap);
end;

function SuspendProcess(PID:DWORD):Boolean;
var
tid,snap:THandle;
TE32:TThreadEntry32;
begin
Result:=False;
snap:=CreateToolHelp32SnapShot(TH32CS_SNAPTHREAD,0);
TE32.dwSize:=SizeOf(TThreadEntry32);
Thread32First(snap,TE32);
repeat
if TE32.th32OwnerProcessID=PID then
begin
tid:=OpenThread($0002,FALSE,TE32.th32ThreadID);
SuspendThread(tid);
Result:=TRUE;
CloseHandle(tid);
end;
until
Thread32Next(snap,TE32)=false;
CloseHandle(snap);
end;

Hope this helps

opc0de
uses tlhelp32; ( add this in your uses clause )
opc0de
+1  A: 

Hi,

You can use my ProcessInfo component to suspend all threads belonging to the process. The approach is similar to what Runner explained to you. The code would be something like this:

var
  Process : TProcessItem;
  AThread: TThreadItem;
begin
  Process := ProcessInfo1.RunningProcesses.FindByName('notepad.exe');
  if Assigned(Process) then
  begin
    for AThread in Process.Threads do
      AThread.SuspendThread;
  end;
end;

You can download source code of ProcessInfo form here

vcldeveloper