Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Access Violation при вызове функции из DLL


Автор: mr.Anderson 7.8.2007, 17:10
Возникла проблема при написании DLL.

Собственно код DLL:
Код

library MyLib;

uses
  SysUtils,
  Classes;

{$R *.res}

function Verify(): Boolean; stdcall; export;
begin
 Result := True;
end;

function GetFileExpression(): String; stdcall; export;
begin
 Result := 'MyExpression';
end;

exports
 Verify,
 GetFileExpression;

begin
end.

DLL позиционируется как плагин к моей программе. В связи с этим я ввел глобальный тип:
Код

type
 TPlugin = record
  Module   : HMODULE;
  FullName : AnsiString;
  Name     : AnsiString;
 end;

А также глобальный динамический массив с плагинами:
Код

var
 plugins : array of TPlugin;

Код загрузки плагинов:
Код

procedure TForm1.LoadPlugins;

 //verifying
 function VerifyPlugin( fullpath: AnsiString ): Boolean;
 var
  lib  : HMODULE;
  func : function: Boolean; stdcall;
 begin
  Result := False;

  lib := LoadLibrary( PAnsiChar( fullpath ) );
  if( lib = 0 ) then
   Exit;

  @func := GetProcAddress( lib, 'Verify' );
  if( Assigned( @func ) ) then
   Result := func();

  FreeLibrary( lib );
 end;

 //loading
const
 path : AnsiString = 'plugins\';
var
 count : Integer;
 srec  : TSearchRec;
begin
 count := 0;

 if( FindFirst( path + '*', faAnyFile, srec ) then
 begin
  repeat
   if( srec.Name <> '.' ) and ( srec.Name <> '..' ) then
    if( VerifyPlugin( path + srec.Name ) ) then
    begin
     Inc( count );
     SetLength( plugins, count );

     plugins[ count-1 ].Module   := LoadLibrary( PAnsiChar( path + srec.Name ) );
     plugins[ count-1 ].FullName := path + srec.Name;
     plugins[ count-1 ].Name     := srec.Name;
    end;
  until FindNext( srec ) <> 0;

  FindClose( srec );
 end;
end;

Код вызова функции из DLL выглядит так (именно здесь происходит ошибка, судя по заверениям отладчика):
Код

procedure TForm1.FormShow( Sender: TObject );
var
 GetFileExpression : function(): String; stdcall;
begin
 LoadPlugins();
 @GetFileExpression := GetProcAddress( plugins[0].Module, 'GetFileExpression' );
 if( Assigned( @GetFileExpression ) ) then
  ShowMessage( GetFileExpression() );
end;

Ошибка в следующем. Выполнение (по отладчику), доходит до строки ShowMessage( GetFileExpression() ); (из последнего фрагмента кода). Верно выводит сообщение с правильным текстом (как в DLL описано). Однако, после этого вылетает Access Violation с ошибкой 'Недопустимая операция с указателем' ('Invalid Pointer Operation'). Как я ни пытался отловить ошибку - найти ее причину не смог. Ошибка 100% где-то в приведенных фрагментах кода, т.к. если убрать вызов ShowMessage, то Access Violation не возникает.

Вопрос описал достаточно подробно, надеюсь. Кто может помочь?

Автор: Snowy 7.8.2007, 17:25
Ну так кто ж тебя учил юзать стринги в dll?
Да ещё для плагинов...
Сейчас конечно тебе тут напомнят про ShareMem...
Но что за плагин, если его можно только на дельфи написать?
Тогда уж bpl юзай.
Или используй общие типы: pointer, dword, PChar...

Автор: ASGDeveloper 7.8.2007, 17:28
Цитата(mr.Anderson @  7.8.2007,  17:10 Найти цитируемый пост)
Вопрос описал достаточно подробно, надеюсь. Кто может помочь?

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

Автор: mr.Anderson 7.8.2007, 17:37
А у меня не компилится и не работает. Даже с ShareMem. После его подключения эта же ошибка стала лезть после закрытия приложения.

Добавлено через 7 минут и 28 секунд
В общем, вопрос решил. Через FastShareMem и обход глюков в OnClose формы.

Автор: skyboy 10.8.2007, 10:59
ShareMem должно быть первым в списке как в библиотеке, так и в твоем приложении(не в unit1.pas, а в dpr-файле!) 
тогда никаких глюков не будет.
впрочем, Showy прав - тогда уж лучше bpl юзать, раз связь с другими ЯП не прредусматривается

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)