15.04.2010, 10:37 | #1 |
Участник
|
Экспорт в Excel: ComExcelDocument_RU - нужно сделать серверным
Дабы не ставить Excel на все машины, массово используется OS Office, идея формировать отчеты на сервере, сохранять файл на сетевые шары, и после того как отчет сформирован и сохранен, выдавать пользователю временную ссылку (в диалоге) на файл, одним щелчком открывается ссылка, пользователь забирает файл, после закрытия диалога, временная шара удаляется.
ComExcelDocument_RU - нужно сделать серверным, но метод WorkSheet.pasteSpecial отказывается работать, причем с любыми параметрами: XLSWorkSheet.pasteSpecial(1); // xlAll = 1 XLSWorkSheet.pasteSpecial(3); // xlValues = 3 XLSWorkSheet.PasteSpecial(COMVariant::createFromStr("Текст")); XLSWorkSheet.pasteSpecial(-4163); ... неизвестная ошибка ... метод pasteSpecial() завершен не верно ниче не помогает. Кто поможет? да... , чуть не забыл, если работать через, insertvalue то все норм., я жеработаю с буфером, вставляю данны блоками. Последний раз редактировалось kair84; 15.04.2010 в 12:15. |
|
15.04.2010, 12:37 | #2 |
Moderator
|
Вот это читали? Параметры pastespecial()
И может покажете фрагмент кода пошире, чем просто один оператор? Вы буфер как заполняете перед тем, как pasteSpecial применять? |
|
15.04.2010, 12:51 | #3 |
Участник
|
да смотрел, вот код:
X++: //Import from Mazzy forum public void InsertText(BookMark _bookMark, TextBuffer _text, int _workSheet = 1) { COM XLSWorkSheet, XLSrange; TextBuffer tempBuffer; // To store clipboard contents ; if (! m_comDocument) { throw error(StrFmt("@DIS6401", this.getApplicationName())); } else { // Initializing XLSWorkSheet object XLSWorkSheet = this.getWorkSheet(_workSheet); if (!XLSWorkSheet) throw error("@DIS6043"); // Initializing XLSRange object XLSrange = this.findRange(_bookMark,_workSheet); if (!XLSrange) throw error("@SYS27391"); XLSrange.select(); // Storing clipboard contents tempBuffer = new TextBuffer(); tempBuffer.fromClipboard(); // Preparing text to be inserted _text.toClipboard(); // Inserting text from clipboard XLSWorkSheet.pasteSpecial(1); // 1 - "Text only" mode // XLSWorkSheet.pasteSpecial(3); // XLSWorkSheet.PasteSpecial(COMVariant::createFromStr("Текст")); // XLSWorkSheet.pasteSpecial(-4163); // Restoring clipboard contents tempBuffer.toClipboard(); }// if return; } |
|
15.04.2010, 13:19 | #4 |
Moderator
|
Попробуйте сделать по аналогии с этим моим сообщением: Параметры pastespecial()
А именно: 1. Закомментируйте у себя строку "XLSrange.select();" - она ни к чему в моем случае 2. Вместо "XLSWorkSheet.pasteSpecial(1);" напишите "XLSrange.pasteSpecial(1);" Плюс обратите внимание вот на это: Ускорение экспорта в Excel - и там про терминал. Вы уверены, что буфер, передающийся в процедуру - тот, который нужен? Не происходит ли подмена на локальный или наоборот? Последний раз редактировалось Gustav; 15.04.2010 в 13:30. |
|
15.04.2010, 14:20 | #5 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: Gustav (2). |
15.04.2010, 15:09 | #6 |
Участник
|
To Gustav: смотрел конечно, у меня тоже все работало замечательно, пока не возникла необходимость формировать файл на сервере
XLSrange.pasteSpecial(1); то же не прокатило, ошибка в СOM объекте. To Максимов: это и есть этот метод, и он круто работает, но только на клиенте. я и класс отчета серверным делал, типа сам буфер уже бутет формироваться на сервере, нифига, есть идея передавать через файл. думаю может то что AOS работает как сервис, и у него проблема с буфером, потому как в 2-х уровневом тоже все работает. |
|
15.04.2010, 16:10 | #7 |
Moderator
|
Цитата:
Проверьте свой TextBuffer внутри своего метода перед pasteSpecial. |
|
15.04.2010, 16:47 | #8 |
Участник
|
Излогаешь вполне понятно, я прочитал тот пост, у меня др. случай, сожержание буфера корректное.
Кроме AOSа, серьезного там ничего нет, буфер по идее не используется. Последний раз редактировалось kair84; 15.04.2010 в 16:53. |
|
16.04.2010, 09:11 | #9 |
Участник
|
В свете новых веяний - не кошерно использовать Excel для серверной автоматизации.
Рекомендуется формировать сразу xlsx файлы посредством MS OpenXML SDK (_http://openxmldeveloper.org), или сторонних продуктов. Скорость формирования выше в разы, по сравнению с COM автоматизацией. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (2). |
16.04.2010, 11:41 | #10 |
Участник
|
У нас, в основном, работа с Excel происходит в терминальном режиме на бездисковых станциях. Поэтому есть своя специфика. Не знаю, можно ли замеченные проблемы применить к работе собственно на сервере. Тем не менее, перечислю с чем столкнулся и как исправил
Создание новой сессии. Подключение к терминалу. Первый запуск Excel В этот момент буфер обмена вообще не инициализирован. Любая попытка что-то вставить через pasteSpecial(1) заканчивается крахом. Необходима принудительная инициализация буфера обмена. Ну, например, открыть блокнот, что-то там написать, выделить, Ctrl+C, Ctrl+V. Однако тот же процесс инициализации буфера можно сделать и в процессе вставки в Excel. В результате, метод insertText() принимает такой вид X++: // Вставка в ячейку Excel через буфер обмена текстовой информации // Код взят с сайта [url]http://forum.mazzy.ru/index.php?showtopic=385&hl=excel[/url] // Можно вставлять много ячеек одной командной используя управляющие коды перехода по ячейкам // Для перехода на соседние ячейки в теле текста следует использовать коды: // num2char(9) - клавиша Tab - следующая ячейка в текущей строке - символ "\t" // num2char(13) - клавиша Enter - следующая ячейка в первом столбце области _bookMark - символ "\n" public void insertText(BookMark _bookMark, TextBuffer _text, int _workSheet = 1) { COM XLSWorkSheet, XLSrange; TextBuffer tempBuffer, // To store clipboard contents tempBufferDouble; int nextI, maxI = 5; str errorMsg; int errorNum; ; // Если содержимое TextBuffer вообще не введено, то PastSpecial даст ошибку, // а если заведена пустая строка, то нет смысла делать PastSpecial if (! _text.size()) { return; } // Initializing XLSWorkSheet object XLSWorkSheet = this.getWorkSheet(_workSheet); if (!XLSWorkSheet) { throw error("@DIS6043"); } // Initializing XLSRange object XLSrange = this.findRange(_bookMark,_workSheet); if (!XLSrange) { throw error("@SYS27391"); } XLSrange.select(); for (nextI = 1; nextI <= maxI; nextI++) { if (nextI > 1) { sleep(1000); } try { // Storing clipboard contents tempBuffer = new TextBuffer(); tempBuffer.fromClipboard(); // Инициализирую буфер обмена, если он по каким-то причинам не был инициализирован // такое случаяет в момент входа в терминальном режиме, особенно на бездисковых станциях XLSrange.value2("Выделите данную ячейку, нажмите Ctrl+C и повторите выполнение отчета"); XLSrange.copy(); XLSrange.value2(""); // Preparing text to be inserted // Теоретически, данная функция возвращает 0, если вставить не удалось // но фактически, она возвращает результат факта отправки данных в буфер обмена, // а не результат реального попадания этих данных в буфер. Т.е. всегда возвращает 1 _text.toClipboard(); // Поэтому факт реального попадания данных в буфер обмена определяем дополнительно // Эта проверка имеет смысл только для самоконтроля // Все равно будет исключение на pasteSpecial() и по try...catch уйдем на следующий шаг цикла // Inserting text from clipboard XLSWorkSheet.pasteSpecial(COMVariant::createFromInt(1)); // 1 - "Text only" mode // Restoring clipboard contents tempBuffer.toClipboard(); // В случае успеха, прерываю цикл break; } catch (Exception::Error) { // Скорее всего, ошибка будет на pasteSpecial(), т.е. надо восстановить буфер tempBuffer.toClipboard(); // в случае ошибки удаляю последнюю строку infolog, // которая генерится автоматически ошибкой COM if (infolog.line()) { infolog.clear(infolog.line()-1); } // предпринимаю очередную попытку сделать вставку через буфер } } // for (nextI) // Если выход из цикла for произошел "штатно", то значение счетчика будет больше максимально допустимого значения if (nextI > maxI) { if (errorMsg) { error(errorMsg); } throw error("Ошибка при копировании данных через буфер обмена."); } } X++: excel = new ComExcelDocument_RU(); excel.newFile(fileName,true); excel.visible(false); ( Excel ) excel.visible(true); Сразу после открытия файла сделать его видимым, что позволяет инициализировать много чего из очень разных настроек MS Office, тут же сделать не видимым, заполнить данными и снова отобразить. Разумеется, это сопровождается мельканием окна Excel. Но, пока я не нашел других способов однозначно инициализировать буфер обмена. |
|
16.04.2010, 14:19 | #11 |
Участник
|
Серьезно - если есть время уйти от этих танцев с бубнами, посмотрите на вариант переделки класса ComExcelDocument_RU для работы через OpenXML. Если у пользователей не у всех еще 2007 - можно ставить дополнение для открытия файлов xlsx в 2003 office или вообще бесплатный Excel Viewer от MS.
|
|
30.04.2010, 13:04 | #12 |
Участник
|
С XLSrange.value2 отрабатывает, в ошибку не валится, но вставляет пустой буфер, видимо класс TxtBuffer от имени процесса AOSа не может передать данные в ClipBoard операционки, с видимым не видимым excel, тоже не получается, в обоих случаях эксель остается не видимым. есть вариант запихнуть данные в буфер через WinAPI, но как это сделать я пока не знаю
Кто работал с буфером через WinAPI ? как в него передать форматированную строку? если можно примеры... |
|
30.04.2010, 15:42 | #13 |
Участник
|
Нашел, как через WinAPI, но не помогло, может буфер только в приложениями работает, а с сервисными процессами нет?
|
|
13.05.2010, 16:52 | #14 |
Участник
|
Нашел способ: из буфера в файл, из файла макросом в эксель, но не построчная. Макрос выполняет импорт данных из указанного файла (в котором текст с табуляторами) в указанную ячейку.
|
|
13.05.2010, 17:04 | #15 |
Moderator
|
Цитата:
P.S. А вообще, если бы вы перешли на использование вывода в Excel при помощи ADODB.Recordset, то у этого объекта есть два метода Save и Open и они бы замечательно вам подошли. После заполнения рекодсета в оперативной памяти можно сохранить его в файле при помощи recordset.Save(имяФайла). Далее файл передаете куда надо. И наконец на другом компе открываете recordset.Open(имяТогоЖеФайла). Файл можно даже не смотреть - он записывается в специальном, не читаемом человеком, формате, но можно принудительно указать и XML (если сильно хочется). Последний раз редактировалось Gustav; 13.05.2010 в 17:35. |
|
14.05.2010, 13:05 | #16 |
Участник
|
Способов уйма (Хоть через ADO, OpenXML, OS Office Calc ....), но они все требуют значительной переработки каждого отчета. нужен был способ не требующи последнего.
Не все данны вставлялись при помощи буфера, часть вписывалась непосредственно в ячейку, а форматирование ... |
|
24.02.2011, 14:44 | #17 |
Участник
|
здравствуйте уважаемые.
Подскажите пожалуйста как решить следующую проблему: Выводим данные в Эксел 2010 с помощью ComExcelDocument_RU. Корсчет банка 30101810100000000859 - выводится в виде экспоненциальной формы представления числа. Как это победить? Переводил корсчет в строку до экспорта, столбец, в который выводится счет, делал текстовым- не помогает. Заранее благодарен за ответ.
__________________
Александр |
|
24.02.2011, 14:51 | #18 |
Moderator
|
Апостроф в начало коррсчета не катит ? Типа вот так: '30101810100000000859
|
|
24.02.2011, 14:52 | #19 |
Участник
|
Это крайний вариант.
__________________
Александр |
|
24.02.2011, 15:00 | #20 |
Moderator
|
Так, а чего? Он же никому не мешает - ни сортировке, ни обратной выгрузке куда-либо, ни работе функции ДЛСТР и т.п...
Ну, конечно, если хочется себя занять, то займите - никто Вас отговаривать не будет. Но кончится тем, что Вы поменяете ComExcelDocument_RU на выгрузку с использованием ADO и CopyFromRecordset - там этой проблемы нет |
|