ActiveDocument + Сервер 1C 8.3 = Разрыв соединения!

Программирование - Практика программирования

При формировании WORD шаблона &НаСервере происходит разрыв соединения с сервером 1С, всех пользователей отключает от сеансов и не дает зайти.

Всем привет! 

У нас было Имеем Windows Server Standart 2007 64x SP2, установленный на нем сервер 1С Предприятия 8.3 и установленный MS Office 2010.

Печатаем УТВЕРЖДЕННЫЕ шаблоны (много шаблонов) WORD из ЗУП 3.1 . Все по классике, внешняя печатная форма + макет, содержащий в себе ActiveDocument. Получаем, заполняем на сервере и передаем на клиент в виде двоичных данных, все работает  стабильно и все довольны, но в один прекрасный момент мы получаем сообщение: разрыв соединения с сервером 1С. И все. Зайти в программу больше не получится, пока не перезапустите службу Агент сервера 1С 8.3.

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

Но случаи участились.

Дальше опытным путем выяснилось, что при сохранении заполненного шаблона на сервере в файл вызывается экземпляр объекта COM (x32), он успешно записывает файл и уходит в забвение, причем не каждый раз, после чего сервер "отключается от клиентов". 

В чем же проблема?  Объяснение здесь. "Камень номер один " цитата :

Причина в том, что код

MSWord = Макет.Получить();

Всегда вызывает экземпляр объекта COM (x32) независимо от того какой разрядности Office установлен.

Автор предлагает заранее создавать пустой файл  COM (x64), потом его открывать и в него копировать заполненный, но не сохраненный шаблон из объекта COM (x32) . В общем, данный метод у меня не взлетел, так как документ всегда возвращался пустым, т.е. даже не шаблон. Проблема, думаю, во взаимодействии  объектов 32х/64х.

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

После сохранения файла (SaveAS) при попытке завершить экземпляр COM (x32) для перевода в двоичные данные сервер также падал.

После всех каруселей было найдено решение:


   

&НаСервере

Договор = ПолучитьМакет("Макет");
ВременныйФайл = ПолучитьИмяВременногоФайла(".doc");

//Было:
ОбъектWord = Договор.Получить(); // Здесь вся беда.
ДокументWord = ОбъектWord.Application.Documents(1);
ДокументWord.Activate();
//Заполняем
ДокументWord.SaveAs(ВременныйФайл,0);
ДокументWord.Close(); // Вылетает сервер.
ОбъектWord.Quit(0); // Вылетает сервер.

//*******************************************************

//Стало:

Договор.Записать(ВременныйФайл); //Это решает проблему полностью. 32х разрядное приложение не вызывается.        
Word = Новый COMОбъект("Word.Application");
Word.Displayalerts = 0;
ДокументWord = Word.Application.Documents.Open(ВременныйФайл); // Можно попробовать через ПолучитьCOMОбъект().
//Заполняем
ДокументWord.SaveAs(ВременныйФайл,0);
ДокументWord.Close();
Word.Quit(0);	



	
ФайлДД= Новый ДвоичныеДанные(ВременныйФайл);
АдресМакета = ПоместитьВоВременноеХранилище(ФайлДД);
УдалитьФайлы(ВременныйФайл);
Возврат АдресМакета; 


Спасибо всем за внимание. Нагуглить симптомы не удалось. Поэтому надеюсь, что кому-нибудь данная статья сэкономит время.

См. также

Лучшие комментарии
39. kiruha 366 03.07.18 16:19 Сейчас в теме
(18) Да это понятно.
Но
1) У клиента может не оказаться Word
2) У клиента может не оказаться лицензии Office
3) У клиента может оказаться не та версия Office
4) У клиента могут оказаться другие настройки Word и документ формируется по другому
5) У клиента просто непонятно что на компе творится и формирование документа Word корректно не происходит

6) Дефит + головняк у 1С ника из за этого
zeegin; kare; +2 Ответить
Остальные комментарии
Сортировка: Древо
1. sergathome 03.07.18 10:38 Сейчас в теме
Дёргать комом на сервере десктопные программы за гранью добра и зла, имхо.
DrAku1a; zeegin; ivanov660; SlavaKron; +4 Ответить
3. kiruha 366 03.07.18 11:36 Сейчас в теме
(1)
А как нужно вызывать Word или Excel на сервере &
4. sergathome 03.07.18 11:38 Сейчас в теме
5. kiruha 366 03.07.18 11:52 Сейчас в теме
(4)
Странно.
А вот в SQL Server есть штатные способы взаимодействия. Тот же OPENROWSET/
Да и во "вражеских" ERP штатно работают.

Может проблема не в сервере ?
6. sergathome 03.07.18 12:14 Сейчас в теме
(5) Проблема в том, что, запуская десктопную программу в контексте сервера, вы разрушаете контекст сервера с вероятностью отнюдь ненулевой (и производитель об этом прямо предупреждает https://support.microsoft.com/ru-ru/help/257757/considerations-for-server-side-automation-of-office). Нет, можно, конечно пить и из лужи, но вот стоит ли ?
10. kare 19 03.07.18 12:56 Сейчас в теме
(3) Сами объекты можно создавать на клиенте предварительно получив на сервере данные для заполнения. Опять же если только это у Вас динамический шаблон без ActiveDocument.
18. AlX0id 03.07.18 14:20 Сейчас в теме
(3) Ком не нужен.
1. Переименовываете в .zip
2. Распаковываете во временную папочку обычным архиватором.
3. Заменяете в нужных файликах требуемые параметры.
4. Запаковываете обратно.
5. Переименовываете в .docx
6. Профит.
kare; sergathome; +2 Ответить
20. kare 19 03.07.18 14:37 Сейчас в теме
(18) изящно, изначально docx должен быть?
32. AlX0id 03.07.18 15:39 Сейчас в теме
(20)
Да, xlsx и docx по сути упакованные xml-ки. А вот doc и xls - нет.
35. kare 19 03.07.18 15:52 Сейчас в теме
(32)ну для этого надо было тогда все шаблоны сохранить из пф потом пересохранить в docx и загрузить обратно в двоичные данные) как новое решение отлично подойдет.
52. zeegin 03.07.18 23:38 Сейчас в теме
(20) А вы не смотрели как это сделано в БСП 3.0.1?

> Существенно ускорено и повышена стабильность формирования печатных форм в формате офисных документов. Команды печати в этом формате теперь доступны во всех видах клиентов в операционных системах семейства Linux, Mac OS, а также в веб-клиенте.

http://downloads.v8.1c.ru/content//SSL/3_0_1_189/change.htm

Теперь собственно используется Office Open XML который разбирается и заполняется на сервере как zip архив.
39. kiruha 366 03.07.18 16:19 Сейчас в теме
(18) Да это понятно.
Но
1) У клиента может не оказаться Word
2) У клиента может не оказаться лицензии Office
3) У клиента может оказаться не та версия Office
4) У клиента могут оказаться другие настройки Word и документ формируется по другому
5) У клиента просто непонятно что на компе творится и формирование документа Word корректно не происходит

6) Дефит + головняк у 1С ника из за этого
zeegin; kare; +2 Ответить
41. kare 19 03.07.18 16:36 Сейчас в теме
(39) я побоялся это описывать @sergathome . Конечно на клиенте в половины случаев все разное.
50. AlX0id 03.07.18 17:04 Сейчас в теме
(39)
А нахрена вообще тогда ставили задачу по формированию документа в ворде? )
Я не говорю, что документы ворда суперские и замечательные. Но если поставили такую задачу - можно решить так. И да - это, конечно же, не универсальное решение.
51. kare 19 03.07.18 17:09 Сейчас в теме
(50) ))) Ворд жил жив и будет жив) актуш)
9. kare 19 03.07.18 12:54 Сейчас в теме
(1) Подскажите тогда каким образом получить такой макет на клиенте? макет держать в двоичных данных и передавать через временное хранилище? тогда уходит редактирование шаблона " на лету" через ActiveDocument что в данном решении не подходило.
16. sergathome 03.07.18 13:52 Сейчас в теме
2. fr13 03.07.18 11:23 Сейчас в теме
А что мешает использовать таблчиный документ как макет, заполнить, записать в поток, из потока в двоичный данные и дальше на клиента?
11. kare 19 03.07.18 13:02 Сейчас в теме
(2) Имеется ввиду вообще без WORD ? или из макета брать данные для заполнения шаблона на клиенте? тогда вопрос как передать макет из обработки с типом ActivDocument на клиент?
12. fr13 03.07.18 13:13 Сейчас в теме
(11) Сделать макет с типом Табличный документ. На сервере его заполнить. Дальше у ТД есть метод Записать. Записать можно в файл, а можно сразу в потоквпамяти. Так вот запись в поток и указать тип сохранения. Дальше у потока есть метод ЗакрытьИПолучитьДвоичныеДанные. Дальше ДД в хранилище и адрес этого хранилища передать на клиент. Никакой word не нужен. Единственное что, так это версия платформы 8.3.9+, но так как у Вас ЗУП 3.1, то скорей всего это ограничение не для Вас
13. kare 19 03.07.18 13:21 Сейчас в теме
(12) )) это здорово конечно, но а как же "Эта форма утверждена и она должна выглядеть именно так вплоть до форматирования" ?
14. fr13 03.07.18 13:25 Сейчас в теме
(13) Речь была не про утвержденную форму. Это уже отдельная история. Если сильно захотеть, то можно сделать. В конце концов *docx можно распаковать и через xpath менять что угодно. Опять же, тема отдельного разговора.
15. kare 19 03.07.18 13:29 Сейчас в теме
(14) согласен с docx, но это совсем другая история )))
30. kembrik 03.07.18 15:30 Сейчас в теме
(13) Для этого надо использовать LaTeX

Надоели мне постоянные танцы вокруг Офиса, делаю сейчас маленькую подсистемку, собирающую формы сразу в PDF
37. kare 19 03.07.18 16:05 Сейчас в теме
(30) Ждем публикацию, интересно будет взглянуть.
7. SlavaKron 03.07.18 12:23 Сейчас в теме
Мой комментарий напрямую не относится к теме, но лучше писать Word.Quit(0).
Например следующий код не закрывает процесс Word:
Word = Новый COMОбъект("Word.Application");
Word.Documents.Add();
Word.Selection.TypeText("Привет!");
Word.Quit();
8. kare 19 03.07.18 12:50 Сейчас в теме
(7)Пробовал с "0", результат был тот же. Хотя конечно же лучше делать как Вы указали.
17. sergathome 03.07.18 13:54 Сейчас в теме
(8) делать лучше так, как чел из 14 года советует ;))
https://infostart.ru/public/270277/
у него там, правда, тоже не без ошибок, но, думаю, разберётесь
19. kare 19 03.07.18 14:35 Сейчас в теме
(17)
Каталог = ПараметрыСеанса.ТекущийПользователь.РабочийКаталог;
	Каталог = ?(Прав(Каталог,1) = "\", Каталог, Каталог+"\");
Макет = Документы.ДоговорыКонтрагентов.ПолучитьМакет("ActiveDocument");
Макет.Записать(ПолноеИмяФайла);


здесь разве не нужен доступ к рабочему каталогу клиента из сервера? его может и не быть?
21. sergathome 03.07.18 14:43 Сейчас в теме
(19)
у него там, правда, тоже не без ошибок, но,
не разобрались, ага. Понятненько.
Короче, схема такая:
1. Через ВременноеХранилище передаём макет на клиент.
2. На клиенте получаем из ВХ и пишем в файл.
3. Там же, на клиенте, открываем файл как угодно.

Синхрофазотрон ?
22. kare 19 03.07.18 14:46 Сейчас в теме
(21) это понятно)) изначально макет есть что?
(9) ранее писал:
макет держать в двоичных данных и передавать через временное хранилище? тогда уходит редактирование шаблона " на лету" через ActiveDocument что в данном решении не подходило.
23. sergathome 03.07.18 14:49 Сейчас в теме
(22) Да что ж вы к этому несчастному АктивДокументу привязались. Двоичные данные он и пох. Укажете при записи файла расширение ему .дос и будет он вордом открываться как миленький. Есстно нужно правильный док указать - тот же, какой при помещении в макет был.
24. kare 19 03.07.18 14:51 Сейчас в теме
(23) если на сервере то в данном случае вызовется объект Word 32x что приведет к описанным в топе проблемам) в том вся соль что макет нужен для редактирования "на лету" если бы все было в двоичных данных топика бы здесь не появилось) Макет(AD) в том виде в котором он используется можно записать только на сервере, конечно без zip и тд и тп. Вариантов реализаций данного функционала масса. Но здесь конкретный случай. Переписывать все ПФ на двоичные данные и заполнение на клиенте это уже совсем другой выход.
25. sergathome 03.07.18 14:58 Сейчас в теме
(24) Вызовется тот, который вы ему скажете. Вы правильно написали всё про 32-64, только на клиенте половины проблем не будет ;)
26. kare 19 03.07.18 15:02 Сейчас в теме
(25) если двоичные данные .записать(**.doc) как он и был помещен туда на выходе мы получим 32х, про клиент - согласен %)
27. sergathome 03.07.18 15:05 Сейчас в теме
(26) да что же вы ересь-то такую несусветную пишете :) Файл - он просто вордовский файл, он не бывает 32 или 64 и откроется он тем вордом, который у вас на клиенте стоит.
28. kare 19 03.07.18 15:08 Сейчас в теме
(27)почему же? я про сервер говорю. ActiveDocument вызывает неявно экземпляр COM (x32) и поэтому все дальнейшие манипуляции нужно делать учитывая это особенность.
29. sergathome 03.07.18 15:29 Сейчас в теме
(28)
//На клиенте получаем макет и заполняем его предварительно полученными данными
ДвоичныеДанныеМакета = ПолучитьИзВременногоХранилища(ПолучитьМакетСКлиента("ПисьмоНаОплатуWord"));
            ИмяВрем = ПолучитьИмяВременногоФайла(".docx");
            ДвоичныеДанныеМакета.Записать(ИмяВрем);
            Попытка
                Документ = ПолучитьCOMОбъект(ИмяВрем); 
                Для Каждого Параметр из СтруктураПараметров.Значение Цикл
                    // пример:
                    Selection = Документ.Content;
                    Selection.Find.Execute("["+Параметр.Ключ+"]",Ложь,Истина,Ложь,,,Истина,,Ложь,Параметр.Значение,2);
                КонецЦикла;
                Документ.Application.Visible = Истина;
                Документ.Application.WindowState = 2;
                Документ.Application.WindowState = 1;
                Документ.Activate();
            Исключение
