当前位置: 首页 > ds >正文

C#基础(⑦user32.dll)

我们来详细学习如何使用 user32.dll,它是 Windows 系统中负责用户界面交互的核心 DLL,包含窗口管理、消息处理、键盘鼠标输入等功能。下面从基础到进阶,一步一步教你调用其中的常用函数。

在 C# 中调用 user32.dll 需要使用 DllImport 特性,这需要引入 System.Runtime.InteropServices 命名空间。所有示例都基于这个前提,先创建一个控制台应用程序(或 Windows 应用程序),并在代码开头添加:

using System;
using System.Runtime.InteropServices; // 必须引入,用于DllImport

第一步:调用最基础的函数 —— 显示消息框(MessageBox)

MessageBox 是 user32.dll 中最常用的函数之一,用于显示系统风格的弹窗。

步骤 1:声明函数

首先需要在 C# 中声明 user32.dll 中的 MessageBox 函数,函数定义要和 DLL 中的原生接口一致:

// 声明 user32.dll 中的 MessageBox 函数
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd,       // 父窗口句柄(null表示无父窗口)string lpText,     // 弹窗内容string lpCaption,  // 弹窗标题uint uType         // 弹窗样式(按钮、图标组合)
);

CharSet = CharSet.Unicode:确保中文等字符正常显示。
返回值 int:表示用户点击的按钮(如 1 = 确定,2 = 取消)。

步骤 2:调用函数

在 Main 方法中调用声明好的函数,测试不同样式的弹窗:

static void Main(string[] args)
{// 示例1:基础弹窗(只有"确定"按钮)int result1 = MessageBox(IntPtr.Zero,       // 无父窗口"这是一个简单的消息框", // 内容"基础示例",         // 标题0x00000000         // 样式:只有"确定"按钮(0));Console.WriteLine($"用户点击了按钮:{result1}"); // 点击"确定"会输出 1// 示例2:带"确定"和"取消"按钮 + 警告图标int result2 = MessageBox(IntPtr.Zero,"是否继续操作?","确认提示",0x00000003 | 0x00000030  // 0x3=确定+取消;0x30=警告图标(组合用 |));Console.WriteLine($"用户点击了按钮:{result2}"); // 确定=1,取消=2
}

运行效果
第一个弹窗只有 “确定” 按钮,点击后控制台输出 1。
第二个弹窗有 “确定”“取消” 按钮和警告图标,点击对应按钮会输出 1 或 2。

第二步:获取屏幕分辨率(GetSystemMetrics)

GetSystemMetrics 函数可以获取系统相关的尺寸信息,比如屏幕宽度、高度。

步骤 1:声明函数

// 声明获取系统尺寸的函数
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(int nIndex);

参数 nIndex:指定要获取的信息(比如 0 = 屏幕宽度,1 = 屏幕高度)。

步骤 2:调用函数

static void Main(string[] args)
{// 获取屏幕宽度(参数 0 表示 SM_CXSCREEN)int screenWidth = GetSystemMetrics(0);// 获取屏幕高度(参数 1 表示 SM_CYSCREEN)int screenHeight = GetSystemMetrics(1);Console.WriteLine($"屏幕分辨率:{screenWidth} × {screenHeight}");// 额外示例:获取任务栏高度(参数 29 表示 SM_CYCAPTION)int taskbarHeight = GetSystemMetrics(29);Console.WriteLine($"任务栏高度:{taskbarHeight} 像素");
}

运行效果

控制台会输出你的屏幕分辨率(如 1920 × 1080)和任务栏高度。

