各位高手们看过来!帮帮我!(200分)

  • 主题发起人 胡一刀007
  • 开始时间

胡一刀007

Unregistered / Unconfirmed
GUEST, unregistred user!
一个执行程序外调dll模块,出现问题!请帮我看看为什么。
以前的贴子我都看过了,可还是没解决什么实际问题!
第一次点击W1按钮时,正常;
第二次点击W1按钮时,出现如下错误:
Access violation at address xxxxxxxx in module 'WRCard.exe'.Read of address xxxxxxxx.
源程序为:
主程序:
unit mainform;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Menus, ComCtrls, XPMenu, ExtCtrls;

type
TGetTrackSource = function (AHandle:THandle
ACaption:String
TrackID:integer):pchar;StdCall;

TRWForm = class(TForm)
StatusBar1: TStatusBar;
MainMenu1: TMainMenu;
I1: TMenuItem;
W1: TMenuItem;
R1: TMenuItem;
S1: TMenuItem;
E1: TMenuItem;
MessageMemo: TMemo;
procedure W1Click(Sender: TObject);
procedure E1Click(Sender: TObject);
private
{ Private declarations }
RWLibHandle:THandle;
WLibHandle:THandle;
SysLibHandle:THandle;

public
{ Public declarations }
end;

var
RWForm: TRWForm;

implementation

{$R *.DFM}
{$I+}
procedure TRWForm.W1Click(Sender: TObject);
var
GetTrackSource:TGetTrackSource;
TempTr2Str,TempTr3Str:String;
Tr2Str,Tr3Str:pchar;
Count:integer;
begin
//装载写卡的模式窗口dll
if WLibHandle =0 then
begin
WLibHandle:=LoadLibrary('TrSource.dll');
if WLibHandle =0 then
raise Exception.Create('写卡模块装载失败!');
MessageMemo.Lines.Append('写卡模块装载成功!');
end
else
MessageMemo.Lines.Append('写卡模块已装载成功!');

MessageMemo.Lines.Append('进入写卡状态,请刷卡!');

//调用写模块dll
@GetTrackSource:=GetProcAddress(WLibHandle,'GetTrackSource');
Tr2Str:=GetTrackSource(Application.Handle,'写二道信息窗',2);
showmessage(Tr2Str);
freeLibrary(WLibHandle);
StrDispose(Tr2Str);
end;

procedure TRWForm.E1Click(Sender: TObject);
begin
FreeLibrary(RWLibHandle);
//FreeLibrary(WLibHandle);
Application.Terminate;
end;

end.

动态链接库为:
library TrSource;

uses
ShareMem,
SysUtils,
Classes,
TrackSFrm in 'TrackSFrm.pas' {TrackSFrm};

{$R *.RES}
exports
GetTrackSource;
begin
end.

unit TrackSFrm;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, Buttons;

type
TTrackSFrm = class(TForm)
GroupBox1: TGroupBox;
TrackIDLabel: TLabel;
TrackIDEdit: TEdit;
WriteBitBtn: TBitBtn;
procedure WriteBitBtnClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

{Declare the export function}
function GetTrackSource(AHandle:THandle;ACaption:String
TrackID:integer):pchar;StdCall;

implementation

{$R *.DFM}
function GetTrackSource(AHandle:THandle
ACaption:String
TrackID:integer):pchar;
var
TrackSFrm: TTrackSFrm;
begin
Application.Handle:=AHandle;
TrackSFrm := TTrackSFrm.Create(Application);
try
TrackSFrm.Caption:=ACaption;
case TrackID of
2: TrackSFrm.TrackIDLabel.Caption:='二道信息:';
3: TrackSFrm.TrackIDLabel.Caption:='三道信息:';
else
Raise Exception.Create('所选磁道号错误!');
end;
TrackSFrm.ShowModal;
result:=StrAlloc(Length(TrackSFrm.TrackIDEdit.Text));
StrPCopy(result,TrackSFrm.TrackIDEdit.Text);
// result:=Pchar(TrackSFrm.TrackIDEdit.Text);
finally
TrackSFrm.Free;
end;
end;


procedure TTrackSFrm.WriteBitBtnClick(Sender: TObject);
begin
Close;
end;

end.
 
实际上你第一次执行以后已经释放那个DLL了,但是它的Handle并没有设为0
所以第二次进去没有再次装载就使用了,当然出错

procedure TRWForm.W1Click(Sender: TObject);
var
GetTrackSource:TGetTrackSource;
TempTr2Str,TempTr3Str:String;
Tr2Str,Tr3Str:pchar;
Count:integer;
begin
//装载写卡的模式窗口dll
if WLibHandle =0 then
begin
WLibHandle:=LoadLibrary('TrSource.dll');
if WLibHandle =0 then
raise Exception.Create('写卡模块装载失败!');
MessageMemo.Lines.Append('写卡模块装载成功!');
end
else
MessageMemo.Lines.Append('写卡模块已装载成功!');

MessageMemo.Lines.Append('进入写卡状态,请刷卡!');

//调用写模块dll
@GetTrackSource:=GetProcAddress(WLibHandle,'GetTrackSource');
Tr2Str:=GetTrackSource(Application.Handle,'写二道信息窗',2);
showmessage(Tr2Str);
freeLibrary(WLibHandle);
StrDispose(Tr2Str);
end;
 
资源的加载与释放要一致,才不会产生内存访问错误。
为了提高程序的调用速度,建议在程序主窗体打开时加载动态连接库,在程序主窗体关闭时
释放之。如果你的动态连接库里有连接大型数据库之类的昂贵操作,你将发现一次加载与多
次加载动态库这两种处理方法之间,性能有着相当大的差别。
 
freeLibrary(WLibHandle);
WLibHandle:=0;//////////////最好判断一下是否成功
StrDispose(Tr2Str);
 
Milpas说的对!
 
多人接受答案了。
 
顶部