OpenProcessによるハンドルの取得について

解決


もんちきTwin Turbo  2018-03-02 04:01:07  No: 49016

何時も参考にさせていただいています。 
もんちきTwin Truboと申します。 
皆様にご教授いただきたく、書き込みさせていただきます。 

現在、OpenProcessを使用して、実行中のプロセスの一覧を取得しようとしています。
作成に当たっては、以下のスレッドを参考にさせていただいています。

https://www.petitmonte.com/bbs/answers?question_id=1652

しかし、期待するように動作しません。
例えば、上記のサンプルでは、メモ帳の起動を検知できません。

原因を調べるため、途中のプロセス一覧を取得する部分で、以下の2行を追加し、値の変化を確認してみました。そうしたところ、インデックスiは正常に増加しますが、hProcessが変化しません。

  for i := 0 to NumProcess -1 do begin 
    hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, 
                            false, ProcessIDs[i]);

    ShowMessage(IntToStr(i));//追加
    ShowMessage(IntToStr(hProcess));//追加
 
    EnumProcessModules(hProcess,@hModule,SizeOf(hModule),Num4); 
    Num4 := GetModuleBaseName(hProcess,hModule,lpBaseName,100); 
    SetString(s,lpBaseName,Num4); 
    SL.Add(s); 
    CloseHandle(hProcess); 
  end;

OSや言語のバージョンの違いによるものでしょうか?
OSは64bit Windows7 professional
Delphiは7です。

よろしくおねがいします。


通りすがり  2018-03-02 05:35:31  No: 49017

そもそもEnumProcessesが返す値はどうなっていますか?EnumProcessesはプロセスを列挙しきれなくても検知できないので

Win32API EnumProcesses(プロセス列挙)の使い方 | 豆知識
http://soundengine.jp/wordpress/tips/tutorial/336/

こんなことが必要ですけどどうでしょう?


take  2018-03-02 18:26:51  No: 49018

Windows7からは他のプロセスの状態を取得しようとしても全てのプロセスが取得出来ない場合があります。
取得方法はMr.XRAY様のページが参考になるかと
http://mrxray.on.coocan.jp/Delphi/plSamples/330_AppProcessList.htm

管理者権限でないと取得出来ないプロセスの場合、管理者権限への昇格が必要なのですが
Windows7からはプログラム中に管理者権限に昇格しようとするとOSが確認メッセージを出して
一時的に処理を止めるかもしれません。


もんちきTwin Turbo  2018-03-02 19:48:09  No: 49019

通りすがり様、take様、ご回答ありがとうございます。

>通りすがり様
>そもそもEnumProcessesが返す値はどうなっていますか?

参考にした過去ログのプログラムでは、ループに入る前にEnumProcessesを以下のように実行しています。
ループが実行されていると言うことは、ここでtrue(0以外?)が返っているのだと思います。

  if not EnumProcesses(@ProcessIDs,SizeOf(ProcessIDs),Num4) then begin 
    ShowMessage('EnumProcesses Failed!'); 
    Exit; 
  end; 

またこの前に以下の2行を追加し引数を確認したところ、それぞれ804と29374392でした。
(最初の@ProcessIDsについては、ポインタのキャストの仕方が良く分かりませんでした。)

  showmessage(IntToStr(SizeOf(ProcessIDs)));
  showmessage(IntToStr(Num4));

これについて変化を見たところ、SizeOf(ProcessIDs)は再起動してもexeから起動しても804で変化せず、
Num4は随時変化しました。また、その後ろの

  NumProcess := Num4 div SizeOf(DWORD);

は、その時々の起動中のプロセス数を返します。
ProcessIDsが変化しないことが要因なのでしょうか??

>take様
>取得方法はMr.XRAY様のページが参考になるかと 

Mr.XRAY様のプロジェクトを参考にさせていただきました。
Mr.XRAY様のプロジェクトに包含されているexeファイルは、どれも正常に動作しました。
また、take様のご指摘通り、管理者権限で実行した場合とそうでない場合で、列挙されるプロセスは変化しました。

ただ、Mr.XRAY様のプロジェクトを自分の環境で開きコンパイルすると、プロセス名は全て  C  一文字
(恐らくドライブレター?)になってしまいました。
氏のプロジェクトはWindows 7 U64(SP1) + Delphi XE Proということでしたが、私のDelphiは7なので、
コンパイラの問題によるということでしょうか?


take  2018-03-02 20:00:47  No: 49020

