Как передать документ Word (ActiveDocument или ДвоичныеДанные) с сервера на клиент

10.08.16

Разработка - Механизмы платформы 1С

Когда мы работаем в файловом варианте и заполняем Word программно, можно не заморачиваться с передачей Word-овского документа на клиент, т.к. после методов <MSWord.Application.Visible = Истина; и  MSWord.Activate();> выполненных НаСервере Word-овский документ отобразится на экране монитора пользователя, но в клиент-серверном варианте так просто поступить не получится.

Метод ПолучитьМакет работает только на сервере. Методы работы или заполнения Word-а работают как на клиенте, так и на сервере. Показывать пользователю документ (Visible = Истина; Activate();) нужно на клиенте. Получается, нам нужно получить документ на сервере и передать его на клиент, чтобы показать. В данной статье будет рассмотрено 2 способа передачи с сервера на клиент. 1 способ для ActiveDocument, второй для ДвоичныеДанные.

Немного об ActiveDocument

 

Что пишет о ActiveDocument 1С:


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


Другими словами: в ДвоичныеДанные вы можете только «Загрузить из файла» и «Выгрузить в файл»

 

А ActiveDocument можно прямо в конфигураторе редактировать в привычном интерфейсе Microsoft Word.  Выглядит это так:

Я писал базу с нуля, где было много шаблонов Word, которые постоянно приходилось переписывать. Было очень удобно в конфигураторе открывать фактически Word, редактировать, перезапускать отладку и смотреть, что получилось. Если у вас шаблон не так часто меняется, то можно в принципе использовать «Двоичные данные».

 

Передача ActiveDocument с сервера на клиент

 

Просто получить ActiveDocument на сервере и передать его на клиент не получится. Но можно документ полностью заполнить на сервере, на клиент передать уже полностью готовый документ, и на клиенте его просто запустить.
Пример кода:

&НаКлиенте 
Процедура ПечатьПисьмаНаКлиенте(Команда)
	
	СтруктураНаПечать = ПечатьПисьмаНаСервереНаФорме(Объект.Ссылка);
	//Или СтруктураНаПечать = ПечатьПисьма(Объект.Ссылка);
	ИмяВрем = ПолучитьИмяВременногоФайла(".docx");
	СтруктураНаПечать.Записать(ИмяВрем);
	ЗапуститьПриложение(ИмяВрем,,,);
	//Или если у вас несколько документов то цикл
	//Для Каждого СтруктураПараметров из СтруктураНаПечать Цикл 
	
КонецПроцедуры  

//Если функция ПечатьПисьма в модуле менеджера то нужно как-то к ней обратиться 
&НаСервере
Функция ПечатьПисьмаНаСервереНаФорме(МассивОбъектов)
	Возврат Документы.ПисьмоНаОплату.ПечатьПисьма(МассивОбъектов);
КонецФункции

&НаСервере
Функция ПечатьПисьма(МассивОбъектов) Экспорт

	//Возможно какой-то запрос 
	
	//Пока Выборка.Следующий() Цикл
		
		//Каким-либо образом получаем макет Active Document
		//Если код в модуле менеджера то нужен код:
		Макет = ПолучитьМакет("ПисьмоНаОплатуWord");
		
		MSWord = Макет.Получить();
		Попытка
			Документ = MSWord.Application.Documents(1);
			Документ.Activate();
			
			//Далее каким-либо образом получаем данные и заполняем Word-овский документ
			//Например
			Selection = Документ.Content;
			Selection.Find.Replacement.Font.Size = 14;
			Selection.Find.Execute("[Название]",Истина,Истина,Ложь,,,Истина,,Истина,Выборка.НаименованиеПолное,2);
			
			
			//Получим путь во временной директории для сохранения туда файла
			ИмяВрем = ПолучитьИмяВременногоФайла(".docx");
			//Сохраним туда файл
			Документ.SaveAs(ИмяВрем);
			//Преобразуем файл в двоичные данные для передачи на клиент
			МойДокументВДвоичныхДанных = Новый ДвоичныеДанные(ИмяВрем);
			//Если код исполняется в цикле можно заполнить структуру:
			//СтруктураВсехДокументов.Вставить("Номер"+Строка(НомерПП),МойДокументВДвоичныхДанных);
			//Закроем Word
			MSWord.Application.Quit();
			//УдалитьФайлы(ИмяВрем);
		Исключение
			// Если произойдет ошибка, выводятся данные об ошибке
			// и объект закрывается.
			Сообщение = Новый СообщениеПользователю();
			Сообщение.Текст = ОписаниеОшибки();
			Сообщение.Сообщить();
			Если MSWord<>Неопределено Тогда
				MSWord.Application.Quit();
			КонецЕсли;
		КонецПопытки;
		
	//КонецЦикла;
	
	Возврат МойДокументВДвоичныхДанных;
	//Возврат СтруктураВсехДокументов;
	
КонецФункции // ПечатьПисьма()

При использовании этого кода на сервере должен быть установлен офисный пакет. Представленный код является шаблоном (примером) для дальнейшего программирования. Краткий анализ кода:

