Delphi实现获取句柄并发送消息的方法
在Delphi中,利用FindWindow查找主窗口、FindWindowEx查找子控件句柄,通过SendMessage或PostMessage发送WM_SETTEXT、WM_CLICK、WM_CLOSE、WM_GETTEXT等消息实现跨进程设置文本、模拟点击、关闭及获取文本操作;keybd_event可模拟组合键如Ctrl+C、Ctrl+V等。该技术是Wi
在Windows开发中,通过句柄跨进程操作窗口是常见的需求,Delphi 在这块提供了非常直接的 API 支持。说实话,这类技术看起来门槛高,但把核心的几招搞清楚后,用起来其实挺顺手。下面直接上干货——从获取句柄到发送消息,一步不落。

先拿下窗口句柄
最基础的操作就是通过窗口标题找到顶层窗体的句柄:
handle := FindWindow(nil,PChar('窗口的标题'));//查到窗体句柄
如果目标窗口里有子控件,比如一个 Edit 框,那就需要用 FindWindowEx 沿着父子关系往下找:
childHandle := FindWindowEx(handle,0,'子窗体类','子窗体标题');
想要一次性把所有子窗口都翻个底朝天?可以用 EnumChildWindows 这个枚举函数,不过得自己写一个回调函数:
EnumChildWindows(主创体句柄,@回调函数,用户参数);
回调函数的典型写法长这样:
function EnumChildProc(ahWND:HWND; param:LPARAM):boolean; stdcall; sendmessage(handle,message,wl,rl)
拿到句柄后,怎么发消息?
SendMessage 是主角。它会把一条消息直接塞进目标窗口的消息队列,而且会等对方处理完才返回。四个参数分别是:目标句柄、消息常量、wParam、lParam。下面这段完整示例展示了如何给记事本的编辑框里塞文本:
unit Unit1;
interface
uses Windows,Messages,Tlhelp32,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls;
type
TForm1=class(TForm)
procedure FormCreate(Sender: TObject);
private
{
Private declarations
}
public
{
Public declarations
}
end;
var Form1: TForm1;
implementation
{
$R *.DFM
}
procedure TForm1.FormCreate(Sender: TObject);
var a,b:PAnsiChar;
h:HWND;
begin
h:= FindWindow(nil,'abc.txt - 记事本');
h:= FindWindowEx(h,0,'edit',nil);
SendMessage(h,WM_SETTEXT,255,Integer(PChar('我来测度了')));
ShowMessage( IntToStr(h));
end;
实际项目中经常用到的几个 SendMessage 场景:
SendMessage(TreeView.Handle,TVM_SETBKCOLOR,0,RGB(255,0,0)); 设置TV背景颜色
SendMessage(Button.Handle,WM_LBUTTONDOWN,0,0); 鼠标左键按下
SendMessage(Button.Handle,WM_LBUTTONUP,0,0); 鼠标左键抬起
SendMessage(Edit.Handle,WM_SETTEXT,255,Integer(PChar('abc'))); 传递文本
SendMessage(Edit.Handle,WM_Char,Wparam('Q'),2); 传递字符
SendMessage(Button.Handle,BM_SETSTYLE,BS_RADIOBUTTON,1); 改变Button风格
SendMessage(ComboBox.Handle,CB_SETDropPEDWIDTH,300,0); 改变CBDownWidth
另外,WM_CUT、WM_COPY、WM_PASTE 这三兄弟专门负责剪切、复制、粘贴,操作剪贴板时很实用。
模拟组合键——keybd_event 的玩法
有些操作没法直接发消息,比如 Ctrl+V,那就得靠键盘模拟:
keybd_event(VK_Control, MapVirtualKey(VK_Control, 0), 0, 0);
keybd_event(ord('V'), MapVirtualKey(ord('V'), 0), 0, 0);
keybd_event(ord('V'), MapVirtualKey(ord('V'), 0), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control, MapVirtualKey(VK_Control, 0), KEYEVENTF_KEYUP, 0);
注意顺序:先按下 Ctrl,再按 V,然后松开 V,最后松开 Ctrl。这套流程在自动化测试或远程控制中经常用到。
常用 wMsg 消息速查表
写代码时最烦的就是记不住那些消息常量。下面把常用的整理出来,方便直接复制粘贴:
- WM_Create —— 创建一个窗口
- WM_DESTROY —— 窗口被销毁时发送
- WM_MOVE —— 移动一个窗口
- WM_SIZE —— 改变窗口大小
- WM_ACTIVATE —— 窗口激活或失去激活
- WM_SETFOCUS —— 窗口获得焦点
- WM_KILLFOCUS —— 窗口失去焦点
- WM_ENABLE —— 窗口启用/禁用状态改变
- WM_SETREDRAW —— 设置窗口能否重画
- WM_SETTEXT —— 设置窗口文本
- WM_GETTEXT —— 获取窗口文本
- WM_GETTEXTLENGTH —— 获取文本长度
- WM_PAINT —— 要求窗口重画
- WM_CLOSE —— 关闭窗口或应用程序
- WM_QUERYENDSESSION —— 用户选择结束会话
- WM_QUIT —— 结束程序运行
- WM_QUERYOPEN —— 恢复窗口大小位置时发送
- WM_ERASEBKGND —— 擦除窗口背景
- WM_SYSCOLORCHANGE —— 系统颜色改变
- WM_SHOWWINDOW —— 隐藏或显示窗口
- WM_ACTIVATEAPP —— 哪个窗口被激活
- WM_FONTCHANGE —— 系统字体资源变化
- WM_TIMECHANGE —— 系统时间变化
- WM_CANCELMODE —— 取消当前模态操作
- WM_SETCURSOR —— 鼠标光标移动
- WM_ENDSESSION —— 系统进程退出
- WM_MOUSEACTIVATE —— 非激活窗口上按鼠标
- WM_CHILDACTIVATE —— 点击 MDI 子窗口标题栏
- WM_QUEUESYNC —— 训练程序的消息同步
- WM_GETMINMAXINFO —— 窗口将要改变大小或位置
- WM_PAINTICON —— 重画最小化窗口图标
- WM_ICONERASEBKGND —— 画图标前擦除背景
- WM_NEXTDLGCTL —— 对话框更改焦点
- WM_SPOOLERSTATUS —— 打印队列变化
- WM_DRAWITEM —— 控件可视外观改变
- WM_MEASUREITEM —— 控件被创建时
- WM_VKEYTOITEM —— 列表框响应键盘消息
- WM_CHARTOITEM —— 列表框响应字符消息
- WM_SETFONT —— 设置控件字体颜色
- WM_GETFONT —— 获取当前字体
- WM_SETHOTKEY —— 关联热键
- WM_GETHOTKEY —— 判断热键关联
- WM_QUERYDRAGICON —— 拖放最小化窗口时获取图标句柄
- WM_COMPAREITEM —— 比较组合框或列表框项位置
- WM_COMPACTING —— 内存不足
- WM_WINDOWPOSCHANGING —— 窗口位置大小即将改变
- WM_WINDOWPOSCHANGED —— 窗口位置大小已改变
- WM_POWER —— 系统进入暂停状态
- WM_COPYDATA —— 跨进程传递数据
- WM_CANCELJOURNAL —— 取消日志激活
- WM_NOTIFY —— 子控件事件通知父窗口
- WM_INPUTLANGCHANGEREQUEST —— 输入语言选择
- WM_INPUTLANGCHANGE —— 输入语言已改变
- WM_TCARD —— Windows 帮助例程初始化
- WM_HELP —— 按下 F1 键
- WM_USERCHANGED —— 用户登录或退出
- WM_NOTIFYFORMAT —— 判断控件使用 ANSI 或 UNICODE
一个完整的枚举子窗口示例
最后给一个实战代码片段,它枚举指定窗口下的所有子控件,找到第一个类名为 'Edit' 的控件并把它的文本取出来:
function EnumChildWindowsProc(hwnd, lparam: Integer): Boolean;
var
buffer: array[0..255] of char;
begin
Result := True;
GetClassName(hwnd,buffer,256);
if StrPas(Buffer)='Edit' then
begin
SendMessage(hwnd,WM_GETTEXT,256,lparam);
Result:=False;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
hwnd: Integer;
buffer: array[0..255] of char;
Begin
hwnd := FindWindow('CabinetWClass',nil);
if hwnd<> 0 then
begin
EnumChildWindows(hwnd,@EnumChildWindowsProc,Longint(@buffer[0]));
Caption := StrPas(buffer);
end;
end;
这段代码的精髓在于回调函数里一旦找到目标控件就返回 False 停止枚举,效率不错。拿到文本后直接往 Caption 里一塞,效果立现。
以上内容覆盖了从句柄获取到消息发送的常见套路,代码可以直接拿去用。搞 Windows 自动化或者桌面辅助工具,这几招基本够用。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















