tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルProcess.GetProcessesの表示順につきまして
記事No10509
投稿日: 2011/04/27(Wed) 21:25
投稿者camputer
 今晩は。2回連続で質問させていただきます。
大変恐縮でございますが、どうぞよろしくお願い致します。
 プログラム歴10年程度 &VBとVBA歴3年程度、
環境:Win7+VB2008EE でございます。

 複数開いているテキストファイル(全てメモ帳)のウィンドウの、
「開いた順番」を知れる方法が無いかなと色々検索いたしております。
Process.GetProcessesで羅列してみましたが、これは何の順番で
Processを見つけてきれくれるのでございましょうか??

http://www.atmarkit.co.jp/fdotnet/dotnettips/233enumwin/enumwin.html
を参考にさせていただきまして、次のようにコーディングいたしました。

        For Each p As Process In Process.GetProcesses()
            If Not p.MainWindowHandle.Equals(IntPtr.Zero) Then
                If (p.ProcessName = "notepad") Then
                    MsgBox(p.MainWindowTitle)
                End If
            End If
        Next

 正常に動作いたしますが、「ウィンドウを開いた順」でも
「ウィンドウの重なり順(上下)」でもございません。
しかし毎回同じ順番でウィンドウが検出されます。

 色々検証いたしましたが、どれも明確なルールに行き着かず
検索いたしましてもなかなか見つからず悩んでおります。
(検証内容は下記のような感じになります。)

 何かヒントや思いつかれる事などございましたら
アドバイスいただきたくどうぞお願いいたします。


==【検証内容】============================
 例えば1.txt 2.txt 3.txtの3つのファイルがある際、
・123の順で開いて上のコードを走らせますと
 今の私の環境では、312の順でProcessが表示されました。
・毎回同じ順で出てきます。
・秀丸で同様な事をやってみましても、同じ結果でございました。
・更に別フォルダの2.txt 3.txt を開きますと、
 33122の順でProcessが表示されます。
 ↑同じファイル名が連続して出てきているので、ファイル名に何か関係するのかな?
などとも考えている次第でございますが。。。
 とんちんかんな質問かもしれませんが、何か思いつかれる事がございましたら、
どうぞよろしくお願い致します。

[ツリー表示へ]
タイトルRe: Process.GetProcessesの表示順につきまして
記事No10512
投稿日: 2011/05/01(Sun) 23:12
投稿者camputer
 かなりとんちんかんな質問でしたでございましょうか。。^^;
もしくは皆様、GWはVBで遊んでおられないとか。。(?)

 こういった、(「コードの書き方」ではなく)
「原理」に近い部分というのは、皆様どのようにお調べになっておられるのでしょうか??
MSに直接聞けるような手段でもあれば面白いのかもしれませんが。

 もし何か質問で至っていない部分などございましたら
有無をいわさずご消去くださいませ。>花ちゃん様

ちなみに
>、「ウィンドウを開いた順」でも
>「ウィンドウの重なり順(上下)」でもございません。
>しかし毎回同じ順番でウィンドウが検出されます。
についてでございますが、以前花ちゃん様からご提示いただいた
>トップレベルウィンドウのハンドルを列挙する
http://www.hanatyan.sakura.ne.jp/patio/read.cgi?no=300
ならば、「ウィンドウの重なり順(上下)」で
綺麗にウィンドウを取ってきてくれます。

 もし「調べられそうな事なのか、調査に困難が予想される事なのか」だけでも
分かると非常に嬉しいです。

 GW後に何かお閃きになられる方がいらっしゃいましたら、
一言でもヒントを教えてやっていただければ幸いでございます。

 何卒よろしくお願い致します。

[ツリー表示へ]
タイトルRe^2: Process.GetProcessesの表示順につきまして
記事No10513
投稿日: 2011/05/01(Sun) 23:51
投稿者オショウ
>  かなりとんちんかんな質問でしたでございましょうか。。^^;
> もしくは皆様、GWはVBで遊んでおられないとか。。(?)

  ええ〜と・・・
  多分、誰かがコメントするとすぐ後追いでコメント書かれる
  ように思いますので、一番?バッターで書きます。