1. НаКлиенте мы просто получаем файл в виде двоичных данных с сервера, записываем во временную папку и открываем оттуда файл.
2. НаСервере мы получаем макет, его заполняем (дан пример заполнения через метод Find. Execute), сохраняем во временную папку (это будет папка на сервере вида: C:\Users\<Имя пользователя, под которым запущена служба 1С>\AppData\Local\Temp\v8_F0FB_7f3.docx), переводим файл в двоичные данные и передаём на клиент. Для сохранения документа можно использовать методы SaveAs, Save, SaveAs2, SaveAs2000.

 

В справке к методу ПолучитьИмяВременногоФайла написано:

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

Опытном путём выявлено, что 1С-ка вырубается с ошибкой, если удалить файл, преобразованный в двоичные данные, и попробовать эти двоичные передать на клиент.

На сервере 1С:Предприятия произошла неисправимая ошибка. Приложение будет закрыто

Я пытался побороть эту ошибку, помещая во временное хранилище двоичные данные, переводя двоичные данные в Неопределено, но победить не удалось. Стоит заметить, что временный файл на сервере 1С-ка со временем сама удаляет корректно.

 

Возможная ошибка на сервере при вызове метода SaveAs:


Ошибка при вызове метода контекста (SaveAs)
Документ.SaveAs(ИмяВрем);
по причине:
Произошла исключительная ситуация (Microsoft Word): Ошибка команды


Мне поначалу эту ошибку не удалось победить, поэтому я стал использовать ДвоичныеДанные. Позже нашёл решение проблемы: необходимо по пути C:\Windows\SysWOW64\config\systemprofile\ и C:\Windows\System32\config\systemprofile\ создать папки Desktop. Туда никаких файлов никто не пишет, похоже, программе важен факт наличия этой папки. Решение нашёл по ссылке: http://devtrainingforum.v8.1c.ru/forum/thread.jsp?id=581998&threadtype=0

Спасибо огромное.

 

Создание папок
C:\Windows\SysWOW64\config\systemprofile\Desktop
C:\Windows\System32\config\systemprofile\Desktop
проблему решило. Тема закрыта.

 

Передача макет Word (Двоичные данные) с сервера на клиент

 

В случае передачи двоичных данных представлю практически весь код. 

//Код в модуле менеджера

// Заполняет список команд печати.
// 
// Параметры:
//   КомандыПечати - ТаблицаЗначений - состав полей см. в функции УправлениеПечатью.СоздатьКоллекциюКомандПечати
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
	
	// Письмо на оплату
	КомандаПечати = КомандыПечати.Добавить();
	КомандаПечати.МенеджерПечати = "Документ.ПисьмоНаОплату";
	КомандаПечати.Идентификатор = "ПисьмоНаОплату";
	КомандаПечати.Представление = НСтр("ru = 'Письмо на оплату'");
	
	КомандаПечати = КомандыПечати.Добавить();
	КомандаПечати.МенеджерПечати = "Документ.ПисьмоНаОплату";
	КомандаПечати.Идентификатор = "ПисьмоНаОплатуWord";
	КомандаПечати.Представление = НСтр("ru = 'Письмо на оплату (Word)'");
	КомандаПечати.СписокФорм = "ФормаДокумента";
	
КонецПроцедуры

Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
	
	ПараметрыВывода.ДоступнаПечатьПоКомплектно = Истина;
	Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПисьмоНаОплату") Тогда
		УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(КоллекцияПечатныхФорм,"ПисьмоНаОплату" ,"Письмо на оплату" , 
			ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Ложь),,"Документ.ПисьмоНаОплату.ПФ_MXL_ПисьмоНаОплату");
	ИначеЕсли УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ПисьмоНаОплатуWord") Тогда
		КоллекцияПечатныхФорм[0].ТабличныйДокумент = Новый ТабличныйДокумент;
		ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Истина)
	КонецЕсли;
	
КонецПроцедуры

// Формирует печатную форму письма
//
// Параметры:
//  
//
Функция ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Word) Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст =
	//Какой-то текст	
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	ПервыйДокумент = Истина;
	СтруктураВсехДокументов = Новый Структура;
	НомерПП = 0;
	
	Пока Выборка.Следующий() Цикл
		
		НомерПП = НомерПП+1;
		
		//...
		
		Если НЕ ПервыйДокумент Тогда
			ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
		КонецЕсли;
		
		СтруктураПараметров = Новый Структура;
		//В переменную СтруктураПараметров попадают все значения которые надо вывести на печать
		//...

		Если Word Тогда
			Для Каждого Параметр из СтруктураПараметров Цикл
				СтруктураПараметров.Вставить(Параметр.Ключ,СтрЗаменить(Параметр.Значение,Символы.Таб,""));
			КонецЦикла;
			СтруктураВсехДокументов.Вставить("Номер"+Строка(НомерПП),СтруктураПараметров);
		Иначе
			// тут должен быть код для обычного макета.
		КонецЕсли;
		
	КонецЦикла;
	
	Если Word Тогда
		//Помещать во временное хранилище не обязательно
		Возврат ПоместитьВоВременноеХранилище(СтруктураВсехДокументов);
	Иначе
		Возврат ТабДокумент;
	КонецЕсли;

КонецФункции // ПечатьПисьма()