Mr.XRAY様のサンプルが Delphi2009以降の文字コードで処理されているようなので
Delphi7 だと string の定義を WideStringにする必要があるかもしれません。
取得する処理のところでブレークポイントを付けてどこで情報が欠落してしまうのかがわかれば改善出来るかと思います。


Mr.XRAY  2018-03-02 20:54:10  No: 49021

>Mr.XRAY様のサンプルが Delphi2009以降の文字コードで処理されているようなので 
>Delphi7 だと string の定義を WideStringにする必要があるかもしれません。 

ですね.
これはサンプルにもよります.使用する関数名の変更が必要な場合もあります.
Delphi 2007 以前のコードを Delphi 2009 以降に移植する場合も同じです.

参考
[DLL 内の関数の使用方法  -  DLL と目的の関数が必ず存在する場合]
http://mrxray.on.coocan.jp/Delphi/Others/Usage_Win32API.htm#03


もんちきTwin Turbo  2018-03-02 20:55:21  No: 49022

take様

>Delphi7 だと string の定義を WideStringにする必要があるかもしれません。 
そうなんですね。
とりあえず、ExePathをWideStringに変更しました。

>取得する処理のところでブレークポイントを付けてどこで情報が欠落してしまうのかがわかれば改善出来るかと思います。

Mr.XRAY様のサンプル06_Toolhelp32Snapshot_FullPathをベースにしています。
Button1Clickの中で値を見てみました。

ListHandle        起動時の値は同じ(起動時の権限によって値は異なる)
                  以降時々変化
ProcEntry.dwSize  権限等に関わらず常に一定(296)

ループ       1  2    3    4    5   ...
ProcessID  :0  4    300  460  512 ...
hProcHandle:0  472  472  472  472 ...

同梱のexeが正常に動くので、私が何か間違えているとは思うのですが…


もんちきTwin Turbo  2018-03-02 21:52:14  No: 49023

Mr.XRAY様、ご回答ありがとうございます。
書き込みが前後して、申し訳ありません。

>これはサンプルにもよります.使用する関数名の変更が必要な場合もあります. 

関数名の変更が必要な場合もあるのですね。

この場合、psapi.dllに仕様が分からないといけないということですね…
勉強しなきゃならないことがいっぱいです。


Mr.XRAY  2018-03-02 22:11:07  No: 49024

>この場合、psapi.dllに仕様が分からないといけないということですね… 

そうなんですか ? よく意味が理解できませんが,
私が貼ったリンクの記事,お読み頂けました ?


Mr.XRAY  2018-03-02 22:33:45  No: 49025

[06_Toolhelp32Snapshot を使用したプロセスの列挙でフルパスを取得]
http://mrxray.on.coocan.jp/Delphi/plSamples/330_AppProcessList.htm#06

↑ が Delphi 7 で動作すればいいんでしょうか ?
(このようにリンクを貼れば,他の方もすぐ参照できます.
このぐらいの手間をかけても損はないと思いますし,私もすぐ調べられます)

参考
[DLL 内の関数の使用方法  -  DLL と目的の関数が必ず存在する場合]
http://mrxray.on.coocan.jp/Delphi/Others/Usage_Win32API.htm#03

の記事に

>実際には,Delphi 2007 以前では,末尾が A の関数を使用します. 

と書いてあります.
ですので,

QueryFullProcessImageNameW
      ↓  変更
QueryFullProcessImageNameA 

にします.
当方の 64 ビット Windows 7 (SP1) + Delphi 7 ではこれで動作しました.


もんちきTwin Turbo  2018-03-02 22:54:05  No: 49026

Mr.XRAY様

ご回答、ありがとうございます。

>そうなんですか ? よく意味が理解できませんが, 
>私が貼ったリンクの記事,お読み頂けました ? 

私の知識ではすぐには十分理解できなかったので、まだ読んでいる最中です。ただdllの引数の型がDelphiの型と一致しない場合があることは分かりましたので、dllから呼び出す関数の仕様を良く理解する必要があるのですね…という趣旨で書きました。

>(このようにリンクを貼れば,他の方もすぐ参照できます.
>このぐらいの手間をかけても損はないと思いますし,私もすぐ調べられます) 

済みません。決して手間を惜しんだ訳ではなく、個人様のHPに直接リンクを張って良いものか分からなかったので、あのような書き方にしました。気をつけます。

ご指摘の通りQueryFullProcessImageNameAに変更したら、期待通りに動作しました。
どうもお手数をおかけしました。申し訳ありません。

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


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加