WPF学习(8) --Windows API函数的使用

一、API函数的介绍

1.FindWindow函数

cs 复制代码
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  • 功能: FindWindow函数用于根据窗口的类名和窗口名称查找窗口的句柄(IntPtr类型)。这个句柄是一个唯一标识窗口的值,用于后续的窗口操作
  • 参数:lpClassName: 窗口类名,可以为null,表示忽略类名。lpWindowName: 窗口名称,也可以为null,表示忽略窗口名称
  • 返回值: 返回找到的窗口句柄。如果没有找到,则返回IntPtr.Zero

2.GetDlgItem函数

cs 复制代码
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDlgItem(IntPtr hWnd, int nIDDlgItem);
  • 功能: GetDlgItem函数用于从指定的对话框或窗口中获取子窗口(通常是控件)的句柄
  • 参数:hWnd: 父窗口或对话框的句柄。nIDDlgItem: 子窗口的控件ID
  • 返回值: 返回子窗口的句柄。如果没有找到,则返回IntPtr.Zero

3.SendMessage函数

cs 复制代码
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);
  • 功能: SendMessage函数用于向指定的窗口发送消息,并等待该消息被处理。它可以用来设置控件的文本、模拟用户输入等
  • 参数:hWnd: 目标窗口的句柄。Msg: 要发送的消息的类型。wParam: 消息的附加参数,通常用于传递小整数值。lParam: 消息的附加参数,这里使用字符串lParam来传递文本
  • 返回值: 返回消息的处理结果,具体值取决于发送的消息类型

4.PostMessage函数

cs 复制代码
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
  • 功能: PostMessage函数也用于向指定窗口发送消息,但它不会等待消息处理完成。消息会被放入消息队列,处理由系统安排
  • 参数:hWnd: 目标窗口的句柄。Msg: 要发送的消息的类型。wParam 和 lParam: 附加参数,用于传递消息的数据
  • 返回值: 返回true表示消息已成功投递,false表示失败

5.SetForegroundWindow函数

cs 复制代码
 [DllImport("user32.dll", SetLastError = true)]
 private static extern bool SetForegroundWindow(IntPtr hWnd);
  • 功能: SetForegroundWindow函数将指定窗口带到前台,并给予它输入焦点。用户能够看到该窗口位于最前面
  • 参数:hWnd: 目标窗口的句柄
  • 返回值: 返回true表示消息已成功投递,false表示失败

6.ShowWindow函数

cs 复制代码
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  • 功能: ShowWindow函数用于设置窗口的显示状态,例如最小化、最大化、隐藏或显示窗口
  • 参数:hWnd: 目标窗口的句柄。nCmdShow: 指定如何显示窗口的整数值,例如:1: 正常显示窗口。2: 最小化窗口。3: 最大化窗口
  • 返回值: 返回true表示窗口状态更改成功,false表示失败

7.SetWindowPos函数

cs 复制代码
 [DllImport("user32.dll", SetLastError = true)]
 private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
  • 功能: SetWindowPos函数用于设置窗口的位置和大小
  • 参数: hWnd: 目标窗口的句柄。
    hWndInsertAfter: 用于定义窗口的Z序(即窗口的前后顺序),例如:
    IntPtr.Zero:窗口放在Z序的顶部。
    new IntPtr(-1):窗口放在Z序的底部。
    X 和 Y: 窗口的新位置(左上角的坐标)。
    cx 和 cy: 窗口的新宽度和高度。
    uFlags: 一些标志,用于控制窗口位置和大小的设置方式。例如:
    0x0001:忽略X和Y参数,只调整窗口大小。
    0x0002:忽略cx和cy参数,只调整窗口位置。
  • 返回值: 返回true表示成功,false表示失败

二、APP进程运行的方法

cs 复制代码
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

 public static bool Run(string processPath, string processName, string arguments) //APP进程运行的方法
 {
     IntPtr hwdLogin = IntPtr.Zero;
     hwdLogin = FindWindow(null, processName);

     if (hwdLogin == 0) // 返回的数组长度为0,表示该进程不存在
     {
         try // 如果进程不存在,则启动它
         {
             ProcessStartInfo startInfo = new ProcessStartInfo
             {
                 FileName = processPath,
                 Arguments = arguments,
                 UseShellExecute = false,  // 使用 false 以便不使用系统外壳来启动进程
             };

             Process process = Process.Start(startInfo);
             return true;
         }
         catch (Exception ex)
         { 
             return false;
         }
     }
     else
     {
         return true;
     }
 }

三、Windows消息 (Windows Messages)

