DOBON.NET DOBON.NETプログラミング掲示板過去ログ

プロセス名からハンドルを取得する方法

環境/言語:[XP C# .NET3.5]
分類:[.NET]

皆様こんにちは。
C#を使ってプログラミングしている者です。
早速ですが、質問があります。

最小化した外部プロセス(プログラム名はtest01.exe)を元の大きさに戻したいと思っています。

http://www.atmarkit.co.jp/fdotnet/dotnettips/151winshow/winshow.html
を参考に、次のようにしたのですが、動きません。
Process[] ps = Process.GetProcessesByName("test01").MainWindowHandle;
でプロセスは取得できていて、デバッガで見るとHandleの番号が2403とありました。
その番号を、handletest01に渡してやればいいと思うのですが、
handletest01 = p.MainWindowHandle;
でうまくいっていないようです。
handletest01の値が、Side 4 , Zero 0となっています。
MainWindowHandleでないのかもと、
handletest01 = p.Handle;
としても同様でした。

プロセス名からハンドルを取得する方法をご教示いただけないでしょうか。

// 外部プロセスのメイン・ウィンドウを起動するためのWin32 API
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr handletest01);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr handletest01,int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr handletest01);
// ShowWindowAsync関数のパラメータに渡す定義値
private const int SW_RESTORE = 9;  // 画面を元の大きさに戻す

IntPtr handletest01;
private void button1_Click(object sender, EventArgs e){
    Process[] ps = Process.GetProcessesByName("test01").MainWindowHandle;
    foreach(Process p in ps) {
        handletest01 = p.MainWindowHandle;
    }
    // メイン・ウィンドウが最小化されていれば元に戻す
    if (IsIconic(handletest01))    ShowWindowAsync(handletest01, SW_RESTORE);
    // メイン・ウィンドウを最前面に表示する
    SetForegroundWindow(handletest01);
}
2009/11/17(Tue) 18:33:39 編集(投稿者)

■No25842に返信(シトロエンさんの記事)

  VBなら・・・

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim ps() As Process = Process.GetProcessesByName("test01")

        For Each p As Process In ps
            If IsIconic(p.MainWindowHandle) Then
                ShowWindowAsync(p.MainWindowHandle, SW_RESTORE)
            End If
            SetForegroundWindow(p.MainWindowHandle)
        Next

    End Sub

以上。
■No25843に返信(オショウさんの記事)
> 2009/11/17(Tue) 18:33:39 編集(投稿者)
オショウさん。
すみません。せっかく教えていただいたのですが、
C#初心者でVBはさわったことがありません。
ただ、参考に、次のようにしてみました。

Process[] ps = Process.GetProcessesByName("test01");
foreach(Process p in ps) {
if (IsIconic(p.MainWindowHandle))
ShowWindowAsync(p.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(p.MainWindowHandle);
}
これで動作を確認したところ、
if (IsIconic(p.MainWindowHandle))
の条件に合致していないことがわかりました。

あらためて考えてみると、そのtest01は、タスクバーに表示せず、タスクトレイに入っています。
その状態って、ひょっとしてIsIconicではないのではないか、と思い至りました。
タスクトレイに入っているときの条件について、
C#で教えていただけばうれしいです。
ウィンドウが非表示なら MainWindowHandle は IntPtr.Zero を返すはずです。
「タスクトレイに入っている」は無関係。
逆に言うと、ウィンドウが非表示のプロセスに対しては Process オブジェクトから直接ウィンドウハンドルを取得することはできません。
必要なら、EnumWindows でトップレベルウィンドウを列挙し、GetWindowThreadProcessId で目的のプロセスに属するウィンドウかどうかを確認、さらにそれが目的のウィンドウかどうか GetWindowLong などを使って調べる必要があるでしょう。要するに面倒です。
■No25844に返信(シトロエンさんの記事)
> あらためて考えてみると、そのtest01は、タスクバーに表示せず、タスクトレイに入っています。

  そういうアプリの場合・・・
  ウィンドウハンドルがあっても、それは最小化されたウィンドウ
  ハンドルではなく、タスクトレイからメッセージをやろとりする
  だけの独自なハンドルだったりするわけで、そのハンドルにどん
  なメッセージをSendMesssage/PostMessageするかは、アプリ独自
  であったりもします。

  そういう場合、どんなメッセージで復帰させるか、SPY++とか使
  ってメッセージの追跡してみないことには、どんなアプリでも、
  一様に・・・と言うわけにはいかないと思われます。

※ 試しに似たアプリがあったので、タスクトレイに格納し、いろいろ
  やってみましたが・・・残念ながら、これだと言うメッセージを、
  捕まえることはできませんでした。

  可能か不可能か・・・と言えば、可能だとは思いますが・・・

以上。

DOBON.NET | プログラミング道 | プログラミング掲示板