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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 05.06.2007, 12:06   #1  
SHiSHok is offline
SHiSHok
Участник
Аватар для SHiSHok
Дети Юза
 
219 / 103 (4) +++++
Регистрация: 28.07.2005
Адрес: Донецк
! контейнер: += трагедия вставки пустой строки.
предлагаю вашему вниманию очередную бочину в энджине аксапты (ax3sp2):
демонстрирует его следующий джобик: кодирует строку в штрих код с попутной вставкой пустой строки в контейнер.
X++:
#define.bug(0)
#define.showstep(1)
#define.str2code("123")

static void Job144(Args _args)
{
container   ret1;
str         cret;
int         clen;
int         i;

// кодирует barcode
str  encode(str _string)
{
    DLLFunction         _BC_Code128;
    DLL                 _barcodeDLL;
    str                 barcodeStr;
;
    try
    {
        _barcodeDLL = new DLL('Bcfont32');
    } catch(Exception::Internal)
    {
        info("barcodeDLL error!!!");
        return '';
    }
    _BC_Code128 = new DLLFunction(_barcodeDLL,'BC_Code128');
    _BC_Code128.returns(ExtTypes::STRING);
    _BC_Code128.arg(ExtTypes::STRING);
    barcodeStr = _BC_Code128.call(_string);
    _barcodeDLL = null;
    _BC_Code128 = null;
    return barcodeStr;
}

;
    try
    {
        cret =  encode(#str2code);
        info("до вставки в контейнер : '"+cret+"'");
        for(i=1;i<10;i++)
        {
            #if.bug(1)
                ret1 += "";
            #endif
            #if.bug(0)
                ret1 = conins(ret1,conlen(ret1)+1,"");
            #endif
            #if.showstep(1)
                cret =  encode(#str2code);
                info(strfmt("вставка %1, строка: '%2', баркод: '%3'",i,#str2code,cret));
            #endif
        }
        cret =  encode(#str2code);
    }
    catch
    {
        info("catch !!!");
    }

    info("после вставки в контейнер : '"+cret+"'");
}
В джобике проверяю как отрабатывает вызов dll функции после разных методов вставки в контейнер: ret1 += "" и ret1 = conins(ret1,conlen(ret1)+1,"")

для начала ставим #define.bug(0) -> происходит 10 вставок в контейнер с помощью conins + 10 удачных кодирований.
теперь ставим #define.bug(1) -> происходит 10 вставок в контейнер оператором += и 10 кодирований из которых 3 правильно, остальные нет.
для чистоты эксперимента можно исключить вызов кодирования в каждой итерации #define.showstep(0).
(совсем забыл, после того как контейнер "уложит" вызов ф-ции кодирования, функция уже нормально не отработает - перезапуск клиента). Т.е. нарушение каких то внутренних структур на лицо.

Вывод: не использовать для контейнера оператор +=<str>

PPS: вывод оказался не верным, что не может не радовать - базовые операторы таки работают нормально.
__________________
--- SHiSHok

Последний раз редактировалось SHiSHok; 06.06.2007 в 16:24. Причина: более понятно написал
Старый 05.06.2007, 12:10   #2  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Можно свофрмулировать более явно (что происходит при вставке пустой строки) и привести минимальный пример?
Старый 05.06.2007, 12:14   #3  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Тоже долго не мог понять, в чем собственно дело.
Если правильно понял, автор пишет, что при использовании += "" для контейнеров перестает правильно происходить преобразование через DLL вызов (возвращает саму строку 123).
С самим контейнером все ОК вне зависимости от того, как вставлять значения
Старый 05.06.2007, 12:20   #4  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
Эффекта, кажется, можно добиться и без контейнера. Эта гадкая barcodeDLL, похоже, не совсем stateless. Если ее в цикле вызывать, она рано или поздно ломается как описано. А если вручную, с участием пользователя, со всеми вытекающими задержками, то все нормально.
Старый 05.06.2007, 12:33   #5  
SHiSHok is offline
SHiSHok
Участник
Аватар для SHiSHok
Дети Юза
 
219 / 103 (4) +++++
Регистрация: 28.07.2005
Адрес: Донецк
для тех у кого все работает (интересно на каком паке работает), поясняю:
в случае с ret1 += "" вызов DLL у меня лажается на 4-й итерации.
в случае с ret1 = conins(ret1,conlen(ret1)+1,"") вызов DLL отрабатывает корректно и на 1000 итераций с вызовом DLL на каждой итерации (не вижу проблем с DLL)
результы у меня:

1) #define.bug(0), окно инфолог:
до вставки в контейнер : '%"$"*%&*!&!*#&"')!1'
вставка 1, строка: '123', баркод: '%"$"*%&*!&!*#&"')!1'
вставка 2, строка: '123', баркод: '%"$"*%&*!&!*#&"')!1'
вставка 3, строка: '123', баркод: '%"$"*%&*!&!*#&"')!1'
вставка 4, строка: '123', баркод: '%"$"*%&*!&!*#&"')!1'
после вставки в контейнер : '%"$"*%&*!&!*#&"')!1'


