DLL学习问题及解决方案(欢迎各位大富翁来此讨论)(0分)

  • 主题发起人 主题发起人 zsy146
  • 开始时间 开始时间
Z

zsy146

Unregistered / Unconfirmed
GUEST, unregistred user!
一、调用函数。
DLL中的格式:
函数如同正常的Application。只不过在工程文件中不同;
工程文件的内容:
Library DLL文件名
uses
DLL中的一些单元(可以是pas);
exports
函数名; //这边注意函数的大小写!与Application中的函数名一致。参数名可以不同,数量类型一定一致。
//如果DLL的输出函数或过程中存在参数为String或动态数组,那么必须在调用这个DLL的项目和DLL库本身的Uses子句中都加上 ShareMem 单元。
如: FunctionA name 'FunA';
begin
//DLL的入口。
end.

应用程序的调用格式:
(1)静态调用
静态连接就是Delphi编译器把对函数或过程的调用编译到可执行代码的方法中。(执行文件中包含了这些函数的编译代码)
调用的代码格式:
A).如同Application中的函数书写(在interfance中声明,在implementation中实现,此时的实现与Application中有所不同,它是没有实现代码的,而用external 定位DLL文件)。
Unit UseDLL
interfance
function FunctionA(ParamsA,ParamsB : integer) : Boolean; stdcall;
implemetation
function FunctionA;stdcall;external 'DLL.dll' name FunA;
end.
B).直接在interface部分书写。
Unit UseDLL
interfance
function FunctionA(ParamsA,ParamsB : integer) : Boolean; stdcall external 'DLL.dll' name FunA;
implemetation
end.

(2)动态调用
DLL中的格式与静态调用中一致。
显式的调用:是指在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态连接库调进来,再用GetProcAddress()获取想要引入的函数。自此,你就可以象使用如同本应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态连接库。
直接调用Win32 的LoadLibary函数,并指定DLL的路径作为参数。LoadLibary返回HINSTANCE参数,应用程序在调用GetProcAddress函数时使用这一参数。GetProcAddress函数将符号名或标识号转换为DLL内部的地址。程序员可以决定DLL文件何时加载或不加载,显式链接在运行时决定加载哪个DLL文件。使用DLL的程序在使用之前必须加载(LoadLibrary)加载DLL从而得到一个DLL模块的句柄,然后调用GetProcAddress函数得到输出函数的指针,在退出之前必须卸载DLL(FreeLibrary)。
Application中的格式:
Unit UseDLL
uses ...
interface
Type
TMyFun = Function (ParamA,ParamB : integer) : integer ; stdcall;//!!!定义一个要调用的函数类
implementation
function UsesMyFun() : boolean;
var
MyFun : TMyFun;
MyHandle : THandle;
begin
Try
MyHandle:=LoadLibrary ('InStrDLL.dll') ;
If MyHandle<= 0 then
Raise Exception.Create( '动态链接库调用失败,错误代码是:'+Inttostr(Getlasterror))
else
@MyFun :=GetProcAddress(MyHandle,'FunA'); //!!!
if not Assigned(MyFun) then
Raise Exception.Create('GetProcAddress调用失败,错误代码是:'+inttostr(getlasterror))
else MyFun(ParamA,ParamB); //!!!!

Freelibrary(Myhandle); // 卸载DLL
finally
;
end;
end;

end.

二、调用窗体。
(1)静态调用
基本和函数相同,要注意的几点:
1、窗体的定义不在interface中,而在调用的函数中创建。
2、DLL中也存在Application变量,所以调用创建窗体的函数时也要传递Application.Handle。这样才能避免Application的冲突。
实例:
**********************DLL.dll*****************************
************************Form.pas************************
Unit FormUnit
Uses ...

Interface
Function CreatForm(AHandle : THandle; AParams : integer) : boolean;stdcall;
implementation
Function CreatForm(AHandle : THandle; AParams : integer) : boolean;
var
FormA : TFormA
begin
Application.Handle := AHandle; //!!!!
FormA := TFormA.Create(Application);
try
with FormA do
if ShowModal = mrOK then
begin
...
end;
finally
FormA.Free;
end;
end;
end.
************************Form.pas************************
**********************DLL.dll*****************************