Windows消息是用于在应用程序和操作系统之间传递信息的机制。每个消息都有一个唯一的整数值(通常表示为十六进制),这个值告诉操作系统或应用程序要执行什么操作。

1. 常见的Windows消息

  • WM_SETTEXT (0x000C):

    • 用途:设置窗口或控件的文本内容。
    • 例如,用于设置文本框中的内容。
  • WM_COMMAND (0x0111):

    • 用途:用于通知窗口某个控件的事件(如按钮点击)。
    • 例如,当一个按钮被点击时,会发送这个消息。
  • WM_CLOSE (0x0010):

    • 用途:请求关闭窗口。
    • 例如,应用程序接收到这个消息时,会尝试关闭自己。
  • WM_PAINT (0x000F):

    • 用途:要求窗口重绘自己。
    • 当窗口需要更新其显示内容时,系统会发送这个消息

四、代码使用实例

cs 复制代码
 /*功能: FindWindow函数用于根据窗口的类名和窗口名称查找窗口的句柄(IntPtr类型)。这个句柄是一个唯一标识窗口的值,用于后续的窗口操作;
参数:lpClassName: 窗口类名,可以为null,表示忽略类名。lpWindowName: 窗口名称,也可以为null,表示忽略窗口名称
返回值: 返回找到的窗口句柄。如果没有找到,则返回IntPtr.Zero*/
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

 /*功能: GetDlgItem函数用于从指定的对话框或窗口中获取子窗口(通常是控件)的句柄
 参数:hWnd: 父窗口或对话框的句柄。nIDDlgItem: 子窗口的控件ID
 返回值: 返回子窗口的句柄。如果没有找到,则返回IntPtr.Zero*/
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr GetDlgItem(IntPtr hWnd, int nIDDlgItem);

 /*功能: SendMessage函数用于向指定的窗口发送消息,并等待该消息被处理。它可以用来设置控件的文本、模拟用户输入等
  参数:hWnd: 目标窗口的句柄。Msg: 要发送的消息的类型。wParam: 消息的附加参数,通常用于传递小整数值。lParam: 消息的附加参数,这里使用字符串lParam来传递文本
 返回值: 返回消息的处理结果,具体值取决于发送的消息类型*/
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);

 /*功能: PostMessage函数也用于向指定窗口发送消息,但它不会等待消息处理完成。消息会被放入消息队列,处理由系统安排
  参数:hWnd: 目标窗口的句柄。Msg: 要发送的消息的类型。wParam 和 lParam: 附加参数,用于传递消息的数据
  返回值: 返回true表示消息已成功投递,false表示失败*/
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

 /*功能: SetForegroundWindow函数将指定窗口带到前台,并给予它输入焦点。用户能够看到该窗口位于最前面。
  参数:hWnd: 目标窗口的句柄。
  返回值: 返回true表示成功,false表示失败*/
 [DllImport("user32.dll", SetLastError = true)]
 private static extern bool SetForegroundWindow(IntPtr hWnd);

 /* 功能: ShowWindow函数用于设置窗口的显示状态,例如最小化、最大化、隐藏或显示窗口。
  参数:hWnd: 目标窗口的句柄。nCmdShow: 指定如何显示窗口的整数值,例如:1: 正常显示窗口。2: 最小化窗口。3: 最大化窗口。
  返回值: 返回true表示窗口状态更改成功,false表示失败*/
 [DllImport("user32.dll")]
 private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

 /* 功能: SetWindowPos函数用于设置窗口的位置和大小。
   参数: hWnd: 目标窗口的句柄。
   hWndInsertAfter: 用于定义窗口的Z序(即窗口的前后顺序),例如:
   IntPtr.Zero:窗口放在Z序的顶部。
   new IntPtr(-1):窗口放在Z序的底部。
   X 和 Y: 窗口的新位置(左上角的坐标)。
   cx 和 cy: 窗口的新宽度和高度。
   uFlags: 一些标志,用于控制窗口位置和大小的设置方式。例如:
   0x0001:忽略X和Y参数,只调整窗口大小。
   0x0002:忽略cx和cy参数,只调整窗口位置。
   返回值: 返回true表示成功,false表示失败*/
 [DllImport("user32.dll", SetLastError = true)]
 private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

 public string ipport;
 private bool isRadmin调取中 = false;

 /* WM_SETTEXT: 常量0x000C,表示一个Windows消息,用于设置窗口或控件的文本内容。通常与SendMessage一起使用
 WM_COMMAND: 常量0x0111,表示一个命令消息,通常用于菜单项选择、按钮点击等操作*/
 private const uint WM_SETTEXT = 0x000C; // 用于设置文本消息
 private const uint WM_COMMAND = 0x0111; // 用于发送命令消息的消息

 public void OpenRadmin()
 {
     if (iPEndPoint!= null) //判断iPEndPoint是否为空
     {
         ipport = iPEndPoint.ToString(); //将其转换为ipport字符串
         var parts = ipport.Split(':'); //将ipport字符串拆分为两部分

         if (parts.Length == 2) //如果拆分结果是两个部分(即符合"IP:Port"格式)
         {
             string ip = parts[0]; //将第一部分作为要打开窗口的IP地址
             string 监控窗口标题 = $"{ip} - 完全控制"; //$"{ip} - 完全控制"是Radmin Viewer中使用的窗口标题格式
             string 参数 = $"/connect:{ip}:{4899}/fullstretch/encrypt"; ///connect:{ip}:{4899}/fullstretch/encrypt"是传递给Radmin的命令行参数,指定要连接的IP和端口,以及其他选项

             IntPtr radminWindow = FindWindow(null, 监控窗口标题); //FindWindow函数查找是否有需要打开的监控窗口,如果没有则返回值为空

             if (radminWindow != IntPtr.Zero) //如果不为空
             {                   
                 ShowWindow(radminWindow, 1); // Radmin 窗口已存在,将窗口从最小化或后台状态恢复到前台
                 SetForegroundWindow(radminWindow); //将其设置为当前的活动窗口

                 int left = 2200; // 窗口左边距
                 int top = 15; // 窗口上边距
                 int width = 800; // 窗口宽度
                 int height = 600; // 窗口高度
                 SetWindowPos(radminWindow, IntPtr.Zero, left, top, width, height, 0); //调整窗口的位置和大小,以确保窗口在屏幕上的正确位置显示
                 return;
             }
             if (isRadmin调取中 == false) //判断Radmin是否启动
             {                       
                 Cls外部进程.Run("C:\\Program Files (x86)\\Radmin Viewer 3\\Radmin.exe", 监控窗口标题, 参数); // 启动 Radmin Viewer 程序,并传递 IP 和连接参数
                 isRadmin调取中 = true;
             } 
             
             string 登录窗口标题 = "Radmin 安全性: " + ip; // 设置窗口标题,用于查找 Radmin Viewer 的安全性登录窗口
       
             IntPtr hwdLogin = WaitForWindow(登录窗口标题, 4000); // 等待 Radmin 登录窗口出现,最长等待 4 秒

             if (hwdLogin == IntPtr.Zero) //如果返回值为空,则没找到这个登录窗口
             {
                 Console.WriteLine("未找到指定的窗口.");
             }
             else
             {                 
                 IntPtr hwdUser = GetDlgItem(hwdLogin, 0x7FF); // 查找用户名输入框控件句柄,0x7FF 可能是用户名输入框的ID,而 0x800 是密码输入框的ID
                 IntPtr hwdPass = GetDlgItem(hwdLogin, 0x800); // 查找密码输入框的控件句柄

                 string user = "THGK";
                 string password = "000000";

                 // 发送用户名和密码到输入框
                 SendMessage(hwdUser, WM_SETTEXT, IntPtr.Zero, user);
                 SendMessage(hwdPass, WM_SETTEXT, IntPtr.Zero, password);

                 // 模拟点击登录按钮
                 PostMessage(hwdLogin, WM_COMMAND, (IntPtr)0x78, IntPtr.Zero);
             }
             isRadmin调取中 = false;
         }
         else
         {
             throw new ArgumentException("ipport 参数格式不正确,应包含 IP 和端口,格式为 'IP:Port'");
         }
     }
 }

 private IntPtr WaitForWindow(string windowTitle, int timeout) //这个方法用于在指定的超时时间内,轮询查找某个窗口是否存在
 {
     IntPtr hwdLogin = IntPtr.Zero;
     int elapsed = 0;
     int interval = 100; // 检查间隔时间为 100 毫秒

     while (elapsed < timeout)
     {
         hwdLogin = FindWindow(null, windowTitle); //通过FindWindow函数查找具有指定标题(windowTitle)的窗口
         if (hwdLogin != IntPtr.Zero)
         {
             return hwdLogin; // 找到窗口,返回句柄
         }
         Thread.Sleep(interval); //轮询间隔为100毫秒,如果在该间隔内没有找到窗口,就休眠100毫秒
         elapsed += interval; //时间累计
     }
     return IntPtr.Zero; // 超过超时时间未找到窗口
 }
相关推荐
Scout-leaf2 天前
WPF新手村教程(三)—— 路由事件
c#·wpf
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode