14

この投稿が重複していないことを願っています。説明させてください:

同様の投稿を検討しましたWindowsで外部プロセスを一時停止/再開する方法? ただし、C++/Python が優先されますが、投稿時点で受け入れられた回答はありません。


私の質問:

Windows SysinternalsのMark RussinovichによるPsSuspendによって提供される機能の Delphi での可能な実装に興味があります。

引用:

PsSuspend を使用すると、ローカル システムまたはリモート システムでプロセスを一時停止できます。これは、プロセスがリソース (ネットワーク、CPU、ディスクなど) を消費している場合に、別のプロセスに使用を許可したい場合に適しています。中断すると、リソースを消費しているプロセスを強制終了するのではなく、後の時点で処理を続行できます。

ありがとうございました。


編集:

部分的な実装で十分です。リモート機能を削除できます。

4

4 に答える 4

13

次のコードを使用してみることができます。ドキュメント化されていない関数NtSuspendProcessとを使用しNtResumeProcessます。Delphi 2009で構築された32ビットアプリケーションからWindows 7 64ビットで試してみましたが、うまくいきました。これらの関数は文書化されていないため、Windows の将来のバージョンから削除される可能性があることに注意してください。

アップデート

次のコードのSuspendProcessおよびラッパーは関数になり、成功した場合は True を返し、そうでない場合は False を返します。ResumeProcess

type
  NTSTATUS = LongInt;
  TProcFunction = function(ProcHandle: THandle): NTSTATUS; stdcall;

const
  STATUS_SUCCESS = $00000000;
  PROCESS_SUSPEND_RESUME = $0800;

function SuspendProcess(const PID: DWORD): Boolean;
var
  LibHandle: THandle;
  ProcHandle: THandle;
  NtSuspendProcess: TProcFunction;
begin
  Result := False;
  LibHandle := SafeLoadLibrary('ntdll.dll');
  if LibHandle <> 0 then
  try
    @NtSuspendProcess := GetProcAddress(LibHandle, 'NtSuspendProcess');
    if @NtSuspendProcess <> nil then
    begin
      ProcHandle := OpenProcess(PROCESS_SUSPEND_RESUME, False, PID);
      if ProcHandle <> 0 then
      try
        Result := NtSuspendProcess(ProcHandle) = STATUS_SUCCESS;
      finally
        CloseHandle(ProcHandle);
      end;
    end;
  finally
    FreeLibrary(LibHandle);
  end;
end;

function ResumeProcess(const PID: DWORD): Boolean;
var
  LibHandle: THandle;
  ProcHandle: THandle;
  NtResumeProcess: TProcFunction;
begin
  Result := False;
  LibHandle := SafeLoadLibrary('ntdll.dll');
  if LibHandle <> 0 then
  try
    @NtResumeProcess := GetProcAddress(LibHandle, 'NtResumeProcess');
    if @NtResumeProcess <> nil then
    begin
      ProcHandle := OpenProcess(PROCESS_SUSPEND_RESUME, False, PID);
      if ProcHandle <> 0 then
      try
        Result := NtResumeProcess(ProcHandle) = STATUS_SUCCESS;
      finally
        CloseHandle(ProcHandle);
      end;
    end;
  finally
    FreeLibrary(LibHandle);
  end;
end;
于 2012-04-14T12:46:39.480 に答える
5

SuspendProcessWindowsにはAPI呼び出しはありません。したがって、あなたがする必要があるのは:

  1. プロセス内のすべてのスレッドを列挙します。サンプルコードについては、 RRUZの回答を参照してください。
  2. SuspendThreadこれらのスレッドのそれぞれを呼び出します。
  3. プログラムの再開部分を実装するには、ResumeThread各スレッドを呼び出します。
于 2012-04-14T11:59:18.287 に答える
5

「すべてのスレッドをサスペンドする」実装には競合状態があります。スナップショットを作成してからサスペンドを完了するまでの間に、サスペンドしようとしているプログラムが 1 つ以上のスレッドを作成した場合はどうなりますか?

ループして、別のスナップショットを取得し、中断していないスレッドを中断し、何も見つからない場合にのみ終了することができます。

文書化されていない関数は、この問題を回避します。

于 2012-06-12T02:27:06.243 に答える
1

ここで次のスニペットを見つけました(作成者: steve10120)。

それらは貴重なものだと思います。私自身の質問に対する別の回答としても投稿せざるを得ません。


再開プロセス:

function ResumeProcess(ProcessID: DWORD): Boolean;
 var
   Snapshot,cThr: DWORD;
   ThrHandle: THandle;
   Thread:TThreadEntry32;
 begin
   Result := False;
   cThr := GetCurrentThreadId;
   Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
   if Snapshot <> INVALID_HANDLE_VALUE then
    begin
     Thread.dwSize := SizeOf(TThreadEntry32);
     if Thread32First(Snapshot, Thread) then
      repeat
       if (Thread.th32ThreadID <> cThr) and (Thread.th32OwnerProcessID = ProcessID) then
        begin
         ThrHandle := OpenThread(THREAD_ALL_ACCESS, false, Thread.th32ThreadID);
         if ThrHandle = 0 then Exit;
         ResumeThread(ThrHandle);
         CloseHandle(ThrHandle);
        end;
      until not Thread32Next(Snapshot, Thread);
      Result := CloseHandle(Snapshot);
     end;
 end;

中断プロセス:

function SuspendProcess(PID:DWORD):Boolean;
 var
 hSnap:  THandle;
 THR32:  THREADENTRY32;
 hOpen:  THandle;
 begin
   Result := FALSE;
   hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
   if hSnap <> INVALID_HANDLE_VALUE then
   begin
     THR32.dwSize := SizeOf(THR32);
     Thread32First(hSnap, THR32);
     repeat
       if THR32.th32OwnerProcessID = PID then
       begin
         hOpen := OpenThread($0002, FALSE, THR32.th32ThreadID);
         if hOpen <> INVALID_HANDLE_VALUE then
         begin
           Result := TRUE;
           SuspendThread(hOpen);
           CloseHandle(hOpen);
         end;
       end;
     until Thread32Next(hSnap, THR32) = FALSE;
     CloseHandle(hSnap);
   end;
 end;

免責事項:

私はそれらをまったくテストしませんでした。楽しんで、フィードバックを忘れないでください。

于 2012-04-19T07:45:41.453 に答える