(2)动态调用
基本上和动态调用函数一致,同样要注意Application.Handle的传递.
如:
Unit FormCallDLL
interface
uses ......
type
TFormCallForm = class(TForm)
public
{ Public declarations }
PassWord : PAnsiChar;
end;

var
FormCallForm: TFormCallForm;
DLLHandle : THandle;

Type
TGetPassword = function (AHandle : THandle;var Password: PChar): Boolean; safecall;//safecall 等同于 HResult ; Stdcall; 防止dll中的异常. 如何理解??
TSetPassword = function (AHandle : THandle;var PassWord: PChar): Boolean; safecall;

implementation

{$R *.dfm}

procedure TFormCallForm.SetButtonClick(Sender: TObject);
var
ASetPassword : TSetPassword;
begin
Try
if DLLHandle <= 0 then
DLLHandle :=LoadLibrary ('DLL/password.dll') ;
If DLLHandle <= 0 then
Raise Exception.Create( '动态链接库调用失败,错误代码是:'+Inttostr(Getlasterror))
else
@ASetPassword:=GetProcAddress(DLLHandle,'SetPass');
if not Assigned(ASetPassword) then
Raise Exception.Create('GetProcAddress调用失败,错误代码是:'+inttostr(getlasterror))
else begin
PassWord := StrAlloc(40);
if ASetPassword(Application.Handle,password) = false then
MessageDlg('PassWord is not set',mtInformation,[mbOK],0);
end;
finally
;
end;
end;

procedure TFormCallForm.TestButtonClick(Sender: TObject);
var
AGetPassword : TGetPassword;
APassword : PansiChar;
begin
if PassWord = nil then
begin
MessageDlg('Set password first', mtInformation, [mbOK], 0);
SetButton.SetFocus;
Exit;
end;
Try
if DLLHandle <= 0 then
DLLHandle:=LoadLibrary ('DLL/password.dll') ;
If DLLHandle <= 0 then
Raise Exception.Create( '动态链接库调用失败,错误代码是:'+Inttostr(Getlasterror))
else
@AGetPassword:=GetProcAddress(DLLHandle,'GetPass');
if not Assigned(AGetPassword) then
Raise Exception.Create('GetProcAddress调用失败,错误代码是:'+inttostr(getlasterror))
else begin
APassword := StrAlloc(40);
APassword := Password;
if AGetPassword(Application.Handle,APassword) then
begin
Label1.Caption := 'You are Wellcome !';
end
else
Label1.Caption := 'Sorry,You are InValid User.';
end;
finally
;
end;
end;

initialization
DLLHandle := 0 ;
DLLHandle :=LoadLibrary ('DLL/password.dll') ;

finalization
Freelibrary(DLLHandle);
DLLHandle := 0;

end.

问题:如果把FreeLibrary(DLLHandle)放在btnClick中,整个程序的窗体会不可见,是什么原因?
 
三、DLL入口,出口。
关于DLL的入口,出口的思考:在这些情况下可以对进程和线程进行初始化和清空等操作。
begin..end 部分是DLL的初始化代码。该部分只被每个进程执行一遍。
在DLL载入,释放,线程创建,释放会调用该入口函数。
***************DLLEntry.dll****************************
library DllEntry;
uses
SysUtils,
Windows,
Dialogs,
Classes;

procedure DLLEntryPoint(dwReason : DWord);
begin
Case dwReason of
DLL_PROCESS_ATTACH: Showmessage('Attaching to Process');
DLL_PROCESS_DETACH: Showmessage('Detaching from process');
DLL_THREAD_ATTACH: messagebeep(0);
DLL_THREAD_DETACH: messagebeep(0);
end;
end;

{$R *.res}

begin
DLLProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
***************DLLEntry.dll****************************
 
建议去看看《Delphi5 Developer Guide》,第九章,
说的比较透彻,
 
接受答案了.
 
这样也行,我还真不知啊。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
844
import
I
I
回复
0
查看
662
import
I
后退
顶部