//Код на форме:
&НаКлиенте 
Процедура Подключаемый_ВыполнитьКомандуПечати(Команда)
	
	ОписаниеКоманды = УправлениеПечатьюКлиентПовтИсп.ОписаниеКомандыПечати(Команда.Имя, ЭтаФорма.Команды.Найти("АдресКомандПечатиВоВременномХранилище").Действие);
	
	Если ОписаниеКоманды.Идентификатор = "ПисьмоНаОплатуWord" Тогда
		Если Модифицированность Тогда
			Если Не Записать() Тогда
				Возврат;
			КонецЕсли;
		КонецЕсли;
		СтруктураНаПечать = ПолучитьИзВременногоХранилища(ПечатьПисьма(Объект.Ссылка,Неопределено,Истина));
		
		Для Каждого СтруктураПараметров из СтруктураНаПечать Цикл
			ДвоичныеДанныеМакета = ПолучитьИзВременногоХранилища(ПолучитьМакетСКлиента("ПисьмоНаОплатуWord"));
			ИмяВрем = ПолучитьИмяВременногоФайла(".docx");
			ДвоичныеДанныеМакета.Записать(ИмяВрем);
			Попытка
				Документ = ПолучитьCOMОбъект(ИмяВрем); 
				Для Каждого Параметр из СтруктураПараметров.Значение Цикл
					//В оригинале тут другой код, но для простаты пример:
					Selection = Документ.Content;
					Selection.Find.Execute("["+Параметр.Ключ+"]",Ложь,Истина,Ложь,,,Истина,,Ложь,Параметр.Значение,2);
				КонецЦикла;
				Документ.Application.Visible = Истина;
				Документ.Application.WindowState = 2;
				Документ.Application.WindowState = 1;
				Документ.Activate();
			Исключение
				// Если произойдет ошибка, выводятся данные об ошибке
				// и объект закрывается.
				Сообщение = Новый СообщениеПользователю();
				Сообщение.Текст = ОписаниеОшибки();
				Сообщение.Сообщить();
				Документ.Application.Quit();
			КонецПопытки;
		КонецЦикла;
	Иначе
		УправлениеПечатьюКлиент.ВыполнитьПодключаемуюКомандуПечати(Команда, ЭтаФорма, Объект);
	КонецЕсли;	
	
КонецПроцедуры  

&НаСервереБезКонтекста
Функция ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Word)
	Возврат Документы.ПисьмоНаОплату.ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Word);
КонецФункции

&НаСервереБезКонтекста
Функция ПолучитьМакетСКлиента(Имя)
	Возврат ПоместитьВоВременноеХранилище(Документы.ПисьмоНаОплату.ПолучитьМакет("ПисьмоНаОплатуWordДвоичныеДанные"));
КонецФункции

Краткий анализ кода:
Своим кодом я внедрился в СтандартныеПодсистемы.Печать. На форме документа 2 кнопки: «Письмо на оплату» (печать в табличный документ) и «Письмо на оплату (Word)» (печать в Word).
1. НаКлиенте на форме я получаю из модуля менеджера (функция ПечатьПисьма) структуру всех параметров. Далее получаю Word из макета (двоичные данные) и заполняю его на клиенте
2. Задача функции ПечатьПисьма модуля менеджера предназначена только для сбора сведений, которыми потом заполнится Word на клиенте.

Замечание: если вам адрес во временном хранилище нужен не сразу и единожды (как у меня), то корректней помещать во временное хранилище с уникальным идентификатором, дабы значение не удалилось пока не закрыли форму:

&НаСервере
Функция ПолучитьМакетСКлиента(Имя)
	Возврат ПоместитьВоВременноеХранилище(Документы.ПисьмоНаОплату.ПолучитьМакет("ПисьмоНаОплатуWordДвоичныеДанные"), УникальныйИдентификатор);
КонецФункции

 

Альтернативы:
1. //infostart.ru/public/270277/ (ActiveDocument) - в данной статье рассмотрена возможность сохранить docx документ в общую папку на сервере. На клиент передаётся полный путь к файлу, инициализируется COM-объект, заполняется и показывается пользователю.

2. Можно сохранить файл Word в общую папку и с клиента его просто получать. Главное, чтобы файл никто не удалил.

ActiveDocument ДвоичныеДанные Word Com передача с сервера на клиент

См. также

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    4506    dsdred    53    

71

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5286    YA_418728146    25    

63

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6408    dsdred    36    

111

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    18470    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12086    human_new    27    

74

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8813    YA_418728146    6    

141

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6277    sebekerga    54    

94

Все скопируем и вставим! (Буфер обмена в 1С 8.3.24)

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Рассмотрим новую возможность 8.3.24 и как её можно эффективно использовать

27.06.2023    15980    SeiOkami    31    

103
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Franco 82 15.10.15 10:34 Сейчас в теме
3. klinval 337 15.10.15 11:37 Сейчас в теме
(1) Franco, в "Альтернативы:" я уже дал ссылку на эту статью
(2) w.r., А в чём вопрос то? Боитесь, что значение будет удалено раньше чем вы успеете его использовать?
Кстати для 2-го примера <Передача макет Word (Двоичные данные) с сервера на клиент> можно и не писать
Возврат ПоместитьВоВременноеХранилище(СтруктураВсехДокументов);
//Можно писать:
Возврат СтруктураВсехДокументов;

,т.к. в СтруктураВсехДокументов попадает СтруктураПараметров, в которую в свою очередь попадает только строковые значения (какое значение на какое заменить). Для строковых значений не нужно сериализовать значение. Именно эта строка написана для примера. Если вы так-же как и я в СтруктураПараметров будете писать только строковые значения, то можно и не помещать во временное хранилище.
4. w.r. 643 15.10.15 12:07 Сейчас в теме
(3)

Да, будет удалено.

Вы, кстати, еще используете без адреса временное хранилище здесь:

&НаСервере
Функция ПолучитьМакетСКлиента(Имя)
    Возврат ПоместитьВоВременноеХранилище(Документы.ПисьмоНаОплату.ПолучитьМакет("ПисьмоНаОплатуWordДвоичныеДанные"));
КонецФункции


И вот тут лучше будет передавать в качестве адреса для временного хранилища идентификатор формы. Те вот так:


&НаСервере
Функция ПолучитьМакетСКлиента(Имя)
    Возврат ПоместитьВоВременноеХранилище(Документы.ПисьмоНаОплату.ПолучитьМакет("ПисьмоНаОплатуWordДвоичныеДанные"), УникальныйИдентификатор);
КонецФункции
6. klinval 337 15.10.15 12:39 Сейчас в теме
(4) w.r., ну в общем случае вы конечно правы и вообще правильно написать:
&НаСервере
Функция ПолучитьМакетСКлиента(Имя)
    Возврат ПоместитьВоВременноеХранилище(Документы.ПисьмоНаОплату.ПолучитьМакет("ПисьмоНаОплатуWordДвоичныеДанные"), УникальныйИдентификатор);
КонецФункции

Но у меня написан код:
&НаКлиенте
...
СтруктураНаПечать = ПолучитьИзВременногоХранилища(ПечатьПисьма(Объект.Ссылка,Неопределено,Истина));
...
&НаСервере
Функция ПолучитьМакетСКлиента(Имя)
	Возврат ПоместитьВоВременноеХранилище(Документы.ПисьмоНаОплату.ПолучитьМакет("ПисьмоНаОплатуWordДвоичныеДанные"));
КонецФункции
Показать

У меня даже нет переменной где бы я запомнил адрес во временном хранилище, т.к. как только я делаю "ПоместитьВоВременноеХранилище" потом сразу делаю "ПолучитьИзВременногоХранилища". Между этими двумя действиями нет ни строчки кода, поэтому пропасть значение до получения не может. Кстати код у меня установлен в рабочей базе и всё работает.
Если же кому-то исходя из специфики задачи нужен будет этот адрес не единожды и он его будет потом использовать вплоть до закрытия формы, то конечно корректней использовать УникальныйИдентификатор.

Другими словами: замечание хорошее, но в моей конкретной реализации задачи ничего не потеряется даже без уникального идентификатора.
Спасибо за замечание, статью позже чуть допишу (вдруг кому-то и правда адрес во временном хранилище нужен будет не единожды и сразу).
7. w.r. 643 15.10.15 13:23 Сейчас в теме
(6)

У меня даже нет переменной где бы я запомнил адрес во временном хранилище, т.к. как только я делаю "ПоместитьВоВременноеХранилище" потом сразу делаю "ПолучитьИзВременногоХранилища". Между этими двумя действиями нет ни строчки кода, поэтому пропасть значение до получения не может.


Вы не внимательно читали видимо описание. Написано:
значение будет удалено после очередного запроса сервера из общего модуля

Т.е. любое выполнение регламентного задания или иных действий параллельно работающих пользователей, использующих общие модули, в промежутке выполнения вашего кода на форме очистит временное хранилище, куда вы поместили макет еше до получения из хранилища
9. klinval 337 15.10.15 15:27 Сейчас в теме
(7) w.r., Провожу следующий эксперимент:
Запускаю отладку.
На коде "Возврат Документы.ПисьмоНаОплату.ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Word);" нажимаю F11. Захожу в модуль менеджера, через "Возврат ПоместитьВоВременноеХранилище(СтруктураВсехДокументов);) успешно возвращаюсь обратно на форму в функцию:
&НаСервере
Функция ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Word)
	Возврат Документы.ПисьмоНаОплату.ПечатьПисьма(МассивОбъектов, ОбъектыПечати, Word);
КонецФункции

Я НаСервере в форме в процедуре ПечатьПисьма (см. скрин). Во временное хранилище произошло помещение объекта, но на клиент ещё не передано (и соответственно не получено из временного хранилища).
Жду 10 минут. Рабочая база, около 100 активных пользователей. За эти 10 минут было выполнено как минимум 4 фоновых задания (часть из них ни один раз) (см. скрин). Я открыл 2 сеанс, там вывел на печать письмо в Word. Ну явно за 10 минут одно из выше перечисленных условий для удаления файла было выполнено (если вы эти условия читаете в контексте всех пользователей и всех сеансов).
Далее 10 минут спустя я жму F11 выхожу на клиент и у меня он спокойно получает из временного хранилища и выходит файл Word на экран моего монитора.

