Как программно вставить файл из буфера обмена в определенную папку средствами 1С?

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

При проектировании удобного интерфейса в 1С программисты часто сталкиваются с задачей "легкого" прикрепления файлов к документам или справочникам. Стандартный путь — нажать кнопку «Добавить», выбрать файл на диске через диалоговое окно, подтвердить выбор — кажется пользователям слишком долгим и перегруженным кликами. Гораздо удобнее скопировать файл в проводнике (нажав Ctrl+C) или во вложении почтового клиента, перейти в 1С и нажать одну кнопку (или Ctrl+V), чтобы файл автоматически загрузился в систему или скопировался в сетевую папку.

В этой статье мы подробно рассмотрим, как реализовать этот механизм. Мы разберем как революционное штатное решение, появившееся в современных версиях платформы 1С, так и альтернативные надежные методы для более старых релизов, попутно проанализировав недостатки старых "костыльных" подходов с эмуляцией клавиатуры.

---

Решение №1: Родной механизм работы с буфером обмена (начиная с версии платформы 8.3.24)

В современных версиях платформы 1С:Предприятие наконец-то появился полноценный штатный механизм для взаимодействия с системным буфером обмена. Теперь разработчикам не нужно использовать внешние скрипты или COM-объекты.

Для реализации этой задачи используется глобальный контекст СредстваБуфераОбмена и новое событие управляемой формы ПриВставкеИзБуфераОбмена(). Напрямую прочитать файлы из буфера в произвольный момент времени мешают ограничения безопасности операционных систем и веб-браузеров, но платформа позволяет перехватить интерактивное действие пользователя (нажатие Ctrl+V или выбор команды вставки).

Рассмотрим по шагам, как настроить этот механизм:

  1. В свойствах управляемой формы найдем и определим обработчик события ПриВставкеИзБуфераОбмена.
  2. Внутри обработчика мы получаем массив объектов, которые пользователь пытается вставить. Если это файлы, они будут представлены типом СсылкаНаФайл.
  3. Используя новые асинхронные методы, мы считываем двоичные данные файла и сохраняем их в целевую директорию.

Посмотрим на практический пример кода в модуле управляемой формы:


