尝试从dll加载过程时Delphi中的错误

Ary*_*yal 2 delphi dll delphi-xe2

从动态或静态加载程序时从dll加载程序时遇到问题.当我把程序从dll放到我的单位时,一切正常.当我尝试用dll做它时它给了我

第一次机会异常,价格为00526399美元.异常类$ C0000005,消息'访问冲突位于0x00526399:读取地址0x00000390'.处理Project1.exe(21988)

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls,Unit2;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Refresh;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;


implementation

type
plist = ^element;
element = record
  artist,title,genre: string[20];
  year,grade: integer;
  wsk: plist;
end;
database = file of element;

var
base: database;
first: plist;
handler: HModule;
{$R *.dfm}



procedure TForm1.Refresh();
var
current: plist;
begin
  ListView1.Clear;
  current:= first;
  while current<>nil do
  begin
    with ListView1.Items.Add do
    begin
      Caption:=current^.artist;
      SubItems.Add(current^.title);
      SubItems.Add(current^.genre);
      SubItems.Add(IntToStr(current^.year));
      SubItems.Add(IntToStr(current^.grade));
    end;
    current:=current^.wsk;
  end;
end;



procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var Save: procedure;
begin
handler:=LoadLibrary('lib.dll');
try
  @Save:=GetProcAddress(handler, PChar(2));
  if @Save = nil then raise Exception.Create('Load nie dziala');
  Save();
finally
FreeLibrary(handler);
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
Load: procedure;
begin
handler:=LoadLibrary('lib.dll');
try
  @Load:=GetProcAddress(handler, PChar(1));
  if @Load = nil then raise Exception.Create('Load nie dziala');
  Load();
finally
FreeLibrary(handler);
end;
Refresh();
end;

procedure TForm1.Button1Click(Sender: TObject);
var
el: element;
Add: procedure(el:element);
begin
el.artist:=Edit1.Text;
el.title:=Edit2.Text;
el.genre:=Edit3.Text;
el.year:=StrToInt(Edit4.Text);
el.grade:=StrToInt(Edit5.Text);
handler:=LoadLibrary('lib.dll');
try
  @Add:=GetProcAddress(handler, PChar(3));
  if @Add = nil then raise Exception.Create('Load nie dziala');
  Add(el);
finally
FreeLibrary(handler);
Refresh();
{Form2:=TForm2.Create(Form1);
Form2.ShowModal;
Form2.Free;}
end;
end;
end.
Run Code Online (Sandbox Code Playgroud)

dll文件如下所示:

  library lib;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  System.SysUtils,
  System.Classes;

{$R *.res}

type plist = ^element;
element = record
  artist,title,genre:string[20];
  year,grade:integer;
  wsk: plist;
end;
database = file of element;

var
first: plist;
base: database;

procedure add(el: element); stdcall;
var current,tmp: plist;
begin
New(current);
current^ := el;
current^.wsk := nil;
if first = nil then
begin
  first:=current;
end else
begin
  tmp:=first;
  while tmp^.wsk<>nil do
  begin
    tmp:=tmp^.wsk;
  end;
  tmp^.wsk:=current;
end;

end;

procedure load();stdcall;
var
  el: element;
  i: integer;
begin
  AssignFile(base, 'baza.dat');
  if not FileExists('baza.dat') then
  begin
    Rewrite(base);
  end else
  begin
    Reset(base);
    for i := 0 to FileSize(base)-1 do
    begin
        read(base, el);
        add(el);
    end;
  end;
  CloseFile(base);
end;

procedure save();stdcall;
var
current: plist;
el: element;
begin
  AssignFile(base, 'baza.dat');
  Rewrite(base);
  current:=first;
  while current<>nil do
  begin
    el:=current^;
    el.wsk:=nil;
    write(base, el);
    current:= current^.wsk;
  end;
end;

exports
add index 1,
load index 2,
save index 3;
begin
end.
Run Code Online (Sandbox Code Playgroud)

它还向我显示了一个错误:

预期';' 但是在第91行收到了标识符'index'

但是出口就像我在网上的红色一样.

Dav*_*nan 5

明显的错误是:

  • 您没有执行太多错误检查.您假设呼叫LoadLibrary始终成功.
  • 调用约定不匹配.您stdcall在DLL和register可执行文件中使用.
  • 序数不符合.在DLL中,它是add(1),load(2)和save(3).在可执行文件中,您添加了(3),load(1)和save(2).
  • 每次从DLL调用函数时,都会加载和卸载DLL.这意味着每次卸载DLL时,DLL中保存状态的全局变量都会丢失.

坦率地说,这段代码真是一团糟.我建议你做以下事情:

  1. 使用函数名称而不是序数切换到加载时间链接.这意味着external在可执行文件中使用关键字.这将通过删除所有这些调用大大简化代码LoadLibrary,GetProcAddress等等.如果需要运行时链接,您可以在以后通过添加delayed关键字.
  2. 停止在DLL中使用全局状态,而是在模块之间来回传递信息.删除所有全局变量.但请确保您不要来回传递Delphi对象.
  3. PChar在模块边界使用而不是短字符串.
  4. 停止使用链接列表和动态分配.这很难做对.TList<T>在DLL中使用来存储元素列表.