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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 12.03.2009, 17:36   #21  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1148 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от Antoncheg Посмотреть сообщение
все работает за исключением последнего куска, выводится файл .xls, но данные остаются в ячейках A1 и A2
ммм... ну правильно всё, мы ж удалили 10 вспомогательных промежуточных колонок, и ячейки K1 и K2 "переехали" соответственно в A1 и A2.
Или вам нужны промежуточные "нарезанные" результаты? Ну, не удаляйте их тогда
Старый 12.03.2009, 17:56   #22  
Antoncheg is offline
Antoncheg
Участник
 
41 / 11 (1) +
Регистрация: 29.02.2008
Цитата:
Сообщение от Gustav Посмотреть сообщение
ммм... ну правильно всё, мы ж удалили 10 вспомогательных промежуточных колонок, и ячейки K1 и K2 "переехали" соответственно в A1 и A2.
Или вам нужны промежуточные "нарезанные" результаты? Ну, не удаляйте их тогда
Спасибо, разобрался, к вечеру сломан мозг, знаете ли с такими конструкциями
Старый 13.03.2009, 11:25   #23  
Antoncheg is offline
Antoncheg
Участник
 
41 / 11 (1) +
Регистрация: 29.02.2008
Сегодня попробовал применить результаты на практике, вот что у меня вышло

X++:
void Exec(str Path,SnQueryTableTmp SnQ)
{

   str strValue;
   str strFormula;
   COMVariant sep;

   #define.xlPasteValues(-4163)
   #define.xlListSeparator(5)
   ;


    xlApp = new COM('Excel.Application');
    xlApp.Visible(true);

    wbks = xlApp.Workbooks();
    wbk = wbks.Add();
    wkss = wbk.Worksheets();
    wks = wkss.Add();
    wks  = wkss.Item(1);
    wks.Name('Итог');
    rng = wks.Range('A1');

//==================================Первая вкладка=======================
    rstAxa = new COM('ADODB.Recordset');
    flds = rstAxa.Fields();

    flds.Append('Дата закрытия'                  ,this.adoTypeToExcel('date'));
    flds.Append('Отгрузочная накладная'          ,this.adoTypeToExcel('str'));
    flds.Append('Заказ'                          ,this.adoTypeToExcel('str'));
    flds.Append('Безналичная накладная'          ,this.adoTypeToExcel('str'));
    flds.Append('Менеджер'                       ,this.adoTypeToExcel('str'));
    flds.Append('Код клиента'                    ,this.adoTypeToExcel('str'));
    flds.Append('Дата отгрузочной накладной'     ,this.adoTypeToExcel('date'));
    flds.Append('Город'                          ,this.adoTypeToExcel('str'));
    flds.Append('Краткое наименование'           ,this.adoTypeToExcel('str'));
    flds.Append('Номенклатура'                   ,this.adoTypeToExcel('str'));
    flds.Append('Код дет. в спецификации'        ,this.adoTypeToExcel('str'));
    flds.Append('Название'                       ,this.adoTypeToExcel('str'));
    flds.Append('Склад'                          ,this.adoTypeToExcel('str'));
    flds.Append('Цена ед.'                       ,this.adoTypeToExcel('num'));
    flds.Append('Себестоимость'                  ,this.adoTypeToExcel('num'));
    flds.Append('Количество'                     ,this.adoTypeToExcel('num'));
    flds.Append('Сумма по позиции'               ,this.adoTypeToExcel('num'));
    flds.Append('Прибыль'                        ,this.adoTypeToExcel('num'));
    flds.Append('Каталожный номер'               ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера1'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера2'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера3'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера4'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера5'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера6'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера7'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера8'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера9'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера10'                ,this.adoTypeToExcel('str'));
    flds.Append('Серийные номера11'                ,this.adoTypeToExcel('str'));
    flds.Append('REF'                            ,this.adoTypeToExcel('str'));
    flds.Append('Квота'                          ,this.adoTypeToExcel('str'));
    flds.Append('Конечный клиент'                ,this.adoTypeToExcel('str'));
    flds.Append('Номер партии'                   ,this.adoTypeToExcel('str'));

    rstAxa.Open();

   // SnQ.setTmpData(SnQ);

    while select SnQ

    {


    sep = xlApp.International(#xlListSeparator);
    strFormula = strFmt('=CONCATENATE(RC[-30]%2RC[-29]%2RC[-28]%2RC[-27]%2RC[-26]%2RC[-25]%2RC[-24]%2RC[-23]%2RC[-22]%2RC[-21])',
                 sep.bStr());
    strValue = strRep(SnQ.findSerialNumbersFromWMS(SnQ), 60);

    rstAxa.AddNew();
     //   fld = flds.Item('Каталожный номер');            fld.Value(SelloutMsTable.A_PartNumber);
    fld = flds.Item('Дата закрытия');                   fld.Value(SnQ.DeliveryDate);
    fld = flds.Item('Отгрузочная накладная');           fld.Value(SnQ.PickingListId);
    fld = flds.Item('Заказ');                           fld.Value(SnQ.SalesId);
    fld = flds.Item('Безналичная накладная');           fld.Value(SnQ.InvoiceIdElect);
    fld = flds.Item('Менеджер');                        fld.Value(SnQ.SalesResponsible);
    fld = flds.Item('Код клиента');                     fld.Value(SnQ.CustAccount);
    fld = flds.Item('Дата отгрузочной накладной');      fld.Value(SnQ.PickingListDate);
    fld = flds.Item('Город');                           fld.Value(SnQ.City);
    fld = flds.Item('Краткое наименование');            fld.Value(SnQ.NameAlial);
    fld = flds.Item('Номенклатура');                    fld.value(SnQ.ItemId);
    fld = flds.Item('Код дет. в спецификации');         fld.Value(SnQ.ChosenPartNumber);
    fld = flds.Item('Название');                        fld.Value(SnQ.ItemName);
    fld = flds.Item('Склад');                           fld.Value(SnQ.InventLocationId);
    fld = flds.Item('Цена ед.');                        fld.Value(SnQ.A_SalesPrice);
    fld = flds.Item('Себестоимость');                   fld.Value(SnQ.SalesCostPrice);
    fld = flds.Item('Количество');                      fld.Value(SnQ.Qty);
    fld = flds.Item('Сумма по позиции');                fld.Value(SnQ.Amount);
    fld = flds.Item('Прибыль');                         fld.Value(SnQ.SalesProfit);
    fld = flds.Item('Каталожный номер');                fld.Value(SnQ.A_PartNumber);
    fld = flds.Item('Серийные номера1');                 fld.Value(strFormula);
    fld = flds.Item('Серийные номера2');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера3');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера4');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера5');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера6');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера7');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера8');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера9');                 fld.Value(strValue);
    fld = flds.Item('Серийные номера10');                fld.Value(strValue);
    fld = flds.Item('Серийные номера11');                fld.Value(strValue);
    fld = flds.Item('REF');                             fld.Value(SnQ.REF);
    fld = flds.Item('Квота');                           fld.value(SnQ.InventQuotationId);
    fld = flds.Item('Конечный клиент');                 fld.Value(SnQ.EndPartnerCode);
    fld = flds.Item('Номер партии');                    fld.Value(SnQ.InventBatchId);

    rstAxa.Update();
    }


    cell = rng.Offset(1,0);
    cell.CopyFromRecordset(rstAxa);

    rng  = wks.Range('T2:T%');
    rng.FormulaR1C1( rng.Value() );
    rng.Copy();
    rng.PasteSpecial(#xlPasteValues);
    xlApp.CutCopyMode(true);

    rng = wks.Columns();
    rng = COM::createFromVariant(rng.Item('U:AD'));
    rng.Delete();

    rstAxa.close();
    actWin = xlApp.ActiveWindow();
  //  actWin.FreezePanes(true);

}
выдает ошибку "Общий сбой"
Старый 13.03.2009, 12:05   #24  
Antoncheg is offline
Antoncheg
Участник
 
41 / 11 (1) +
Регистрация: 29.02.2008
да, и если в наборе 1 серийный номер, то результат в виде скленных одних и тех же серийных номеров
Старый 13.03.2009, 12:31   #25  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1148 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Ой, йо... Вы не воспринимайте всё уж так буквально в моем джобе!! Там strValue пишется одинаково во все 10 колонок только для того, чтобы В РАМКАХ ПРИМЕРА чем-то их заполнить а-ля "60 серийников" - ну не генерить же мне 600 тестовых уникальных значений! Точно так же функция strRep у меня используется для формирования строки из 60 одинаковых серийников: исходная строка "1234567890123, " повторяется 60 раз. Вы же подаете на вход этой функции свою длиннющую строку, уже содержащую сотни серийников и повторяете ее 60 раз - конечно Excel'ю плохеет! Наверное, строка получается больше и 911, и 32767 символов...
Цитата:
Сообщение от Antoncheg Посмотреть сообщение
да, и если в наборе 1 серийный номер, то результат в виде скленных одних и тех же серийных номеров
Ну, ясное дело, если его прописать одинаково во все 10 колонок! Между строк предполагалось, что Вы модифицируете свой алгоритм так, что для каждой из 10 колонок он будет возвращать очередные 60 серийников. При этом не забудьте откусить запятую и пробел после последнего серийника!

