DLL, string и sharemem

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
tria
постоялец
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10
Контактная информация:

DLL, string и sharemem

Сообщение tria »

В процессе написания ДЛЛ.
Нужно передавать string и record.
В вызывающей программе и в ДЛЛ первым модулем в uses прописал sharemem.
Откомпилировал fpcmemdll и fpcmemdll.dll положил возле вызывающей программы.
Все одно при попытке вызова функции с параметром типа string вылет.

Что делаю не так?
Должна ли такая схема в будущем работать в Линукс?
Если отказаться от sharemem, то как лучше передавать string?
Лазарь 1.6.4

Код:
Проба обратного вызова процедуры из формы вызывающей программы.
Вызывающая программа:

Код: Выделить всё

//Эта процедура будет вызваться из ДЛЛ
procedure Imp_MyShowMes(fm:TForm1; txt:string);
begin
  fm.MyShowMes(txt);
end;

procedure TForm1.MyShowMes(txt:string);
begin
  ShowMessage(txt);
end;

//Процедура загружает ДЛЛ, передает в нее ссылку на форму
//и вызывает процедуру, которая вызывает Imp_MyShowMes
procedure TForm1.Button2Click(Sender: TObject);
type
  TDLLShowMes=procedure(fm:Tform); stdcall;
var
  DLLhnd: THandle = 0;
  DLLShowMes:TDLLShowMes;
begin
  DLLhnd:=LoadLibrary('CallBackDLL.dll');
  If DLLhnd=0 Then begin
    ShowMessage('CallBackDLL.dll не найдена');
    Exit;
  end;
  DLLShowMes:=TDLLShowMes(GetProcAddress(DLLhnd, 'DLLShowMes'));
  If DLLShowMes=nil Then begin
    ShowMessage('DLLShowMes не найдена');
    Exit;
  end;
  DLLShowMes(self);
end;

exports Imp_MyShowMes index 1 name 'Imp_MyShowMes';


Код в ДЛЛ:

Код: Выделить всё

library CallBackDLL;

{$mode objfpc}{$H+}

uses
  sharemem,
  Classes, Windows
  { you can add units after this };

type
  TProcImp_MyShowMes=procedure(fm:pointer; txt:string);stdcall; //: Imp_MyShowMes(fm:TForm1);stdcall;

var fm:Pointer;

procedure DLLShowMes(fm:Pointer);
var EXEProc:TProcImp_MyShowMes;
begin
  EXEProc:=TProcImp_MyShowMes(GetProcAddress(GetModuleHandle(nil), 'Imp_MyShowMes'));
  EXEProc(fm, 'Привет из ДЛЛЛ');
end;

exports DLLShowMes;
LearnMagic
новенький
Сообщения: 66
Зарегистрирован: 10.11.2016 22:13:38

Сообщение LearnMagic »

var fm:Pointer;

procedure DLLShowMes(fm:Pointer);
var EXEProc:TProcImp_MyShowMes;
begin
EXEProc:=TProcImp_MyShowMes(GetProcAddress(GetModuleHandle(nil), 'Imp_MyShowMes'));
EXEProc(fm, 'Привет из ДЛЛЛ'); какая из fm используется и инициализирована ли она
end;
Аватара пользователя
serbod
постоялец
Сообщения: 449
Зарегистрирован: 16.09.2016 10:03:02
Откуда: Минск
Контактная информация:

Сообщение serbod »

Рекомендую в экпортируемых функциях DLL использовать только типы фиксированного размера памяти. То есть ShortString и packed record без динамических массивов и строк.

А также рекомендую проектировать DLL как библиотеку функций, а не как приложение.
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3067
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

serbod писал(а):Рекомендую в экпортируемых функциях DLL использовать только типы фиксированного размера памяти. То есть ShortString и packed record без динамических массивов и строк.
А также рекомендую проектировать DLL как библиотеку функций, а не как приложение.
Так, конечно, надежнее всего. Но по опыту вполне можно и динамические структуры передавать. Самое важное - правильно указывать порядок аргументов - ключевые слова cdecl или stdcall в описании функций/процедур.
tria
постоялец
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10
Контактная информация:

Сообщение tria »

LearnMagic писал(а):var fm:Pointer;

procedure DLLShowMes(fm:Pointer);
var EXEProc:TProcImp_MyShowMes;
begin
EXEProc:=TProcImp_MyShowMes(GetProcAddress(GetModuleHandle(nil), 'Imp_MyShowMes'));
EXEProc(fm, 'Привет из ДЛЛЛ'); какая из fm используется и инициализирована ли она
end;


fm - это форма из вызывающего приложения:

Код: Выделить всё

DLLShowMes(self);
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3067
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

tria, в лазаре использовать формы из dll крайне нежелательно. Это даже в делфи плохо работает, а там это на порядок лучше реализовано. На худой конец, можно использовать формы чисто локализованные в dll, но данные туда и обратно передавать только обычными переменными.
tria
постоялец
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10
Контактная информация:

Сообщение tria »

Снег Север писал(а):
serbod писал(а):Рекомендую в экпортируемых функциях DLL использовать только типы фиксированного размера памяти. То есть ShortString и packed record без динамических массивов и строк.
А также рекомендую проектировать DLL как библиотеку функций, а не как приложение.
Так, конечно, надежнее всего. Но по опыту вполне можно и динамические структуры передавать. Самое важное - правильно указывать порядок аргументов - ключевые слова cdecl или stdcall в описании функций/процедур.


Шел вчера домой, и сам об этом подумал. И таки да, в ехе забыл указать:

Код: Выделить всё

//Эта процедура будет вызваться из ДЛЛ
procedure Imp_MyShowMes(fm:TForm1; txt:string); [color=#FF0000]stdcall;[/color]


Но это была проба технологии, а в реалии мне нужно будет передвать и строки, и record содержащие variant.

Добавлено спустя 2 минуты 2 секунды:
Снег Север писал(а):tria, в лазаре использовать формы из dll крайне нежелательно. Это даже в делфи плохо работает, а там это на порядок лучше реализовано. На худой конец, можно использовать формы чисто локализованные в dll, но данные туда и обратно передавать только обычными переменными.


В ДЛЛ у меня не будет формы. Форма взята как пример объекта из вызывающей ДЛЛ программы.
Мне в ДЛЛ нужно будет вызывать методы объектов основной программы.
Аватара пользователя
Снег Север
долгожитель
Сообщения: 3067
Зарегистрирован: 27.11.2007 15:14:47
Контактная информация:

Сообщение Снег Север »

Для винды я реализовывал такое через messaage'ы. Просто и надежно. Передаем в dll handle главной формы и ловим в ней. Если же нужна кроссплатформенность, то просто не знаю, как там в *nix'ах.
Ответить