Как вернуть строку указателя с ctypes в Python 2.7 - PullRequest
0 голосов
/ 07 ноября 2019

Я работаю над внедрением нового фискального устройства. И он использует библиотеку OPOS / UPOS для общения. Я очень плохо знаком с ctypes и совсем не имею опыта работы с Си. Тем не менее, мне удалось заставить его работать, в основном.

Но у меня возникают проблемы с возвратом строки из универсального метода DirectIO. Документация гласит: «Эта команда должна использоваться сразу после EndFiscalReceipt () для получения уникального идентификатора последней квитанции"

"Параметры: - Данные [in] игнорируются. - Obj [in / out] Значение для чтения. "

и добавляет к нему пример .NET:

int iData = 0;
string strReferenceID = "";
fiscalPrinter.EndFiscalReceipt();
fiscalPrinter.DirectIO(CMD_EKASA_RECEIPT_ID, ref iData, ref strReferenceID);
// strReferenceID will contain latest receipt ID, e.g. "O−7DBCDA8A56EE426DBCDA8A56EE426D1A"

первый параметр (CMD_EKASA_RECEIPT_ID) - это выполненная команда, поэтому она не указана выше.

Однако python не является .NET, и я никогда не работал с .NET.

Я следовал инструкциям в ctypes doku (https://docs.python.org/2.7/library/ctypes.html), защищаю аргументы этого метода и возвращаюсь в init:

self.libc.DirectIO.argtypes = [ctypes.c_int32, ctypes.c_int32, ctypes.c_char_p]
self.libc.DirectIO.restype = ctypes.c_char_p

Чем пытались получить разные способы получения строки ответа, но в моем случае ни один из них не работает:

s = ""
c_s = ctypes.c_char_p(s)
result = self.send_command(CMD_EKASA_RECEIPT_ID, 0, c_s)

p = ctypes.create_string_buffer(40)
poin = ctypes.pointer(p)
result = self.send_command(CMD_EKASA_RECEIPT_ID, 0, poin)

p = ctypes.create_string_buffer(40)
result = self.send_command(CMD_EKASA_RECEIPT_ID, 0, p)

s = ctypes.create_string_buffer('\000' * 32)
result = self.send_command(CMD_EKASA_RECEIPT_ID, 0, s)

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

Однако есть еще одна вещь, которая не имеет смысла для меня. Мой коллега показал мне, как вы можете видеть аргументы метода и возвращаться взаголовок файл. Для этого есть:

int DirectIO(int iCommand, int* piData, const char* pccString);

Что означает, что он возвращает целое число? Если я не ошибаюсь.

Итак, я думаю, что я должен передать методу какой-то указатель на строку, созданную в python, и C изменит ее на то, что я должен прочитать. Таким образом, я думаю, что мой подход к решению правильный.

Я также пробовал этот подход, но он мне тоже не подходит Как передать указатель обратно в ctypes?

и я начинаю чувствовать отчаяние. Не уверен, правильно ли я понимаю проблему и ищу решение в нужном месте.

Ответы [ 2 ]

0 голосов
/ 08 ноября 2019

Я решил свою проблему. Все дело было в распределении памяти. Каждый пример в сети, который я читал, создавал пустую строку, например s = "". Но это не правильно!

Когда выделенная пустая строка "" C библиотека не имела памяти, куда записывать результат.

это был почти правильный подход,

self.libc = ctypes.cdll.LoadLibrary(LIB_PATH)
self.libc.DirectIO.argtypes = [ctypes.c_int32, ctypes.c_int32, ctypes.c_char_p]
result_s = ctypes.c_char_p("")
log.info('S address: %s | S.value: "%s"' % (result_s, result_s.value))
self.libc.DirectIO(CMD_EKASA_RECEIPT_ID, 0, result_s)
log.info('S address: %s | S.value: "%s"' % (result_s, result_s.value))

возвращает:

S address: c_char_p(140192115373700) | S.value: ""
S address: c_char_p(140192115373700) | S.value: ""

требуется лишь небольшая модификация:

self.libc = ctypes.cdll.LoadLibrary(LIB_PATH)
self.libc.DirectIO.argtypes = [ctypes.c_int32, ctypes.c_int32, ctypes.c_char_p]
result_s = ctypes.c_char_p(" " * 10)
log.info('S address: %s | S.value: %s' % (result_s, result_s.value))
self.libc.DirectIO(CMD_EKASA_RECEIPT_ID, 0, result_s)
log.info('S address: %s | S.value: %s' % (result_s, result_s.value))

сейчас, печать result_s после вызова self.libc.DirectIO возвращает другую строку, чем было до звонка.

S address: c_char_p(140532072777764) | S.value: "          "
S address: c_char_p(140532072777764) | S.value: "0-C12A22F5"
0 голосов
/ 07 ноября 2019

В теге есть linux, но OPOS не работает на Linux.

Или вы работаете в среде эмуляции, такой как Wine?

В любом случае, если у вас нет подходящей среды, вы можете столкнуться с неприятностями с небольшим количеством ничего.

Сначала работайте в 32-битной среде Windows, создайте что-то, что там работает, а затем перенесите это в другую среду.

Поскольку в OPOS используется технология OLE / COM, первым используемым пакетом будет win32com или comtypes.


UnifiedPOS является концептуальной спецификацией, и в нем отсутствуют фактические программные компоненты.

Существует три типа программного обеспечения, которые на самом деле работают: OPOS, JavaPOS и POS для .NET.
OPOS и POS для .NET работают только в 32-битной среде Windows.

Только среда JavaPOS может работать в среде Linux, и она обычно доступна только из Java.

Если вы хотите что-то сделать в Python, вам нужно создать библиотеку Wrapper (или клей), которая вызывает Java из Python.


Если интерфейс C UnifiedPOS (OPOS) работает в Linux без использования эмулятора Windows или Wrapper for Java, это может быть оригинальная библиотека / компонент, созданный поставщиком принтера со ссылкой на UnifiedPOS.

В этом случае, я думаю, что подробную спецификацию можно услышать только от поставщика, который ее создал.


Для объяснения, метод DirectIO и DirectIOEvent определяются как метод / событие, которое поставщики могут свободно определять и использовать.

Поэтому в документе UnifiedPOS определены только имена и параметры методов / событий.

Необходимо спросить поставщика, который предоставляет метод DirectIO / DirectIOEvent, какую функцию имеет объект службы конкретного поставщика, и поставщик должен определить, что означает этот параметр.

Спецификация OPOS была принята UnifiedPOS с середины, но до тех пор она существовала как единая спецификация.

Остальная часть названия здесь. MCS: выпуски OPOS

Это корень возвращаемого значения метода вашей библиотеки, являющегося целым числом.

Кстати, на данный момент это последняя спецификация UnifiedPOS.
Документ - retail / 17-07-32 (Периферийная архитектура UnifiedPOS для розничной торговли, версия 1.14.1)

...