2012-02-16 3 views
1

무수히 많은 다른 user32 함수를 시도하고 상당히 광범위하게 온라인을 조사했지만이 작업을 수행하는 방법에 대해 궁금합니다. 그러나 불행히도 나는이 문제를 해결할 수 없었습니다. 해결책은 아직 없습니다.스레드의 보이는 창 제목 얻기

5 개의 스레드가있는 응용 프로그램이 있습니다. 이러한 스레드는 .NET 프로세스 클래스 인 GetProcessById 메서드를 통해 쉽게 액세스 할 수 있으며 프로세스의 PID를 제공합니다. 그러나 스레드 ID를 제공하고 창 (부모 또는 자식)을 열거하는 데 사용할 수있는 함수가없는 것으로 나타났습니다. 이 스레드 중 하나에는 총 10 개의 창 (9 개는 숨김)이 표시됩니다. 보이는 스레드의 제목은 프로그래밍 방식으로 얻으려는 것입니다.

최근의 접근 방식은 프로세스 핸들을 가져 와서 EnumChildWindows를 통해 처리하고 각 창 핸들을 컬렉션에 추가하는 방법입니다.하지만 컬렉션은 항상 비어 있습니다.

enter image description here

거기에 뭔가 내가 놓친 거지 :

는 여기가 ProcessThreadsView 도구에 표시되는 내용의 스크린 샷입니까? 나는 그가 어떻게하고 있는지보기 위해 도구의 저자에게 전자 메일을 보냈지 만, 나는 당신에게 설치 방법이 있는지를 물어볼 것이라고 생각했다.

업데이트 :

[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를 사용

, 이것은 내가있어 무엇 : 나는이 내가 그것을 호출하고 어떻게, GetGUIThreadInfo를 사용하여 시도했다

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

콜백은 귀하의 코드와 매우 비슷한 코드로 실행되지 않습니다 (위의 업데이트 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을 반환한다는 것입니다. GUIDREADINFO 구조체의 hwndActive 속성에 액세스 할 때), 내가 알고있는 스레드에 대해서도 (ID 6500) 내가 지정한 특정 스레드에 대해서조차도 마찬가지입니다. 따라서 ID를 제공 할 때 ID가 맞는지 궁금합니다. (Process.GetProcessById (processId)에 의해 생성 된 컬렉션에서 이러한 ID를 얻습니다 .Threads). 함수에 대한 문서에서는 GetWindowThreadProcessId를 사용하여 스레드 ID를 얻을 수 있다고 말합니다. 그러나이 스레드에 대한 창이 필요합니다. –

+0

그래서 다음 중 하나를 전달합니다. http://msdn.microsoft. com/ko-kor/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를 도구를 통해 볼 수있는 것과 일치시켰다)라고 말하면서 도구의 출력이 주어진다는 것을 말하면 꽤 안전하다고 생각합니다. 마치 창 나는 스레드 중 하나가 소유하고 싶습니다. 왜 이것이 작동하지 않는지에 관해서는 혼란 스럽습니다. –

+0

이 코드를 실행하여 Notepad ++ 프로세스 용 창을 성공적으로 발견했습니다. 나는 그것이 효과가있을 것이라고 확신한다. 메모장 프로세스 나 그런 식으로 시도해 보시기 바랍니다. –

+0

내가 왜 아무 것도 볼 수없는 이유에 대한 아이디어가 있습니까? 나는 제안한대로 모든 창을 나열하는 일을 시도했다. 일련의 내부 창과 다른 겉으로는 무의미한 항목들이있다. –