第三步:查找窗口并操作(FindWindow + SetWindowText)

    FindWindow:根据窗口标题或类名查找窗口句柄(类似窗口的 “身份证”)。
    SetWindowText:修改窗口的标题。

    // 查找窗口(根据类名和窗口名)
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);// 修改窗口标题
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern bool SetWindowText(IntPtr hWnd, string lpString);

    步骤 2:调用函数(实战:修改记事本窗口标题)
    先手动打开一个记事本(Notepad),标题默认为 “无标题 - 记事本”。
    运行以下代码:

    static void Main(string[] args)
    {// 查找记事本窗口(类名"Notepad",标题"无标题 - 记事本")IntPtr notepadWnd = FindWindow("Notepad", "无标题 - 记事本");if (notepadWnd != IntPtr.Zero){// 找到窗口后,修改标题bool success = SetWindowText(notepadWnd, "被C#修改过的标题 - 记事本");if (success){Console.WriteLine("记事本标题修改成功!");}else{Console.WriteLine("标题修改失败");}}else{Console.WriteLine("未找到记事本窗口,请先打开记事本");}
    }

    运行效果

    如果记事本已打开且标题正确,它的标题会被改为 “被 C# 修改过的标题 - 记事本”。

    四、移动鼠标:SetCursorPos 函数

    SetCursorPos 可以直接设置鼠标指针在屏幕上的位置,非常直观。

    步骤 1:声明函数

    using System;
    using System.Runtime.InteropServices;class User32Demo
    {// 声明 SetCursorPos 函数:设置鼠标位置[DllImport("user32.dll")]public static extern extern bool SetCursorPos(int X, int Y);// 参数:X(水平坐标)、Y(垂直坐标),返回值:是否成功
    }

    步骤 2:使用函数移动鼠标

    static void Main(string[] args)
    {// 1. 移动鼠标到屏幕左上角(0, 0)bool success1 = SetCursorPos(0, 0);Console.WriteLine($"移动到左上角:{ (success1 ? "成功" : "失败") }");// 等待1秒,让你看清效果System.Threading.Thread.Sleep(1000);// 2. 移动鼠标到屏幕中心(假设屏幕分辨率是1920×1080)int screenWidth = 1920;  // 可通过前面学的 GetSystemMetrics(0) 获取实际宽度int screenHeight = 1080; // 可通过 GetSystemMetrics(1) 获取实际高度bool success2 = SetCursorPos(screenWidth / 2, screenHeight / 2);Console.WriteLine($"移动到中心:{ (success2 ? "成功" : "失败") }");// 等待1秒System.Threading.Thread.Sleep(1000);// 3. 移动鼠标到右下角bool success3 = SetCursorPos(screenWidth - 10, screenHeight - 10);Console.WriteLine($"移动到右下角:{ (success3 ? "成功" : "失败") }");
    }

    运行效果

    鼠标会依次移动到屏幕左上角 → 中心 → 右下角,每次移动后会在控制台显示结果。

    五、发送窗口消息:SendMessage 函数

    SendMessage 是 user32.dll 中非常强大的函数,它可以向指定窗口发送各种消息(如点击按钮、输入文本、关闭窗口等),实现对窗口的精细控制。

    先理解:什么是 “窗口消息”?
    Windows 系统中,所有窗口交互都是通过 “消息” 机制实现的。例如:

    点击按钮 → 窗口收到 WM_LBUTTONDOWN(左键按下)消息
    键盘输入 → 窗口收到 WM_CHAR(字符输入)消息
    窗口关闭 → 窗口收到 WM_CLOSE 消息

    SendMessage 就是手动给窗口发送这些消息,模拟用户操作。

    步骤 1:声明函数和常用消息常量

    class User32Demo
    {// 声明 SendMessage 函数:发送消息到窗口[DllImport("user32.dll", CharSet = CharSet.Unicode)]public static extern IntPtr SendMessage(IntPtr hWnd,    // 目标窗口句柄(通过 FindWindow 获取)uint Msg,       // 消息类型(如 WM_CLOSE 表示关闭窗口)IntPtr wParam,  // 消息参数1(根据消息类型变化)string lParam   // 消息参数2(字符串类型,如输入的文本));// 常用消息常量(可在微软文档中查询更多)public const uint WM_CLOSE = 0x0002;         // 关闭窗口消息public const uint WM_SETTEXT = 0x000C;       // 设置窗口文本(如输入框内容)public const uint WM_LBUTTONDOWN = 0x0201;   // 鼠标左键按下public const uint WM_LBUTTONUP = 0x0202;     // 鼠标左键释放(模拟点击)
    }

    步骤 2:实战 1:关闭指定窗口(发送 WM_CLOSE 消息)

    以关闭记事本为例:

    static void Main(string[] args)
    {// 1. 先找到记事本窗口(确保已打开,标题为"无标题 - 记事本")IntPtr notepadWnd = FindWindow("Notepad", "无标题 - 记事本");if (notepadWnd == IntPtr.Zero){Console.WriteLine("未找到记事本窗口");return;}// 2. 发送关闭窗口消息(WM_CLOSE)SendMessage(notepadWnd, User32Demo.WM_CLOSE, IntPtr.Zero, null);Console.WriteLine("已发送关闭消息,记事本应该会关闭");
    }// 注意:需要先声明前面学过的 FindWindow 函数
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    运行效果

    如果记事本已打开,会收到关闭消息并弹出保存提示(和手动点击关闭按钮效果一致)。

    步骤 3:实战 2:向记事本输入文本(发送 WM_SETTEXT 消息)

    记事本的编辑区域是一个子窗口(类名 "Edit"),需要先找到它的句柄,再发送输入消息:

    static void Main(string[] args)
    {// 1. 找到记事本主窗口IntPtr notepadWnd = FindWindow("Notepad", null); // 忽略标题,找所有记事本if (notepadWnd == IntPtr.Zero){Console.WriteLine("请先打开一个记事本");return;}// 2. 找到记事本的编辑区域子窗口(类名"Edit",无标题)IntPtr editWnd = FindWindowEx(notepadWnd, IntPtr.Zero, "Edit", null);if (editWnd == IntPtr.Zero){Console.WriteLine("未找到编辑区域");return;}// 3. 发送输入文本消息(WM_SETTEXT)SendMessage(editWnd, User32Demo.WM_SETTEXT, IntPtr.Zero, "这是通过 SendMessage 输入的文本!");Console.WriteLine("已向记事本输入文本");
    }// 额外声明 FindWindowEx 函数(用于查找子窗口)
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindowEx(IntPtr hWndParent,  // 父窗口句柄IntPtr hWndChildAfter, // 起始子窗口(null表示从第一个开始)string lpClassName, // 子窗口类名string lpWindowName // 子窗口标题
    );

    运行效果

    记事本的编辑区域会自动填入文本 “这是通过 SendMessage 输入的文本!”。

    http://www.xdnf.cn/news/19818.html

    相关文章:

  • 各省市信息化项目管理办法中的网络安全等级保护如何规定的?
  • 前缀树约束大语言模型解码
  • 05 Centos 7尝试是否有网络
  • 深入浅出 RabbitMQ-RabbitMQ消息确认机制(ACK)
  • 解锁WebRTC在数字人领域的无限潜能
  • 【音视频】火山引擎实时、低延时拥塞控制算法的优化实践
  • centos系统如何判断是是x86还是x64?
  • ansible变量+管理机密
  • AV1 HEADERS详解
  • 专为 SOC 分析师和 MSSP 设计的威胁搜寻指南
  • flink中的窗口的介绍
  • mysql5.6+分页时使用 limit+order by 会出现数据重复问题
  • Mysql杂志(七)
  • Shell脚本入门:从零到精通
  • C# 原型模式(C#中的克隆)
  • “转”若惊鸿,电磁“通”——耐达讯自动化RS485转Profinet点亮能源新章
  • 【NestJS】HTTP 接口传参的 5 种方式(含前端调用与后端接收)
  • 【卷积神经网络】卷积神经网络的三大核心优势:稀疏交互、参数共享与等变表示
  • C++之基于正倒排索引的Boost搜索引擎项目介绍
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘black’问题
  • 【提示词】...(后续单元)在Prompt 的作用
  • 【linux仓库】万物至简的设计典范:如何用‘文件’这一个概念操纵整个Linux世界?
  • 在Docker中安装MySQL时3306端口占用问题
  • 论文学习30:LViT: Language Meets Vision Transformerin Medical Image Segmentation
  • 使用云手机进行游戏搬砖划算吗?
  • 国内真实的交换机、路由器和分组情况
  • 【保姆级喂饭教程】把chrome谷歌浏览器中的插件导出为CRX安装包
  • LeetCode 925.长按键入
  • 数据结构:希尔排序 (Shell Sort)
  • 【51单片机】【protues仿真】基于51单片机呼叫系统