编辑
2025-02-03
C# 应用
00
请注意,本文编写于 92 天前,最后修改于 92 天前,其中某些信息可能已经过时。

目录

创建 WinForms 项目
设计用户界面
用户界面布局
引入 Windows API 以获取窗口信息
P/Invoke 声明
加载进程并显示控件信息
主要代码
ListItem类

在Windows操作系统中,应用程序可以包含许多控件窗口。了解并调试这些控件对于开发人员和系统管理员来说是非常有价值的。本文将介绍如何使用C#和Windows Forms构建一个工具,可以列出正在运行的带窗口的进程,并显示其窗口控件的详细信息,包括它们的句柄、类名和文本内容。

创建 WinForms 项目

首先,我们需要在Visual Studio中创建一个新的Windows Forms项目。

  1. 打开Visual Studio。
  2. 选择“创建新项目”。
  3. 选择“Windows 窗体应用(.NET Framework)”,然后点击“下一步”。
  4. 设置项目名称、位置并选择合适的 .NET 框架版本,最后点击“创建”。

设计用户界面

在设计界面上,我们将需要以下控件:

  • 一个 ListBox 控件,用于显示进程列表。将其命名为 btnGetInfo
  • 一个 Button 按钮,用于触发获取控件信息的操作。将其命名为 buttonGetControls,并设置文本为“获取控件信息”。
  • 一个 TextBox 控件,用于显示控件的详细信息。将其命名为 txtMsg,并设置 Multiline 属性为 true

用户界面布局

image.png

引入 Windows API 以获取窗口信息

我们需要引入一些 Windows API 函数,以便获取窗口的句柄、文本和类名。

P/Invoke 声明

在代码顶部引入以下命名空间:

C#
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms;

然后,添加需要的P/Invoke声明:

C#
[DllImport("user32.dll", SetLastError = true)] static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); // Windows API declarations [DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll", SetLastError = true)] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam); [DllImport("user32.dll", SetLastError = true)] static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count); [DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr hWnd); private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr lParam);

加载进程并显示控件信息

我们需要编写代码来加载当前正在运行的进程,以及遍历每个窗体控件并获取其详细信息。

主要代码

加载进程列表:

MainForm 类中添加以下方法,用于加载带窗口的进程:

C#
private void LoadProcesses() { lstProcess.Items.Clear(); Process[] processes = Process.GetProcesses(); foreach (Process proc in processes) { if (proc.MainWindowHandle != IntPtr.Zero) { lstProcess.Items.Add(new ListItem(proc.ProcessName, proc.MainWindowHandle)); } } lstProcess.DisplayMember = "Name"; }

ListItem类

C#
public class ListItem { public string Name { get; } public IntPtr WindowHandle { get; } public ListItem(string name, IntPtr windowHandle) { Name = name; WindowHandle = windowHandle; } public override string ToString() { return Name; } }

获取并显示控件信息:

C#
private void btnGetInfo_Click(object sender, EventArgs e) { if (lstProcess.SelectedItem != null) { ListItem selectedItem = (ListItem)lstProcess.SelectedItem; IntPtr hwnd = selectedItem.WindowHandle; txtMsg.Clear(); TraverseControls(hwnd, 0); } } private void TraverseControls(IntPtr hWnd, int indentLevel) { if (IsWindowVisible(hWnd)) { StringBuilder sbText = new StringBuilder(256); StringBuilder sbClass = new StringBuilder(256); GetWindowText(hWnd, sbText, sbText.Capacity); GetClassName(hWnd, sbClass, sbClass.Capacity); string indent = new string(' ', indentLevel * 2); txtMsg.AppendText($"{indent}Handle: {hWnd}, Class: {sbClass}, Text: {sbText}\r\n"); EnumChildWindows(hWnd, (childHWnd, lParam) => { TraverseControls(childHWnd, indentLevel + 1); return true; }, IntPtr.Zero); } }

通过上述步骤,我们构建了一个功能齐全的WinForms应用程序,能够列出正在运行的带窗口的进程,并显示其窗口所有控件的详细信息。

如果您有任何问题或进一步的需求,请随时告诉我!

本文作者:rick

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!