AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 15.04.2010, 10:37   #1  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
Lightbulb Экспорт в 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  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Вот это читали? Параметры pastespecial()

И может покажете фрагмент кода пошире, чем просто один оператор? Вы буфер как заполняете перед тем, как pasteSpecial применять?
Старый 15.04.2010, 12:51   #3  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
да смотрел, вот код:
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  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Попробуйте сделать по аналогии с этим моим сообщением: Параметры pastespecial()

А именно:

1. Закомментируйте у себя строку "XLSrange.select();" - она ни к чему в моем случае
2. Вместо "XLSWorkSheet.pasteSpecial(1);" напишите "XLSrange.pasteSpecial(1);"

Плюс обратите внимание вот на это: Ускорение экспорта в Excel - и там про терминал. Вы уверены, что буфер, передающийся в процедуру - тот, который нужен? Не происходит ли подмена на локальный или наоборот?

Последний раз редактировалось Gustav; 15.04.2010 в 13:30.
Старый 15.04.2010, 14:20   #5  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,691 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Вот это еще посмотри

http://forum.mazzy.ru/index.php?showtopic=385
За это сообщение автора поблагодарили: Gustav (2).
Старый 15.04.2010, 15:09   #6  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
To Gustav: смотрел конечно, у меня тоже все работало замечательно, пока не возникла необходимость формировать файл на сервере
XLSrange.pasteSpecial(1); то же не прокатило, ошибка в СOM объекте.

To Максимов: это и есть этот метод, и он круто работает, но только на клиенте.

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

думаю может то что AOS работает как сервис, и у него проблема с буфером, потому как в 2-х уровневом тоже все работает.
Старый 15.04.2010, 16:10   #7  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от kair84 Посмотреть сообщение
To Максимов: это и есть этот метод, и он круто работает, но только на клиенте.
kair84, Владимир Максимов говорит о своем посте в теме по ссылке, который идёт за первым постом Максима Горбунова. Там говорится о проблеме "пустого" TextBuffer и кода в его методе значительно больше, чем в методе Максима Горбунова, который Вы используете (я не слишком витиеват ?)

Проверьте свой TextBuffer внутри своего метода перед pasteSpecial.
Старый 15.04.2010, 16:47   #8  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
Излогаешь вполне понятно, я прочитал тот пост, у меня др. случай, сожержание буфера корректное.
Кроме AOSа, серьезного там ничего нет, буфер по идее не используется.

Последний раз редактировалось kair84; 15.04.2010 в 16:53.
Старый 16.04.2010, 09:11   #9  
player is offline
player
Участник
 
107 / 69 (3) ++++
Регистрация: 25.08.2007
В свете новых веяний - не кошерно использовать Excel для серверной автоматизации.
Рекомендуется формировать сразу xlsx файлы посредством MS OpenXML SDK (_http://openxmldeveloper.org), или сторонних продуктов. Скорость формирования выше в разы, по сравнению с COM автоматизацией.
За это сообщение автора поблагодарили: S.Kuskov (2).
Старый 16.04.2010, 11:41   #10  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,691 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
У нас, в основном, работа с 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("Ошибка при копировании данных через буфер обмена.");
    }
}
Однако даже явный "пинок" буфера обмена далеко не всегда заставляет его инициализироваться. Поэтому следующий вариант - это отображение созданного экземпляра Excel перед его наполнением. Т.е. открытие Excel выглядит так

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  
player is offline
player
Участник
 
107 / 69 (3) ++++
Регистрация: 25.08.2007
Серьезно - если есть время уйти от этих танцев с бубнами, посмотрите на вариант переделки класса ComExcelDocument_RU для работы через OpenXML. Если у пользователей не у всех еще 2007 - можно ставить дополнение для открытия файлов xlsx в 2003 office или вообще бесплатный Excel Viewer от MS.
Старый 30.04.2010, 13:04   #12  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
С XLSrange.value2 отрабатывает, в ошибку не валится, но вставляет пустой буфер, видимо класс TxtBuffer от имени процесса AOSа не может передать данные в ClipBoard операционки, с видимым не видимым excel, тоже не получается, в обоих случаях эксель остается не видимым. есть вариант запихнуть данные в буфер через WinAPI, но как это сделать я пока не знаю

