[BlueLeaf1336]> PROBLEMS> 探求其之壱>

探求其之壱 > プロセスの列挙

historyTOP

2006/02/04:作成

overviewTOP

えらく間が開いてしまいましたが、続きます。まず、タスクマネージャのプロセスタブで一覧されているようなプロセスの列挙をやります。実際にははるか前にパクリ終わってます。ただ、なんとなくですが、プロセスの列挙とそのプロセスに対する処理(メモリの使用量と取ったりすること)を分離しました。

つまり、プロセスの列挙だけを行う関数に、プロセスを見つけた時に呼び出してほしい関数を渡しておいて、プロセス発見時に随時呼び出してもらうようにしました。

プロセス列挙関数TOP

まずは、プロセスの列挙だけを行う関数です。前述したとおり、引数にプロセス発見時に呼び出したい関数を渡すようになっています。

uses
    TLHELP32, PSAPI;

type
    //  プロセスが見つかったときに呼び出してほしい関数型定義
    TCancel = Boolean;
    TProcessFound = function(const ProcessEntry: TProcessEntry32;
                    const Err: Boolean; const ErrText: string): TCancel of object;

//-----------------------------------------------------------------------------
//  プロセス一覧を取得
//  http://nienie.com/~masapico/api_sample_ps05_c.html
//  http://nienie.com/~masapico/api_EnumProcesses.html
//  http://support.microsoft.com/default.aspx?scid=kb;ja;JP175030
//  http://www.borland.co.jp/qanda/delphi/d0003287.html
//  http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=13
procedure SnapShotProcess(CallBack: TProcessFound);
var
    SnapShot: THandle;
    PE32: TProcessEntry32;
begin
    //  構造体の初期化
    FillChar(PE32, SizeOf(PE32), 0);
    PE32.dwSize := SizeOf(PE32);

    try
        // システム中の情報のスナップショットをとる
        SnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

        //  成功した場合
        if (SnapShot <> INVALID_HANDLE_VALUE) then
        begin
            try
                // 最初のプロセスの検索
                if Process32First(SnapShot, PE32) then
                begin
                    //  通知
                    repeat
                        if CallBack(PE32, False, '') then break;

                    // 次のプロセスの検索
                    until not Process32Next(SnapShot, PE32);
                end
                //  検索失敗
                else CallBack(PE32, False, '');
            finally
                CloseHandle(SnapShot);
            end;
        end
        //  失敗した場合
        else
        begin
            CallBack(PE32, True, SysErrorMessage(GetLastError()));
        end;
    except
        on E: Exception do CallBack(PE32, True, E.Message);
    end;
end;

プロセスIDからプロセスハンドルを取得する関数TOP

それから、プロセスIDからプロセスハンドルを取得する関数を作っておきます。プロセスを列挙する関数で直接取得できるのは、TProcessEntry32 構造体に含まれているプロセスIDなんですが、実際にプロセスの情報を取得しようとすると必要になってくるのは、プロセスのハンドルだからです。

あー、その前に、内容を理解しているわけではありません。多分どっかからパクってきてます。参考にしたURLをコメントに書いてないので、ひょっとしたら、PlatformSDKから自分で探したのかも知れません。忘れました。

//-----------------------------------------------------------------------------
//  プロセスハンドルの取得
function GetProcessHandle(const ProcessID: Cardinal;
                var Handle: THandle; var Err: string): Boolean;
begin
    Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessID);
    Result := (Handle <> 0);
    if not Result then Err := SysErrorMessage(GetLastError());
end;

バイト数を文字列表示する関数TOP

それから、しょうもないことですが、得られた情報がバイト単位だった場合に、文字列に変換する関数も作っておきます。1024バイト未満であればそのまま、それ以上であればキロバイト単位で表示、1024キロバイト以上ならさらにメガバイト単位で表示する、それだけのものです。

//-----------------------------------------------------------------------------
//  バイト数を文字列表示
function B2S(const ByteSize: Int64): string;
var
    Check: double;
begin
    Check := ByteSize;
    if (Check < 1024) then
    begin
        Result := FormatFloat('#,##0.00 B', Check);
    end
    else
    begin
        Check := Check / 1024;

        if (Check < 1024) then
        begin
            Result := FormatFloat('#,##0.00 KB', Check);
        end
        else
        begin
            Check := Check / 1024;
            Result := FormatFloat('#,##0.00 MB', Check);
        end;

        //Result := FormatFloat('#,##0.00 KB', Check);
    end;
end;

今のところかけている取得処理TOP

ここまでの関数を使って、前回放置した時点でかけていたプロセス情報の取得処理です。TProcessMemoryCounters という構造体を仲介に、GetProcessMemoryInfo というAPIを使っていくつかのメモリに関する情報を取得するところまでです。

実際には、グリッドに表示しているのですが、そのあたりの処理は除去しました。おかげで、何の意味もない単なる関数呼び出しの羅列になりましたが、そのあたりはあれで。

//-----------------------------------------------------------------------------
//  見つかったプロセスから情報を取得
//  http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/jpperfmo/html/_win32_GetProcessMemoryInfo.asp
//  http://www.ccn.aitai.ne.jp/~ccc/C++/Psapi.txt
//  http://nienie.com/~masapico/api_EmptyWorkingSet.html
function TForm1.ProcessFound(const ProcessEntry: TProcessEntry32;
                    const Err: Boolean; const ErrText: string): TCancel;

    function GetValue(const Valid: Boolean; const Value: string): string;
    begin
        if Valid then Result := Value else Result := '#VAL';
    end;

var
    hProcess: THandle;
    Err2: string;
    pmc: TProcessMemoryCounters;
    GetProcessMemoryInfoSucceeded: Boolean;
begin
    //  エラーの場合は無視
    if not Err then
    begin
        //  プロセスのメモリ情報を取得
        FillChar(pmc, SizeOf(pmc), 0);
        GetProcessMemoryInfoSucceeded := False;

        //  プロセスハンドル取得
        if GetProcessHandle(ProcessEntry.th32ProcessID, hProcess, Err2) then
        begin
            pmc.cb := SizeOf(pmc);
            GetProcessMemoryInfo(hProcess, @pmc, SizeOf(pmc));
            GetProcessMemoryInfoSucceeded := True;
        end;

        //  イメージ名
        //ProcessEntry.szExeFile;

        //  PID
        IntToStr(ProcessEntry.th32ProcessID);

        //  メモリ使用量
        GetValue(GetProcessMemoryInfoSucceeded, B2S(pmc.WorkingSetSize));

        //  最大メモリ使用量
        GetValue(GetProcessMemoryInfoSucceeded, B2S(pmc.PeakWorkingSetSize));

        //  ページフォルト
        GetValue(GetProcessMemoryInfoSucceeded, B2S(pmc.PageFaultCount));

        //  仮想メモリサイズ
        GetValue(GetProcessMemoryInfoSucceeded, B2S(pmc.PagefileUsage));

        //  ページプール
        GetValue(GetProcessMemoryInfoSucceeded, B2S(pmc.QuotaPagedPoolUsage));

        //  非ページプール
        GetValue(GetProcessMemoryInfoSucceeded, B2S(pmc.QuotaNonPagedPoolUsage));
    end;

    //  全プロセスを列挙する(列挙をキャンセルせずに続ける)
    Result := False;
end;

進捗状況TOP

今のところ、チェックの入っているデータまで取れてます。ただし、権限が足りないのか一部のプロセスの情報は取り出せないようです。でもまぁ後回し。

EOFTOP