P.S. Подозреваю, что серийники нужно сначала прочитать в массив, а потом писать в колонки: в колонку 1 - с 1-го по 60-й, в колонку 2 - с 61-го по 120-й, в колонку 3 - с 121-го по 180-й и т.д. Добавляя запятую и пробел после каждого серийника и не делая этого после последнего серийника. А можно сразу в элемент массива записывать серийник+запятую+пробел (за исключением последнего). Соответственно, если заполненных элементов массива меньше 600, то оставшиеся непрописанными элементы массива будут давать пустые строки, которые при слиянии в Excel не окажут никакого влияния на результат. Остались неясности?
За это сообщение автора поблагодарили: Antoncheg (1).
Старый 16.04.2009, 12:11   #26  
Antoncheg is offline
Antoncheg
Участник
 
41 / 11 (1) +
Регистрация: 29.02.2008
Коллеги, еще вопросик, внедрил данный код, работает успешно, но на машинах с английским офисом. На русском эксель выдает вместо результата формулы #ИМЯ?, попробовал заменить CONCACENATE на СЦЕПИТЬ, в русском работает (офисе), английском - нет. Возможно ли как-нибудь обойти данную ситуацию? Заранее благодарен!
Старый 16.04.2009, 13:07   #27  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1148 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Фрагмент для превращения текста в формулы и затем в значения (типа нижеследующего) на правильный столбец настроен?
X++:
    rng  = wks.Range('T2:T%');
    rng.FormulaR1C1( rng.Value() );
    rng.Copy();
    rng.PasteSpecial(#xlPasteValues);
    xlApp.CutCopyMode(true);
Старый 16.04.2009, 13:23   #28  
Antoncheg is offline
Antoncheg
Участник
 
41 / 11 (1) +
Регистрация: 29.02.2008
Да все так
Старый 16.04.2009, 14:22   #29  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1148 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от Gustav Посмотреть сообщение
Можно проверить Application.LanguageSettings.LanguageID( msoLanguageIDInstall ) , где msoLanguageIDInstall = 1. Если 1033, то SHOW.DETAIL, а если 1049, то ПОКАЗАТЬ.ДЕТАЛИ.
Попробуйте аналогично проверить у себя языковые настройки. Что при английском и что при русском Excel'ях выдает?
Старый 16.04.2009, 17:31   #30  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1148 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Тема, на самом деле, интересная и до конца не решенная.
В интернете ответа пока не нашёл, но нашёл достаточно подробное описание проблемы:
http://www.gotdotnet.ru/Forums/Windows/107618.aspx
Цитата:
Сообщение от туда
Проблема состоит в следующем. Мне надо сформировать из проекта на C# таблицу в Excel. В ней кроме данных должны присутствовать и формулы - самые простые - Сумма. Проблема в том, что в разных версиях Excel функции называются по разному - СУММ() в русской версии, и SUM() - в английской. Мне надо, чтобы выходная таблица корректно формировалась независимо от локализации Excel'я. Среди свойств ячейки (диапазона) есть Formula и FormulaLocal. Как я полагал, в свойстве FormulaLocal хранится локализованный вариант формулы ( например, СУММ(E2:E8) ), а в Formula - независимый от локализации (то есть - SUM(E2:E8) ). Но когда я присваиваю при формировании таблицы из моей программы свойству Formula нужной ячейки значение "=SUM(E2:E8)", Excel его не понимает (экспериментирую с русской версией). Понимает только "=СУММ(E2:E8)". С русской версией Excel моя программа будет работать нормально, а как быть, если на машине пользователя стоит английская версия?
..........
(вопрошающему отвечают, но, как оказывается, не совсем удачно):
Используйте свойство Formula. Присваивайте ему формулу в АНГЛИЙСКОМ варианте.
Пример: Range("A10").Formula = "=SUM(A1:A9)"
В этом случае свойство FormulaLocal вернет правильную локализованную версию формулы: "=СУММ(A1:A9)" для русского офиса.
..........
В том то и дело, что это не работает. Я это указал в начальном письме. Если я присваиваю свойству Formula значение "=SUM(A1:A9)", то в ячейке появляется сообщение "#ИМЯ?", т.е. - формула содержит нераспознанный текст. А если я пишу макрос напрямую на VBA, не через C#, то тогда все нормально. Этот глюк не изменился и после апдейта на Office XP. Вот я и задал этот вопрос - может дело еще в чем-то.
Предлагаю Antoncheg'у и всем желающим поучаствовать в небольшом эксперименте, запустив следующий маленький джобик. Разыскиваются люди, у которых в боксе будет выдано значение 2.
X++:
static void Job161_TestFormula(Args _args)
{
    COM xlApp = new COM ('Excel.Application');
    COM wbk;
    COM rng;
    COMVariant cv;
    ;
    wbk = xlApp.Workbooks();
    wbk = wbk.Add();
    rng = xlApp.Range('A1');

    rng.Formula('=СУММ(1+1)'); 
    cv = rng.Text();

    // здесь ожидаются значения: #NAME? или #ИМЯ? или 2
    box::info(cv.bStr()); 

    wbk.Close(false); // чтобы не оставался скрытый экземпляр Excel
    xlApp.Quit();
}
Припоминаю, что эта проблема возникала у Ивана Кашперука в теме: Помогите сделать действие в Excel через COM . И мы тогда никакого вразумительного ответа не нашли, кроме того, что зафиксировали проблему
Старый 16.04.2009, 18:15   #31  
ivas is offline
ivas
Участник
Аватар для ivas
 
247 / 65 (3) ++++
Регистрация: 22.12.2005
Цитата:
Предлагаю Antoncheg'у и всем желающим поучаствовать в небольшом эксперименте, запустив следующий маленький джобик. Разыскиваются люди, у которых в боксе будет выдано значение 2.
выдало 2
русский офис 2007
__________________
aLL woRk aNd nO JoY MAKes jAck a dULL Boy
Старый 16.04.2009, 19:23   #32  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1148 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
ivas, спасибо! Значит, всё-таки, это нам не снится, а происходит наяву... угу...

Что ж, можно попробовать поразбираться дальше, померяться региональными и иными настройками. Пока же предлагаю (надеюсь, как временное решение) написанный по горячим следам статический метод для определения языка формул:
X++:
// Определение языка формул Excel для свойства Range.Formula
// (именно Formula, а не FormulaLocal !!!)
// подробности см. здесь: 
// [noparse]http://www.axforum.info/forums/showthread.php?p=195646#post195646[/noparse]

// СПОСОБ:
// помещаем в "международное" свойство формулу на русском языке
// и проверяем последующую реакцию Excel
// по окончании проверки удаляем временные объекты
static str excelFormulaLanguage(COM _excelApplication = null)
{
    str         ret;
    COM         workbook;
    COM         range;
    COMVariant  rangeText;
    boolean     separateSession = false;
    ;

    // если сессия не передается параметром...
    if (! _excelApplication)
    {
        // ...то пробуем прицепиться к существующей
        _excelApplication = COM::getObject('Excel.Application');

        // если существующей тоже нет...
        if (! _excelApplication)
        {
            // то создаем отдельную - кратковременную - только лишь для определения языка
            _excelApplication = new COM('Excel.Application');
            separateSession = true;
        }
    }

    workbook = _excelApplication.Workbooks();
    workbook =  workbook.Add();
    range    = _excelApplication.Range('A1');

    // помещаем в "международное" свойство формулу на русском языке
    // и проверяем последующую реакцию Excel
    range.NumberFormat('0'); // на всякий случай
    range.Formula('=СУММ(1+1)');
    range.Calculate(); // на всякий случай
    rangeText = range.Text();

    if (rangeText.bStr()=='2')  // здесь ожидаются значения: #NAME? или #ИМЯ? или 2
        ret = 'Russian';
    else
        ret = 'English';

    workbook.Close(false); // закрываем без сохранения нашу временную книгу

    if (separateSession)
        _excelApplication.Quit();

    return ret;
}
Старый 17.04.2009, 07:22   #33  
ViV is offline
ViV
Axapta Retail User
Самостоятельные клиенты AX
Axapta Retail User
 
200 / 79 (3) ++++
Регистрация: 14.09.2005
Цитата:
Сообщение от Gustav Посмотреть сообщение
Предлагаю Antoncheg'у и всем желающим поучаствовать в небольшом эксперименте, запустив следующий маленький джобик. Разыскиваются люди, у которых в боксе будет выдано значение 2.
Аналогично как и у ivas - выдало 2 на русском офисе 2007.
Старый 24.06.2009, 16:34   #34  
Antoncheg is offline
Antoncheg
Участник
 
41 / 11 (1) +
Регистрация: 29.02.2008
Давно не заглядывал в этот топик, вот результат #NAME?
Офис 2003 сп3 английский

Последний раз редактировалось Antoncheg; 24.06.2009 в 17:09.
Старый 24.06.2009, 17:32   #35  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1148 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от Antoncheg Посмотреть сообщение
Давно не заглядывал в этот топик, вот результат #NAME?
Офис 2003 сп3 английский
соответственно, для этого вашего случая описанный выше метод excelFormulaLanguage вернет "English" и для range.Formula() надо будет использовать идентификатор функции "CONCATENATE" (а не "СЦЕПИТЬ").

Последний раз редактировалось Gustav; 25.06.2009 в 00:36.
Старый 26.06.2009, 10:48   #36  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,555 / 2404 (86) +++++++++
Регистрация: 20.08.2005
Проблемы со свойствами Formula и FormulaR1C1 - в способе их вызова из Ax

Все функции из Com-объектов вызываются не напрямую, а через специальный интерфейс IDispatch, в котором реализуется пара методов IDispatch::GetIdOfNames и IDispatch::Invoke. Первый метод по имени функции возвращает ее идентификатор (DispId), а второй - вызывает по этому идентификатору функцию выполнения.
В обоих этих методах в качестве входного параметра присутствует языковый идентификатор - LCID. И Excel, как многоязыковая система, использует этот идентификатор для определения используемого языка. Т.е., если вызвать Formula() с параметром языка 0x0409 (en-Us), то функция внутри будет оперировать с передаваемыми данных, считая их англоязычными, если передать 0x0419 (ru), то, соответственно, русскоязычными.
Dax при вызове подставляет константу LOCALE_USER_DEFAULT, что соответствует языку интерфейса по умолчанию, что для русского интерфейса Windows аналогично вызову Invoke() с параметром 0x0419 (ru) - отсюда и проблемы с интерпретацией буфера. Excel требует вводить имена функций на русском.
В VBA при вызове подставляется другая константа LOCALE_NEUTRAL (0x0000). Эту константу Excel интерпретирует как код языка по умолчанию и требует вводить английские (точнее, американские) имена функций.
Фактически, свойства Formula и FormulaR1C1 позволяют использовать любой язык, поддерживаемый Excel

Свойства FormulaLocal и FormulaR1C1Local игнорируют передаваемый LCID и всегда используют LOCALE_USER_DEFAULT, что и приводит к одинаковым результатам при вызове из AX всех этих свойств

Ну и в заключение, я набросал небольшую DLL, с помощью которой можно делать языконезависимый вызов свойств Formula и FormulaR1C1 из Ax
X++:
static void ExcelFormula(Args _args)
{
    COM xlApp;
    COM wbk;
    COM rng;
    COMVariant cv;
    int iDispatch;

    DLL             _DLL      = new DLL("ComCall.dll");
//Получение DispId для свойства Formula
    DllFunction     FormulaDispId = new DllFunction(_dll, "FormulaDispId");
//Получение DispId для свойства FormulaR1C1
    DllFunction     FormulaR1C1DispId = new DllFunction(_dll, "FormulaR1C1DispId");

//Установка свойства Formula для указанного объекта Range
    DllFunction     SetFormula = new DllFunction(_dll, "Set_Formula");
//Получение свойства Formula для указанного объекта Range
//первый вызов - для получения размера используемого буфера результата
    DllFunction     GetFormulaLen = new DllFunction(_dll, "Get_Formula");
//второй вызов - для получения свойства
    DllFunction     GetFormula = new DllFunction(_dll, "Get_Formula");
    int             dispId;
    int             dispIdR1C1;
    Binary          buf;
    int             len;
    ComVariant      var;
    ;
    FormulaDispId.returns(ExtTypes::DWord);
    FormulaDispId.arg(ExtTypes::DWord);

    FormulaR1C1DispId.returns(ExtTypes::DWord);
    FormulaR1C1DispId.arg(ExtTypes::DWord);

    SetFormula.returns(ExtTypes::DWord);
    SetFormula.arg(ExtTypes::DWord, ExtTypes::DWord, ExtTypes::String);

    //Для получения размера буфера
    GetFormulaLen.returns(ExtTypes::DWord);
    GetFormulaLen.arg(ExtTypes::DWord, ExtTypes::DWord, ExtTypes::Dword);

    //Для получения результата буфера
    GetFormula.returns(ExtTypes::DWord);
    GetFormula.arg(ExtTypes::DWord, ExtTypes::DWord, ExtTypes::Pointer);

    xlApp = new COM ('Excel.Application');

    wbk = xlApp.Workbooks();
    wbk = wbk.Add();
    rng = xlApp.Range('A1');

    iDispatch = rng.interface();

    dispId = FormulaDispId.call(iDispatch);
    dispIdR1C1 = FormulaR1C1DispId.call(iDispatch);

    SetFormula.Call(iDispatch, dispId, '=sum(B1:D1)');

    cv = rng.Text();
    print cv.bStr();

    len = GetFormulaLen.call(iDispatch, dispId, 0);
    buf = New Binary(len+1);
    GetFormula.call(iDispatch, dispId, buf);
    print "dll " + buf.string(0);

    len = GetFormulaLen.call(iDispatch, dispIdR1C1, 0);
    buf = New Binary(len+1);
    GetFormula.call(iDispatch, dispIdR1C1, buf);
    print "dll R1C1 " + buf.string(0);

    var = rng.formula();
    print "Dax " + var.bStr();

    rng = xlApp.Range('A2');
    rng.Formula('=sum(B1:D1)');
    cv = rng.Text();

    print cv.bStr();

    wbk.Close(False); // чтобы не оставался скрытый экземпляр Excel
    xlApp.Quit();
    pause;
}
Несколько комментариев
  1. Первый параметр, передаваемый во все функции - интерфейс IDispatch требуемого объекта. Можно получить с помощью вызова com.Interface(). DLL работает только c объектом RANGE
  2. Пары функций Set_Formula() и Get_Formula() позволяет работать как со свойством Formula, так и FormulaR1C1
    Второй параметр - значение DispId требуемой функции (эти значения можно получить с помощью FormulaDispId() и FormulaR1C1DispId()), если передавать 0, то будет использоваться вызов свойства Formula.
    Если необходим массовый вызов функций, то рекомендую сначала получить DispID и сохранить его, а затем подставлять это значение в вызовы, что увеличит скорость работы (не будет постоянных поисков необходимого dispId)
  3. Третий параметр для Set_Formula() - строка, содержащая в себе необходимую формулу на английском языке. Функция возвращает 1 в случае успешного выполнения[/B]
  4. Третий параметр для Get_Formula() - ссылка на буфер, в который будет помещена строка с формулой (или другим значением, содержащимся в ячейке) на английском языке. Функция возвращает размер требуемого буфера (без учета нулевого символа в конце). Можно использовать двумя способами.
    Первый способ - сначала получить размер буфера, передав в третий параметр 0. После этого создать буфер требуемого размера и еще раз сделать вызов, передав уже его в вызов третьим параметром
    Второй способ - создать буфер большого размера и подставлять в вызов его. В этом случае возможно получение исключения, если данные все-таки будут больше
Вложения
Тип файла: zip ComCall.zip (35.3 Кб, 43 просмотров)
__________________
Axapta v.3.0 sp5 kr2
За это сообщение автора поблагодарили: Wamr (5), tolstjak (1), ZVV (2), Antoncheg (1).
Старый 30.06.2009, 13:14   #37  
Antoncheg is offline
Antoncheg
Участник
 
41 / 11 (1) +
Регистрация: 29.02.2008
Цитата:
Сообщение от Gustav Посмотреть сообщение
соответственно, для этого вашего случая описанный выше метод excelFormulaLanguage вернет "English" и для range.Formula() надо будет использовать идентификатор функции "CONCATENATE" (а не "СЦЕПИТЬ").
Да, но если на разных машинах установлены разные версии офиса, становится проблематично...
Старый 01.07.2009, 16:24   #38  
tolstjak is offline
tolstjak
Участник
 
440 / 16 (1) ++
Регистрация: 05.01.2003
Недавно стал разбираться с возможностью использования данного функционала при формировании отчетов в Эксел. Столкнулся с проблемой, которая для остальных возможно не является таковой.
Ее суть:

static void aaa_TestADO_2(Args _args)
{
// ----------------------------------------------------------------------------
// ADODB.Recordset в оперативной памяти без привязки к источнику данных
// ----------------------------------------------------------------------------
// EmplTable emplTable;
InventTrans inventTrans;
InventTable inventTable;
PurchLine purchLine;
InventDim inventDim;

Voucher voucher;
AccountNum account;
TransDate date1;
// TransDate toDate;
// TransDate nDate, date1;
ItemID itemID;
str itemName;
InventQTY qty;
InventTransRefID zakaz;
ItemGroupID itemGroupID;
SysDim podraz;
InventLocationID locationID;


COM rstAxa; // ADO: Recordset
COM flds, fld; // ADO: Fields, Field
COM xlApp; // Excel.Application
COM wbks, wbk; // Workbooks, Workbook
COM wkss, wks; // Worksheets, Worksheet
COM rng, cell, rngCR; // все Range
COM font; // Range.Font
COM entCol; // Range.EntireColumn
COM actWin; // Excel.Application.ActiveWindow
int i, iMax;



// ============================================================================
// СНАЧАЛА ВЛОЖЕННАЯ ФУНКЦИЯ
// ----------------------------------------------------------------------------
// функция для задания типа поля нашего Recordset-а в оперативной памяти
// в данном демо-джобе используется для наглядности
// для простоты используем всего 3 типа данных: число, строка и дата
int adoTypeToExcel(str _type)
{
switch (_type)
{
// используются значения констант перечисления DateTypeEnum из топика TypeProperty (ADO)
// (см. справку по ADO в файле ADO210.CHM - можно поискать на своем компе)
case 'num' : return 5; // adDouble
case 'str' : return 8; // adBSTR
case 'date': return 133; // adDBDate
case 'memo': return 203; // adLongVarChar


}
return 8;
}
// ============================================================================
// ТЕПЕРЬ ОСНОВНОЙ ПРОЦЕСС
// Recordset создается в оперативной памяти - без Connection!
rstAxa = new COM('ADODB.Recordset');
// формируем структуру нашего Recordset-а в "мозгах"
flds = rstAxa.Fields();
flds.Append('Zakaz' , adoTypeToExcel('str' ));
flds.Append('Voucher' , adoTypeToExcel('str' ));
flds.Append('Цех' , adoTypeToExcel('str' ));
flds.Append('НомГруппа', adoTypeToExcel('str' ));
flds.Append('Номенклатура' , adoTypeToExcel('str' ));
flds.Append('Наименование' , adoTypeToExcel('str' ));
flds.Append('Склад' , adoTypeToExcel('str' ));


// flds.Append('BirthDate' , adoTypeToExcel('date'));

flds.Append('Кол-во' , adoTypeToExcel('num' ));
flds.Append('Сумма' , adoTypeToExcel('num' ));

// и наконец открываем его
rstAxa.Open();
// ----------------------------------------------------------------------------
while select * from inventTrans
// where ((inventTrans.DateFinancial >= fromDate && inventTrans.DateFinancial <= toDate)
where ((inventTrans.DateFinancial >= 01\01\2009 && inventTrans.DateFinancial <= 31\05\2009)

&& inventTrans.TransType == 3)
// && inventTrans.StatusReceipt == 1)
join inventTable
where (inventTrans.ItemId == inventTable.ItemId && inventTable.dataAreaId == "ssm")

join purchLine
where (inventTrans.ItemId == purchLine.ItemId && inventTrans.InventTransId == purchLine.InventTransId)
join InventDim
where (inventTrans.inventDimId == inventDim.inventDimId)
{
itemID = inventTrans.ItemId;
itemName = inventTrans.itemName();
zakaz = inventTrans.TransRefId;
qty = inventTrans.Qty;
// amount0 = inventtrans.CostAmountPhysical;
amount0 = inventTrans.CostAmountPosted;
itemGroupID = inventTable.ItemGroupId;
podraz = purchLine.Dimension[2];
voucher = inventTrans.Voucher;
locationID = inventDim.InventLocationId;





// бежим по таблице "......." Axapta
// и добавляем записи (выбранные поля) в Recordset в оперативной памяти
rstAxa.AddNew();
// fld = flds.Item('Zakaz' ); fld.Value(inventTrans.TransRefId );
// fld = flds.Item('Voucher' ); fld.Value(inventTrans.Voucher );
fld = flds.Item('Цех' ); fld.Value(purchLine.Dimension[2] );
fld = flds.Item('НомГруппа' ); fld.Value(inventTable.ItemGroupId);
fld = flds.Item('Номенклатура' ); fld.Value(inventTrans.ItemId );
fld = flds.Item('Наименование' ); fld.Value(itemName);
fld = flds.Item('Склад' ); fld.Value(inventDim.InventLocationId );

// fld = flds.Item('BirthDate' ); fld.Value(emplTable.BirthDate );
fld = flds.Item('Кол-во' ); fld.Value(inventTrans.Qty );
fld = flds.Item('Сумма' ); fld.Value(inventTrans.CostAmountPosted );


rstAxa.Update();
}
// к этому моменту в оперативной памяти сформирована НАША таблица "Список сотрудников"
// ----------------------------------------------------------------------------
// перед выгрузкой в Excel встанем на первую запись НАШЕЙ ТАБЛИЦЫ В ПАМЯТИ
// и изменим имя сотрудника, дату его рождения и ID
// НЕ БОЙТЕСЬ!!! Аксаптовская таблица EmplTable при этом НЕ ЗАТРАГИВАЕТСЯ!!! ))
// rstAxa.MoveFirst();
// fld = flds.Item('Name' ); fld.Value('Самый молодой cотрудник с очень длинным именем');
// fld = flds.Item('BirthDate'); fld.Value(1\3\2006); // 1-е марта 2006 года
// fld = flds.Item('EmplId' ); fld.Value('000333');
// потом обратите внимание, что в Excel ведущие нули у 000333 сохранятся!
// rstAxa.Update();
// ----------------------------------------------------------------------------
// готовим новую рабочую книгу Excel для приема данных из Axapta:
xlApp = new COM('Excel.Application');
xlApp.Visible(true);
wbks = xlApp.Workbooks();
wbk = wbks.Add();
wkss = wbk.Worksheets();
wks = wkss.Item(1);
wks.Name('AdoTestSheet');
rng = wks.Range('A1');
// ----------------------------------------------------------------------------
// выводим строку имен полей (1-я строка листа Excel)
flds = rstAxa.Fields();
iMax = flds.Count() - 1;
for (i = 0; i <= iMax; i += 1)
{
fld = flds.Item(i);
cell = rng.Offset(0, i);
cell.Value2(fld.Name());
}
rngCR = rng.CurrentRegion();
font = rngCR.Font();
font.Bold(true); // делаем выведенные заголовки жирным шрифтом
// ----------------------------------------------------------------------------
// выводим данные, начиная со 2-й строки листа Excel
cell = rng.Offset(1, 0);
cell.CopyFromRecordset(rstAxa);
// ----------------------------------------------------------------------------
// подгоняем ширину столбцов Excel
rngCR = rng.CurrentRegion();
entCol = rngCR.EntireColumn();
entCol.AutoFit();
// замораживаем строку заголовков Excel
cell.Select();
actWin = xlApp.ActiveWindow();
actWin.FreezePanes(true);
// ----------------------------------------------------------------------------
rstAxa.Close();
}


С комментариями все работает, а если убрать комментарии со строк

// fld = flds.Item('Zakaz' ); fld.Value(inventTrans.TransRefId );
// fld = flds.Item('Voucher' ); fld.Value(inventTrans.Voucher );

выдается ошибка: Вариантный тип, который используется методом СОМ - объекта, не поддерживается.

В чем может быть засада??

Заранее благодарен.

P.S. Ах 30 SP1
office 2003 SP3
__________________
Александр
Старый 01.07.2009, 19:31   #39  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,462 / 969 (35) +++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от tolstjak
С комментариями все работает, а если убрать комментарии со строк

// fld = flds.Item('Zakaz' ); fld.Value(inventTrans.TransRefId );
// fld = flds.Item('Voucher' ); fld.Value(inventTrans.Voucher );

выдается ошибка: Вариантный тип, который используется методом СОМ - объекта, не поддерживается.

В чем может быть засада??

Заранее благодарен.

P.S. Ах 30 SP1
office 2003 SP3
Поля с правым выравниванием.

Хотя, вообще-то, в COM-объекты крайне не желательно передавать данные "как есть" (за исключением целочисленных). Лучше "оборачивать" их в ComVariant. В данном случае примерно так:

X++:
   ComVariant _comVariant;
    ;

    // и добавляем записи (выбранные поля) в Recordset в оперативной памяти
    rstAxa.AddNew();
    fld = flds.Item('Zakaz' );
    _comVariant = new ComVariant();
    _comVariant.bStr(inventTrans.TransRefId);
    fld.Value(_comVariant);

    fld = flds.Item('Voucher' ); 
    _comVariant.bStr(inventTrans.Voucher);
    fld.Value(_comVariant);
За это сообщение автора поблагодарили: tolstjak (1).
Старый 01.07.2009, 21:27   #40  
tolstjak is offline
tolstjak
Участник
 
440 / 16 (1) ++
Регистрация: 05.01.2003
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Поля с правым выравниванием.

Хотя, вообще-то, в COM-объекты крайне не желательно передавать данные "как есть" (за исключением целочисленных). Лучше "оборачивать" их в ComVariant. В данном случае примерно так:

X++:
   ComVariant _comVariant;
    ;

    // и добавляем записи (выбранные поля) в Recordset в оперативной памяти
    rstAxa.AddNew();
    fld = flds.Item('Zakaz' );
    _comVariant = new ComVariant();
    _comVariant.bStr(inventTrans.TransRefId);
    fld.Value(_comVariant);

    fld = flds.Item('Voucher' ); 
    _comVariant.bStr(inventTrans.Voucher);
    fld.Value(_comVariant);
Все получилось. Большое спасибо.
__________________
Александр
Теги
ado, excel, экспорт

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Исследование скорости экспорта данных из Axapta в Excel (коллективный эксперимент) Gustav DAX: База знаний и проекты 79 13.02.2014 13:18
[Excel] - Несколько версий Excel на машине клиента Андре DAX: Программирование 11 07.08.2007 13:45
Вызов Item() для коллекций Excel Владимир Максимов DAX: Программирование 15 17.08.2006 19:47
"Такая строка уже сущ." при переносе из Excel! Zelenhof DAX: Программирование 2 13.01.2003 13:41
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 22:33.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.