powered by simpleCommunicator - 2.0.50     © 2025 Programmizd 02
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Получить структуру из С-шной DLL
25 сообщений из 39, страница 1 из 2
Получить структуру из С-шной DLL
    #40086013
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Имеется оборудование, укомплектованное документацией и примером на С#. Задача его включить в проект на Delphi

Проблема возникла с тем, чтобы получить результат из функции

Код: plaintext
1.
    sBeginTrxResult = ctm_begin_customer_transaction(szTransactionID); 


сама функция объявлена как:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
/*-[Enumerations.]------------------------------------------------------------*/
enum CTMBeginTransactionError {CTM_BEGIN_TRX_SUCCESS = 0, CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS,
 CTM_BEGIN_TRX_ERROR_NOT_CONNECTED, CTM_BEGIN_TRX_ERROR_UNHANDLED_EXCEPTION = 99};

/*-[Structures.]--------------------------------------------------------------*/
#pragma pack(push) // Store the current data structure alignment.
#pragma pack(1)    // Set the data structure alignment to 1 byte.
struct CTMBeginTransactionResult {
    char *  szTransactionID;
    enum CTMBeginTransactionError error;
};
#pragma pack(pop)  // Restore the original data structure alignment.

/*-[Functions.]---------------------------------------------------------------*/
LIBCTMCLIENT_FUNC
CTMBeginTransactionResult  ctm_begin_customer_transaction(const char * szTransactionID);



где LIBCTMCLIENT_FUNC насколько я понимаю - extern "C"
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
/*-[Preprocessor directives.]-------------------------------------------------*/
#ifdef __cplusplus
    #define LIBCTMCLIENT_C_LINKAGE extern "C"
#else
    #define LIBCTMCLIENT_C_LINKAGE
#endif
/*-[Preprocessor directives.]-------------------------------------------------*/
#ifdef __cplusplus
    #define LIBCTMCLIENT_C_LINKAGE extern "C"
#else
    #define LIBCTMCLIENT_C_LINKAGE
#endif

#ifdef WIN32
    #ifdef COMPILING_LIBCTMCLIENT
        #define LIBCTMCLIENT_FUNC LIBCTMCLIENT_C_LINKAGE __declspec(dllexport)
    #else
        #define LIBCTMCLIENT_FUNC LIBCTMCLIENT_C_LINKAGE __declspec(dllimport)
    #endif
#else
    #define LIBCTMCLIENT_FUNC LIBCTMCLIENT_C_LINKAGE
#endif



Предположительно на Delphi это может выглядеть как
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
  CTMBeginTransactionError = ( 
    CTM_BEGIN_TRX_SUCCESS, 
    CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS, 
    CTM_BEGIN_TRX_ERROR_NOT_CONNECTED, 
    CTM_BEGIN_TRX_ERROR_UNHANDLED_EXCEPTION); 

  CTMBeginTransactionResult = packed record
    szTransactionID: PAnsiChar;
    error: CTMBeginTransactionError;
  end;
  PCTMBeginTransactionResult = ^PCTMBeginTransactionResult;

  function CTM_BeginCustomerTransaction(const transactionId: PAnsiChar): CTMBeginTransactionResult; cdecl; 
  external 'libctmclient-0.dll' name 'ctm_begin_customer_transaction';


однако такой вариант не передает данные в библиотеку, что подтверждают логи внутреннего сервиса

Варианты
Код: pascal
1.
2.
3.
4.
5.
6.
 
function CTM_BeginCustomerTransaction(const transactionId: PAnsiChar): Pointer; cdecl;
  external 'libctmclient-0.dll' name 'ctm_begin_customer_transaction';

function CTM_BeginCustomerTransaction(const transactionId: PAnsiChar): PCTMBeginTransactionResult; cdecl; 
  external 'libctmclient-0.dll' name 'ctm_begin_customer_transaction';


отлично передают параметр в библиотеку, но вызывают сложности с получением ответа по причине того, что адрес на который указывает указатель содержит нечто не очень похожее на ответ. (ориентируюсь, что в поле error должно быть либо значение перечисления CTM_BEGIN_TRX_SUCCESS либо альтернативное из перечисления значение.)

