1. ホーム
  2. windows

[解決済み] Windowsでプロセスを中断/再開するには?

2023-04-22 02:08:38

質問

Unixでは、プロセスの実行を一時的に中断し、シグナルで再開することができます。 SIGSTOPSIGCONT . Windows でシングルスレッドプロセスをプログラミングなしでサスペンドするにはどうすればよいですか?

どのように解決するのですか?

コマンドラインからそれを行うことはできません、あなたはいくつかのコードを記述する必要があります。また、アプリケーションがそれを行うために必要なすべての権限を持っていると仮定します (例は、エラー チェックを行わない場合です)。

ハードな方法

まず、指定されたプロセスのすべてのスレッドを取得し、次に SuspendThread 関数を呼び出してそれぞれを停止させます (そして ResumeThread で再開します)。これは動作しますが、スレッドが任意の時点で停止する可能性があり、サスペンド/レジュームの順序が予測できないため、アプリケーションによってはクラッシュしたりハングアップしたりします(たとえば、デッドロックが発生する可能性があります)。シングルスレッド アプリケーションでは、これは問題ではないかもしれません。

void suspend(DWORD processId)
{
    HANDLE hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

    THREADENTRY32 threadEntry; 
    threadEntry.dwSize = sizeof(THREADENTRY32);

    Thread32First(hThreadSnapshot, &threadEntry);

    do
    {
        if (threadEntry.th32OwnerProcessID == processId)
        {
            HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE,
                threadEntry.th32ThreadID);
            
            SuspendThread(hThread);
            CloseHandle(hThread);
        }
    } while (Thread32Next(hThreadSnapshot, &threadEntry));

    CloseHandle(hThreadSnapshot);
}

スレッドを再開するには、中断されたスレッドをスキップする必要があり、サスペンド/レジュームの順序のためにデッドロックを引き起こすことが容易であることに注意してください。シングルスレッド・アプリケーションでは、冗長ですが動作します。

文書化されていない方法

Windows XP 以降では NtSuspendProcess がありますが、それは 非ドキュメンテッド . 読む この記事 を読んでください (ドキュメント化されていない関数のリファレンスは news://comp.os.ms-windows.programmer.win32).

typedef LONG (NTAPI *NtSuspendProcess)(IN HANDLE ProcessHandle);

void suspend(DWORD processId)
{
    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId));

    NtSuspendProcess pfnNtSuspendProcess = (NtSuspendProcess)GetProcAddress(
        GetModuleHandle("ntdll"), "NtSuspendProcess");

    pfnNtSuspendProcess(processHandle);
    CloseHandle(processHandle);
}

デバッガ方法

プログラムを中断することは、通常デバッガが行うことであり、そのために DebugActiveProcess 関数を使います。これはプロセスの実行を(すべてのスレッドをまとめて)中断します。再開するには DebugActiveProcessStop .

この関数は、プロセス ID を指定してプロセスを停止させることができます。構文は非常に簡単で、停止させたいプロセスの ID を渡すだけで完了です。コマンドラインアプリケーションを作成する場合、プロセスを停止させるためにそのインスタンスを実行し続ける必要があります(さもなければ終了されます)。そのためには 備考 のセクションを参照してください。

void suspend(DWORD processId)
{
    DebugActiveProcess(processId);
}

コマンドラインから

Windowsのコマンドラインにはそのためのユーティリティがないと言いましたが、PowerShellからWindowsのAPI関数を呼び出すことは可能です。まず、以下のファイルをインストールします。 インヴォークウィンドウズアピ スクリプトをインストールしてから、次のように記述します。

Invoke-WindowsApi "kernel32" ([bool]) "DebugActiveProcess" @([int]) @(process_id_here)

もちろん、頻繁に必要な場合は alias を作ることができます。