Кто работал с буфером через WinAPI ? как в него передать форматированную строку? если можно примеры...
Старый 30.04.2010, 15:42   #13  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
Нашел, как через WinAPI, но не помогло, может буфер только в приложениями работает, а с сервисными процессами нет?
Старый 13.05.2010, 16:52   #14  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
Нашел способ: из буфера в файл, из файла макросом в эксель, но не построчная. Макрос выполняет импорт данных из указанного файла (в котором текст с табуляторами) в указанную ячейку.
Старый 13.05.2010, 17:04   #15  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от kair84 Посмотреть сообщение
Нашел способ: из буфера в файл, из файла макросом в эксель, но не построчная. Макрос выполняет импорт данных из указанного файла (в котором текст с табуляторами) в указанную ячейку.
Так а вы просто своему файлу дайте расширение не TXT, а XLS. И прямо Excel'ем открывайте. И получится без макросов.

P.S. А вообще, если бы вы перешли на использование вывода в Excel при помощи ADODB.Recordset, то у этого объекта есть два метода Save и Open и они бы замечательно вам подошли. После заполнения рекодсета в оперативной памяти можно сохранить его в файле при помощи recordset.Save(имяФайла). Далее файл передаете куда надо. И наконец на другом компе открываете recordset.Open(имяТогоЖеФайла). Файл можно даже не смотреть - он записывается в специальном, не читаемом человеком, формате, но можно принудительно указать и XML (если сильно хочется).

Последний раз редактировалось Gustav; 13.05.2010 в 17:35.
Старый 14.05.2010, 13:05   #16  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
Способов уйма (Хоть через ADO, OpenXML, OS Office Calc ....), но они все требуют значительной переработки каждого отчета. нужен был способ не требующи последнего.
Не все данны вставлялись при помощи буфера, часть вписывалась непосредственно в ячейку, а форматирование ...
Старый 24.02.2011, 14:44   #17  
tolstjak is offline
tolstjak
Участник
 
440 / 16 (1) ++
Регистрация: 05.01.2003
здравствуйте уважаемые.

Подскажите пожалуйста как решить следующую проблему:
Выводим данные в Эксел 2010 с помощью ComExcelDocument_RU.
Корсчет банка 30101810100000000859 - выводится в виде экспоненциальной формы представления числа. Как это победить?
Переводил корсчет в строку до экспорта, столбец, в который выводится счет, делал текстовым- не помогает.

Заранее благодарен за ответ.
__________________
Александр
Старый 24.02.2011, 14:51   #18  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Апостроф в начало коррсчета не катит ? Типа вот так: '30101810100000000859
Старый 24.02.2011, 14:52   #19  
tolstjak is offline
tolstjak
Участник
 
440 / 16 (1) ++
Регистрация: 05.01.2003
Цитата:
Сообщение от Gustav Посмотреть сообщение
Апостроф в начало кода не катит ? Типа вот так: '30101810100000000859
Это крайний вариант.
__________________
Александр
Старый 24.02.2011, 15:00   #20  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от tolstjak Посмотреть сообщение
Это крайний вариант.
Так, а чего? Он же никому не мешает - ни сортировке, ни обратной выгрузке куда-либо, ни работе функции ДЛСТР и т.п...

Ну, конечно, если хочется себя занять, то займите - никто Вас отговаривать не будет. Но кончится тем, что Вы поменяете ComExcelDocument_RU на выгрузку с использованием ADO и CopyFromRecordset - там этой проблемы нет
Теги
excel, pastespecial

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Вывод всех меток из заданного уровня на заданных языках в Excel wojzeh DAX: Программирование 0 19.03.2010 23:45
Помогите сделать действие в Excel через COM kashperuk DAX: Программирование 25 10.09.2007 15:59
dynamicsusers: DL Tips And Tricks: ADO Database Reader (Jet way) - Excel Example Blog bot DAX Blogs 0 02.08.2007 03:50
Экспорт в Excel - поле формата "Дата" Ned DAX: Программирование 15 25.04.2003 10:01

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 02:06.