none
他のプロセスのハンドルを取得する場合、取得できたかどうか確認したい。 RRS feed

  • 質問

  • Takaです。教えてください。

    現在、VC#2005でWindwsFormを作成しています。同じPC上で動いている他のhogeを含むプロセスの中のcomboBox1のハンドルを取得したいので途中まで書いてますがうまくいきません。とりあえずハンドルが取得できたかどうか確認したいのでその方法を教えてください。

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter,string lpszClass,string lpszWindow);

    System.Diagnostics.Process[] hProcesses = System.Diagnostics.Process.GetProcesses();
    System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
    foreach (System.Diagnostics.Process hProcess in hProcesses)
    {
      if (hProcess.ProcessName.Contains("hoge")) myProcess = hProcess;
    }
    IntPtr tComboHandle = WinAPI.FindWindowEx(myProcess.Handle, IntPtr.Zero, "comboBox1", null);

    ここで、hogeを含むプロセスを格納したmyProcessのIDを調べると、spy++で確認したhogeのプロセスのIDと同じなのでmyProcessまでは目的のプロセスを格納できていると思われますが、tComboHandleに0しか入らないので、myProsess.Handleが正しくハンドルを指定しているか知りたいのでその見方を教えてください。ちなみに、unsefe設定にして

    int result = *myProcess.Handle;

    のように考えましたが「* または -> 演算子はポインタに対して使用してください。」となってしまいます。 

    ちなみに myProcess.Handle はspy++で確認したハンドルとは異なり、毎回違う値になるので、ハンドルの値ではなくハンドルのポインタ、と理解してます。

    2007年3月25日 9:38

回答

  • プロセス名から取得できないということなので、
    別の方法でその表示されているWindowを特定できませんかね?

    たとえば、その表示されているWindowのクラス名が特定なものであれば、FindWindow(FinddWindowEx)
    でウィンドウハンドルを取得できますし。
    2007年3月26日 2:47

すべての返信

  • FindWindowEx関数に指定するものはプロセスハンドルではなく
    ウィンドウハンドルです。

    Process.Handleではなく、
    Process.MainWindowHandleプロパティを使うとどうなりますか?

    また、
    >WinAPI.FindWindowEx(myProcess.Handle, IntPtr.Zero, "comboBox1", null);
    はcomboBox1というクラス名になっているのでしょうか?
    Spy++で確認してみてください。

    また、コントロールIDがわかれば(Spy++でわかるはず)、GetDlgItem関数(WinAPI)でも取得できます。
    (こちらのほうが同じクラス名のコントロールが複数あったとしてもピンポイントで取得できるはず。)
    2007年3月25日 9:58
  • 蒼の洞窟さん、

    ご回答頂きましてありがとうございました。

    なるほど、.Handleだとプロセスハンドルをさすのですね。ということで、 myProcess.MainWindowHandle にしてみました。結果はおもわしくありません。

    現在、前回同様にmyProcessに該当プロセスが入ってるのを確認し、子クラス名が違っているもしくは包まれていることを考慮してクラス名をnull指定(子クラスすべてがHitすると理解)にしてみました。ちなみに、前回の子クラス名以外にもspy++で表示されるクラス名をいろいろためしましたがnull指定時と同じ結果となります。

    IntPtr parentWindowHandle = myProcess.MainWindowHandle;
    IntPtr tComboHandle = WinAPI.FindWindowEx(parentWindowHandle, IntPtr.Zero, null, null);

    とりあえず、親WindowハンドルのparentWindowHandleですが、たとえばspy++で見た一番上位のWindowの「メッセージオプション->選択されたオブジェクト->ウィンドウ」の表記が 00410490 だったとします。ここで


    MessageBox.Show(Convert.ToString(parentWindowHandle.ToString("X")));

    とすると 51046C が表示されます。spy++のウィンドウのところの値がA-Fが出ないので10進表記かと思い、

    MessageBox.Show(Convert.ToString(parentWindowHandle.ToString()));

    とすると 5309548 が表示されます。spy++で見る場所、同じプロセス名があるかなどいろいろやりましたが、プロセスIDは一致しますがウィンドウハンドルが一致しません。FindWindowEXで検索した子クラスは、上記のようにnull指定や、クラス名をspy++で確認したものにいろいろと変えてみましたが、

    MessageBox.Show(Convert.ToString(tComboHandle.ToString("X")));

    で確認すると必ず 0 になり、まったくHitしてないと思われます。

    2007年3月26日 0:28
  • どうも、IntPtrの値をそのまま16進表記できないようです。
    int型にキャストして、16進表記にしてみるとSpy++の値と同じになります。

    以下試したコード
    using System;
    using System.Text;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    public class Test
    {
        [DllImport("user32", EntryPoint = "GetWindowText", CharSet = CharSet.Auto)]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
        public static void Main()
        {
            using (Process p = new Process())
            {
                p.StartInfo.FileName = "notepad";
                p.Start();
    
                p.WaitForInputIdle();
    
                System.Console.WriteLine("{0:X}", p.MainWindowHandle);
                System.Console.WriteLine("{0:X}", (int)p.MainWindowHandle);
    
                StringBuilder sb = new StringBuilder(256);
                GetWindowText(p.MainWindowHandle, sb, sb.Capacity);
                System.Console.WriteLine("{0}", sb.ToString());
            }
        }
    }
    2007年3月26日 0:52
  • 蒼の洞窟さん、

    Windowのハンドルの値を表示できました。ありがとうございました。

    さて、問題はまだ続いており、どうやら、相手先のプログラムがデルファイで作られているらしく、spy++で表示できるWindowの上位に見えない TApplication というWindowが隠されており、

    myHTHProcess.MainWindowHandle

    だと見えているWindowではなく、隠れているTApplication がヒットしてしまいます。このTApplicationは見えているWindowとは別に独立しているもののようで、プロパティを見ても子Windowがありません。

    ということで、プロセスまでを取得できた後に、最上位から掘り下げるのではなく任意のクラス名でいきなり検索する方法は無いかと探しています。

    2007年3月26日 2:37
  • プロセス名から取得できないということなので、
    別の方法でその表示されているWindowを特定できませんかね?

    たとえば、その表示されているWindowのクラス名が特定なものであれば、FindWindow(FinddWindowEx)
    でウィンドウハンドルを取得できますし。
    2007年3月26日 2:47
  • 蒼の洞窟さん、

    FindWindowで正しいウィンドウハンドルを取得できました。おしゃる通り、特殊な名前なので問題ありませんでした。ありがとうございました。

    ちなみに、

    IntPtr myHandle = WinAPI.FindWindow("hoge", null);

    MessageBox.Show(myHandle.ToString("X"),"");

    という感じで、MessageBoxにであればそのまま16進表記でウィンドウハンドルを表示できましたので、そんな方法で確認しました。

    2007年3月26日 3:26