Я только что купил разделяемую библиотеку (.so shared object), которая представляет SDK устройства.
Продавец не прислал мне файлы заголовков .h для разработки на C / C ++. Они прислали мне примеры Pascal и Java, используя интерфейс (класс java) и глобальные функции Pascal, ссылаясь на stdcalls, также ссылающиеся на этот внешний файл .so.
Они прислали мне примеры и демонстрацию того, как использовать общий объект .so в Pascal и Java.
Они также отправили мне документ с подробным описанием всех вызовов функций (типа параметров и т. Д.) В файле .so. который я нашел в файле .so и увидел на нем точно символы функций.
Мой вопрос заключается в том, как создать заголовок C ++, который я могу использовать в качестве объекта класса в C ++.
Я сделал очень грязное использование этого .so, используя dlopen, dlsym и dlclose прямо на моем программном обеспечении, но я чувствовал это очень грязным. Итак, я хотел бы создать для этого класс, подобный интерфейсу Java, чтобы я мог сделать более чистый код, а также запускать отдельно в потоке, не замораживая свой графический интерфейс, как сейчас происходит.
Определения функций Pascal (Lazarus), которые они предоставляют мне:
THREAD_READ1 = class(TThread)
fEvent:PRTLEvent;
procedure Execute; override;
constructor Create;
destructor Destroy; override;
end;
{ Functions headers }
function SDK_Initialize: integer; stdcall; external 'sdk.so';
function SDK_Finalize: integer; stdcall; external 'sdk.so';
function SDK_DigitalREAD(pTemplate: Pointer): integer; stdcall; external 'sdk.so';
function SDK_READBMP(var iRetorno, iSize: Integer): Pointer; stdcall; external 'sdk.so';
function SDK_READ(pTemplate: Pointer; var sTemplate: integer; pImage: Pointer; var sImage:integer; intWHITE: integer; intIMG: integer): integer; stdcall; external 'sdk.so';
function SDK_Cancel: integer; stdcall; external 'sdk.so';
function SDK_Compare(pSample1, pSample2: Pointer): integer; stdcall; external 'sdk.so';
function SDK_Version: PAnsiChar; stdcall; external 'sdk.so';
function SDK_Return(intReturn: integer): PAnsiChar; stdcall; external 'sdk.so';
Мне нужно знать, как перенести и обернуть эти вызовы функций в класс C ++ и запустить некоторые функции в другой поток, например:
Class Device : public QObject {
Q_OBJECT
private:
QThread thread1;
QThread *thread2;
...
public:
SDK functions here
...
};
Я не знаю, как построить заголовок функции в коде выше. И я не знаю также, чтобы сделать это потокобезопасным следующим образом:
Я должен вызвать SDK_READ в потоке, чтобы перевести устройство в состояние чтения и не заморозить мой графический интерфейс в ожидании ответа устройства.
Я также должен вызвать SDK_Cancel для отмены состояния чтения и завершения потока, выполняющего любые функции SDK_READ
Функции SDK * можно сопоставить с GCC в соотношении 1: 1, поскольку компилятор Lazarus, Freepascal, обычно совместим с gcc на уровне компоновки. Все типы являются примитивными типами, поэтому для этого просто требуется базовое преобразование синтаксиса и использование любого макроса соглашения о вызовах stdcall. Параметры VAR добавляют одну дополнительную * косвенность.
Остерегайтесь «integer», которое обычно int32, но, строго говоря, это зависит от режима компилятора. (objfpc и delphi = int32, режимы по умолчанию и TP = int16). Это единственная хорошая вещь в деривации класса TThread, поскольку он гарантирует, что это режим Object Pascal.
Класс Thread_read1_, тем не менее, является нативным Object (OOP) Pascal и не может быть интерфейсирован из внешнего кода (даже существенно отличающейся от версии FreePascal или Delphi) и должен был бы переноситься так же, как любой класс C ++ для простого интерфейса C или другого компилятора C ++. (например, сравните с тем, когда gcc несколько раз менял сортировку для классов C ++ в прошлом).
Теоретически вы можете попытаться взломать его, но это не рекомендуется, тем более что TThread также создает много контекста TLS. Эта часть заголовка не может быть повторно использована из внешних языков или версий.
Тратить 5000 евро на использование Delphi в качестве конвертера заголовков для преобразования 10 функций, как полагает Руди, может быть немного излишне.
— ответ после более подробной информации в личной почте
Все это очень неясно, и заголовок не дает много информации. В личном письме автор объяснил ситуацию, и кажется, что функции работают нормально, но не при использовании из потоков.
Возможно, что выполнение кода FPC в потоках не инициализировано FPC
время выполнения приводит к проблемам.
URL, который я разместил в комментариях ранее (
http://wiki.freepascal.org/Multithreaded_Application_Tutorial#External_threads
) описывает некоторые причины, созданные людьми, которые встроили CEF (браузер Chrome)
в приложениях Lazarus. CEF также имеет внутреннюю резьбу и вызывает паскали обратного вызова в своих потоках.
В основном есть две возможные причины:
потоки в FPC RTL не были инициализированы (сделано путем создания фиктивного потока)
Если код Pascal использует компоненты среды выполнения FPC, такие как динамическая память
управление или стандартные файловые дескрипторы, которые используют переменные TLS, вы должны
вызовите функцию, чтобы сделать это. (бит «ExternalThread» в ссылке).
Это может быть кусок пирога, если SDK сделает завернутые эти кусочки в SDK
для тебя. Получение доступа к потенциально не экспортируемому (или, возможно, частично
даже не связаны в) символы RTL, статически связанные с .so будут
очень трудно, хотя, так что общение с поставщиком SDK кажется единственным вменяемым
проспект ИМХО, или отказаться от стремления потока и, например, работать с работником
приложение, которое связывает SDK, который управляется с помощью каналов.
API SDK немного наивен и не звучит, если он был повторен, и не подготавливает ситуацию, когда в одном приложении может быть многоязычная среда выполнения.
Других решений пока нет …