Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1700340
  • 博文数量: 607
  • 博客积分: 10031
  • 博客等级: 上将
  • 技术积分: 6633
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-30 17:41
文章分类

全部博文(607)

文章存档

2011年(2)

2010年(15)

2009年(58)

2008年(172)

2007年(211)

2006年(149)

我的朋友

分类:

2010-06-22 18:05:49

KeyLife富翁笔记
作者 : cainiao168
标题 : delphi dll
关键字:
分类 : 个人专区
密级 : 公开
(评分: , 回复: 0, 阅读: 778) »»

KeyLife富翁笔记  
作者 : lisa1002
标题 : dll文件
关键字: dll文件
分类 : 个人专区
密级 : 公开
(评分: , 回复: 0, 阅读: 269) »»
一、开使你的第一个DLL专案  
  1.File->Close all->File->New﹝DLL﹞

 代码:


  //自动产生Code如下  
  library Project2;  
  //这有段废话  
  uses  
  SysUtils,  
  Classes;  

  {$R *.RES}  

  begin  
  end.



  2.加个Func进来:  
  代码:


  library Project2;  
  uses  
  SysUtils,  
  Classes;  

Function MyMax ( X , Y : integer ) : integer ; stdcall ;  
begin  
if X > Y then  
Result := X  
else  
Result := Y ;  
end ;  
//切记:Library 的名字大小写没关系,可是DLL-Func的大小写就有关系了。  
// 在 DLL-Func-Name写成MyMax与myMAX是不同的。如果写错了,立即  
// 的结果是你叫用到此DLL的AP根本开不起来。  
//参数的大小写就没关系了。甚至不必同名。如原型中是 (X,Y:integer)但引  
// 用时写成(A,B:integer),那是没关系的。  
//切记:要再加个stdcall。书上讲,如果你是用Delphi写DLL,且希望不仅给  
// Delphi-AP也希望BCB/VC-AP等使用的话,那你最好加个Stdcall ; 的指示  
//参数型态:Delphi有很多种它自己的变量型态,这些当然不是DLL所喜欢的  
// ,Windows/DLL的母语应该是C。所以如果要传进传出DLL的参数,我们  
// 尽可能照规矩来用。这两者写起来,后者会麻烦不少。如果你对C不熟  
// 的话,那也没关系。我们以后再讲。  

  {$R *.RES}  

  begin  
  end.



  3.将这些可共享的Func送出DLL,让外界﹝就是你的Delphi-AP啦﹞使用:光如此,你的AP还不能用到这些,你还要加个Exports才行。  
  代码:  


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



  4.好了,可以按 Ctrl-F9编译了。此时可不要按F9。DLL不是EXE┌不可单独执行的,如果你按F9,会有ErrorMsg的。这时如果DLL有Error,请修正之。再按Ctrl-F9。此时可能有Warning,不要紧,研究一下,看看就好。再按Ctrl-F9,此时就『Done , Compiled 』。同目录就会有个 *.dll 。恭喜,大功告成了。  

二、进行测试:开个新application:  
  1.加个TButton  
  代码:


  ShowMessage ( IntToStr(MyMax(30,50)) ) ;



  2.告知Exe到那里抓个Func  
  代码:


  //在Form,interface,var后加  
  Function MyMax ( X , Y : integer ) : integer ; stdcall ; external ’MyTestDLL.dll’ ;  
  // MyTestDLL.dll为你前时写的DLL项目名字  
  // DLL名字大小写没关系。不过记得要加 extension的 .DLL。在Win95或NT,  
  // 是不必加 extension,但这两种OS,可能越来越少了吧。要加extension


  可以了,简单吧。


  上面的例子是不是很简单?熟悉Delphi的朋友可以看出以上代码和一般的Delphi程序的编写基本是相同的,只是在TestDll函数后多了一个stdcall参数并且用exports语句声明了TestDll函数。只要编译上面的代码,就可以

在Delphi中静态调用DLL

  调用一个DLL比写一个DLL要容易一些。首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较。同样的,我们先举一个静态调用的例子。  


unit Unit1;  

interface  

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

type  
TForm1 = class(TForm)  
Edit1: TEdit;  
Button1: TButton;  
procedure Button1Click(Sender: TObject);  
private  
{ Private declarations }  
public  
{ Public declarations }  
end;  