Вариант"убрать/добавить packed в record опробован.
перевести функцию в процедуру с прямым набором параметров
Код: pascal
1.
 procedure CTM_BeginCustomerTransaction(out result: PCTMBeginTransactionResult; const transactionId: PAnsiChar); 


приводит к тому, что оборудование не получает входящий параметр (как бы сдвигает его по порядку вправо)
(исследовано на другой процедуре где входящих параметров больше)
Вариант обратного перечисления паремтров.. вырождается к функции с указателем... параметр в оборудование уходит, ответ... неопределен
Код: pascal
1.
 procedure CTM_BeginCustomerTransaction(const transactionId: PAnsiChar;out result: PCTMBeginTransactionResult); 



Линковка cdecl подтверждается декларацией этой же функции в С#
Код: c#
1.
2.
3.
4.
5.
6.
7.
public partial class CtmCClient
 {
   ... 
   [DllImport("libctmclient-0.dll", EntryPoint = "ctm_begin_customer_transaction", CallingConvention = CallingConvention.Cdecl)]
   public static extern CTMBeginTransactionResult BeginCustomerTransaction([MarshalAs(UnmanagedType.LPStr)] string transactionId);
   ...
 }


что отвратительно, пример на С# работает...


Собственнно вопрос к знатокам...
Как правильно получить содержимое или что требуется для того, чтобы эту информацию получить
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086018
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maremoraCTMBeginTransactionError

Вот это - просто integer. Как возвращается структура - надо гуглить.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086032
Barlone
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если это 32х-разрядная dll, собранная msvc компилятором, то результат будет в eax:edx. Для C++ builder есть http://docwiki.embarcadero.com/RADStudio/Sydney/en/Msreturn А как delphi это объяснить - не знаю. Разве что сказать, что функция возвращает int64, и вручную сдвигами выделить части структуры.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086038
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Barlone,
Это про декларацию fastcall - у emba и ms они разные. Тут же декларация cdecl - должно работать в первоначальном варианте.
Код: pascal
1.
2.
function CTM_BeginCustomerTransaction(transactionId: PAnsiChar): CTMBeginTransactionResult; cdecl; 
  external 'libctmclient-0.dll' name 'ctm_begin_customer_transaction';


Надо смотреть, что передается в transactionId и как он принимается библиотекой?
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086040
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ziv-2014

Надо смотреть, что передается в transactionId и как он принимается библиотекой?


туда честно передается нультерминированная строка ... хоть адресом на массив хоть
Код: pascal
1.
2.
3.
4.
5.
6.
7.
var
  p: PAnsiChar;
  r: PCTMBeginTransactionResult;
begin
  p := PAnsiChar('234567');
  r:= CTM_BeginCustomerTransaction(p);
end;


судя по тому, что библиотека далее ведет себя ожидаемо (согласно логу) то со входящим параметром все нормально
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086050
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Barlone
.... и вручную сдвигами выделить части структуры.

еще бы понять куда... сдвигать и от чего плясать..
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086052
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Берёшь тестовую программу на Си, компилируешь в ассемблер, смотришь как возвращается
структура. Компилируешь свою программу на Дельфи, смотришь в её ассемблер, сравниваешь.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086065
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maremora,
У тебя же возвращает структуру, а не указатель?
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086069
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ziv-2014,

В том и вопрос, что по доке - структуру, причем по значению. А вот "по-делфийски" - любое упоминание структуры в декларации функции/процедуры на первом месте убивает в хлам передачу параметров функции в библиотеку.
в С# примере - все прекрасно, но там явно об этом побеспокоился компоновщик самого шарпа..
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086082
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maremora,
Быть такого не может, я еще пойму, что есть проблемы с возвратом результата функции.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086086
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maremoraА вот "по-делфийски" - любое упоминание структуры в декларации функции/процедуры на первом
месте убивает в хлам передачу параметров функции в библиотеку.