.....

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


Какие тут особенности ? ПолучитьСОМОбъект, который есть
Функция  ПолучитьСОМОбъект(ИмяФайла)
Word = Новый COMОбъект("Word.Application");
Word.Displayalerts = 0;
ДокументWord = Word.Application.Documents.Open(ИмяФайла);
Возврат ДокументWord;
КонецФункции
?

И, главное, даже если оно рухнет, по неважно даже каким причинам, то сервер не завалится.
31. kare 19 03.07.18 15:37 Сейчас в теме
(29) здесь двоичные данные записанные НА КЛИЕНТЕ в DOCX, капитан. Зачем мне то что я говорил (9) ?
макет держать в двоичных данных и передавать через временное хранилище? тогда уходит редактирование шаблона " на лету" через ActiveDocument что в данном решении не подходило.

Может сделаете тоже самое только на сервере и с doc?без двоичных данных? в чем холивар ?
34. sergathome 03.07.18 15:46 Сейчас в теме
(31) Здесь ваш АктивДокумент, который есть двоичные данные вордового файла, по-факту. Что же вы никак это не вкурите-то///
АктивДокумент = ДвоичныеДанные("ИмяФайла.doc")
36. kare 19 03.07.18 16:04 Сейчас в теме
(34) Мне не понятно к чему Вы пишите про двоичные данные и docx если в статье идет про ActiveDocument + &НаСервере ?
38. sergathome 03.07.18 16:13 Сейчас в теме
(36) пытался объяснить как то же самое сделать на клиенте. сдаюсь. не смог.
40. kare 19 03.07.18 16:35 Сейчас в теме
(38) я правильно понимаю Вас? Вы рекомендуете все шаблоны переписать на клиент ручками пересохранив Макет в doc потом загрузив обратно в макет двоичные данные далее переписать везде код для работы с клиентом и организовать заполнение на клиенте? и это все из за дерганья com на серевере? риали?
43. sergathome 03.07.18 16:38 Сейчас в теме
(40) исполните вот это и вкурите уже что такое волшебный ваш ActiveDocument
&НаКлиенте
Процедура ОткрытьАктивДокумент()
//На клиенте получаем макет и заполняем его предварительно полученными данными
	ДвоичныеДанныеМакета = ПолучитьИзВременногоХранилища(ПолучитьМакетСКлиента("Макет"));
    ИмяВрем = ПолучитьИмяВременногоФайла(".doc");
    ДвоичныеДанныеМакета.Записать(ИмяВрем);
			
	Документ = ПолучитьCOMОбъект(ИмяВрем); 
    Документ.Application.Visible = Истина;
    Документ.Application.WindowState = 2;
    Документ.Application.WindowState = 1;
    Документ.Activate();
КонецПроцедуры

&НаКлиенте
Функция  ПолучитьСОМОбъект(ИмяФайла)
	Word = Новый COMОбъект("Word.Application");
	Word.Displayalerts = 0;
	ДокументWord = Word.Application.Documents.Open(ИмяФайла);
	Возврат ДокументWord;
