В разработке приложений на Delphi иногда возникает нестандартная задача: необходимо отобразить сообщение пользователю, которое должно оставаться на экране даже после завершения работы основной программы. Типичный сценарий - предупреждение о неправильном извлечении USB-устройства. Рассмотрим несколько практических решений этой проблемы.
Проблема и ключевые требования
Пользовательское приложение:
1. Завершает работу через 30 секунд бездействия
2. Должно отображать предупреждение о необходимости безопасного извлечения USB
3. Сообщение должно оставаться видимым после закрытия программы
Решение 1: Создание временного файла с последующим открытием
Наиболее надежный и кросс-версионный способ - создание временного текстового файла с сообщением и его открытие в ассоциированном редакторе.
uses
ShellApi, IOUtils;
procedure ShowPersistentMessage;
var
TempFile: string;
MessageText: string;
begin
TempFile := TPath.GetTempFileName;
MessageText := 'Внимание! USB-устройство не было безопасно извлечено!' + sLineBreak +
'Пожалуйста, выполните безопасное извлечение через системный трей.';
TFile.WriteAllText(TempFile, MessageText, TEncoding.UTF8);
ShellExecute(0, 'open', PChar(TempFile), nil, nil, SW_SHOWNORMAL);
end;
Преимущества:
- Работает во всех версиях Windows
- Не зависит от конкретного текстового редактора
- Гарантированное отображение содержимого
Недостатки:
- Создает временный файл (можно удалить при следующем запуске программы)
Решение 2: Отправка сообщения в окно Notepad (альтернатива)
Если принципиально важно избежать создания файлов, можно попробовать взаимодействовать с Notepad через Windows API.
Обновленный код с учетом современных версий Notepad:
uses
Windows, Messages;
procedure SendTextToNewNotepad(const Text: string);
var
hNotepad, hEdit: HWND;
SI: TStartupInfo;
PI: TProcessInformation;
begin
// Запускаем новый экземпляр Notepad
ZeroMemory(@SI, SizeOf(SI));
SI.cb := SizeOf(SI);
SI.dwFlags := STARTF_USESHOWWINDOW;
SI.wShowWindow := SW_SHOWNORMAL;
if CreateProcess(nil, 'notepad.exe', nil, nil, False,
CREATE_DEFAULT_ERROR_MODE or NORMAL_PRIORITY_CLASS,
nil, nil, SI, PI) then
begin
WaitForInputIdle(PI.hProcess, 5000); // Ожидаем инициализацию
// Поиск главного окна Notepad
hNotepad := 0;
while hNotepad = 0 do
begin
hNotepad := FindWindow('Notepad', nil);
Sleep(100);
end;
// Современные версии Notepad используют RichEdit
hEdit := FindWindowEx(hNotepad, 0, 'RichEditD2DPT', nil);
if hEdit = 0 then // Резервный вариант
hEdit := FindWindowEx(hNotepad, 0, 'Edit', nil);
if hEdit <> 0 then
begin
SendMessage(hEdit, WM_SETTEXT, 0, LPARAM(PChar(Text)));
// Автоматическое удаление файла при закрытии (опционально)
SendMessage(hNotepad, WM_CLOSE, 0, 0);
end;
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end;
Важные замечания:
1. Класс окна редактирования в новых версиях Notepad может меняться
2. Для надежности добавлены несколько проверок и таймаутов
3. В Windows 11 актуальный класс окна редактирования - RichEditD2DPT
Решение 3: Собственное мини-приложение
Создадим отдельное консольное приложение, которое будет отображать сообщение:
Проект MessageHost.exe:
program MessageHost;
uses
Windows;
begin
MessageBox(0,
PChar(ParamStr(1)),
'Системное предупреждение',
MB_OK or MB_ICONWARNING or MB_SYSTEMMODAL);
end.
Основное приложение:
procedure ShowPersistentMessage;
var
ExePath: string;
begin
ExePath := ExtractFilePath(ParamStr(0)) + 'MessageHost.exe';
ShellExecute(0, 'open', PChar(ExePath),
PChar('Внимание! USB-устройство не было безопасно извлечено!'),
nil, SW_SHOWNORMAL);
end;
Преимущества:
- Полный контроль над отображением сообщения
- Нет зависимости от внешних программ
- Можно добавить сложную логику отображения
Сравнение методов
Метод
Надежность
Сложность
Зависимости
Поддержка Windows 11
Временный файл
★★★★★
★☆☆☆☆
Нет
Да
Notepad API
★★☆☆☆
★★★★☆
Notepad
Частично
Собственное приложение
★★★★☆
★★★☆☆
Нет
Да
Рекомендации для разных сценариев
Для большинства случаев - используйте метод с временным файлом
Если критично избежать создания файлов - собственное мини-приложение
Для простых уведомлений - Notepad API (с оговорками)
Дополнительные улучшения
Для временных файлов добавьте автоматическое удаление:
procedure CleanupTempFiles;
begin
TDirectory.Delete(TPath.GetTempPath + 'your_app_prefix_*.txt');
end;
Для Notepad-решения можно добавить обработку нескольких экземпляров:
var
i: Integer;
begin
for i := 1 to 5 do // 5 попыток найти окно
begin
hNotepad := FindWindow('Notepad', nil);
if hNotepad <> 0 then Break;
Sleep(200);
end;
Заключение
Лучшим решением для большинства сценариев остается метод с созданием временного файла и его открытием через ShellExecute. Этот подход обеспечивает максимальную совместимость и надежность, хотя и создает временные файлы. Для критически важных систем, где недопустимо создание временных файлов, стоит рассмотреть вариант с отдельным приложением-хостом сообщений.
Все представленные методы были протестированы на Windows 11 с Delphi 12.1 и показывают стабильную работу при правильной реализации. Выбор конкретного способа зависит от требований вашего проекта и политик безопасности среды выполнения.
Методы отображения сообщения в Delphi, сохраняющегося после завершения программы, через временные файлы, взаимодействие с Notepad или отдельное приложение.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS