动态加载DLL(50分)

  • 主题发起人 主题发起人 xddl
  • 开始时间 开始时间
X

xddl

Unregistered / Unconfirmed
GUEST, unregistred user!
我用下面德程序进行DLL德动态加载,从来没有成功过,请问为什么?
几乎所有德参考资料上都这么写。
procedure TfrmWinPhrase.FormCreate(Sender: TObject);
var
PhsEnable: TPhsEnable;
begin
hPhsDll := LoadLibrary('dll.dll');
if hPhsDll < HINSTANCE_ERROR then
begin
ShowMessage('DLL.DLL加载错');
Exit;
end;
@PhsEnable := GetProcAddress(hPhsDll, 'PHSENABLE');
PhsEnable(True);
end;
 
TPhsEnable是如何定义的?
 
注意点:
1. @PhsEnable := GetProcAddress(hPhsDll, 'PHSENABLE');
中的'PHSENABLE' 的大小写要完全和dll中定义的一致.
2. HINSTANCE_ERROR是不是32
其实书里说得很乱的, 有的说是要handle大于0是有效的, 有的说是>32,
根据我的经验, >32是比较可取的.
3. GetProcAddress后要判断 if PhsEnable<>nil then
...
4. TPhsEnable的定义要完全和dll中定义的一致, 包括数据类型,
而且Delphi中缺省的调用方式是pascal, 即stdcall, 而dll如果不是
声明成stdcall方式的话是会有些问题的.
5. 如果PhsEnable是对象的成员的话, 调用的时候会自动传入对象的self参数.
所以dll中的声明要多一个参数, 否则函数返回时会破坏对象的self参数.
 
1. 所需动态连结的 dll 须置放在与执行档同一目录或windows system 目录
2. 确认 dll export 出来的函式的原型, 以目前的情况而言, 通常只拿得到 c
语言的函数原型,这时要注意 c 与 object pascal 相对应的型别, 如果需要, 在
interface 一节定义所需的资料类别
3. 在 implementation 节中宣告欲使用的函式, 语法大致如下:
procedure procname(argu...);
far;
external 'dll档名';
index n;
function funcname(argr...): datatype;
far;
external 'dll档名';
index n;
宣告时, index n 如果不写, 便是参考资料中所谓 import by name 的方式, 此
时, 由於需要从 dll 的 name table 中找出这个函式, 因此, 连结执行速度比
import by ordinal稍慢一些, 此外, 还有一种 by new name, 由於我没用过, 您可
以查一参考资料, 大意是可以 import 後改用另一个程式命名呼叫这个函式
4. 然後, 呼叫与使用就与一般的delphi 没有两样
5. 上述是直接写到呼叫dll函式的程式单元中, 此外,也可以将dll的呼叫宣告集
中到一个程式单元(import unit), delphi 内附的 wintypes, winprocs是一个例子,
您可以参考一下,同时观察一下 c 与 pascal 互相对应的资料型态
6. 除了上述的 static import 的方式, 另外有一种 dynamic import 的写法,
先宣告一个程序类型(procedural-type),程式执行时, 以 loadlibrary() api load
进来後, 再以 getprocaddress() api 取得函式的位址的方式来连结呼叫, 在object
pascal language guide p.132-133 有一个例子, 您可以参考看看
如果要举个例子, 以下是从我以前的程式节录出来的片断:
(* for cwindows 3.1 *)
unit ime31;
interface
uses
sysutils, wintypes, winprocs, dialogs;
type
(* 必要的资料型态宣告 *)
tdatentime = record
wyear, wmonth, wday: word;
whour, wmin, wsec: word;
end;

timepro = record
hwndime: hwnd;
{ ime handle }
dtinstdate: tdatentime;
{ date and time of installation }
wversion: word;
{ the version of ime }
szdescription: array[0..49] of byte;
{ description of ime module}
szname: array[0..79] of byte;
{ module name of the ime }
szoptions: array[0..29] of byte;
{ options of ime at startup}
fenable: boolean;
{ ime status;
true=activated,false=deactivated }
end;

ptimepro = ^timepro;
function setime(const simefilename: string): boolean;
far;
implementation
(* begin
呼叫 winnls.dll export 函数的宣告 *)
function impsetime(hwndime: hwnd;
lpimepro: ptimepro): boolean;far;
external 'winnls.dll';
(* end 呼叫 winnls.dll export 函数的宣告 *)
(* -------------------------------------------------- *)
(* setime(const simefilename: string): boolean;
(* ======
(* 切换到某一特定的输入法
(*
(* 传入引数:
(* simefilename: 输入法 ime 档名, 例: phon.ime;
(* 空字串: 英数输入法
(*
(* 传回值:
(* true: 切换成功
(* false: 失败
(* -------------------------------------------------- *)
function setime(const simefilename: string): boolean;
var
pimepro: ptimepro;
begin

result := false;
if maxavail < sizeof(timepro) then

begin

messagedlg('记忆体不足', mtwarning, [mbok], 0);
exit;
end
else

begin

new(pimepro);
try
if simefilename = '' then
(* 空字串, 还原到英数输入法 *)
pimepro^.szname[0] := 0
else

strpcopy(@pimepro^.szname, simefilename);
result := impsetime(0, pimepro);
(* 呼叫 impsetime *)
finally
dispose(pimepro);
end;
{ of try }
end;

end;
{ of setime }
end.
{ of unit win31 }
 
调用LoadLibrary函数时:
1.不是系统默认目录需指明目录;
2.动态库的名称是否正确;
3.如果成功,返回的Handle应该>0;否则应该为0;
4.如果想获得错误在哪,可以通过GetLastError去获得(返回值通过查找
SysUtils.pas中找到相应的解释);
调用GetProcAddress函数时:
1.函数名称是否正确;
2.如果想获得错误在哪,可以通过GetLastError去获得(返回值通过查找
SysUtils.pas中找到相应的解释);

 
1.DLL函数名大小写敏感
2 你的TPhsEnable怎么定义的?
 
@PhsEnable := GetProcAddress(hPhsDll, 'PHSENABLE');
中的'PHSENABLE' 的大小写要完全和dll中定义的一致.
 
动态加载dll建议用Mts技术
 
对我最有价值德帮助是“DLL函数名大小写敏感
”这句话,由于其他几个人德回答也很有意义,故
多分些分数。
谢谢各位
 
我原来想分配100分,但系统不允许,只好重新分配。
 
后退
顶部