05.06.2007, 12:06 | #1 |
Участник
|
контейнер: += трагедия вставки пустой строки.
предлагаю вашему вниманию очередную бочину в энджине аксапты (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+"'"); } для начала ставим #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 |
Участник
|
Можно свофрмулировать более явно (что происходит при вставке пустой строки) и привести минимальный пример?
|
|
05.06.2007, 12:14 | #3 |
Участник
|
Тоже долго не мог понять, в чем собственно дело.
Если правильно понял, автор пишет, что при использовании += "" для контейнеров перестает правильно происходить преобразование через DLL вызов (возвращает саму строку 123). С самим контейнером все ОК вне зависимости от того, как вставлять значения |
|
05.06.2007, 12:20 | #4 |
Banned
|
Эффекта, кажется, можно добиться и без контейнера. Эта гадкая barcodeDLL, похоже, не совсем stateless. Если ее в цикле вызывать, она рано или поздно ломается как описано. А если вручную, с участием пользователя, со всеми вытекающими задержками, то все нормально.
|
|
05.06.2007, 12:33 | #5 |
Участник
|
для тех у кого все работает (интересно на каком паке работает), поясняю:
в случае с 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 |
Участник
|
Контейнеры здесь не при чем.
Все дело в том, что входной параметр функции в 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 v.3.0 sp5 kr2 |
|
|
За это сообщение автора поблагодарили: EVGL (3), SHiSHok (2), petr (3), gl00mie (5), rumpleteazer (1), Logger (3). |
06.06.2007, 15:37 | #7 |
Участник
|
2AndyD: исчерпываюе, проверил - действительно так.
небольшой ремарк: дабы в джобике было все прозрачно вызов API функции выдрал из классов BarcodeCode128 (sys) - подлежит фиксу (за что ж такой сис слой ...) PS: после прояснения ситуации немного отлегло - хоть базовая логика работает (а то уж думал : как дальше что то писать под ax, если баги в элементарных операциях) PPS: ко всему прочему остается добавить что вставка в контейнер операторами += и conins работает по разному (выделение памяти по крайней мере)
__________________
--- SHiSHok Последний раз редактировалось SHiSHok; 06.06.2007 в 16:19. |
|
24.09.2007, 12:38 | #8 |
Участник
|
И хотя AndyD ответил достаточно исчерпывающе, все же у меня есть еще один вопрос по данной теме, а именно:
Для трансформации LPSTR в BSTR AndyD предлагает следующий код: X++: ComVariant var = ComVariant::createFromStr(_string);
;
_BC_Code128.arg(ExtTypes::STRING);
barcodeStr = _BC_Code128.call(var.int()); X++: _BC_OCode128.arg(ExtTypes::BStrAnsi); barcodeStr = _BC_Code128.call(string); |
|
24.09.2007, 13:51 | #9 |
Участник
|
Насчет 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 |
Участник
|
Хм.
Стал разбираться в функции 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; } Прошу прощения у почтенной публики 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 |
Member
|
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, баг, штрихкод |
|
Опции темы | Поиск в этой теме |
Опции просмотра | |
|