Delphi下的DLL开发
- 格式:docx
- 大小:18.22 KB
- 文档页数:3
Delphi制作DLL的方法一 Dl l的制作一般步骤二参数传递三 DL L的初始化和退出清理[如果需要初始化和退出清理]四全局变量的使用五调用静态载入六调用动态载入七在DLL建立一个TF orM八在DLL中建立一个TMDIC hildF orM九示例:十 Del phi制作的Dll与其他语言的混合编程中常遇问题:十一相关资料一 Dll的制作一般分为以下几步:1在一个DL L工程里写一个过程或函数2写一个Ex ports关键字,在其下写过程的名称。
不用写参数和调用后缀。
二参数传递1参数类型最好与win dow C++的参数类型一致。
不要用DE LPHI的数据类型。
2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。
成功或失败的返回值最好为1[成功]或0[失败].一句话,与wi ndows c++兼容。
3用stdc all声明后缀。
4最好大小写敏感。
5 无须用far调用后缀,那只是为了与w indow s 16位程序兼容。
三D LL的初始化和退出清理[如果需要初始化和退出清理]1 DL LProc[SysU tils单元的一个P ointe r]是DL L的入口。
在此你可用你的函数替换了它的入口。
但你的函数必须符合以下要求[其实就是一个回调函数]。
如下:pro cedur e Dll Enter Point(dwRe ason: DWOR D);fa r;std call;dwRe ason参数有四种类型:DL L_PRO CESS_ATTAC H:进程进入时DL L_PRO CESS_DETAC H:进程退出时DL L_THR EAD_A TTACH :线程进入时DL L_THR EAD_D ETACH :线程退出时在初始化部分写:D LLPro c :=@DLLE nterP oint;Dl lEnte rPoin t(DLL_PROC ESS_A TTACH);2如Form上有Tdc omCon necti on组件,就Uses Acti vex,在初始化时写一句CoI nitia lize(nil);3 在退出时一定保证Dco mConn ectio n.Con necte d :=False,并且数据集已关闭。
Delphi DLL 参数1. 什么是 Delphi DLL?Delphi是一种基于Object Pascal语言的集成开发环境(IDE),是由Embarcadero Technologies开发的。
Delphi可用于开发各种类型的应用程序,包括桌面应用程序、Web应用程序和移动应用程序。
Delphi中的DLL(动态链接库)是一种可重用的代码库,可以在不同的应用程序中共享和调用。
2. DLL 的优势使用DLL的主要优势在于代码重用和模块化开发。
通过将代码放入DLL中,我们可以将其用于多个应用程序中,避免重复编写相同的代码。
此外,DLL还提供了一种有效的方式来实现模块化开发,使得应用程序的开发和维护更加简单和可靠。
3. Delphi DLL 的参数在Delphi中,DLL的参数是指在调用DLL函数时传递给函数的值或引用。
参数可以是输入参数、输出参数或输入/输出参数。
下面是一些常见的DLL参数类型:•整数参数:在Delphi中,整数参数可以是Byte、ShortInt、Word、SmallInt、Cardinal、Integer等类型。
这些参数可以用于传递整数值,如计数器、索引等。
•浮点数参数:浮点数参数可以是Single、Double、Extended等类型。
这些参数用于传递浮点数值,如坐标、价格等。
•字符串参数:字符串参数可以是AnsiString、WideString、UnicodeString 等类型。
这些参数用于传递文本信息,如文件路径、用户名等。
•指针参数:指针参数用于传递内存地址,可以是PChar、PByte、PInteger 等类型。
通过指针参数,我们可以在DLL函数内部修改传入的参数值。
•数组参数:数组参数可以是静态数组或动态数组。
通过数组参数,我们可以传递一组相关的值,如图像像素、数据集等。
•记录参数:记录参数可以是自定义的记录类型。
通过记录参数,我们可以传递一组相关的字段值,如学生信息、订单详情等。
⽤Delphi制作DLL的⽅法 ⼀ Dll的制作⼀般步骤 ⼆参数传递 三 DLL的初始化和退出清理[如果需要初始化和退出清理] 四全局变量的使⽤ 五调⽤静态载⼊ 六调⽤动态载⼊ 七在DLL建⽴⼀个TForM ⼋在DLL中建⽴⼀个TMDIChildForM 九⽰例: ⼗ Delphi制作的Dll与其他语⾔的混合编程中常遇问题: ⼗⼀相关资料 ⼀ Dll的制作⼀般分为以下⼏步: 1 .在⼀个DLL⼯程⾥写⼀个过程或函数 2 .写⼀个Exports关键字,在其下写过程的名称。
不⽤写参数和调⽤后缀。
⼆参数传递 1 .参数类型最好与window C++的参数类型⼀致。
不要⽤DELPHI的数据类型。
2 .最好有返回值[即使是⼀个过程],来报出调⽤成功或失败,或状态。
成功或失败的返回值最好为1[成功]或0[失败].⼀句话,与windows c++兼容。
3 .⽤stdcall声明后缀。
4 .最好⼤⼩写敏感。
5 .⽆须⽤far调⽤后缀,那只是为了与windows 16位程序兼容。
三 DLL的初始化和退出清理[如果需要初始化和退出清理] 1 .DLLProc[SysUtils单元的⼀个Pointer]是DLL的⼊⼝。
在此你可⽤你的函数替换了它的⼊⼝。
但你的函数必须符合以下要求[其实就是⼀个回调函数]。
如下: procedure DllEnterPoint(dwReason: DWORD);far;stdcall; dwReason参数有四种类型: DLL_PROCESS_ATTACH:进程进⼊时 DLL_PROCESS_DETACH进程退出时 DLL_THREAD_ATTACH 线程进⼊时 DLL_THREAD_DETACH 线程退出时 在初始化部分写: DLLProc := @DLLEnterPoint; DllEnterPoint(DLL_PROCESS_ATTACH); 2 .如Form上有TdcomConnection组件,就Uses Activex,在初始化时写⼀句CoInitialize (nil); 3 .在退出时⼀定保证DcomConnection.Connected := False,并且数据集已关闭。
标题:Delphi中使用DLL调用及结构参数传递的方法一、引言在Delphi中,我们经常需要使用动态信息库(DLL)来实现对外部功能的调用。
而在调用DLL时,有时需要传递结构参数,本文将介绍在Delphi中使用DLL进行结构参数传递的方法。
二、调用DLL1. 静态信息和动态信息在Delphi中,我们可以通过静态信息和动态信息两种方式调用DLL。
静态信息是将DLL文件直接嵌入到可执行文件中,而动态信息则是在程序运行时加载DLL文件。
一般来说,动态信息是更为常用的方式。
2. 使用动态信息调用DLL在Delphi中使用动态信息调用DLL,一般需要使用`LoadLibrary`函数加载DLL文件,然后使用`GetProcAddress`函数获取DLL中的函数位置区域,最后通过指针调用DLL函数。
示例代码如下:```delphivarhDLL: THandle; // DLL句柄addFunc: function(a, b: Integer): Integer; stdcall; // DLL函数指针beginhDLL := LoadLibrary('MyDll.dll'); // 加载DLLif hDLL <> 0 thenbegin@addFunc := GetProcAddress(hDLL, 'Add'); // 获取DLL中的Add函数位置区域if Assigned(addFunc) thenbegin// 调用DLL函数Result := addFunc(1, 2);end;FreeLibrary(hDLL); // 释放DLLend;end;```三、结构参数传递在DLL调用中,有时我们需要传递结构参数,即将自定义的结构体作为函数参数传递给DLL中的函数。
下面将介绍在Delphi中如何实现结构参数的传递。
1. 定义结构体我们需要在Delphi中定义需要传递的结构体。
动态链接库是一个能够被应用程序和其它的DLL调用的过程和函数的集合体,它里面包含的是公共代码或资源。
由于DLL代码使用了内存共享技术,在某些地方windows也给了DLL一些更高的权限,因而DLL中可以实现一些一般程序所不能实现的功能,如实现windows的HOOK、ISAPI等。
同时,DLL还为不同语言间代码共享提供了一条方便的途径。
因而DLL在编程时应用较为广泛,本文将介绍如何在 Delphi 中建立和使用DLL。
一.DLL 库内存共享机制从使用效果看,DLL和unit 很像,它们都可以被别的工程模块所调用,但二者在内部的实现机制上确存在着差别。
如果一个程序模块中用uses语句引用了某个unit,编译程序在编译该模块时,便会连同unit一起编译,并把编译后的可执行代码链接到本程序模块中,这就是一个程序模块能够调用所引用unit中过程和函数的原因。
当同一个unit被多个工程所引用时,则每个工程中都含有该unit 的可执行代码,当含有该unit的多个工程同时执行时,unit的可执行代码会随不同工程而多次被调入内存,造成内存资源的浪费。
DLL则不同,它即使被某个工程调用,编译后仍是独立的,也就是说编译后,一个DLL库形成一个单独的可执行文件,而不与任何其它的可执行文件连接在一起,因而DLL库并不从属于某个特定的工程,当多个工程调用同一个DLL库时只有第一个工程把DLL库调入内存,其余工程并不重复调入同一个DLL库到内存,而是到同一个共享内存区读取。
并且,DLL的执行代码是在程序运行期间动态调入的,而不是如unit在程序运行时就与整个工程一起调入内存。
这样便可消除unit带来的相同代码多处占用内存的弊病。
二 Delphi中DLL库的建立在Delphi环境中,编写一个DLL同编写一个一般的应用程序并没有太大的区别。
事实上作为DLL主体的DLL函数的编写,除了在内存、资源的管理上有所不同外,并不需要其它特别的手段。
Delphi中高级DLL的编写和调用2001年06月14日10:54:38 赛迪网苏涌根据Delphi提供的有关DLL编写和调用的帮助信息,你可以很快完成一般的DLL编写和调用的应用程序。
本文介绍的主题是如何编写和调用能够传递各种参数(包括对象实例)的DLL。
例如,主叫程序传递给DLL一个ADOConnection 对象示例作为参数,DLL中的函数和过程调用通过该对象实例访问数据库。
需要明确一些基本概念。
对于DLL,需要在主程序中包含exports子句,用于向外界提供调用接口,子句中就是一系列函数或过程的名字。
对于主叫方(调用DLL的应用程序或其它的DLL),则需要在调用之前进行外部声明,即external保留字指示的声明。
这些是编写DLL和调用DLL 必须具备的要素。
另外需要了解Object Pascal 中有关调用协议的内容。
在Object Pascal 中,对于过程和函数有以下五种调用协议:指示字参数传递顺序参数清除者参数是否使用寄存器register 自左向右被调例程是pascal 自左向右被调例程否cdecl 自右向左调用者否stdcall 自右向左被调例程否safecall 自右向左被调例程否这里的指示字就是在声明函数或过程时附加在例程标题之后的保留字,默认为register,即是唯一使用CPU寄存器的参数传递方式,也是传递速度最快的方式;pascal: 调用协议仅用于向后兼容,即向旧的版本兼容;cdecl: 多用于C和C++语言编写的例程,也用于需要由调用者清除参数的例程;stdcall: 和safecall主要用于调用W indows API 函数;其中safecall还用于双重接口。
在本例中,将使用调用协议cdecl ,因为被调用的DLL中,使用的数据库连接是由主叫方传递得到的,并且需要由主叫方处理连接的关闭和销毁。
下面是DLL完整源程序和主叫程序完整源程序。
包括以下四个文件:Project1.DPR {主叫程序}Unit1.PAS {主叫程序单元}Project2.DPR {DLL}Unit2.PAS {DLL单元}{---------- DLL 主程序Project2.DPR ----------}library Project2;usesSysUtils,Classes,Unit2 in 'Unit2.pas' {Form1};{$R *.RES}{ 下面的语句用于向调用该DLL的程序提供调用接口}exportsDoTest; { 过程来自单元Unit2 }beginend.{---------- DLL中的单元Unit2.PAS ----------}unit Unit2;interfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Db, ADODB, StdCtrls, Menus;typeTForm1 = class(TForm)ADOConnection1: TA DOConnection;{ 本地数据库连接}Memo1: TMemo; { 用于显示信息}privatepublicend;{ 该过程向外提供}procedure DoTest(H: THandle; { 获得调用者的句柄}A Conn: TADOConnection;{ 获得调用者的数据库连接}S: string; { 获得一些文本信息}N: Integer); { 获得一些数值信息}cdecl; { 指定调用协议}implementation{$R *.DFM}procedure DoTest(H: THandle; AConn: TA DOConnection; S: string; N: Integer); beginApplication.Handle := H; { 将过程的句柄赋值为调用者的句柄}{ 上面语句的作用在于,DLL的句柄和调用者的句柄相同,在任务栏中就不会} { 各自出现一个任务标题了。
深入Delphi下的DLL编程作者:岑心引言相信有些计算机知识的朋友都应该听说过―DLL‖。
尤其是那些使用过windows操作系统的人,都应该有过多次重装系统的―悲惨‖经历——无论再怎样小心,没有驱动损坏,没有病毒侵扰,仍然在使用(安装)了一段时间软件后,发现windows系统越来越庞大,操作越来越慢,还不时的出现曾经能使用的软件无法使用的情况,导致最终不得不重装系统。
这种情况常常是由于dll文件的大量安装和冲突造成的。
这一方面说明DLL的不足,另一方面也说明DLL的重要地位,以至我们无法杜绝它的使用。
DLL(动态链接库,Dynamic Link Library)简单来说是一种可通过调用执行的已编译的代码模块。
DLL是windows系统的早期产物。
当时的主要目的是为了减少应用程序对内存的使用。
只有当某个函数或过程需要被使用时,才从硬盘调用它进入内存,一旦没有程序再调用该DLL了,才将其从内存中清除。
光说整个windows系统,就包括了成百上千个dll文件,有些dll文件的功能是比较专业(比如网络、数据库驱动)甚至可以不安装的。
假如这些功能全部要包括在一个应用程序(Application program)里,windows将是一个数百M大小的exe文件。
这个简单的例子很容易解释DLL的作用,而调用DLL带来的性能损失则变得可被忽略不计。
多个应用程序调用同一个DLL,在内存里只有一个代码副本。
而不会象静态编译的程序那样每一个都必须全部的被装入。
装载DLL时,它将被映射到进程的地址空间,同时使用DLL的动态链接并非将库代码拷贝,而仅仅记录函数的入口点和接口。
同时DLL还能带来的共享的好处。
一家公司开发的不同软件可能需要一些公用的函数/过程,这些函数/过程可能是直接的使用一些内部开发的DLL;一些常用的功能则可以直接使用windows 的标准DLL,我们常说的windows API就是包含在windows几个公用DLL文件里的函数/过程;理论上(如果不牵涉作者的版权),知道一个DLL的声明及作用(函数定义的输入参数及返回值),我们完全可以在不清楚其实现(算法或编译方式)的情况下直接使用它。
一、开使你的第一个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函数。
只要编译上面的代码,就可以玫揭桓雒 狣elphi.dll的动态链接库。
现在,让我们来看看有哪些需要注意的地方:
1.在DLL中编写的函数或过程都必须加上stdcall调用参数。
在Delphi 1或Delphi 2环境下该调用参数是far。
从Delphi 3以后将这个参数变为了stdcall,目的是为了使用标准的Win32参数传递技术来代替优化的register参数。
忘记使用stdcall参数是常见的错误,这个错误不会影响DLL的编译和生成,但当调用这个DLL时会发生很严重的错误,导致操作系统的死锁。
原因是register参数是Delphi的默认参数。
2.所写的函数和过程应该用exports语句声明为外部函数。
正如大家看到的,TestDll函数被声明为一个外部函数。
这样做可以使该函数在外部就能看到,具体方法是单激鼠标右键用“快速查看(Quick View)”功能查看该DLL文件。
(如果没有“快速查看”选项可以从Windows CD上安装。
)TestDll函数会出现在Export Table栏中。
另一个很充分的理由是,如果不这样声明,我们编写的函数将不能被调用,这是大家都不愿看到的。
3.当使用了长字符串类型的参数、变量时要引用ShareMem。
Delphi中的string类型很强大,我们知道普通的字符串长度最大为256个字符,但Delphi 中string类型在默认情况下长度可以达到2G。
(对,您没有看错,确实是两兆。
)这时,如果您坚持要使用string类型的参数、变量甚至是记录信息时,就要引用ShareMem单元,而且必须是第一个引用的。
既在uses语句后是第一个引用的单元。
如下例:uses
ShareMem,
SysUtils,
Classes;
还有一点,在您的工程文件(*.dpr)中而不是单元文件(*.pas)中也要做同样的工作,这一点Delphi自带的帮助文件没有说清楚,造成了很多误会。
不这样做的话,您很有可能付出死机的代价。
避免使用string类型的方法是将string类型的参数、变量等声明为Pchar 或ShortString(如:s:string[10])类型。
同样的问题会出现在当您使用了动态数组时,解决的方法同上所述。