Перейти к содержанию
Fire Monkey от А до Я
  • 0

Проблемы при передачи структуры (struct) с языка C++ в Delphi


Dmitry_4501

Вопрос

Всем доброго времени суток, имеется проблема...

Есть библиотека sciter, я хочу ее использовать в Delphi, но имеющиеся там *привязки*(bindings) ориентированы на Delphi 7 (но это не самое главное, они рассчитаны на версию библиотеки 3.x, в то время, как библиотека уже давно 4.4.x, собственно там много чего нет).
Но у библиотеки есть C PLAIN API, при помощи которого можно запросто подружить ее с Delphi, чем я собственно и занимаюсь, но возникла проблема..

Есть основная функция, которая возвращает структуру с кучей других функций (ISciterAPI), она в принципе работает, некоторые функции я пробовал из нее вызывать и они работали отлично, но работают лишь несколько первых функций нормально, остальные же сыплются на Access Violation, хотя на других языках это работает нормально. 

Структура выглядит таким образом, потом при помощи другой функции возвращается указатель на эту структуру ISciterAPI* (В самой структуре функций намного больше).

typedef struct ISciterAPI {
  UINT version;
  LPCWSTR SciterClassName(void);
  UINT SciterVersion(BOOL major);
};
typedef ISciterAPI* LPSciterAPI;

В Delphi я все оформляю так:

type
  PSciterAPI = ^ISciterAPI;
  ISciterAPI = packed record
    version: UINT;
    SciterClassName: function(): LPCWSTR; // LPCWSTR - PWideChar;
    SciterVersion: function(major: Integer): UINT; // Использовал до этого BOOL, но наткнулся на статью, где рассказывалось о том, что он немного странно работает, мол BOOL false = 0, а BOOL true = -1; Поэтому напрмиер функция SciterVersion у меня не работала правильно, но при использовании Integer все стало нормально работать.
  end;

Но, как я уже сказал ранее - только некоторые функции работают, остальные падают с исключением ACCESS VIOLATION.

Почему так может быть?

P.S: Единственный пока рабочий для меня вариант - написание отдельной библиотеки, которая выносит все эти функции в экспорт, соответственно их теперь можно вызывать непосредственно из самой библиотеки, минуя ISciterAPI, но минусы такого подхода в том, что эта библиотека по сути является посредником между программой на Delphi и Sciter...

Изменено пользователем Дмитрий Потапов
немного подкорректировал код
Ссылка на комментарий

Рекомендуемые сообщения

  • 0

макросы разворачиваем в уме:
sciter-x-api.h UINT
SCFN( SciterVersion )(BOOL major);
sciter-x-types.h  #
define SCFN(name) (__stdcall *name)
итог:
SciterVersion: function(major:
bool) UINT; stdcall;
и всетаки попробуй bool оставить

Изменено пользователем Slym
Ссылка на комментарий
  • 0
4 часа назад, Slym сказал:

макросы разворачиваем в уме:
sciter-x-api.h UINT
SCFN( SciterVersion )(BOOL major);
sciter-x-types.h  #
define SCFN(name) (__stdcall *name)
итог:
SciterVersion: function(major:
bool) UINT; stdcall;
и всетаки попробуй bool оставить

Начну по порядку:
1. SCFN я сразу же расшифровал как: __stdcall *НАЗВАНИЕ ФУНКЦИИ* - например __stdcall SciterVersion(bool major)

2. Я изначально использовал тип BOOL в Delphi, но так как его значение true является (-1), то я перешел на Integer, ведь функции и с ним работают нормально, по крайней мере что бы я не проверил подставив Integer вместо BOOL, результат был ожидаемым и ничего нигде не падало с каким-либо исключением. Из-за того, что значение BOOL (true) является -1, функции не считали его как true, они принимали значения (true - 1, false - 0)? Соответственно функция SciterVersion(true) (BOOL) возвращала то же, что и SciterVersion(false), а вот когда я перешел на Integer, результат функции SciterVersion(1) и SciterVersion(0) стал отличаться.

К сожалению, но ничего из этого мне не помогает, и вообще было предпринято мною изначально. 
Пока-что, единственный мой выход из ситуации *костыль* в виде отдельной DLL-библиотеки-посредника, с которой связывается мой Delphi-код, а та в свою очередь вызывает одноименный метод структуры ISciterAPI в нужной мне библиотеке и возвращает мне через этого *посредника* мне обратно в Delphi-код. Выглядит ужасно, но это работает...

Хотелось бы все-таки обойтись без этого костыля. Сейчас у меня работает это примерно так:

1. Delphi (вызывает функцию SciterVersion(1)) из DLL-посредника

2. DLL-посредник связывается с основной библиотекой и вызывает оттуда одноименный метод структуры ISciterAPI

3. DLL-посредник возвращает мне результат, полученный из основной функции.

Минус этого подхода для меня в том, что после серьезного обновления библиотеки, или любого другого, которое хоть как-то заденет API, мне придется переписывать DLL-посредника для соответствия последним изменениям API Sciter. А так же придется переписывать код Delphi для соответствия последним моим изменениям DLL-посредника. ЭТО КРАЙНЕ НЕУДОБНО

 

Ссылка на комментарий
  • 0
В 04.10.2020 в 11:55, Дмитрий Потапов сказал:

SciterVersion: function(major: Integer): UINT;

а где тут stdcall?

type
  PSciterAPI = ^ISciterAPI;
  ISciterAPI = packed record
    version: UINT;
    SciterClassName: function(): LPCWSTR;stdcall;
    SciterVersion: function(major: BOOL): UINT;stdcall;
  end;

Изменено пользователем Slym
Ссылка на комментарий
  • 0
1 час назад, Slym сказал:

а где тут stdcall?

type
  PSciterAPI = ^ISciterAPI;
  ISciterAPI = packed record
    version: UINT;
    SciterClassName: function(): LPCWSTR;stdcall;
    SciterVersion: function(major: BOOL): UINT;stdcall;
  end;

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

Ссылка на комментарий
  • 0

там еще дефайны стоят #if defined(WINDOWS) && !defined(WINDOWLESS)
т.к. нельзя пропускать функции в структуре - надо точно знать с какими дефайнами длл сбилдена.
если лень описывать ненужную функцию делай заглушкой SciterGetPPI: pointer;  - повторюсь пропускать нельзя

Ссылка на комментарий
  • 0
3 часа назад, Slym сказал:

там еще дефайны стоят #if defined(WINDOWS) && !defined(WINDOWLESS)
т.к. нельзя пропускать функции в структуре - надо точно знать с какими дефайнами длл сбилдена.
если лень описывать ненужную функцию делай заглушкой SciterGetPPI: pointer;  - повторюсь пропускать нельзя

WINDOWLESS - это Lite версия библиотеки, я же использую обычную версию, так что все правильно в этом случае. 

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...