Для особо ленивых:
https://stackoverflow.com/questions/24741218/how-c-compiler-treats-a-struct-return-value-from-a-function-in-asm
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Program_Control_(Delphi)#Handling_Function_Results

Для ещё более ленивых: обломись, никак ты эту структуру не получишь.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086095
Barlone
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014
Barlone,
Это про декларацию fastcall - у emba и ms они разные. Тут же декларация cdecl - должно работать в первоначальном варианте.
Код: pascal
1.
2.
function CTM_BeginCustomerTransaction(transactionId: PAnsiChar): CTMBeginTransactionResult; cdecl; 
  external 'libctmclient-0.dll' name 'ctm_begin_customer_transaction';


Надо смотреть, что передается в transactionId и как он принимается библиотекой?
Это не только fastcall - msvc всегда возвращает структуры до 8 байт в RDX:RAX. Вон и по ссылке на stackoverflow выше говорят то же самое
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086097
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В первую очередь спасибо всем откликнувшимся.
Barlone - отдельное спасибо за первую же мысль, оказавшуюся верной.

Итак, основная суть проблемы в том, что граждане (не будем показывать пальцами), которые кодят только в Delphi годами (а некоторые и десятилетиями) но примитивный код, не совсем ясно представляют себе саму суть ответа который был дан.

Фразовая конструкция "то результат будет в eax:edx" не дает понимания того, что происходит, куда рушится мир...

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

Идеологически правильная декларация функции все же в моем случае должна была выглядеть следующим образом:
Код: pascal
1.
 function CTM_BeginCustomerTransaction(const transactionId: PAnsiChar): Int64; cdecl;



Как верно указал Barlone а потом Dimitry Sibiryakov вопрос в том, что нет понимания того, что происходит.

в моем случае (задача функции получить идентификатор, и вернуть его же в поле структуры szTransactionID
вызываем процедуру с точкой останова после отработавшей процедуры
Код: pascal
1.
2.
3.
4.
5.
6.
7.
var
  p: PAnsiChar;
  r: Int64;
begin
  p := PAnsiChar('234567');
  r:= CTM_BeginCustomerTransaction(p);
end;


имеем результатом значение r = 49066528 (Watch list)

Именно в настоящий момент начинается "волшебство" для альтернативноодаренных.
1) открываем обычный виндовс калькулятор, переводим его в режим "программист" и взираем на шестнадцатиричное значение 00000002ECB220. (в разных случаях оно может быть разным, но вспомним, что у меня вторая часто структуры перечисление где успешный код = 0 ... т.е. фактически имеет отображение 0000000

2) открываем окно состояния регистров (да-да, то самое, которое открывается когда кошка пробежала по клавиатуре)
View \ Debug window \ Registers
и наконец начинаем понимать о чем "говорили старые зайцы" увидев напротив строчки именуемой EAX вышеозначенный текст
2ECB220 а напротив EDX 0000000
3) в моем случае первое поле это адрес строки т.е оное значение ищем в окошке содержимого памяти
(поскольку об окне содержимого памяти тоже кто-то может не знать, то его найти можно там же рядышком
View \ Debug window \ Memory)

4) Грусть и некоторое недоумение настигают обычно когда долистываешь до нужного адреса... по дампу памяти.
тихо и смирно там обитает моя исходная строка '234567'#0 которую теперь нужно просто скопировать в свой блок памяти

5) результатом r shr 32 получаем тот блок данных, который превращается в мое перечисление

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

Еще раз всем спасибо. Тема оказалась познавательна
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086101
white_nigger
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что-то долго и мутно. Реально возвращается структура, умещающаяся в 8 байт в eax:edx, как и сказано на стековерфлоу. Один в один, указатель в младшем и енум в старшем регистрах. Не совсем понятно в чем проблема была
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086127
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
white_nigger,
все верно, все так и есть...
проблема в том, чтобы увязать рухнувшее мировоззрение о том, что:
1) заявленная структура - CTMBeginTransactionResult не заполнится сама
2) структура как результат присвоения впрямую по полям не вычитывается
3) оба регистра можно рассматривать как что-то другое путем манипуляции с другим типом