● 以前にもどこかの掲示板の順序の話を見た記憶があるのです
  が、列挙される順番に法則はありません。
  PID順に並べても多分、ソーティングされたようにはなって
  いないはすです。

  よって、起動順序を獲得したいのであれば、常駐プログラム
  を作って、プログラムの起動監視を行う必要があります。

  そうすれば、起動順番は獲得できますので・・・

以上。

[ツリー表示へ]
タイトルRe^3: Process.GetProcessesの表示順につきまして
記事No10514
投稿日: 2011/05/02(Mon) 01:31
投稿者camputer
 オショウ様

 どうもありがとうございます!m(_ _)m
>以前にもどこかの掲示板の順序の話を見た記憶があるのです
>が、列挙される順番に法則はありません。
 左様でございましたか。。何故か毎回同じ順序で列挙されるので、
何かしらルールがあるのでは、と疑っておりました。ただしかし
現象から推察いたしまするに、開いた順序とは全く無関係のものなので
ございましょうね。

>起動順序を獲得したいのであれば、常駐プログラム
>を作って、プログラムの起動監視を行う必要があります。
 はい、どうもありがとうございます。常駐プログラムの作成も
面白そうでございますね^^ 全然検索いたしておりませんが、
タスクマネージャ上で目的のプロセスが増えたのを
監視するようなイメージでございましょうか。

 それにいたしましても、英語サイトですら今回の「列挙順序」の
話がひっかかってくれません。。上級者の方々からすれば、直感で
おそらく無意味な物かもしくは法則が無いに等しいような物、と
見抜いてらっしゃられるのかもしれませんね。。。

 この度はご親切に、遅い時間にも関わらずお教えいただきまして
誠にありがとうございました!!
今後もどうぞよろしくお願い致します!m(_ _)m

[ツリー表示へ]
タイトルRe^4: Process.GetProcessesの表示順につきまして
記事No10515
投稿日: 2011/05/02(Mon) 10:09
投稿者shu
返されたリストの並び順がどのようになっているか?というよりどのような並び順で
使用したいかにより並び替えを行えばよいのではないでしょうか?
メソッドの説明で並び順についてかかれていなければそれは特定の
並び順にはしていないとみるのが良いのではないでしょうか。
ちなみにStartTimeというプロパティがあるので、起動順に並べ変える
ことは可能かもしれません。

[ツリー表示へ]
タイトルRe^5: Process.GetProcessesの表示順につきまして
記事No10516
投稿日: 2011/05/02(Mon) 12:06
投稿者camputer
 shu様

 どうもありがとうございます!!!
 VB関連の掲示板でよくご活躍をご拝見いたしております。
この度はご閲覧いただき誠にありがとうございます。m(_ _)m

>ちなみにStartTimeというプロパティがあるので、起動順に並べ変える
>ことは可能かもしれません。
 さっきから検索してみておりますが、
p.StartTime
といった物が結構出てまいりますね。面白くなりそうでございます。^_^b

> 返されたリストの並び順がどのようになっているか?というよりどのような並び順で
> 使用したいかにより並び替えを行えばよいのではないでしょうか?
 はい、仰られます通り、「並び替え」にまで目がいっておりませんでした。