В ИТС нашёл в теме"Передача файлов между клиентом и сервером"
При одновременной работе с файлом на клиенте и на сервере необходимо использовать передачу файла через временное хранилище (методы ПоместитьФайл, ПоместитьФайлы, ПолучитьФайл, ПолучитьФайлы, НачатьПомещениеФайла, ПоместитьВоВременноеХранилище, ПолучитьИзВременногоХранилища)...
....
Для сохранения данных во временном хранилище между несколькими серверными вызовами, при помещении его в хранилище необходимо использовать параметр УникальныйИдентификаторФормы метода ПоместитьФайл, передав в него идентификатор текущей формы. Такие значение будут удалены их временного хранилища только при закрытии указанной формы.

Там конечно говорится про другой метод, но всё-таки имеется ввиду серверный вызов в пределах одного сеанса / одного кода, а не всех пользователей! Для указанного там в примере метода "Переместитьфайл" то-же самое написано в СП как и для ПоместитьВоВременноеХранилище
Если параметр не указан, помещенное значение будет удалено, после очередного запроса сервера из общего модуля, при контекстном и неконтекстном серверном вызове из формы, при серверном вызове из модуля команды или при получении формы.

Там даже приведён код с пометкой "Правильно:" вызов без уникального идентификатора. После этого вызова идёт всего один серверный вызов. И прямо указывается, что код корректный, но если нужно сделать несколько серверных вызова с сохранением адреса, то нужно использовать уникальный идентификатор! Почитайте ссылку.

Пока набирал сообщение уходил на обед и оставил точку останова в том же месте (значение уже помещено во временное хранилище, но на клиенте ещё не получено). Вернулся с обеда, нажал F5 - всё работает.
Прикрепленные файлы:
8. w.r. 643 15.10.15 13:42 Сейчас в теме
(6)

Еще могут отработать подписки на события. Сам сталкивался давным давно с этим, когда начинал работать со временным хранилищем

Вообще, передача объектов с клиента на сервер у 1С реализвона хреново. Например, из клиентского общего модуля нельзя получить имена реквизитов формы, тк нельзя передать форму с клиента на сервер, если ты не находишься собственно в самой форме. А процедура ПолучитьРеквизиты для УФ работает только на сервере. И тут никакие временные хранилища не помогут уже
10. klinval 337 15.10.15 15:37 Сейчас в теме
(8) w.r., Ну уж за час у нас точно куча подписок было отработано в рабочей базе))
Давайте на минуту представим, что
Если параметр не указан, помещенное значение будет удалено, после очередного запроса сервера из общего модуля, при контекстном и неконтекстном серверном вызове из формы, при серверном вызове из модуля команды или при получении формы.

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

Первый вопрос: почему у меня тогда ничего не удалилось ни в течении часа ни в течении 10 минут на рабочей базе БП 3.0?

Второе: методы "ПоместитьФайл, ПоместитьФайлы, ПоместитьВоВременноеХранилище" получается вообще некорректно использовать без Уникального идентификатора, т.к. любое действие любого пользователя базы может привести к очистке адреса хранилища. На большом количестве народу (1000+ одновременно работающих пользователей) данные методы будут давать корректный (не очищенный) адрес только в 50% случаев, а то и меньше. Не думаю, что это так, тем более я на практике привёл пару исчерпывающих тестов.
У меня: Бухгалтерия предприятия, редакция 3.0 (3.0.41.64) , 1С:Предприятие 8.3 (8.3.6.2332).
12. w.r. 643 16.10.15 10:08 Сейчас в теме
(10)

Протестировал. Правда не очищается временное хранилище причем даже с вызовом сервера, если находишься в текущей форме.

У меня между методами
ПоместитьВоВременноеХранилище()
и
ПолучитьИзВременногоХранилища()
, выполнился метод
СоединенияИБВызовСервера.ПараметрыБлокировкиСеансов()
. Может 8.3.6 так работает, на 8.2 точно очищалось. Попробую протестировать на базе с 8.2 и отпишусь
13. w.r. 643 16.10.15 10:14 Сейчас в теме
(10)

у вас вариант базы клиент-серверный или файловый?
14. klinval 337 16.10.15 10:18 Сейчас в теме
(13) w.r., конечно клиент-серверный. Как я написал в статье для файловой базы можно вообще не заморачиваться, выполнил на сервере запрос, чтобы получить данные, получил Word (не важно откуда) заполнил и показал пользователю. Ничего передавать на клиент не надо, лепота))
5. w.r. 643 15.10.15 12:19 Сейчас в теме
(3)

Оффтоп. Еще совет - если не используете форму на сервере, тогда лучше использовать &НаСервереБезКонтекста
11. Franco 82 16.10.15 09:46 Сейчас в теме
(3) прошу прощения за невнимательность
2. w.r. 643 15.10.15 11:08 Сейчас в теме
Один вопрос - когда помещаете во временнное хранилище не указываете адрес:

Если Word Тогда
   //Помещать во временное хранилище не обязательно
   Возврат ПоместитьВоВременноеХранилище(СтруктураВсехДокументов);
Иначе
   Возврат ТабДокумент;
КонецЕсли;


ПоместитьВоВременноеХранилище(<Данные>, <Адрес>)
Параметры:

<Данные> (обязательный)

Тип: Произвольный.
Данные, которые необходимо поместить во временное хранилище.
<Адрес> (необязательный)

Тип: УникальныйИдентификатор; Строка.
Уникальный идентификатор формы, во временное хранилище которой надо поместить данные и вернуть новый адрес. Или адрес во временном хранилище, по которому надо поместить данные. Адрес должен получен ранее с помощью данного метода.
В случае, если передается УникальныйИдентификатор формы или адрес в хранилище, то значение будет автоматически удалено после закрытия этой формы.
Если передан УникальныйИдентификатор, не являющийся уникальным идентификатором формы, то значение будет удалено после завершения сеанса пользователя.
Если параметр не указан, помещенное значение будет удалено после очередного запроса сервера из общего модуля, при контекстном и неконтекстном серверном вызове из формы, при серверном вызове из модуля команды или при получении формы.
15. Kirill_K 05.11.15 15:51 Сейчас в теме
А как у вас в варианте с ActiveDocument работает на сервере эта конструкция?

Макет = ПолучитьМакет("ПисьмоНаОплатуWord");
        
        MSWord = Макет.Получить();


В макет у меня попадает ОболочкаActiveDocument, а Получить() падает с ошибкой вызова метода контекста.
В СП написано, что для этого типа метод Получить() доступен только на толстом клиенте.
16. klinval 337 05.11.15 18:22 Сейчас в теме
(15) Kirill_K, у меня рабочего кода на руках нет, ибо сейчас в отпуске. Сделал обработку (см вложение). где всего пару строк кода. У меня дома на 8.2 (файловая база) не падает на методе "Получить()"! На работе практически самая свежая 8.3 и там тоже никакой ошибки на этой строчке (файловая или клиент-серверная).
Тупо в обработке нажмите на "Команда1" - будет ошибка?
Прикрепленные файлы:
СоздатьТестWord.epf
Kirill_K; +1 Ответить
17. Kirill_K 06.11.15 10:41 Сейчас в теме
(16) 8.2 клиент-серверная падает, а в файловой 8.3 ком-объект создается.
Значит, обновляться нужно, спасибо.
18. klinval 337 06.11.15 11:37 Сейчас в теме
(17) Kirill_K, код который написан у меня в статье я писал для клиент-серверной 8.3.6. Всё работало. Поэтому после обновления возможно и у вас заработает. Но для чистоты эксперимента я когда выйду на работу попробую на клиент-серверной обработку из 16 сообщения.
23. micha26 03.04.16 12:09 Сейчас в теме
(18) доброго дня - у меня 8.3.6 клиент сервер - запустил вашу обработку стопорится на Получить(). В чем может быть проблема?
24. klinval 337 04.04.16 09:12 Сейчас в теме
(23) micha26,
1. У вас офис на сервере установлен?
2. Если да, то на пользователе под которым работает агент 1С нормально запускается?
3. Обработка из 16-го сообщения работает?
25. micha26 04.04.16 12:40 Сейчас в теме
(24) офис установлен, пользователю даны права на запуск офиса, нет стопорится также.
26. klinval 337 04.04.16 13:28 Сейчас в теме
(25) micha26, обработка маленькая, на какой из строк стопорится?:
	Word = Новый COMОбъект("Word.Application");
	Word.Visible=1;
	Документ = Word.Documents.Add();
	ИмяВрем = ПолучитьИмяВременногоФайла(".docx");
	Документ.SaveAs(ИмяВрем);
	Сообщить(ИмяВрем);

И ещё: а если в обработке переделать процедуру с серверной на клиентскую: тоже не работает?
19. klinval 337 09.11.15 15:34 Сейчас в теме
(17) Kirill_K, попробовал в серверном режиме на 8.3.6.2332: ничего не вырубается. После строчки:
MSWord = Макет.Получить();

в переменной MSWord появляется COMОбъект. Походу Вам правильный совет - это обновиться.
Кстати в справке даже в 8.3.6.2332 написано, что метод Получить() якобы работает только в толстом клиенте:)
46. websamson 306 07.06.18 07:38 Сейчас в теме
(16) {ВнешняяОбработка.СоздатьТестWord.Форма.Форма.Форма(26)}: Ошибка при вызове метода контекста (Получить)
MSWord = Макет.Получить();
20. пользователь 16.11.15 17:05
Сообщение было скрыто модератором.
...
21. gmtv 12 20.12.15 21:28 Сейчас в теме
Не пойму в чем дело?
ошибка при вызове метода контекста save типы не совпадают
22. klinval 337 22.12.15 09:17 Сейчас в теме
(21) gmtv, есть пример-обработка, выслал её в личку.
27. micha26 06.04.16 18:10 Сейчас в теме
На SaveAs, без разницы клиент или серверная.
28. klinval 337 06.04.16 21:33 Сейчас в теме
(27) micha26,
Это решение пробовали?:
Возможная ошибка на сервере при вызове метода SaveAs:

Ошибка при вызове метода контекста (SaveAs)
Документ.SaveAs(ИмяВрем);
по причине:
Произошла исключительная ситуация (Microsoft Word): Ошибка команды