2) #define.bug(1), окно инфолог:
до вставки в контейнер : '%"$"*%&*!&!*#&"')!1'
вставка 1, строка: '123', баркод: '%"$"*%&*!&!*#&"')!1'
вставка 2, строка: '123', баркод: '%"$"*%&*!&!*#&"')!1'
вставка 3, строка: '123', баркод: '%"$"*%&*!&!*#&"')!1'
вставка 4, строка: '123', баркод: '123'
после вставки в контейнер : '123'


ЗЫ: пойман глюк был на баркоде, посему вызов баркода для демонстрации и предлагаю (на длительные эксперименты нет времени)
__________________
--- SHiSHok

Последний раз редактировалось SHiSHok; 05.06.2007 в 12:37.
Старый 06.06.2007, 11:04   #6  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
Контейнеры здесь не при чем.
Все дело в том, что входной параметр функции в dll имеет тип BSTR, а не LPSTR, который вы передаете в нее.
Особенность этого типа (BSTR) в том, что он хранит размер строки (ну и еще - это юникод). Причем, это размер хранится в первых четырех байтах памяти, в которой размещена строка. В функцию передается не начало блока (где хранится размер), а смещение на четыре байта, т.е. указатель на саму строку. За счет этого такой тип можно передавать как обычную юникодную строку.
Если вызываемая функция ожидает в параметре тип BSTR, то она может проверить размер строки, просто обратившись к памяти по смещению -4 от начала стороки (для этого есть специальные функции в OLE API).

Что происходит в вашем случае - вы передаете в качестве параметра обычную строку (тип LPSTR или char * для языка C). Этот тип не предусматривает хранение размера перед сторокой, по-этому при размещении в памяти данные копируются с начального адреса. При этом, блок памяти выделяется системой последовательно после уже размещенного в памяти другого объекта. Если в последнем двойном слове этого объекта не ноль, то проверка на размер для типа BSTR верное какое-то число (конечно, это не размер строки, но проверка обычно идет на !0) и алгоритм отработает, как если бы тип был правильный. Если же 0 - то просто возвращается входная строка.

Ну и на последок - пример рабочего кода
X++:
str  encode(str _string)
{
    DLLFunction         _BC_Code128;
    DLL                 _barcodeDLL;
    str                 barcodeStr;
    ComVariant          var = ComVariant::createFromStr(_string);
;
    try
    {
        _barcodeDLL = new DLL('Bcfont32');
    } catch(Exception::Internal)
    {
        info("barcodeDLL error!!!");
        return '';
    }
    _BC_Code128 = new DLLFunction(_barcodeDLL,'BC_Code128');
    _BC_Code128.returns(ExtTypes::String);
    _BC_Code128.arg(ExtTypes::DWord);
    barcodeStr = _BC_Code128.call(var.int());
    _barcodeDLL = null;
    _BC_Code128 = null;
    return barcodeStr;
}
Кстати, это самый простой способ получения юникода в Axapta 3.0
__________________
Axapta v.3.0 sp5 kr2
За это сообщение автора поблагодарили: EVGL (3), SHiSHok (2), petr (3), gl00mie (5), rumpleteazer (1), Logger (3).
Старый 06.06.2007, 15:37   #7  
SHiSHok is offline
SHiSHok
Участник
Аватар для SHiSHok
Дети Юза
 
219 / 103 (4) +++++
Регистрация: 28.07.2005
Адрес: Донецк
2AndyD: исчерпываюе, проверил - действительно так.
небольшой ремарк: дабы в джобике было все прозрачно вызов API функции выдрал из классов BarcodeCode128 (sys) - подлежит фиксу (за что ж такой сис слой ...)

PS: после прояснения ситуации немного отлегло - хоть базовая логика работает (а то уж думал : как дальше что то писать под ax, если баги в элементарных операциях) PPS: ко всему прочему остается добавить что вставка в контейнер операторами += и conins работает по разному (выделение памяти по крайней мере)
__________________
--- SHiSHok

Последний раз редактировалось SHiSHok; 06.06.2007 в 16:19.
Старый 24.09.2007, 12:38   #8  
petr is offline
petr
Участник
Соотечественники
 
561 / 201 (8) ++++++
Регистрация: 30.05.2005
Адрес: Швейцария
И хотя AndyD ответил достаточно исчерпывающе, все же у меня есть еще один вопрос по данной теме, а именно:

Для трансформации LPSTR в BSTR AndyD предлагает следующий код:
X++:
ComVariant var = ComVariant::createFromStr(_string);
;
_BC_Code128.arg(ExtTypes::STRING);
barcodeStr = _BC_Code128.call(var.int());
В KR3 Microsoft использует такую конструкцию (я так понимаю тоже для перевода строки из формата LPSTR в BSTR):
X++:
    _BC_OCode128.arg(ExtTypes::BStrAnsi);
barcodeStr = _BC_Code128.call(string);
Это одно и тоже или тут тоже могут быть подводные камни?
Старый 24.09.2007, 13:51   #9  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
Насчет KR3 не могу сказать, но в KR2 с ExtTypes::BStrAnsi картина точно такая, как при использовании ExtTypes::String. Т.е. передается обычная ANSI строка с нулевым байтом в конце и без установки размера строки в начальном двойном слове.

PS Вывод неверный - причина в следующем сообщении
__________________
Axapta v.3.0 sp5 kr2

Последний раз редактировалось AndyD; 25.09.2007 в 11:36.
Старый 25.09.2007, 11:35   #10  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
Хм.
Стал разбираться в функции BC_Code128 и вот какая картина открывается.

Внутри BC_Code128, для проверки правильности данных в передаваемой строке вызывается системная функция SysStringByteLen(), в которую в качестве параметра передается тип BSTR. Внутри этой функции и проверяется смещение на четые байта от начала строки - берется ее размер. Если там не ноль, то BC_Code128 считает, что строка валидная и обрабатывает ее.
А здесь начинаются чудеса. Обрабатывается уже не тип BSTR, а обыкновенная ANSI-строка. Т.е., получается, нужен некий аналог паскалевской строки.

Теперь о том, как ее получить.
Начиная с KR2 можно передавать строку как тип ExtTypes::BStrAnsi - как раз передается паскалевская строка в вызываемую функцию (опять же, ожидал увидеть юникод, по-этому в предыдущем сообщении сделал неверный вывод).
Если не установлен KR2 или выше, то можно использовать такой код
X++:
str  encode(str _string)
{
    DLLFunction         _BC_Code128;
    DLL                 _barcodeDLL;
    str                 barcodeStr;
    Binary    pStr = new Binary(strlen(_string) + 4 + 1);
    Binary    ptr = new Binary(4);
;
    try
    {
        _barcodeDLL = new DLL('Bcfont32');
    } catch(Exception::Internal)
    {
        info("barcodeDLL error!!!");
        return '';
    }
    _BC_Code128 = new DLLFunction(_barcodeDLL,'BC_Code128');
    _BC_Code128.returns(ExtTypes::String);
    _BC_Code128.arg(ExtTypes::DWord);
    pStr.DWord(0, strlen(_string));
    pStr.String(4, _string);
    ptr.Binary(0, pStr);
    barcodeStr = _BC_Code128.call(ptr.DWord(0)+4);
    _barcodeDLL = null;
    _BC_Code128 = null;
    return barcodeStr;
}
В общем, сбила меня с толку функция SysStringByteLen() - проверять правильность напечатанного штрих-кода я не стал, а, как выяснилось, зря
Прошу прощения у почтенной публики

PS. Если кому интересно
В KR2 для преобразования строки в тип ExtTypes::BStrAnsi вызывается функция SysAllocStringByteLen() из oleaut32.dll. В принципе, можно использовать ее для явного преобразования из кода x++. Только не забывать, что необходимо освобождать полученную память с помощью вызова SysFreeString().

Ну и кода получится значительно больше, чем при использовании моего подхода
__________________
Axapta v.3.0 sp5 kr2

Последний раз редактировалось AndyD; 25.09.2007 в 12:02.
За это сообщение автора поблагодарили: Logger (2).
Старый 22.01.2008, 19:01   #11  
glibs is offline
glibs
Member
Сотрудники компании It Box
Most Valuable Professional
Лучший по профессии 2011
Лучший по профессии 2009
 
4,942 / 911 (40) +++++++
Регистрация: 10.06.2002
Адрес: I am from Kyiv, Ukraine. Now I am in Moscow. For private contacts: glibs@hotmail.com
Code-127 не работает с русскими буквами.

http://www.barcode.kiev.ua/types_c128.html

При передаче в .DLL русских букв она, похоже, зависает. Декодирование производится через .DLL.

BarcodeCode128.validateCharacters() изложите примерно в следующей редакции.

// GLIBS: Bug fix. For Code-128 additional validatuin is required.
#LOCALMACRO.allowedSymbols
"!@#$%^&*-_+=,./\'<>?:;\\[]`~|{}()0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
#ENDMACRO
protected boolean validateCharacters(BarCodeString barcodeString)
{
boolean ret;
;

ret = super(barcodeString);

if (strnfind(barcodeString, #allowedSymbols, 1, 9999))
{
ret = false;
}

return ret;

}

Только error ("..."); допишите.
__________________
С уважением,
glibs®
За это сообщение автора поблагодарили: Logger (4), SHiSHok (2).
Теги
bstr, lpstr, баг, штрихкод

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Цветные строки в Grid Sergo DAX: База знаний и проекты 14 19.04.2012 10:02
контейнер: '+=' vs 'conins' небольшое исследование SHiSHok DAX: Программирование 6 18.02.2010 15:58
При повторном вызове linkActive проваливается в validateWrite(Строки общего журнала ГК) Lemming DAX: Программирование 6 25.10.2007 13:50
При создании строки в закупке статус строки становится "Отменено" AlexUnik DAX: Функционал 4 27.09.2004 16:05
Функция "Удалить строки" Oks DAX: Функционал 1 03.07.2002 18:09

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

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

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