2012-02-16 8 views
1

私はこれをやってみたいと思っていました。私は無数のさまざまなuser32関数を試してきましたが、非常に幅広くオンラインで研究しましたが、残念ながら私は解決策はまだありません。スレッドの可視ウィンドウのタイトルを取得する

5つのスレッドを持つアプリケーションがあります。これらのスレッドは、プロセスのPIDを提供する.NET ProcessクラスのGetProcessByIdメソッドを介して簡単にアクセスできます。しかし、スレッドIDを提供し、そのウィンドウ(親または子)を列挙するために使用できる関数があるとは思われません。これらのスレッドの1つには、合計10個のウィンドウがあり、9個のウィンドウが表示され、1個のウィンドウが表示されます。表示されているスレッドのタイトルは、プログラムで取得しようとしているものです。

私の最近のアプローチは、プロセスハンドルをつかんで、EnumChildWindowsを通してそれを置いて、それぞれのウィンドウハンドルをコレクションに追加しようとしましたが、コレクションは常に空です。ここで

は、私がProcessThreadsViewツールで見るもののスクリーンショットです:

enter image description here

は、私が行方不明です何かはありますか?彼がどのようにしているのかを知るためにツールの作者に電子メールを送りましたが、確立されたアプローチがあるかどうかを聞いてみました。

アップデート:私はこれは私がそれを呼び出しています方法です、GetGUIThreadInfoを使用して試してみました:

[StructLayout(LayoutKind.Sequential)] 
public struct Rect 
{ 
    public int Left; 
    public int Top; 
    public int Right; 
    public int Bottom; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct GUITHREADINFO 
{ 
    public uint cbSize; 
    public uint flags; 
    public IntPtr hwndActive; 
    public IntPtr hwndFocus; 
    public IntPtr hwndCapture; 
    public IntPtr hwndMenuOwner; 
    public IntPtr hwndMoveSize; 
    public IntPtr hwndCaret; 
    public Rect rcCaret; 
} 

static IEnumerable<IntPtr> EnumerateThreadWindowHandlesByProcessId(int processId) 
{ 
    List<IntPtr> threadWindowHandles = new List<IntPtr>(); 

    foreach (ProcessThread thread in Process.GetProcessById(processId).Threads) 
    { 
     GUITHREADINFO threadInfo = new GUITHREADINFO(); 
     threadInfo.cbSize = (uint)Marshal.SizeOf(threadInfo); 
     bool returnValue = GetGUIThreadInfo((uint)thread.Id, out threadInfo); 
     threadWindowHandles.Add(threadInfo.hwndActive); 
    } 

    return threadWindowHandles; 
} 

アップデート2:EnumThreadWindowsを使用して

、これは私が持っているものです。

public delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam); 

[DllImport("user32.dll")] 
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam); 

private static bool ThreadWindows(IntPtr handle, IntPtr param) 
{ 
    //get window from handle later, testing for now 
    logger.Info("foo bar"); 

    return true; 
} 

[STAThread] 
public void Execute() 
{ 
    Process[] processes = Process.GetProcessesByName("MyProcessName"); 

    Process processOfInterest = processes[0]; 

    foreach (ProcessThread thread in processOfInterest.Threads) 
    { 
     EnumThreadWindows(thread.Id, new EnumThreadDelegate(ThreadWindows), IntPtr.Zero); 
    } 
} 

答えて

4

(前回の回答が厳しくなった場合には謝罪しました。それは私には明らかだったので、それはOPにも明らかであり、間違っていると思っていましたが、試していなかったことについては何もしていませんでした。)

EnumThreadWindowsは間違いなくあなたが望む機能ですそれはうまくいくはずです。システム上で実行されているすべてのアプリケーションに対して、EnumThreadWindowsIsWindowVisibleを使用してProcessThreadsViewから情報を複製することができました。 (また、「可視」は「有効」と同じではないことに注意してください)。

[UnmanagedFunctionPointer(CallingConvention.StdCall)] 
[return: MarshalAs(UnmanagedType.Bool)] 
private delegate bool EnumThreadWindowsProc(IntPtr handle, int param); 

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
private static extern bool EnumThreadWindows(uint threadId, 
    EnumThreadWindowsProc callback, int param); 

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool IsWindowVisible(IntPtr handle); 

[DllImport("user32.dll", CharSet = CharSet.Unicode)] 
static extern int GetWindowText(
    IntPtr handle, 
    [MarshalAs(UnmanagedType.LPWStr)] StringBuilder caption, 
    int count); 

[DllImport("user32.dll", CharSet = CharSet.Unicode)] 
static extern int GetWindowTextLength(IntPtr handle); 

static void Main(string[] args) 
{ 
    var callback = new EnumThreadWindowsProc(Program.ThreadWindows); 

    foreach (var proc in Process.GetProcesses()) 
    { 
     foreach (ProcessThread thread in proc.Threads) 
     { 
      Program.EnumThreadWindows((uint)thread.Id, callback, 0); 
     } 
    } 

    Console.ReadLine(); 
} 