КонецФункции

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

Насчет рили будете смеяцо когда сервак завалится при паре сотне юзеров в базах ;)) и будет падать каждые полчаса...
45. kare 19 03.07.18 16:52 Сейчас в теме
(43)
-Владимир Владимирович, женщина может стать президентом ?
-Нет!
-Почему же?
-Я же не женщина.

можно АД сохранить в файл и передать на клиент без участия COM. Только всю логику в каждой обработке заполнения придется переделать под клиент когда она сделана под СЕРВЕР. из за того что бы не менять пару строчек кода и опять про преимущества клиента почитайте (39).
47. sergathome 03.07.18 16:54 Сейчас в теме
(45) это свежий аргумент. ушёл думать. раньше следующего понедельника не ждите.
48. kare 19 03.07.18 16:59 Сейчас в теме
(47)будем скучать, возвращайтесь.
49. kare 19 03.07.18 17:02 Сейчас в теме
(43)
Насчет рили будете смеяцо когда сервак завалится при паре сотне юзеров в базах ;)) и будет падать каждые полчаса...


я не смеюсь, серьезно. Просто я не понял : "Переделываем все на клиент !!!!!!" когда проблема решилась и больше не возвращалась.
44. sergathome 03.07.18 16:46 Сейчас в теме
(42)
будете смеяцо когда сервак завалится при паре сотне юзеров в базах ;)) и будет падать каждые полчаса...

рецепт 18 работает только для docx, на минуточку...
46. kare 19 03.07.18 16:53 Сейчас в теме
(44) Опечатка (39)
смеяцо

153 пользователя полет нормальный.
33. kare 19 03.07.18 15:43 Сейчас в теме
(29) То что данное решение имеет свои плюсы так как выполняется на клиенте это факт. Но я разве ставил под сомнение это?
54. klinval 257 05.07.18 15:05 Сейчас в теме
Конечно прикольно когда проблему описанную в моей статье кто-то решает другим способом, а потом этот другой способ тоже пробуют переделать (плюс параллельно обоснуют и докапываются до причины ошибки)...

Я только одного не понял: а создание папок проблему уже не решает?
C:\Windows\SysWOW64\config\systemprofile\Desktop
C:\Windows\System32\config\systemprofile\Desktop

Плюс можно банально отказаться от ActiveDocument и работать с двоичными данными. Пробовали?

См. тут и тут
55. kare 19 05.07.18 16:24 Сейчас в теме
(54)
1)изначально были в системе до появления "сбоя".
2)Да.
60. klinval 257 09.07.18 15:19 Сейчас в теме
(55) Нашёл свой же комментарий (тут: https://infostart.ru/public/407448/):
Макет = Документы.ДоговорыКонтрагентов.ПолучитьМакет("ActiveDocument");
Макет.Записать(ПолноеИмяФайла);

Так вот как оказывается можно ещё сохранить! Не заметил, что у ОболочкаActiveDocument есть метод Записать. Обязательно обновите статью, т.к. многие сваливаются на методе SaveAs, а Записать() у ОболочкаActiveDocument фактически является альтернативой

Сама статья тут: https://infostart.ru/public/270277/

Ни у меня ни у CeHbKA эту проблему хоть и касались, но так полно и подробно как у вас и у https://infostart.ru/public/568913/ не разбиралась, поэтому по любому плюс за статью))
56. kiruha 366 05.07.18 17:57 Сейчас в теме
а нельзя ли
вместо
Word = Новый COMОбъект("Word.Application");
Word.Displayalerts = 0;
ДокументWord = Word.Application.Documents.Open(ВременныйФайл); /

изменить на
Word = ПолучитьCOMОбъект(ВременныйФайл);
 

тк создание COMОбъект в большом количестве приводит к невозможности его создания
При ПолучитьCOMОбъект такого не происходит, даже когда Новый COMОбъект уже не работает
57. kare 19 06.07.18 13:00 Сейчас в теме
(56)можно , в коде указанно.

ДокументWord = Word.Application.Documents.Open(ВременныйФайл); // Можно попробовать через ПолучитьCOMОбъект().
58. aspirator23 370 07.07.18 14:27 Сейчас в теме
Вроде бы все вопросы задали. Остался главный. А что это за фильм с Траволтой? -:)
59. kare 19 07.07.18 22:24 Сейчас в теме
Оставьте свое сообщение