&НаКлиенте
Асинх Процедура ПриВставкеИзБуфераОбмена(ДанныеБуфераОбмена, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Отменяем стандартное поведение системы
    
    // Проверяем, содержатся ли в буфере файлы
    Если ДанныеБуфераОбмена.СодержитФайлы() Тогда
        
        МассивФайлов = ДанныеБуфераОбмена.ПолучитьФайлы();
        
        Для Каждого ФайлСсылка Из МассивФайлов Цикл
            
            // Получаем имя исходного файла
            ИмяФайла = ФайлСсылка.Имя;
            ПутьДляСохранения = "C:\TargetFolder\" + ИмяФайла; // Задаем целевую папку
            
            Попытка
                // Асинхронно получаем двоичные данные файла из буфера обмена
                ДвоичныеДанные = Ждать ФайлСсылка.ПолучитьДвоичныеДанныеАсинх();
                
                // Записываем данные в целевую папку на диске
                Ждать ДвоичныеДанные.ЗаписатьАсинх(ПутьДляСохранения);
                
                ПоказатьПредупреждение(, "Файл успешно сохранен: " + ИмяФайла);
            Исключение
                ВызватьИсключение "Не удалось сохранить файл из буфера: " + ОписаниеОшибки();
            КонецПопытки;
            
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

Преимущества этого метода: Полная кроссплатформенность, высокая скорость работы, абсолютная стабильность при работе в RDP/сетевом окружении и отсутствие зависимости от фокуса окон или раскладки клавиатуры.

---

Решение №2: Использование PowerShell для старых версий платформ (до 8.3.24)

Если ваша компания работает на более старых версиях платформы, где встроенного объекта СредстваБуфераОбмена еще нет, отличной и надежной альтернативой станет использование системного интерпретатора PowerShell, встроенного во все современные версии Windows.

PowerShell умеет напрямую обращаться к API операционной системы и запрашивать список путей к скопированным файлам через командлет Get-Clipboard с параметром -Format FileDropList. Этот метод избавлен от недостатков эмуляции клавиатуры, так как работает в фоновом режиме.

Разберем алгоритм реализации:

  1. Из 1С мы запускаем фоновую команду PowerShell. Она считывает буфер обмена и записывает полные пути к скопированным файлам в текстовый файл во временном каталоге.
  2. 1С считывает этот текстовый файл.
  3. Для каждого найденного пути 1С выполняет стандартное быстрое копирование методом КопироватьФайл() в целевую папку.

Посмотрим на пример программной реализации этого алгоритма:


&НаКлиенте
Процедура ВставитьФайлИзБуфераЧерезPowerShell()
    
    // Определяем пути к временным файлам
    КаталогВременныхФайлов = КаталогВременныхФайлов();
    ФайлСпискаПутей = КаталогВременныхФайлов + "clip_files.txt";
    
    // Формируем команду PowerShell для выгрузки путей к файлам из буфера
    КомандаPS = "powershell -NoProfile -Command ""Get-Clipboard -Format FileDropList | Select-Object -ExpandProperty Path | Out-File '" + ФайлСпискаПутей + "' -Encoding UTF8""";
    
    // Запускаем PowerShell в скрытом окне и ждем завершения его работы
    ЗапуститьПриложение(КомандаPS, , Истина);
    
    ФайлРезультата = Новый Файл(ФайлСпискаПутей);
    Если ФайлРезультата.Существует() Тогда
        
        ТекстДокумент = Новый ТекстовыйДокумент;
        ТекстДокумент.Прочитать(ФайлСпискаПутей, КодировкаТекста.UTF8);
        
        КоличествоСтрок = ТекстДокумент.КоличествоСтрок();
        Если КоличествоСтрок = 0 Тогда
            ПоказатьПредупреждение(, "Буфер обмена не содержит скопированных файлов!");
            Возврат;
        КонецЕсли;
        
        ЦелевойКаталог = "C:\TargetFolder\"; // Ваша папка для хранения документов
        
        Для Шаг = 1 По КоличествоСтрок Цикл
            
            ИсходныйПуть = СокрЛП(ТекстДокумент.ПолучитьСтроку(Шаг));
            Если ПустаяСтрока(ИсходныйПуть) Тогда
                Продолжить;
            КонецЕсли;
            
            ФайлИсточник = Новый Файл(ИсходныйПуть);
            Если ФайлИсточник.Существует() Тогда
                НовыйПуть = ЦелевойКаталог + ФайлИсточник.Имя;
                Попытка
                    КопироватьФайл(ИсходныйПуть, НовыйПуть);
                    Сообщить("Успешно скопирован файл: " + ФайлИсточник.Имя);
                Исключение
                    ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка копирования файла: " + ОписаниеОшибки());
                КонецПопытки;
            КонецЕсли;
            
        КонецЦикла;
        
        // Удаляем временный файл списка
        Попытка
            УдалитьФайлы(ФайлСпискаПутей);
        Исключение
        КонецПопытки;
        
    Иначе
        ПоказатьПредупреждение(, "Не удалось получить данные из буфера обмена.");
    EndIf;
    
КонецПроцедуры

Преимущества метода: Работает незаметно для пользователя, не требует фокуса на активном окне, не зависит от текущей раскладки клавиатуры и работает на любых версиях платформы 1С.

---

Решение №3: Использование внешней компоненты VanessaExt

Для старых версий систем существует еще один профессиональный подход — использование специализированных внешних компонент. Популярная библиотека VanessaExt (написанная по технологии Native API и активно используемая в тестировании) содержит готовые методы для прямого обращения к буферу обмена операционной системы.

Компонента загружается прямо в сессию 1С из макета и предоставляет простой API для получения путей к файлам, находящимся в буфере обмена Windows, без использования внешних командных файлов и утилит PowerShell.

---

Решение №4: Почему эмуляция клавиатуры (WScript.Shell / SendKeys) — это плохой путь?

На просторах форумов часто встречается решение, основанное на симуляции нажатий клавиш через COM-объект WScript.Shell. Суть метода заключается в программном вызове стандартного диалога выбора файла в 1С, последующей отправке серии нажатий клавиш Tab для позиционирования в область проводника, отправке сочетания Ctrl+V и нажатии Enter.

Проанализируем пример такого кода, предложенный участниками обсуждения:


// Пример нестабильной эмуляции клавиатуры
wsh = Новый COMОбъект("WScript.Shell");
wsh.AppActivate(ПолучитьЗаголовокСистемы());
// Запуск паузы для ожидания реакции интерфейса
Для Инд = 0 По 10000 Цикл КонецЦикла; 

wsh.SendKeys("^O"); // Вызов стандартного окна открытия файлов в 1С
wsh.SendKeys("C:\Temp"); // Переход в нужную временную папку
wsh.SendKeys("{ENTER}");

// Посылаем несколько раз TAB для фокуса на списке файлов
wsh.SendKeys("{TAB}{TAB}{TAB}{TAB}{TAB}"); 
wsh.SendKeys("^{V}"); // Эмулируем Ctrl+V для вставки файла из буфера
wsh.SendKeys("{ESCAPE}"); // Закрываем окно открытия файлов

Почему мы настоятельно НЕ рекомендуем использовать данный способ:

---

Особенности работы с буфером обмена в RDP-сессиях

При использовании тонкого или толстого клиента 1С внутри терминальной сессии RDP важно понимать физику процесса копирования файлов:

Для отслеживания успешного окончания копирования при использовании внешних методов (например, PowerShell или AutoIt) рекомендуется использовать циклическую проверку размера файла. Недостаточно просто проверить существование файла методом Файл.Существует(), так как операционная система резервирует имя и размер файла в целевом каталоге в самом начале транзакции.

Правильный подход к проверке окончания копирования: считывать размер файла на диске с интервалом в 500 миллисекунд. Если размер файла перестал расти и не равен нулю в течение двух итераций проверки подряд — копирование успешно завершено, и файл можно безопасно прикреплять к объекту 1С.

← На главную