我想知道我将如何去做这件事,因为我已经尝试了无数不同的 user32 函数并在网上进行了相当广泛的研究,但不幸的是我还没有想出一个解决方案。
有一个应用程序有 5 个线程。只要进程的 PID,就可以通过 .NET Process 类的 GetProcessById 方法轻松访问这些线程。但是,似乎没有可用于提供线程 ID 并枚举其窗口(父窗口或子窗口)的函数。其中一个线程共有 10 个窗口,其中 9 个隐藏,1 个可见。该可见线程的标题是我试图以编程方式获得的。
我最近的方法是获取进程句柄,将其放入 EnumChildWindows,并尝试以这种方式将每个窗口句柄添加到一个集合中,但我的集合始终是空的。
这是我在 ProcessThreadsView 工具中看到的屏幕截图:
有什么我想念的吗?我给该工具的作者发了电子邮件,想看看他是怎么做的,但我想我会请大家看看是否有既定的方法。
更新:我试过使用 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);
}
}
最佳答案
我相信您正在寻找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
返回任何有用信息。
If the specified thread does not exist or have an input queue, the function will fail.
关于c# - 获取线程的可见窗口的标题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9318058/