どうもありがとうございます。
 なるほど(・o・ 、Processesの中身(プロパティ)を調べてみるべきだったので
ございますね。せっかく魔界の仮面弁士様からオブジェクトブラウザでの
検索方法をお教えいただいておりましたのに。。orz

 shu様は一体、何故このようなプロパティをご存知なのでございましょう。。(?_?
やはり経験値でございましょうか。。

 今からちょっと外に出てまいりますが、今晩から是非試させていただきます!
お陰でGW後半が楽しめそうでございます^^
この度はお休みのところ、ご親切にアドバイスいただきまして
誠にありがとうございました!m(_ _)m

[ツリー表示へ]
タイトルRe^6: Process.GetProcessesの表示順につきまして
記事No10517
投稿日: 2011/05/02(Mon) 14:05
投稿者shu

>  shu様は一体、何故このようなプロパティをご存知なのでございましょう。。(?_?
> やはり経験値でございましょうか。。
今回のはMSDNでProcessのメンバ一覧より見つけただけです。多分それっぽいものが
あるんじゃないかなと予想はつけていましたが、知っていたわけではありません。

[ツリー表示へ]
タイトルRe^7: Process.GetProcessesの表示順につきまして
記事No10520
投稿日: 2011/05/03(Tue) 01:09
投稿者camputer
 どうもありがとうございます!m(_ _)m
なんとお調べになってくださったのでございましたか。お休みの中
誠にありがとうございます。
私も今調べて参りましたが、
http://msdn.microsoft.com/ja-jp/library/system.diagnostics.process_members(v=VS.80).aspx
にshu様が仰られたとおりの物が載っておりますね。
 勉強になりました。では今からコーディングしてまいります!!^^
この度はご親切に誠にありがとうございました!!

[ツリー表示へ]
タイトル【解決】Re^8: Process.GetProcessesの表示順につきまして
記事No10527
投稿日: 2011/05/09(Mon) 10:04
投稿者camputer
 おはようございます。見事にファイルのOPEN時間順で並んでくれました^^

↓2次元配列に入れてp.StartTimeでソートしてみました。
(2次元配列のソート方法がなかなか見つからず弱冠苦労いたしました。。- -;)
短いコードですので、ここに貼り付けさせていただきます。


(変数名に全角文字を使用している事はどうぞ許してやってください^^;
Fortranなどと違い変数名に全角文字を入れるとコード全体の中のどの辺に
変数があるのか一目で分かるので、意図的にやってしまっております。)

        Public 配列_notepad(1)() As Object


        Dim リスト_StartTime As ArrayList = New ArrayList
        Dim リスト_WindowTitle As ArrayList = New ArrayList

        For Each p As Process In Process.GetProcesses()
            If Not p.MainWindowHandle.Equals(IntPtr.Zero) Then
                If (p.ProcessName = "notepad") Then
                    リスト_StartTime.Add(p.StartTime)
                    リスト_WindowTitle.Add(p.MainWindowTitle)
                End If
            End If
        Next

        配列_notepad(0) = リスト_StartTime.ToArray
        配列_notepad(1) = リスト_WindowTitle.ToArray
        Array.Sort(配列_notepad(1), 配列_notepad(0))
        Array.Sort(配列_notepad(1), 配列_notepad(1))

        For i As Integer = 0 To 配列_notepad(0).Length - 1
            MsgBox(配列_notepad(0)(i) & "/" & 配列_notepad(1)(i))
        Next


 動作確認はXP上で行ってみました。未保存ファイル(メモ帳ショートカットから起動)に
つきましても、そのOPEN時間を取れます。
おそらくOSによって弱冠挙動が変わるのではないかと思いますが、
今回いただけたアドバイスのおかげでまた面白いスキルが1つ手に入りました。

 この度は連休の中、ご親切に誠にありがとうございました!!m(_ _)m

[ツリー表示へ]
タイトルRe: 【解決】Re^8: Process.GetProcessesの表示順につきまして
記事No10528
投稿日: 2011/05/09(Mon) 12:16
投稿者YuO
解決されてはいる物の,やらない方がよいことをされているようなので……。

>         Public 配列_notepad(1)() As Object
>         Dim リスト_StartTime As ArrayList = New ArrayList
>         Dim リスト_WindowTitle As ArrayList = New ArrayList

これらはやめた方が良いです。

・Objectの配列→本当にObjectの配列でないなら使わない
 今回の場合,クラスまたは構造体を一つ作って使うことになります。
 .NET Framework4以降にはTupleクラスという物があるのですが……。
・System.Collectionsのコレクション→System.Collections.Genericのコレクションを使う
 ArrayListよりList(Of T),HashtableよりDictionary(Of TKey, TValue)


ちなみに,Array.FindAllメソッドを使うと,配列の絞り込みができます。
MSDN: Array.FindAll(T) メソッド (System)
http://msdn.microsoft.com/ja-jp/library/1kkxfxdd(VS.90).aspx
また,配列のソートに比較関数を渡すことができます。
MSDN: Array.Sort(T) メソッド (T[], Comparison(T)) (System)
http://msdn.microsoft.com/ja-jp/library/cxt053xf(VS.90).aspx
これらを使って,

' ここから
' 元のコードの置き換え部分
Dim processes As Process() = Process.GetProcesses()
Dim notepads As Process() = Array.FindAll(processes, AddressOf Notepadプロセスの検索)
Array.Sort(notepads, AddressOf Notepadプロセスのソート)

' ここから下はメソッドの外側
' 絞り込みやソートの為の関数群
Shared Function Notepadプロセスの検索 (ByVal p As Process) As Boolean
  If p Is Nothing Then Return False
  If p.MainWindowHandle = IntPtr.Zero Then Return False
  ' 明示的に「大文字・小文字を区別しない」比較を行う
  Return String.Equals(p.ProcessName, "notepad", StringComparison.InvariantCultureIgnoreCase)
End Function

Shared Function Notepadプロセスのソート (ByVal x As Process, ByVal y As Process) As Integer
  If x Is y Then Return 0
  If x Is Nothing Then Return -1
  If y Is Nothing Then Return 1
  ' ウィンドウタイトルでの比較
  Dim titleResult As Integer = x.MainWindowTitle.CompareTo(y.MainWindowTitle)
  ' ウィンドウタイトルが異なれば,ウィンドウタイトルの比較結果でソートする
  If startTimeResult <> 0 Then Return startTimeResult
  ' ウィンドウタイトルが同じであれば,開始時間の比較結果でソートする
  Return x.StartTime.CompareTo(y.StartTime)
End Function
' ここまで

のようにも書けます。


VB 2008ならLINQが使えるので……。
For Each p In _
  From p0 In Process.GetProcesses() _
  Where p0 IsNot Nothing _
  Where p0.MainWindowHandle <> IntPtr.Zero _
  Where String.Equals(p0.ProcessName, "notepad", StringComparison.InvariantCultureIgnoreCase) _
  Order By p0.MainWindowTitle, p0.StartTime

    MsgBox(p.StartTime & "/" & p.MainWindowTitle)
Next
または,
For Each p In _
  Process.GetProcesses() _
  .Where(Function(p0) p0 IsNot Nothing) _
  .Where(Function(p0) p0.MainWindowHandle <> IntPtr.Zero) _
  .Where(Function(p0) String.Equals(p0.ProcessName, "notepad", StringComparison.InvariantCultureIgnoreCase)) _
  .OrderBy(Function(p0) p0.MainWindowTitle) _
  .ThenBy(Function(p0) p0.StartTime)

    MsgBox(p.StartTime & "/" & p.MainWindowTitle)
Next
と書くこともできます。
# 個人的には後者が好きだけれど,VBだとFunctionって記述が面倒……。

[ツリー表示へ]
タイトルRe^2: 【解決】Re^8: Process.GetProcessesの表示順につきまして
記事No10529
投稿日: 2011/05/09(Mon) 13:13
投稿者camputer
 YuO様
 どうもありがとうございます!!m(_ _)m
前にもアドバイスいただきましたcamputerと申します。
この度はコーディングの例示までいただき誠にありがとうございます。

 今一通り読ませていただきました。非常に面白そうですので是非とも今すぐ
試してみたいのですが、弱冠時間がございません故、今日の夜以降に
試させていただきますm(_ _)m
ちゃんと理解してから再度ご報告させていただきます。

 まずお礼だけさせていただきます、誠にありがとうございます!!

[ツリー表示へ]
タイトルRe^3: 【解決】Re^8: Process.GetProcessesの表示順につきまして
記事No10530
投稿日: 2011/05/12(Thu) 12:59
投稿者camputer
 この度は誠にありがとうございました!!m(_ _)m
 始め何故かMsgBoxの表示順がおかしかったので結構悩みましたが、
すべてうまく動作いたしました。

 あとLINQ自体を存じませんでした^^;
Whereなど全て調べてまいりましたが、VBはいくらでも覚える事が
ございますねー。。(そろそろ、「作ってみたい物がある→検索&学習」の方針を
変更して、一度きちんと勉強するという事をせねばならない気が。。。-v-;)

 非常に勉強になりました!!(←すべてきちんと理解していないので
過去形で書くべきではないような気もいたしますが。。。)
また怪しいコードを書きそうになっておりましたら、どうぞ御指摘してやってください!!
この度はご親切にどうもありがとうございました!!!camputer

[ツリー表示へ]