C#中如何使用SendMessage?

来源:程序开发作者:桃乃木香奈头衔:网络博主
导读:本期聚焦于小伙伴创作的《C#中如何使用SendMessage?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#中如何使用SendMessage?》有用,将其分享出去将是对创作者最好的鼓励。

SendMessage是Windows操作系统提供的核心消息传递函数,用于向指定的窗口句柄发送消息,并等待窗口处理完消息后再返回,在C#中调用该函数需要先导入对应的Windows API,再结合具体场景传递正确的参数即可完成消息发送。

C#中如何使用SendMessage?

SendMessage的基本定义

SendMessage属于User32.dll中的导出函数,其原生C++定义如下:

LRESULT SendMessage(
  HWND   hWnd,
  UINT   Msg,
  WPARAM wParam,
  LPARAM lParam
);

各个参数的含义分别为:

  • hWnd:接收消息的窗口句柄,如果为NULL则没有窗口接收消息
  • Msg:要发送的消息标识符,比如WM_SETTEXT、WM_LBUTTONDOWN等
  • wParam:消息的第一附加参数,不同消息对应的含义不同
  • lParam:消息的第二附加参数,不同消息对应的含义不同

C#中导入SendMessage API

由于C#不能直接调用Windows API,需要使用DllImport特性导入User32.dll中的SendMessage函数,同时需要定义对应的参数类型和常量,具体代码如下:

using System;
using System.Runtime.InteropServices;

public class Win32Api
{
    // 导入SendMessage函数,设置字符集为Auto适配不同系统
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    // 定义常用消息常量
    public const uint WM_SETTEXT = 0x000C;       // 设置窗口文本消息
    public const uint WM_GETTEXT = 0x000D;       // 获取窗口文本消息
    public const uint WM_LBUTTONDOWN = 0x0201;   // 鼠标左键按下消息
    public const uint WM_LBUTTONUP = 0x0202;     // 鼠标左键抬起消息
    public const uint BM_CLICK = 0x00F5;         // 按钮点击消息
}

常用使用场景示例

场景一:向记事本窗口发送文本

首先需要获取记事本编辑区域的窗口句柄,再发送WM_SETTEXT消息设置文本内容,获取窗口句柄可以使用FindWindow和FindWindowEx函数,导入代码如下:

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

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

发送文本的完整示例代码:

class Program
{
    static void Main(string[] args)
    {
        // 查找标题为"无标题 - 记事本"的窗口句柄
        IntPtr notepadHwnd = Win32Api.FindWindow("Notepad", "无标题 - 记事本");
        if (notepadHwnd != IntPtr.Zero)
        {
            // 查找记事本中的编辑控件句柄,类名是Edit
            IntPtr editHwnd = Win32Api.FindWindowEx(notepadHwnd, IntPtr.Zero, "Edit", null);
            if (editHwnd != IntPtr.Zero)
            {
                // 要发送的文本
                string text = "这是通过SendMessage发送的测试文本";
                // 分配非托管内存存储文本
                IntPtr textPtr = Marshal.StringToHGlobalUni(text);
                // 发送设置文本消息
                Win32Api.SendMessage(editHwnd, Win32Api.WM_SETTEXT, IntPtr.Zero, textPtr);
                // 释放非托管内存
                Marshal.FreeHGlobal(textPtr);
                Console.WriteLine("文本发送成功");
            }
            else
            {
                Console.WriteLine("未找到记事本编辑区域");
            }
        }
        else
        {
            Console.WriteLine("未找到记事本窗口");
        }
    }
}

场景二:模拟点击按钮

如果要模拟点击一个窗口中的按钮,只需要获取按钮的句柄,然后发送BM_CLICK消息即可,示例代码如下:

class Program
{
    static void Main(string[] args)
    {
        // 假设目标窗口标题是"测试窗口",按钮的文本是"确定"
        IntPtr targetHwnd = Win32Api.FindWindow(null, "测试窗口");
        if (targetHwnd != IntPtr.Zero)
        {
            // 查找窗口中文本为"确定"的按钮句柄,按钮类名是Button
            IntPtr buttonHwnd = Win32Api.FindWindowEx(targetHwnd, IntPtr.Zero, "Button", "确定");
            if (buttonHwnd != IntPtr.Zero)
            {
                // 发送按钮点击消息
                Win32Api.SendMessage(buttonHwnd, Win32Api.BM_CLICK, IntPtr.Zero, IntPtr.Zero);
                Console.WriteLine("按钮点击模拟成功");
            }
        }
    }
}

场景三:获取窗口文本内容

发送WM_GETTEXT消息可以获取指定窗口的文本内容,需要先发送WM_GETTEXTLENGTH消息获取文本长度,再分配足够的内存接收文本,示例代码如下:

class Program
{
    static void Main(string[] args)
    {
        IntPtr editHwnd = Win32Api.FindWindowEx(Win32Api.FindWindow("Notepad", "无标题 - 记事本"), IntPtr.Zero, "Edit", null);
        if (editHwnd != IntPtr.Zero)
        {
            // 先获取文本长度
            int textLength = (int)Win32Api.SendMessage(editHwnd, 0x000E, IntPtr.Zero, IntPtr.Zero);
            // 分配内存,多分配2个字节存放终止符
            IntPtr textBuffer = Marshal.AllocHGlobal((textLength + 1) * 2);
            // 发送获取文本消息
            Win32Api.SendMessage(editHwnd, Win32Api.WM_GETTEXT, (IntPtr)(textLength + 1), textBuffer);
            // 将非托管内存中的文本转换为C#字符串
            string content = Marshal.PtrToStringUni(textBuffer);
            // 释放内存
            Marshal.FreeHGlobal(textBuffer);
            Console.WriteLine($"获取到的文本内容:{content}");
        }
    }
}

使用注意事项

  • SendMessage是同步函数,会等待目标窗口处理完消息才返回,如果目标窗口无响应会导致调用线程阻塞,需要谨慎使用,耗时场景可以考虑PostMessage异步发送消息
  • 传递字符串等复杂参数时,需要手动分配和释放非托管内存,避免内存泄漏
  • 不同消息对应的wParam和lParam含义不同,使用前需要查阅对应的Windows消息文档,确保参数传递正确
  • 如果目标窗口是其他进程的窗口,需要确保当前进程有足够的权限访问该窗口句柄,否则会调用失败

C#SendMessageWindows_API消息传递句柄操作修改时间:2026-06-28 04:33:40

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。