Как программно перехватить текст из окна «Служебные сообщения» в обычном приложении 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8 (особенно в режиме обычного приложения) часто возникает необходимость программно получить текст, который был выведен в окно «Служебные сообщения». Это может потребоваться для логгирования ошибок, автоматического анализа результатов выполнения процедур или передачи данных в другие системы. Поскольку стандартные механизмы не всегда позволяют дотянуться до содержимого этого окна, разработчики прибегают к имитации действий пользователя.

В данной статье мы подробно разберем, как реализовать такой перехват, почему возникают ошибки при использовании разных раскладок клавиатуры и какие альтернативные подходы существуют для решения этой задачи.

Решение проблемы через WshShell.SendKeys

Один из наиболее распространенных способов — использование объекта Wscript.Shell и его метода SendKeys. Этот метод позволяет отправлять команды нажатия клавиш активному окну. Рассмотрим типичный алгоритм действий: нам нужно перевести фокус в окно сообщений, выделить весь текст и скопировать его в буфер обмена.

Проанализируем ситуацию, когда стандартный код перестает работать при смене раскладки клавиатуры. Рассмотрим пример кода, который часто используется для этой цели:


WshShell = Новый COMОбъект("Wscript.Shell");
// Переводим фокус в окно "Служебные сообщения" (Ctrl+Alt+O)
WshShell.sendKeys("^%(o)"); 
// Выделяем все содержимое (Ctrl+A)
WshShell.SendKeys("^(a)");

Проблема заключается в том, что метод SendKeys крайне чувствителен к текущей раскладке клавиатуры в операционной системе. Если у пользователя включена русская раскладка, то команда ^(a) (Ctrl + A) не будет распознана как команда «Выделить всё». Логичным кажется заменить латинскую букву на кириллическую, но здесь кроется важный нюанс, связанный с регистром.

Выясним причину ошибки: когда мы пишем WshShell.SendKeys("^(Ф)"), символ «Ф» является заглавным. В языке SendKeys использование заглавной буквы автоматически интерпретируется как нажатие клавиши Shift. Таким образом, команда превращается в Ctrl + Shift + а, что в интерфейсе 1С не приводит к выделению текста.

Правильный вариант для русской раскладки — использование строчной (маленькой) буквы. Рассмотрим исправленный код:


WshShell = Новый COMОбъект("Wscript.Shell");
// Для английской раскладки:
WshShell.sendKeys("^%(o)");
WshShell.SendKeys("^(a)");

// Для русской раскладки (обратите внимание на маленькую 'щ' и 'ф'):
WshShell.sendKeys("^%(щ)");
WshShell.SendKeys("^(ф)");

Важный совет: Чтобы код был универсальным, необходимо либо проверять текущую раскладку через WinAPI, либо посылать последовательно команды для обеих раскладок, хотя это может вызвать нежелательные побочные эффекты.

Почему стандартный метод ПолучитьСообщенияПользователю() не работает?

Часто программисты пытаются использовать встроенный метод платформы ПолучитьСообщенияПользователю(). Разберем, почему в обычном приложении для перехвата вывода через процедуру Сообщить() он бесполезен.

Метод ПолучитьСообщенияПользователю() предназначен для работы с объектами типа СообщениеПользователю. Эти объекты создаются в управляемом интерфейсе или при выполнении кода на стороне сервера. В обычном приложении (толстый клиент) классическая команда Сообщить() отправляет строку напрямую в текстовый поток окна сообщений, минуя очередь объектов сообщений.

Проанализируем контексты применения этого метода:

  1. Серверный код: Сообщения накапливаются в очереди и передаются на клиент после завершения серверного вызова.
  2. Фоновые задания: Единственный способ получить информацию о ходе выполнения задания.
  3. Управляемые формы: Здесь метод работает штатно для объектов СообщениеПользователю.

В обычном же приложении окно «Служебные сообщения» является визуальным элементом, содержимое которого после вывода методом Сообщить() платформой больше не кэшируется в виде программных объектов.

Альтернативный перехват через использование WinAPI

Если решение с SendKeys кажется нестабильным (так как оно зависит от фокуса окна и раскладки), рассмотрим более профессиональный подход — использование функций Windows API. Окно служебных сообщений в 1С — это стандартное дочернее окно операционной системы.

Посмотрим на алгоритм реализации через WinAPI:

  1. Используем функцию FindWindowEx, чтобы найти дескриптор (HWND) окна 1С, а затем внутри него — дочернее окно сообщений. Класс этого окна обычно имеет программное имя, специфичное для версии платформы (например, V8TextControl).
  2. После нахождения окна мы можем отправить ему системное сообщение WM_GETTEXT.
  3. Это сообщение позволяет считать текст напрямую из памяти окна, не имитируя нажатия клавиш и не очищая буфер обмена пользователя.

Этот метод гораздо надежнее, так как он работает «в тихом режиме» и не зависит от того, какая раскладка выбрана у пользователя в данный момент.

Метод рефакторинга: Переопределение вывода

Самый стабильный способ — это не перехватывать уже выведенные сообщения, а контролировать процесс их вывода. Проанализируем, как это можно внедрить в существующую конфигурацию.

Вместо прямого использования встроенной функции Сообщить(), создадим общую процедуру-обертку в глобальном модуле:


Процедура СообщитьПользователю(ТекстСообщения) Экспорт
    // 1. Выводим стандартно на экран
    Сообщить(ТекстСообщения);
    
    // 2. Дублируем в массив для последующего анализа
    ГлобальныйКонтейнерСообщений.Добавить(ТекстСообщения);
    
    // 3. Дополнительно можно записывать в текстовый лог на диске
    ЗаписатьВЛогФайл(ТекстСообщения);
КонецПроцедуры

После создания такой обертки мы можем воспользоваться механизмом «Поиск и замена» по всей конфигурации, чтобы заменить все вызовы Сообщить( на ОбщегоНазначения.СообщитьПользователю(. Это гарантирует, что ни одно сообщение не будет упущено, и нам не придется полагаться на нестабильные методы имитации пользовательского ввода.

Итоги

Мы рассмотрели несколько подходов к решению задачи. Если вам нужно быстрое решение «здесь и сейчас» для разовой задачи, используйте WshShell.SendKeys, но обязательно помните про строчный регистр символов для русской раскладки (ф вместо Ф). Для создания надежных тиражируемых решений лучше использовать рефакторинг кода с внедрением собственной процедуры вывода сообщений или низкоуровневое чтение через WinAPI.

← На главную