Мне поначалу эту ошибку не удалось победить, поэтому я стал использовать ДвоичныеДанные. Позже нашёл решение проблемы: необходимо по пути C:\Windows\SysWOW64\config\systemprofile\ и C:\Windows\System32\config\systemprofile\ создать папки Desktop. Туда никаких файлов никто не пишет, похоже, программе важен факт наличия этой папки. Решение нашёл по ссылке: http://devtrainingforum.v8.1c.ru/forum/thread.jsp?id=581998&threadtype=0
29. micha26 07.04.16 16:01 Сейчас в теме
(28) да ходил по этой ссылке, не помогло. Макет с двоичными данными делал та же фигня получается.
30. klinval 337 08.04.16 09:07 Сейчас в теме
(29) micha26, даже не знаю что тогда... Такое ощущение, что проблема не на стороне 1С. Может антивирус или брандмауэр что-то блокирует? Попробуйте хотя-бы локально все по-вырубать и на клиенте SaveAS() сделать.
31. micha26 08.04.16 15:12 Сейчас в теме
(30) отрубал все для примера сделал следующее:

&НаСервере
Функция ПолучитьСтруктуруДанных()
    ФайлWord = Справочники.Партнеры.ПолучитьМакет("РазовыйДоговорДв"); //двоичные данные на актив забил болт
    АдресФайла = ПоместитьВоВременноеХранилище(ФайлWord);
    Возврат АдресФайла;
КонецФункции
&НаКлиенте
Процедура ПечатьРазовогоДоговора(Команда)
          ПутьКФайлу = "D:\Doc\Разовый договор.doc";
          СтруктураДанных = ПолучитьСтруктуруДанных(); // значение = e1cib/tempstorage/7230a82d-ab89-4e08-b05a-e7122515ab93
          ФайлWord = ПолучитьИзВременногоХранилища(ПутьКФайлу); // Ошибка при вызове метода контекста (ПолучитьИзВременногоХранилища)
//всякая ересь по получению данных
Показать

Один хрен не работает...куда копать уже не представляю.
32. klinval 337 09.04.16 23:34 Сейчас в теме
(31) micha26, похоже у вас ошибка в строчке:
//На момент исполнения кода в переменной ПутьКФайлу содержится значение:"D:\Doc\Разовый договор.doc"
ФайлWord = ПолучитьИзВременногоХранилища(ПутьКФайлу);

Вместо ПутьКФайлу вам нужно использовать СтруктураДанных
33. micha26 10.04.16 10:15 Сейчас в теме
(32) да похоже верно - проверю.
34. micha26 10.04.16 12:24 Сейчас в теме
(33) micha26,
&НаКлиенте
Процедура ПечатьРазовогоДоговора(Команда)
          ПутьКФайлу = "D:\Doc\Разовый договор.doc";
          СтруктураДанных = ПолучитьСтруктуруДанных(); 
		  ФайлWord = ПолучитьИзВременногоХранилища(СтруктураДанных);
		  ФайлWord.Записать(ПутьКФайлу); // Файл записывается в папку
		  Попытка
		  Word = Новый COMОбъект("Word.Application");
	      Исключение
		  Сообщить(ОписаниеОшибки());
		  Возврат;
	      КонецПопытки;
	      Договор = Word.Open(ПутьКФайлу); // Здесь останавливается Word.Open - метод объекта не обнаружен в принципе можно убрать на фиг.
КонецПроцедуры
Показать

Что-то я нить потерял, как теперь данные заполнить в документе.
35. micha26 10.04.16 21:39 Сейчас в теме
(34) Вообщем переделал все на фиг - сохраняю шаблоны в выделенную папку на сервере, делаю запрос на сервере, сохраняю значения в реквизиты для печати и на клиенте заменой загоняю значения в шаблон. Шустро работает.
36. klinval 337 11.04.16 09:17 Сейчас в теме
(34) micha26,
Вместо Word = Новый COMОбъект("Word.Application"); и Open(ПутьКФайлу); можно использовать Документ = ПолучитьCOMОбъект(ИмяВрем); (как в принципе и написано у меня в статье)
          ФайлWord.Записать(ПутьКФайлу); // Файл записывается в папку
          Попытка
          Word = Новый COMОбъект("Word.Application");
          Исключение
          Сообщить(ОписаниеОшибки());
          Возврат;
          КонецПопытки;
          Договор = Word.Open(ПутьКФайлу);

ИмяВрем = ПолучитьИмяВременногоФайла(".docx");
            ДвоичныеДанныеМакета.Записать(ИмяВрем);
            Попытка
                Документ = ПолучитьCOMОбъект(ИмяВрем); 

Что касается метода Open: он вроде используется так: Word.Documents.Open(ПутьКФайлу).

37. micha26 12.04.16 09:24 Сейчас в теме
(36) я таким макаром сделал:
&НаКлиенте
	    Попытка
	        Word = Новый COMОбъект("Word.Application"); 
	    Исключение
	        Сообщить("Ошибка: " + ОписаниеОшибки(), СтатусСообщения.Внимание);
	    КонецПопытки;
	    ЗаполнитьДанныеДоговора(); //запрос на сервере
	    //Путь к шаблону
	    Word.Documents.Add("D:\Doc\РазовыйДоговор.doc");
	    ШаблонWord = Word.ActiveDocument;
            //далее заполнение заменой
