动态数据库
Dd字母对于你来说一定很熟悉吧,它是Dynamic database 的缩写形式,函数的可执行代码位于一个 动态数据库中,该 动态数据库 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。动态数据库还有助于共享数据和资源。多个应用程序可同时访问内存中单个 动态数据库 副本的内容。
动态数据库是一个能够被应用程序和其它的DLL调用的过程和函数的集合体,它里面包含的是公共代码或资源。由于动态数据库代码使用了内存共享技术,在某些地方windows也给了动态数据库一些更高的权限,因而动态数据库中可以实现一些一般程序所不能实现的功能,如实现windows的HOOK、ISAPI等。
同时,动态数据库还为不同语言间代码共享提供了一条方便的途径。因而动态数据库在编程时应用较为广泛,本文将介绍如何在 Delphi 中建立和使用动态数据库。
从使用效果看,动态数据库和unit 很像,它们都可以被别的工程模块所调用,但二者在内部的实现机制上确存在着差别。如果一个程序模块中用uses语句引用了某个unit,编译程序在编译该模块时,便会连同unit一起编译,并把编译后的可执行代码链接到本程序模块中,这就是一个程序模块能够调用所引用unit中过程和函数的原因。
当同一个unit被多个工程所引用时,则每个工程中都含有该unit的可执行代码,当含有该unit的多个工程同时执行时,unit的可执行代码会随不同工程而多次被调入内存,造成内存资源的浪费。动态数据库则不同,它即使被某个工程调用,编译后仍是独立的。
也就是说编译后,一个动态数据库形成一个单独的可执行文件,而不与任何其它的可执行文件连接在一起,因而动态数据库
并不从属于某个特定的工程,当多个工程调用同一个动态数据库时只有第一个工程把动态数据库调入内存,其余工程并不重复调入同一个动态数据库到内存,而是到同一个共享内存区读取。并且,动态数据库的执行代码是在程序运行期间动态调入的,而不是如unit在程序运行时就与整个工程一起调入内存。这样便可消除unit带来的相同代码多处占用内存的弊病。Delphi中动态数据库的建立
在Delphi环境中,编写一个动态数据库同编写一个一般的应用程序并没有太大的区别。事实上作为动态数据库主体的动态数据库函数的编写,除了在内存、资源的管理上有所不同外,并不需要其它特别的手段。
一般工程文件的格式为:
program 工程标题;
uses 子句;
程序体
而DLLs工程文件的格式为:
library 工程标题;
uses 子句;
exprots 子句;
它们主要的区别有两点1.一般工程文件的头标用program关键字,而动态数据库工程文件头标用library 关键字。不同的关键字通知编译器生成不同的可执行文件。用program关键字生成的是.exe文件,而用library关键字生成的是.dll文件。
2.假如动态数据库要输出供其它应用程序使用的函数或过程,则必须将这些函数或过程列在exports子句中。而这些函数或过程本身必须用export编译指令进行编译。 在Delphi主菜单file 中选new...项,在弹出的窗口中双击动态数据库图标,便会自动给出动态数据库源模块框架,如下:
Library project1;
{...注释...}
uses
SysUtils, Classes;
begin
end.
接下来便可在USES和begin之间加入想在该动态数据库中实现的过程和函数的定义,并用export和exprots保字把它们引出,以便别的模块引用,在begin和end之间加入初始化代码,初始化代码是用来对动态数据库变量初始化的。应注意,即便无初始化代码begin与end也不可省略,如下例:
library minmax;
function Min(X, Y: Integer): Integer; export;
begin
if X
end;
function Max(X, Y: Integer): Integer; export;
begin
if X > Y then Max := X else Max := Y;
end;
exports
Min index 1,
Max index 2;
begin
end.
经编译后,并以minmax.动态数据库存盘后,一个动态数据库文件便形成了。
动态数据库的访问访问动态数据库有两种方式,一种是静态引用,另一种是动态引用。
1、用静态引用这种方法装入动态数据库要做两件事情:为动态数据库创建一个输入单元,以及用USES把输入单元连接到要使用动态数据库 函数的程序模块中。为动态数据库创建的输入单元与普通的单元的区别仅在于:在它的接口处声明的过程、函数,并不在它的实现部分给出真正的实现代码,而是用external关键字把过程、函数的实现细节委托给外部动态数据库模块。
external命令的使用语法如下:
procedure /function 过程/函数名;external 动态数据库模块名;
下面给出为上面创建的minmax.动态数据库写的输入单元源文件testdll .pas,从中可看出输入单元与一般单元的一些差别,代码如下所示:
unit testdll;
interface
uses
function Min (X, Y: Integer): Integer;
function Max (X, Y: Integer): Integer;
implementation
function Min; external ‘minmax.Dd’;
function Max; external ‘minmax.Dd’;
end.
一个应用程序若想调用minmax.Dd中的函数,只须在其uses语句中加入testdll 单元即可。
2、动态装入动态数据库,要用到Windows的三个API函数。Loadlibrary、Freelibrary和GetprocAddress 。 loadlibrary函数用来装入动态数据库,其调用格式如下:
function loadlobrary (DdfileName:Pchar): THandle:
当不再需要一个动态数据库时,应调用FreeLibrary函数将其释放,以空出宝贵的内存资源,其调用格式如下:
procedure FreeLibrary (Libmodule:THandle)
Libmodule 为由LoadLibrary调用得到的动态数据库句柄。在用loadlobrary 函数装入某个动态数据库和调用FreeLibrary释放该动态数据库之间的程序段中, 可以使用该动态数据库中的过程和函数,具体使用方法是:用GetprocAddress函数把动态数据库中函数的地址传递给程序中某个函数变量,再用该变量实现动态数据库函数的调用。GetprocAddress函数声名如下
function GetprocAddress (Libmodule:THandle:procname:pchar):TFarProc:
在调用动态数据库时应注意, 所需动态数据库须与应用程序在同一目录或Windows System 目录下。
动态数据库是 Windows下程序组织的一种重要方式,使用动态数据库可以极大地保护用户在不同开发工具、不同时期所做的工作,提高编程效率。
静态数据库在静态库情况下,函数和数据被编译进一个二进制文件(通常扩展名为*.LIB),Visual C++的编译器在处理程序代码时将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为"静态链接",此时因为应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。
静态数据库是一种1用户模块它提供了函数的完整的目标代码(在静态库*.lib中)如果程序调用中的静态数据库的函数,则在进行连接时连接程序将中所包含的该函数的代码复制到运行文件中. 动态数据库也包含了其所提供的函数的目标代码,但是在程序连接动态数据库中的函数时,连接程序并不拦包含在动态数据库中的函数的目标代码复制到运行文件而只是简单记录了函数的位置信息。
有了这些信息程序在执行时就可找到目标代码!