Windows下Delphi程序终止后保留提示及记事本交互问题
问题:Delphi程序退出后通过记事本显示提示消息的实现问题
需求背景
在Windows 11 Pro环境下,使用Delphi 11.3-12.1开发程序,要求程序终止后仍显示提示消息(如“未移除USB驱动器”)。程序会在30秒无操作后自动执行USB断开并退出,担忧托盘提示无法被操作员注意到,因此选择通过记事本展示消息。
现有尝试代码
主逻辑代码
ExecuteProcess('Notepad.EXE','','', false, false, false, I); Notepad := FindWindow('Notepad', nil); if Bool(Notepad) then begin NoteEdit := FindWindowEx(Notepad, 0, 'Edit', nil); if Bool(NoteEdit) then begin S:='Ciao' + #13 + 'Questa e'' una prova ....'; SendMessage(NoteEdit, WM_SETTEXT, 0, Longint(S)); end;
变量定义
Notepad: HWND; NoteEdit: HWND;
ExecuteProcess函数实现
function ExecuteProcess(const FileName, Params: string; Folder: string; WaitUntilTerminated, WaitUntilIdle, RunMinimized: boolean; var ErrorCode: integer): boolean; var CmdLine: string; WorkingDirP: PChar; StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; begin Result := true; CmdLine := '"' + FileName + '" ' + Params; if Folder = '' then Folder := ExcludeTrailingPathDelimiter(ExtractFilePath(FileName)); ZeroMemory(@StartupInfo, SizeOf(StartupInfo)); StartupInfo.cb := SizeOf(StartupInfo); if RunMinimized then begin StartupInfo.dwFlags := STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_SHOWMINIMIZED; end; if Folder <> '' then WorkingDirP := PChar(Folder) else WorkingDirP := nil; if not CreateProcess(nil, PChar(CmdLine), nil, nil, false, 0, nil, WorkingDirP, StartupInfo, ProcessInfo) then begin Result := false; ErrorCode := GetLastError; exit; end; with ProcessInfo do begin CloseHandle(hThread); if WaitUntilIdle then WaitForInputIdle(hProcess, INFINITE); if WaitUntilTerminated then repeat Application.ProcessMessages; until MsgWaitForMultipleObjects(1, hProcess, false, INFINITE, QS_ALLINPUT) <> WAIT_OBJECT_0 + 1; CloseHandle(hProcess); end; end;
遇到的问题
- 记事本已打开时,无法新建标签页展示消息
- 记事本未打开时,虽能启动但无法设置文本,怀疑
FindWindowEx使用了错误的类名 - 希望不创建临时文本文件,直接动态设置记事本内容,且参考的fisi-pjm代码无法正常弹出消息
解决方案
1. 实现记事本新标签页打开
Windows 11的记事本支持多标签,启动时传入"-"作为参数,即可打开空白新标签(无论是否已有记事本实例)。修改ExecuteProcess调用:
ExecuteProcess('Notepad.EXE', '-', '', false, true, false, ErrorCode);
2. 正确定位记事本编辑控件
Windows 11的记事本编辑控件类名已从Edit改为RichEditD2DPT,同时需增加进程初始化等待逻辑,避免窗口未创建就查找。修改后的主逻辑代码:
var ErrorCode: Integer; Notepad: HWND; NoteEdit: HWND; S: string; begin // 启动记事本并打开新空白标签 if ExecuteProcess('Notepad.EXE', '-', '', false, true, false, ErrorCode) then begin // 循环等待记事本窗口创建,最多等待5秒 Notepad := 0; for var i := 1 to 50 do begin Notepad := FindWindow('Notepad', nil); if Notepad <> 0 then Break; Sleep(100); end; if Notepad <> 0 then begin // 查找Windows 11记事本的编辑控件 NoteEdit := FindWindowEx(Notepad, 0, 'RichEditD2DPT', nil); if NoteEdit <> 0 then begin S := '未移除USB驱动器' + #13#10 + '请确保已安全移除USB设备后再关闭此窗口'; // 使用PWideChar适配Unicode编码,避免乱码 SendMessage(NoteEdit, WM_SETTEXT, 0, LPARAM(PWideChar(S))); // 置顶记事本窗口,确保操作员能看到 SetForegroundWindow(Notepad); end; end; end; end;
关键说明
- 调用ExecuteProcess时设置
WaitUntilIdle := true,确保记事本进程初始化完成后再执行后续逻辑 - 增加循环等待窗口创建的逻辑,解决进程启动延迟导致的查找失败问题
- 替换编辑控件类名为
RichEditD2DPT,适配Windows 11记事本的控件结构 - 使用
PWideChar传递字符串,避免Unicode编码乱码问题 - 调用
SetForegroundWindow将记事本窗口置顶,提升提示的可见性
内容的提问来源于stack exchange,提问作者Daniele
相关产品推荐
相关产品推荐