private static bool ThreadWindows(IntPtr handle, int param) 
{   
    if (Program.IsWindowVisible(handle)) 
    { 
     var length = Program.GetWindowTextLength(handle); 
     var caption = new StringBuilder(length + 1); 
     Program.GetWindowText(handle, caption, caption.Capacity); 

     Console.WriteLine("Got a visible window: {0}", caption); 
    } 

    return true; 
} 

EnumThreadWindowsを試してみるとどういうことがありますか?あなたのコールバックはいつまでも発砲しますか?

+0

私はEnumThreadWindowsとEnumChildWindowsの両方を試しました。どちらも私のスレッドには何も返しません。 –

+0

@mikelこれが真の場合、スレッドはトップレベルのウィンドウには添付されません。 –

+0

あなたのコードによく似たコードでコールバックが実行されることはありません(上記のUpdate 2)。コールバックをインラインで追加し、単一のものを宣言して、それをすべてのEnumThreadWindows呼び出しに渡すことを試みました。 –

4

私はあなたがGetGUIThreadInfoを探していると思います。

更新:p/invokeにはいくつかの問題があります。

rectフィールドは間違っています(ここでは重要ではありません)。これを使用してください:

[StructLayout(LayoutKind.Sequential)] 
public struct Rect 
{ 
    public int Left; 
    public int Top; 
    public int Right; 
    public int Bottom; 
} 

System.Drawing.Rectangleではなくです。

他のフィールドの型宣言もオフです。それはこのようにする必要があります:

[StructLayout(LayoutKind.Sequential)] 
public struct GUITHREADINFO 
{ 
    public uint cbSize; 
    public uint flags; 
    public IntPtr hwndActive; 
    public IntPtr hwndFocus; 
    public IntPtr hwndCapture; 
    public IntPtr hwndMenuOwner; 
    public IntPtr hwndMoveSize; 
    public IntPtr hwndCaret; 
    public Rect rcCaret; 
} 

あなたの戻り値をチェックし、関数呼び出しが失敗した理由を見分けることができるように、あなたのDllImport属性にSetLastError = trueを使用するのが賢明だろう。また、構造体サイズを渡しているので、はrefで構造体を渡す必要があります。

[DllImport("user32.dll", SetLastError=true)] 
static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui); 

エラーコードはMarshal.GetLastWin32Error()を使用してください。しかし、GetGUIThreadInfoがfalseを返す場合にのみこれをチェックしてください。

上記の変更を行うと、有効なスレッドIDが与えられたときにGetGUIThreadInfoの呼び出しが機能します。 GetGUIThreadInfoが有用なものを返すためには、他のプロセスが入力フォーカスを持つ必要があることにも注意してください。

指定されたスレッドが存在しないか、入力キューがある場合、関数は失敗します。

+0

この関数の主な点は、スレッドごとに0を返すことですGUITHREADINFO構造体のhwndActiveプロパティにアクセスするとき)、私が知っているスレッド(ID 6500)の後ろの特定のスレッドであっても。だから、私はそれが正しいID(私はProcess.GetProcessById(processId)によって生成されたコレクションからこれらを取得しています。関数のドキュメントでは、GetWindowThreadProcessIdを使ってスレッドIDを取得できると言われていますが、私には必要ないウィンドウが必要です。 –

+0

したがって、次のいずれかを渡しています:http://msdn.microsoft。 com/en-us/library/system.diagnostics.processthread.id.aspxこれでうまくいくはずです。しかし、GetGUIThreadInfo.P/invokeの呼び出し方法が間違っているのがわかりません。 –

+0

ええと、P/Invokeは私が見た場所です。元の質問を更新して、私が何を持っているかを示しました。 –

1

アップデート2のコードは正常です(eraAccessProcessは実際にはprocessOfInterestであることを前提としています)。そのコードは機能します。私が見ることができ、障害のための唯一の原因は、次のとおりです。

  1. processOfInterestは、あなたが実際に興味があるプロセスではありません
  2. プロセスが本当にウィンドウに関連している何のスレッドを持っていないこと。
+0

私はそれを貼り付けたときに変数名を変更するのを忘れてしまった。ProcessThreadsViewでこのプロセスにアクセスすると、上記の5つのスレッドが表示され、スレッド6500は問題のウィンドウを所有しているように見える。だから、これは確かに私が望んでいるプロセス(foreachループ内のスレッドIDをツールを見ているものと一致させたもの)であり、ツールからの出力を与えても、ウィンドウのように表示される私はスレッドの1つが所有してほしいです。なぜこれが機能していないのか、私は混乱しています。 –

+0

私はこのコードを実行し、Notepad ++プロセス用のウィンドウを見つけました。私はそれが動作すると確信しています。私はメモ帳のプロセスなどを試してみることをお勧めします。 –

+0

なぜ私は何も見えないのですか?あなたが示唆したように、私は単にすべてのウィンドウをリストアップしようとしました、そして、私が得るのは一連の内部ウィンドウと他の一見無関係なアイテムです。 –

関連する問題