Этот нетиповой для учебника по Delphi комплект допущений слишком примитивен, чтобы зная этот момент, понять чего спрашивают..
Да, я видел этот ответ не один раз пока искал ответ, натыкался на несколько умных статей.. Но регистры процессора и пол-переменной это нештано. Сложилась мозаика - когда сложилась.

Последний пост описание - в первую очередь был для тех, кто тоже смотрит на мир через веру в добро, а натыкается на вселенскую несправедливость.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086133
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Borland/Emba идут своим путем, в итоге код получается не совместимым.
Поэтому я никогда не передаю в результате функции структуру или вещественные числа.
Всегда делаю var параметром.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086144
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maremora,

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

Си:
'In common x86 calling conventions, objects that fit in two registers are returned in RDX:RAX'
Delphi:
'Int64 is returned in EDX:EAX.'

авторФразовая конструкция "то результат будет в eax:edx" не дает понимания того, что происходитФразовая конструкция + ссылки описывает и дает ответ на вопрос абсолютно точно и полностью, прямо как в анекдоте про воздушный шар :)

Зачем и о чем весь остальной пафос не понятно.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086145
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014,

где ты конкретно тут видишь свой 'свой путь' - не понятно.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086150
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maremora

Идеологически правильная декларация функции все же в моем случае должна была выглядеть следующим образом:
Код: pascal
1.
 function CTM_BeginCustomerTransaction(const transactionId: PAnsiChar): Int64; cdecl;



Во-первых, UInt64 более корректно, а во-вторых, это только для х32
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086162
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
white_nigger
Что-то долго и мутно. Реально возвращается структура, умещающаяся в 8 байт в eax:edx, как и сказано на стековерфлоу. Один в один, указатель в младшем и енум в старшем регистрах. Не совсем понятно в чем проблема была
Проблема, как я понимаю, в том, что если объявить в Delphi функцию с тем же возвращаемым результатом, как в исходной фунции Си, то в этом возвращаемом результате будет совсем не то, что нужно. Т.е. в Delphi, для 32-битной программы, нужно сделать вот такой хак, как сделал ТС: результат объявить как Int64, а потом, уже после вызова внешней функции, это преобразовать в запись CTMBeginTransactionResult.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086164
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
makhaon,
Результаты по некоторым типам в stdcall и cdecl в си и delphi не совпадают.
fastcall и register, который по сути тот же fastcall, но со своими особенностями.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086198
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
s62


white_nigger
Что-то долго и мутно. Реально возвращается структура, умещающаяся в 8 байт в eax:edx, как и сказано на стековерфлоу. Один в один, указатель в младшем и енум в старшем регистрах. Не совсем понятно в чем проблема была


Проблема, как я понимаю, в том, что если объявить в Delphi функцию с тем же возвращаемым результатом, как в исходной фунции Си, то в этом возвращаемом результате будет совсем не то, что нужно. Т.е. в Delphi, для 32-битной программы, нужно сделать вот такой хак, как сделал ТС: результат объявить как Int64, а потом, уже после вызова внешней функции, это преобразовать в запись CTMBeginTransactionResult.


Именно.
Несуразность выливается в то, что вместо прямого импорта функции и далее работы с полями record как это впрямую выглядит, нужно делать дополнительную неявную обвязку, которая будет мониторить "особенности реализации". Это в некоторой мере нелояльно к сотрудникам поддержки. Прочие моменты можно обсуждать и далее.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086204
maremora
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Fr0sT-Brutal,

Да это так, но разработчики оборудования и не предоставляют и не собираются поставлять библиотек другой битности.

По поводу UInt64 замечание корректное, спасибо.
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086217
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maremoraПо поводу UInt64 замечание корректное

Вообще-то это без разницы, сдвиги в дельфи не расширяют знак.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Получить структуру из С-шной DLL
    #40086219
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Но вообще-то и сдвиги не нужны, можно использовать Move(), absolute или case. Потом уже просто работаешь со структурой как структурой.
...
Рейтинг: 0 / 0
25 сообщений из 39, страница 1 из 2
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Получить структуру из С-шной DLL
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]