c# - 获取线程的可见窗口的标题

标签 c# windows winapi user-interface pinvoke

我想知道我将如何去做这件事,因为我已经尝试了无数不同的 user32 函数并在网上进行了相当广泛的研究,但不幸的是我还没有想出一个解决方案。

有一个应用程序有 5 个线程。只要进程的 PID,就可以通过 .NET Process 类的 GetProcessById 方法轻松访问这些线程。但是,似乎没有可用于提供线程 ID 并枚举其窗口(父窗口或子窗口)的函数。其中一个线程共有 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);
    }
}

最佳答案

我相信您正在寻找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/

相关文章:

c# - 在编译代码或外部文件中嵌入大量常量

c# - 如何将字符串转换为唯一标识符?

python - select() 可以在 Windows 下使用 Python 中的文件吗?

c# - WPF 通过菜单打开

java - 哪个 native Windows 库处理文件、文件大小、创建日期? (与 JNI 一起使用)

C# 如何返回 null 或模型

c# - Datatrigger 绑定(bind)到 ControlTemplate 和 ContentPresenter 中样式 TargetType 的属性

c++ - TextOut 到设备上下文的中心

C# 检查是否按下了多个键(全局键盘 Hook )

c++ - 将 DllMain winapi .dll 导入 Visual Studio 项目 C++