Показать

Как бы заработало и шаблоны шустро править можно
38. klinval 337 12.04.16 09:57 Сейчас в теме
(37) micha26, ну в принципе как вариант. Я в альтернативах в конце статьи об этом варианте тоже упомянул:
2. Можно сохранить файл Word в общую папку и с клиента его просто получать. Главное, чтобы файл никто не удалил.
39. micha26 12.04.16 12:16 Сейчас в теме
(38) за что вам премного благодарен ))))
40. micha26 14.04.16 14:59 Сейчас в теме
А кстати если кому интересен полный код стучитесь в личку.
41. CeHbKA 300 10.08.16 10:02 Сейчас в теме
Прекрасная статья! Всё понятно и доходчиво написано.

По правде говоря мне пришло уведомление на гневный комментарий в моей теме со ссылкой на вашу статью где меня "ну просто опустили" (дословная цитата). Странно, прочитал всё от корки до корки, нигде никто меня не опускал)))) Гневный комментарий тоже удалён))) Видимо его автор сильно неуверен в себе, раз позволяет себе такое.

Насчёт кода на сервере, которым я записывал файл, вот он (в начале лета приводил в порядок всю свою базу наработок):
//Получает макет ActiveDocument и записывает его в файл
Функция ПолучитьМакет(Документ) Экспорт
	
	Каталог = ПараметрыСеанса.ТекущийПользователь.РабочийКаталог;
	Каталог = ?(Прав(Каталог,1) = "\", Каталог, Каталог+"\");
	Если ЗначениеЗаполнено(Каталог) Тогда
		Попытка
			ПолноеИмяФайла = Каталог+Документ.Номер+".doc";
			Макет = Документы.ДоговорыКонтрагентов.ПолучитьМакет("ActiveDocument");
			Макет.Записать(ПолноеИмяФайла);
			
			Возврат ПолноеИмяФайла;						
		Исключение
			Сообщение = Новый СообщениеПользователю;
			Сообщение.Текст = "Не удалось записать файл "+ОписаниеОшибки();		
			Сообщение.Сообщить(); 
			Возврат Неопределено;			
		КонецПопытки; 			
	Иначе
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = "Не указан каталог. Сохранение файла невозможно";
		Сообщение.Сообщить(); 
		Возврат Неопределено;
	КонецЕсли; 	
КонецФункции // ()
Показать


Спасибо, что поставили ссылку на статью. Рад, что хоть чем-то смог помочь. Сейчас отредактирую её и приведу данный листинг кода.
42. klinval 337 10.08.16 10:19 Сейчас в теме
(41) CeHbKA,
Макет = Документы.ДоговорыКонтрагентов.ПолучитьМакет("ActiveDocument");
Макет.Записать(ПолноеИмяФайла);

Так вот как оказывается можно ещё сохранить! Не заметил, что у ОболочкаActiveDocument есть метод Записать. Обязательно обновите статью, т.к. многие сваливаются на методе SaveAs, а Записать() у ОболочкаActiveDocument фактически является альтернативой
43. artms 282 27.10.17 09:02 Сейчас в теме
Есть ещё вариант заполнения на сервере https://infostart.ru/public/675307/
44. micha26 12.04.18 16:49 Сейчас в теме
Понять не могу только у меня спотыкается на этом месте:

ОбъектВ = ПолучитьМакет("СервисныйДоговор").Получить(); // метод получить не обнаружен

ОбъектВ получается это оболочка активного документа...
45. klinval 337 12.04.18 20:44 Сейчас в теме
(44) Попробуйте обработку из (16) сообщения и посмотрите цепочку сообщений связанных с (16). Похоже это ваш случай (у вас Платформа 8.2 же?)
47. Mihamak 16.12.19 10:27 Сейчас в теме
Столкнулся с проблемой, при заполнении Active doc на сервере. Если два пользователя одновременно запустят печать , произойдет наложение активных документов, и либо все зависнет, либо заполнится некорректно. Если ли способ разделить заполнение, чтобы оно работало параллельно?
48. user1274438 24.12.19 11:05 Сейчас в теме
(47) Нужно использовать ADODB.Recordset или типа того. Тут на инфостарте (и не только) есть много примеров работы с Word/Excel через ADO. какой-то конкретный предлагать не буду - сочтут за рекламу.
49. user1338406 09.01.20 19:09 Сейчас в теме
50. user1694672 08.12.21 15:26 Сейчас в теме
Спасибо за статью! вопрос - как программно поместить рисунок в отчет с макетом подобного класса?
51. Pim 180 24.02.22 10:17 Сейчас в теме
Я так понял, прочитав статью, передать именно ActiveDocument нет возможности с клиента на сервер?
Коллеги, тогда как вы решаете проблему с замусориванием временной папки?
52. nike1978 09.06.23 12:12 Сейчас в теме
Добрый день, подскажите пожалуйста, как можно вывести изображение номенклатуры табличной части документа?
Оставьте свое сообщение