При автоматизации рабочего процесса часто возникает задача перехватить нажатие системных клавиш и выгрузить графические данные из буфера обмена сразу на диск. Попытка решить эту задачу с помощью встроенного компонента MSScriptControl.ScriptControl или вызова команд через WScript.Shell нередко приводит к синтаксическим ошибкам вроде «Предполагается наличие скобки» или системным сообщениям об отсутствии исполняющего ядра. Разберем по шагам, почему возникают эти ошибки и как правильно организовать выгрузку данных без установки сторонних библиотек.
Проанализируем исходный код, который передавался в объект MSScriptControl.ScriptControl с указанием языка VBScript. В коде объявлялась процедура с типами данных и ссылками на сборки .NET Framework:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If Not System.Windows.Forms.Clipboard.GetDataObject() Is Nothing Then
Dim oDataObj As IDataObject = System.Windows.Forms.Clipboard.GetDataObject()
' ...
End If
End Sub
Выясним причину падения скрипта:
As IDataObject, конструкцией Handles и прямым присваиванием при объявлении переменных принадлежит платформе VB.NET, а не скриптовому языку VBScript.Variant, а ключевое слово As вызывает ошибку синтаксического анализатора (отсюда сообщение компилятора о неверной структуре строки).MSScriptControl работает в устаревшей среде COM и не умеет напрямую вызывать методы сборок System.Windows.Forms и System.Drawing. В VBScript отсутствуют штатные средства для работы с битовыми массивами графики в буфере обмена.При попытке обойти ограничение программисты часто переходят на команды PowerShell, передавая текст скрипта в метод Run объекта WScript.Shell:
oShell = CreateObject("WScript.Shell");
Текст = """& {[void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); ...}""";
oShell.Run(Текст);
В этом случае Windows выдает ошибку: «Отсутствует исполняющее ядро для расширения имени файла». Причина заключается в том, что метод Run объекта WScript.Shell ожидает первым параметром путь к исполняемому файлу либо зарегистрированному системному документу. Нельзя передать блок кода напрямую в системную оболочку: ОС пытается интерпретировать первую строку как имя файла на диске и завершает операцию сбоем.
Чтобы выгрузить данные из системного буфера обмена в графический файл, задействуем системный интерпретатор powershell.exe, присутствующий на всех современных версиях Windows. Вызов можно выполнять как из платформы 1С:Предприятие 7.7, так и из 8.x.
Рассмотрим обязательные ключи запуска PowerShell:
-NoProfile — отключает загрузку пользовательских профилей, ускоряя запуск процесса.-ExecutionPolicy Bypass — обходит установленные в системе политики ограничения выполнения сценариев.-Sta (Single-Threaded Apartment) — критически важный параметр. Класс System.Windows.Forms.Clipboard требует однопоточного режима, без этого флага обращение к буферу вернет пустое значение или вызовет исключение потока.-WindowStyle Hidden — предотвращает появление консольного окна на экране пользователя.Посмотрим на пример кода в 1С, который формирует команду и сохраняет графические данные из буфера обмена в файл:
Процедура СохранитьБуферВФайл(ИмяФайла)
КомандаPS = "Add-Type -AssemblyName System.Windows.Forms; "
+ "Add-Type -AssemblyName System.Drawing; "
+ "$img = [System.Windows.Forms.Clipboard]::GetImage(); "
+ "If ($img -ne $null) { "
+ " $img.Save('" + ИмяФайла + "', [System.Drawing.Imaging.ImageFormat]::Jpeg); "
+ " $img.Dispose(); "
+ "}";
СтрокаЗапуска = "powershell.exe -NoProfile -ExecutionPolicy Bypass -Sta -WindowStyle Hidden -Command """ + КомандаPS + """";
oShell = СоздатьОбъект("WScript.Shell");
// 0 - скрытый режим окна, 1 - ожидать завершения выполнения
oShell.Run(СтрокаЗапуска, 0, 1);
КонецПроцедуры
Рассмотрим подробнее логику работы скрипта внутри PowerShell:
Add-Type подключают стандартные системные сборки для работы с оконными объектами и форматами графики.[System.Windows.Forms.Clipboard]::GetImage() извлекает находящийся в буфере объект. Это работает быстрее и надежнее, чем захват всего рабочего стола через CopyFromScreen, поскольку данные уже помещены в память системной клавишей.If ($img -ne $null) предотвращает сбои, если в буфере обмена находился обычный текст или файлы вместо графических данных.Save сохраняет данные в требуемом формате (поддерживаются Bmp, Jpeg, Png, Gif), после чего Dispose() освобождает системные дескрипторы GDI.При использовании этого механизма необходимо учитывать условия среды выполнения: