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,701 / 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,701 / 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.
Теги
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, время: 05:10.