var  
Form1: TForm1;  

implementation  

{$R *.DFM}  

//本行以下代码为我们真正动手写的代码  

function TestDll(i:integer):integer;stdcall;  
external ’Delphi.dll’;  

procedure TForm1.Button1Click(Sender: TObject);  
begin  
Edit1.Text:=IntToStr(TestDll(1));  
end;  

end.


  上面的例子中我们在窗体上放置了一个编辑框(Edit)和一个按钮(Button),并且书写了很少的代码来测试我们刚刚编写的Delphi.dll。大家可以看到我们唯一做的工作是将TestDll函数的说明部分放在了implementation中,并且用external语句指定了Delphi.dll的位置。(本例中调用程序和Delphi.dll在同一个目录中。)让人兴奋的是,我们自己编写的TestDll函数很快被Delphi认出来了。您可做这样一个实验:输入“TestDll(”,很快Delphi就会用fly-by提示条提示您应该输入的参数是什么,就像我们使用Delphi中定义的其他函数一样简单。注意事项有以下一些:  
一、调用参数用stdcall  
  和前面提到的一样,当引用DLL中的函数和过程时也要使用stdcall参数,原因和前面提到的一样。  

二、用external语句指定被调用的DLL文件的路径和名称  
  正如大家看到的,我们在external语句中指定了所要调用的DLL文件的名称。没有写路径是因为该DLL文件和调用它的主程序在同一目录下。如果该DLL文件在C:\,则我们可将上面的引用语句写为external ’C:\Delphi.dll’。注意文件的后缀.dll必须写上。  

三、不能从DLL中调用全局变量  
  如果我们在DLL中声明了某种全局变量,如:var s:byte 。这样在DLL中s这个全局变量是可以正常使用的,但s不能被调用程序使用,既s不能作为全局变量传递给调用程序。不过在调用程序中声明的变量可以作为参数传递给DLL。  

四、被调用的DLL必须存在  
  这一点很重要,使用静态调用方法时要求所调用的DLL文件以及要调用的函数或过程等等必须存在。如果不存在或指定的路径和文件名不正确的话,运行主程序时系统会提示“启动程序时出错”或“找不到*.dll文件”等运行错误。  

在Delphi中动态调用DLL

  动态调用DLL相对复杂很多,但非常灵活。为了全面的说明该问题,这次我们举一个调用由C++编写的DLL的例子。首先在C++中编译下面的DLL源程序。  


#include  

extern ”C” _declspec(dllexport)  
int WINAPI TestC(int i)  
{  
return i;  
}



  编译后生成一个DLL文件,在这里我们称该文件为Cpp.dll,该DLL中只有一个返回整数类型的函数TestC。为了方便说明,我们仍然引用上面的调用程序,只是将原来的Button1Click过程中的语句用下面的代码替换掉了。  


procedure TForm1.Button1Click(Sender: TObject);  
type  
TIntFunc=function(i:integer):integer;stdcall;  
var  
Th:Thandle;  
Tf:TIntFunc;  
Tp:TFarProc;  
begin  
Th:=LoadLibrary(’Cpp.dll’); {装载DLL}  
if Th>0 then  
try  
Tp:=GetProcAddress(Th,PChar(’TestC’));  
if Tp<>nil  
then begin  
Tf:=TIntFunc(Tp);  
Edit1.Text:=IntToStr(Tf(1)); {调用TestC函数}  
end  
else  
ShowMessage(’TestC函数没有找到’);  
finally  
FreeLibrary(Th); {释放DLL}  
end  
else  
ShowMessage(’Cpp.dll没有找到’);  
end;


  大家已经看到了,这种动态调用技术很复杂,但只要修改参数,如修改LoadLibrary(’Cpp.dll’)中的DLL名称为’Delphi.dll’就可动态更改所调用的DLL。  

一、定义所要调用的函数或过程的类型  
  在上面的代码中我们定义了一个TIntFunc类型,这是对应我们将要调用的函数TestC的。在其他调用情况下也要做同样的定义工作。并且也要加上stdcall调用参数。  

二、释放所调用的DLL  
  我们用LoadLibrary动态的调用了一个DLL,但要记住必须在使用完后手动地用FreeLibrary将该DLL释放掉,否则该DLL将一直占用内存直到您退出Windows或关机为止。  

  现在我们来评价一下两种调用DLL的方法的优缺点。静态方法实现简单,易于掌握并且一般来说稍微快一点,也更加安全可靠一些;但是静态方法不能灵活地在运行时装卸所需的DLL,而是在主程序开始运行时就装载指定的DLL直到程序结束时才释放该DLL,另外只有基于编译器和链接器的系统(如Delphi)才可以使用该方法。动态方法较好地解决了静态方法中存在的不足,可以方便地访问DLL中的函数和过程,甚至一些老版本DLL中新添加的函数或过程;但动态方法难以完全掌握,使用时因为不同的函数或过程要定义很多很复杂的类型和调用方法。对于初学者,笔者建议您使用静态方法,待熟练后再使用动态调用方法。

使用DLL的实用技巧

一、编写技巧  
  1 、为了保证DLL的正确性,可先编写成普通的应用程序的一部分,调试无误后再从主程序中分离出来,编译成DLL。  

  2 、为了保证DLL的通用性,应该在自己编写的DLL中杜绝出现可视化控件的名称,如:Edit1.Text中的Edit1名称;或者自定义非Windows定义的类型,如某种记录。  

  3 、为便于调试,每个函数和过程应该尽可能短小精悍,并配合具体详细的注释。  

  4 、应多利用try-finally来处理可能出现的错误和异常,注意这时要引用SysUtils单元。  

  5 、尽可能少引用单元以减小DLL的大小,特别是不要引用可视化单元,如Dialogs单元。例如一般情况下,我们可以不引用Classes单元,这样可使编译后的DLL减小大约16Kb。  

二、调用技巧  
  1 、在用静态方法时,可以给被调用的函数或过程更名。在前面提到的C++编写的DLL例子中,如果去掉extern ”C”语句,C++会编译出一些奇怪的函数名,原来的TestC函数会被命名为@TestC$s等等可笑的怪名字,这是由于C++采用了C++ name mangling技术。这个函数名在Delphi中是非法的,我们可以这样解决这个问题:  
改写引用函数为  


function TestC(i:integer):integer;stdcall;  
external ’Cpp.dll’;name ’@TestC$s’;


其中name的作用就是重命名。  

  2 、可把我们编写的DLL放到Windows目录下或者Windows\system目录下。这样做可以在external语句中或LoadLibrary语句中不写路径而只写DLL的名称。但这样做有些不妥,这两个目录下有大量重要的系统DLL,如果您编的DLL与它们重名的话其后果简直不堪设想,况且您的编程技术还不至于达到将自己编写的DLL放到系统目录中的地步吧!  

三、调试技巧
  1 、我们知道DLL在编写时是不能运行和单步调试的。有一个办法可以,那就是在Run|parameters菜单中设置一个宿主程序。在Local页的Host Application栏中添上宿主程序的名字就可进行单步调试、断点观察和运行了。  

  2 、添加DLL的版本信息。开场白中提到了版本信息对于DLL是很重要的,如果包含了版本信息,DLL的大小会增加2Kb。增加这么一点空间是值得的。很不幸我们如果直接使用Project|options菜单中Version选项是不行的,这一点Delphi的帮助文件中没有提到,经笔者研究发现,只要加一行代码就可以了。如下例:  


library Delphi;  

uses  
SysUtils,  
Classes;  

{$R *.RES}  
//注意,上面这行代码必须加在这个位置  

function TestDll(i:integer):integer;stdcall;  
begin  
Result:=i;  
end;  

exports  
TestDll;  

begin  
end.



  3 、为了避免与别的DLL重名,在给自己编写的DLL起名字的时候最好采用字符数字和下划线混合的方式。如:jl_try16.dll。  

  4 、如果您原来在Delphi 1或Delphi 2中已经编译了某些DLL的话,您原来编译的DLL是16位的。只要将源代码在新的Delphi 3或Delphi 4环境下重新编译,就可以得到32位的DLL了。  

[后记]:除了上面介绍的DLL最常用的使用方法外,DLL还可以用于做资源的载体。例如,在Windows中更改图标就是使用的DLL中的资源。另外,熟练掌握了DLL的设计技术,对使用更为高级的OLE、COM以及ActiveX编程都有很多益处。  



2008-4-29 14:40:53  

阅读(944) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~