簡體   English   中英

嘗試從dll加載過程時在Delphi中出現錯誤

[英]Errors in Delphi while trying to load procedures from dll

從dll加載過程時,無論是動態加載還是靜態加載,我都遇到問題。 當我將程序從dll放到我的單元中時,一切正常。 當我嘗試使用dll時,它給了我

第一次機會例外為$ 00526399。 帶有消息“在0x00526399發生訪問沖突:讀取地址0x00000390”的異常類$ C0000005。 處理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.

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.

它還顯示了一個錯誤:

預期為“;” 但在第91行收到了標識符'index'

但是導出就像我在網上一樣完成。

明顯的錯誤是:

  • 您無需執行太多錯誤檢查。 您假定對LoadLibrary的調用始終成功。
  • 調用約定不匹配。 您在DLL中使用stdcall並在可執行文件中register
  • 常規項目不匹配。 在DLL中添加(1),加載(2)和保存(3)。 在可執行文件中,您具有添加(3),加載(1)和保存(2)的功能。
  • 每次從DLL調用函數時,都將加載和卸載DLL。 這意味着每次卸載DLL時,保持狀態的DLL中的全局變量都會丟失。

坦白說,這段代碼真是一團糟。 我建議您執行以下操作:

  1. 切換到使用功能名稱而不是常規名稱的加載時間鏈接。 這意味着在可執行文件中使用external關鍵字。 通過刪除對LoadLibraryGetProcAddress等的所有調用,這將大大簡化代碼。如果需要運行時鏈接,則可以稍后使用delayed關鍵字添加它。
  2. 停止在DLL中使用全局狀態,而是在模塊之間來回傳遞信息。 刪除所有全局變量。 但是請確保不要來回傳遞Delphi對象。
  3. 在模塊邊界上使用PChar而不是短字符串。
  4. 停止使用鏈接列表和動態分配。 很難做到這一點。 在DLL中使用TList<T>來存儲元素列表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM