2014-09-28 1 views
2

동적으로 또는 정적으로로드 할 때 DLL에서 프로 시저를로드하는 동안 문제가 있습니다. DLL에서 내 장치로 프로 시저를 넣을 때 모든 것이 잘 동작합니다.DLL에서 프로 시저를로드하는 동안 델파이의 오류

Expected ';' but received and identifier 'index' at line 91

그러나 : 그것은 또한 나에게 오류를 보여줍니다

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. 

: 나는 DLL을 함께 할 할 때 그것은 DLL 파일은 다음과 같습니다 저

First chance exception at $00526399. Exception class $C0000005 with message 'access violation at 0x00526399: read of address 0x00000390'. Process 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. 

에게 제공 수출은 웹상에서 빨간색처럼 이루어집니다.

답변

5

명백한 오류는 다음과 같습니다

  • 당신이 많은 오류 검사를 수행하지 않습니다. LoadLibrary에 대한 호출이 항상 성공했다고 가정합니다.
  • 호출 규칙이 일치하지 않습니다. DLL에 stdcall을 사용하고 실행 파일에 register을 사용합니다.
  • 서수가 일치하지 않습니다. DLL에서는 add (1), load (2) 및 save (3)입니다. 실행 파일에 add (3), load (1) 및 save (2)가 있습니다.
  • DLL에서 함수를 호출 할 때마다 DLL을로드하고 언로드합니다. 즉, DLL을 언로드 할 때마다 상태를 보유하는 DLL의 전역 변수가 손실됩니다.

솔직히이 코드는 진짜 엉망입니다. 다음 작업을 수행하는 것이 좋습니다.

  1. 서수가 아닌 함수 이름을 사용하여로드 시간을 전환합니다. 즉, 실행 파일에 external 키워드를 사용합니다. 이렇게하면 LoadLibrary, GetProcAddress 등의 호출을 모두 제거하여 코드를 크게 단순화 할 수 있습니다. 런타임 연결이 필요한 경우 나중에 delayed 키워드를 사용하여 추가 할 수 있습니다.
  2. DLL에서 전역 상태 사용을 중지하고 모듈간에 정보를 앞뒤로 전달합니다. 모든 전역 변수를 제거하십시오. 그러나 델파이 객체를 앞뒤로 전달하지 않도록하십시오.
  3. 모듈 경계의 짧은 문자열보다는 PChar을 사용하십시오.
  4. 연결 목록 및 동적 할당 사용을 중지합니다. 그렇게하기가 어렵습니다. 요소 목록을 저장하려면 DLL에 TList<T>을 사용하십시오.
관련 문제