создание dll под фпц

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Аватара пользователя
Attid
долгожитель
Сообщения: 2588
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

создание dll под фпц

Сообщение Attid »

а ткнитика меня в особености создания длл под фпц.

хотел плагин под IBexpert написать, стянул исходник тестового плагина под дельфю, создал проэкт в лазаре скопипастил, скомпилил,
и тишина =( не видит его эксперт пример функции в длл

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

procedure get_plugin_info_ex(Intf: TIBEInterfaceEx; PluginInfo: pointer); stdcall;
begin
  with PIBEPluginInfoEx(PluginInfo)^ do
  begin
    PluginName := 'Just a test plugin';
    Description := 'No description';
    PlaceMenu := '2;11';
    MenuStructure := PChar('CFormat Statement (Example)|B|Uplugin_update_action_ex' + #13#10 +
                           '    CFormat Statement|Eformat_select');
  end;
end;

exports
  get_plugin_info_ex,

Аватара пользователя
Attid
долгожитель
Сообщения: 2588
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

Сообщение Attid »

код на дельфи который вызывает эксперт при загрузке

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

procedure TIBEPluginsList.LoadPlugin(const FileName: string);

var

  PluginInfoEx : PIBEPluginInfoEx;

  GetInfoEx : TGetPluginInfoProcEx;

  Lib: THandle;

  Plugin : TIBEPlugin;

begin

  Lib := Windows.LoadLibrary(PChar(FileName));

  if Lib <= HINSTANCE_ERROR then

    Exit;

  try

    GetInfoEx := GetProcAddress(Lib, PChar('get_plugin_info_ex'));

    if (@GetInfoEx = nil) then

      Exit;

    New(PluginInfoEx);

    try

      GetInfoEx(IBEIEx, PluginInfoEx);



      Plugin := TIBEPlugin.Create;

      Plugin.FileName := FileName;

      Plugin.PluginName := PluginInfoEx.PluginName;

      Plugin.Description := PluginInfoEx.Description;

      Plugin.PlaceMenu := PluginInfoEx.PlaceMenu;

      Plugin.CreatePluginMenu(PluginInfoEx.MenuStructure);



      Self.Add(Plugin);

    finally

      Dispose(PluginInfoEx);

    end;

  finally

    FreeLibrary(Lib);

  end;

end;


Юра
постоялец
Сообщения: 163
Зарегистрирован: 25.05.2005 10:20:09
Откуда: Украина, Киев

Сообщение Юра »

PIBEPluginInfoEx глянь. Если там используются длинные строки в качестве полей, то плохо...
Аватара пользователя
Attid
долгожитель
Сообщения: 2588
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

Сообщение Attid »

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

  PIBEPluginInfoEx = ^TIBEPluginInfoEx;

  TIBEPluginInfoEx = record

    PluginName  : PChar;

    Description : PChar;

    MenuStructure : PChar;

    PlaceMenu : PChar;

  end;



IBEIntfEx.pas
Юра
постоялец
Сообщения: 163
Зарегистрирован: 25.05.2005 10:20:09
Откуда: Украина, Киев

Сообщение Юра »

Проблема вероятно здесь:

MenuStructure := PChar('CFormat Statement (Example)|B|Uplugin_update_action_ex' + #13#10 +
' CFormat Statement|Eformat_select');

Здесь создается временная строка, которая при выходе из функции освобождается, и указатель на освобожденную память возвращается вызывающей программе.
Присвой строку глобальной переменной, а уже потом возвращай на нее указатель.
Либо для теста верни просто строковую константу.
Аватара пользователя
Attid
долгожитель
Сообщения: 2588
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

Сообщение Attid »

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

const mstr='CFormat Statement|B|'#13#10'   CFormat Statement|Eformat_selectd';
var Pcharmstr : PChar;

попробывал варианты

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

//    MenuStructure := mstr;
//    MenuStructure := PChar(mstr);
    Pcharmstr:=PChar(mstr);
    MenuStructure := Pcharmstr;


безполезно =( у меня вообще подозрения что PChar в 2,2,* сломали =) пойду попробую 2,0,4 поставить на вм
Последний раз редактировалось Attid 13.11.2007 20:25:41, всего редактировалось 1 раз.
halyavin
новенький
Сообщения: 25
Зарегистрирован: 23.10.2007 16:35:55

Сообщение halyavin »

А функцию plugin_update_action_ex вы экспортируете?
Аватара пользователя
Attid
долгожитель
Сообщения: 2588
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

Сообщение Attid »

нет, но на дельфи я его тоже не экспортирую и тоже все работает.

как проверю на 2,0,4 попробую воспроизвести на минимальном примере.
Последний раз редактировалось Attid 13.11.2007 20:25:52, всего редактировалось 1 раз.
halyavin
новенький
Сообщения: 25
Зарегистрирован: 23.10.2007 16:35:55

Сообщение halyavin »

Я понял почему не работает dll'ка у меня - это ошибка компилятора (я юзаю довольно старый 2.0.4).

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

.globl   P$TESTEX_GET_PLUGIN_INFO_EX$TIBEINTERFACEEX$POINTER
P$TESTEX_GET_PLUGIN_INFO_EX$TIBEINTERFACEEX$POINTER:
# Temps allocated between ebp-8024 and ebp+0
   pushl   %ebp
   movl   %esp,%ebp
   subl   $8020,%esp
   movl   %eax,3928(%esp)
   pushl   %eax
   movl   %ebx,-8024(%ebp)
   movl   %esi,-8020(%ebp)
   movl   %edi,-8016(%ebp)
# Var Intf located at ebp+8
# Var PluginInfo located at ebp+12
# здесь копируется параметр Intf.
   movl   8(%ebp),%esi
   leal   -8008(%ebp),%edi
   cld
   movl   $2002,%ecx
   rep
   movsl

вместо movl 8(%ebp),%esi должно стоять leal 8(%ebp),%esi. В результате этой ошибки в esi оказывается ноль (первое поле структуры TIBEInterfaceEx), а не указатель на структуру в стеке и происходит исключение при копировании параметра Intf. Так что нужно найти версию компилятора, в которой на этом месте будет стоять leal. Кроме этого, могут возникнуть проблемы с разным выравниванием структур в fpc/delphi. И не следует забывать о директиве {$MODE} - без нее integer двухбайтный.
Если у вас в дизасме стоит leal, то выложите куда-нибудь скомпиленную dll'ку вместе с ассемблерным листингом (семейство опций -a).
PS Это ошибка прошла не замеченной скорее всего потому, что никто 8Kb структуры копированием не передает - но поправлять IBExpert похоже уже поздно.
Аватара пользователя
Attid
долгожитель
Сообщения: 2588
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

Сообщение Attid »

halyavin
в мантис отпишешь ?

архив тута
halyavin
новенький
Сообщения: 25
Зарегистрирован: 23.10.2007 16:35:55

Сообщение halyavin »

Хм... все оказывается немного хитрее, чем я думал. Free Pascal по-другому передает большие параметры - он запихивает в стек указатель на структуру, а в процедуре его копирует. Delphi же записывает в стек саму структуру и в процедуре параметр тоже копирует. Поэтому в программах, написанных целиком на Free Pascal, или целиком на Delphi все нормально. А вот на границе dll получаются глюки (как при вызове Free Pascal из Delphi, так и наоборот). Кто соотвествует стандартам в данном случае - не понятно.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Погодите, погодите... Что-то я не припомню, чтобы Дельфи структуры по значению передавал. А FPC теоретически это может делать - он поступает в соответствии с ABI конкретной операционки, некоторые из которых (один из примеров - powerpc/darwin) предписывают запихивать структуры в стек целиком (зачем - остается совершенно непонятным).

Может быть, во избежание копирования, надо объявлять параметр Intf как const или var?
halyavin
новенький
Сообщения: 25
Зарегистрирован: 23.10.2007 16:35:55

Сообщение halyavin »

Тут как раз лишние копирование у дельфи, а не у fpc. Поэтому ни var, ни const не вылечат (точнее если поставить var и в вызывающем коде и в вызываемом, то будет все ok, но вызывающий код на дельфи мы править-то не можем). Дельфи прекрасно передает структуры по значению, иначе бы код исходного дельфового плагина не компилился.
Юра
постоялец
Сообщения: 163
Зарегистрирован: 25.05.2005 10:20:09
Откуда: Украина, Киев

Сообщение Юра »

Мы говорим про stdcall. И если для него дельфи пихает всю структуру в стек, то FPC должен делать также. Иначе не будет совместимости, как в данном случае...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Забавная получается хрень, однако...
Действительно, пока нет stdcall - передает указатель и копирует в вызываемой процедуре. Добавляем stdcall - начинает пихать все в стек на вызывающей стороне. При этом в WinAPI ведь нет ни одной ф-ции, для которой это могло бы быть нужно...
Ответить