二○○四年同学聚会建立的同学论坛,因为平时访问量太少,已经关闭了。
delphi函数参考手册
名称 类型 说明
abort 函数 引起放弃的意外处理
abs 函数 绝对值函数
addexitproc 函数 将一过程添加到运行时库的结束过程表中
addr 函数 返回指定对象的地址
adjustlinebreaks 函数 将给定字符串的行分隔符调整为cr/lf序列
align 属性 使控件位于窗口某部分
alignment 属性 控件标签的文字位置
allocmem 函数 在堆栈上分配给定大小的块
allowgrayed 属性 允许一个灰度选择
ansicomparestr 函数 比较字符串(区分大小写)
ansicomparetext 函数 比较字符串(不区分大小写)
ansilowercase 函数 将字符转换为小写
ansiuppercase 函数 将字符转换为大写
append 函数 以附加的方式打开已有的文件
arctan 函数 余切函数
assignfile 函数 给文件变量赋一外部文件名
assigned 函数 测试函数或过程变量是否为空
autosize 属性 自动控制标签的大小
backgrounddi2001.jpg 属性 背景色
beginthread 函数 以适当的方式建立用于内存管理的线程
bevelinner 属性 控件方框的内框方式
bevelouter 属性 控件方框的外框方式
bevelwidth 属性 控件方框的外框宽度
blockread 函数 读一个或多个记录到变量中
blockwrite 函数 从变量中写一个或多个记录
borderstyle 属性 边界类型
borderwidth 属性 边界宽度
break 命令 终止for、while、repeat循环语句
brush 属性 画刷
caption 属性 标签文字的内容
changefileext 函数 改变文件的后缀
chdir 函数 改变当前目录
checked 属性 确定复选框选中状态
chr 函数 返回指定序数的字符
closefile 命令 关闭打开的文件
color 属性 标签的颜色
columns 属性 显示的列数
comparestr 函数 比较字符串(区分大小写)
concat 函数 合并字符串
continue 命令 继续for、while、repeat的下一个循环
copy 函数 返回一字符串的子串
cos 函数 余弦函数
ctl3d 属性 是否具有3d效果
cursor 属性 鼠标指针移入后的形状
date 函数 返回当前的日期
datetimetofiledate 函数 将delphi的日期格式转换为dos的日期格式
datetimetostr 函数 将日期时间格式转换为字符串
datetimetostring 函数 将日期时间格式转换为字符串
datetostr 函数 将日期格式转换为字符串
dayofweek 函数 返回星期的数值
dec 函数 递减变量值
decodedate 函数 将日期格式分解为年月日
decodetime 函数 将时间格式分解为时、分、秒、毫秒
delete 函数 从字符串中删除子串
deletefile 命令 删除文件
diskfree 函数 返回剩余磁盘空间的大小
disksize 函数 返回指定磁盘的容量
dispose 函数 释放动态变量所占的空间
disposestr 函数 释放字符串在堆栈中的内存空间
ditherbackgrounddi2001.jpg?使背景色的色彩加重或减少50%
dragcursor 属性 当鼠标按下时光标的形状
dragmode 属性 按动的作用方式
dropdowncount 属性 容许的显示数据项的数目
editmask 属性 编辑模式
enabled 属性 是否使标签呈现打开状态
encodedate 函数 将年月日合成为日期格式
encodetime 函数 将时、分、秒、毫秒合成为时间格式
endmargin 属性 末尾边缘
eof 函数 对有类型或无类型文件测试是否到文件尾
eoln 函数 返回文本文件的行结束状态
erase 命令 删除外部文件
exceptaddr 函数 返回引起当前意外的地址
exclude 函数 从集合中删除一些元素
exceptobject 函数 返回当前意外的索引
exit 命令 立即从当前的语句块中退出
exp 函数 指数函数
expandfilename 函数 返回包含绝对路径的字符串
extendedselect 属性 是否允许存在选择模式,true时,multiselect才有意义
extractfiledir 函数 返回驱动器和路径
extractfileext 函数 返回文件的后缀
extractfilename 函数 返回文件名
extractfilepath 函数 返回指定文件的路径
fileage 函数 返回文件已存在的时间
fileclose 命令 关闭指定的文件
filecreate 命令 用指定的文件名建立新文件
filedatetodatetime 函数 将dos的日期格式转换为delphi的日期格式
fileexists 函数 检查文件是否存在
filegatattr 函数 返回文件的属性
filegetdate 函数 返回文件的dos日期时间标记
fileopen 命令 用指定的存取模式打开指定的文件
filepos 函数 返回文件的当前指针位置
fileread 命令 从指定的文件读取
filesearch 命令 在目录中搜索指定的文件
fileseek 函数 改变文件的指针
filesetattr 函数 设置文件属性
filesetdate 函数 设置文件的dos日期时间标记
filesize 函数 返回当前文件的大小
filewrite 函数 对指定的文件做写操作
fillchar 函数 用指定的值填充连续字节的数
findclose 命令 终止findfirst/findnext序列
findfirst 命令 对指定的文件名及属性搜索目录
findnext 命令 返回与文件名及属性匹配的下一入口
floattodecimal 函数 将浮点数转换为十进制数
floattostrf 函数 将浮点数转换为字符串
floattostr 函数 将浮点数转换为字符串
floattotext 函数 将给定的浮点数转换为十进制数
floattotextfmt 函数 将给定的浮点数转换为十进制数
flush 函数 将缓冲区的内容刷新到输出的文本文件中
fmtloadstr 函数 从程序的资源字符串表中装载字符串
fmtstr 函数 格式化一系列的参数,其结果以参数result返回
font 属性 设置字体
format 函数 格式化一系列的参数并返回pascal字符串
formatbuf 函数 格式化一系列的参数
formatdatetime 函数 用指定的格式来格式化日期和时间
formatfloat 函数 指定浮点数格式
frac 函数 返回参数的小数部分
freemem 函数 按给定大小释放动态变量所占的空间
getdir 返回指定驱动器的当前目录
getheapstatus 返回内存管理器的当前状态
getmem 建立一指定大小的动态变量,并将指针指向该处
getmemorymanager 返回内存管理器的入口点
glyph 函数 按钮上的图象
halt 停止程序的执行并返回到操作系统
hi 返回参数的高地址位
high 返回参数的上限值
hint 属性 提示信息
int 返回参数的整数部分
include 添加元素到集合中
insert 在字符串中插入子串
inttohex 将整型数转换为十六进制数
inttostr 将整型数转换为字符串
ioresult 返回最新的i/o操作完成状态
isvalidident 测试字符串是否为有效的标识符
items 属性 默认显示的节点
kind 属性 摆放样式
largechange 属性 最大改变值
layout 属性 图象布局
length 函数 返回字符串的动态长度
lines 属性 缺省显示内容
ln 函数 自然对数函数
lo 函数 返回参数的低地址位
loadstr 函数 从应用程序的可执行文件中装载字符资源
lowercase 函数 将给定的字符串变为小写
low 函数 返回参数的下限值
max 属性 最大值
maxlength 属性 最大长度
min 属性 最小值
mkdir 命令 建立一子目录
move 函数 从源到目标复制字节
multiselect 属性 允许同时选择几个数据项
name 属性 控件的名字
new 函数 建立新的动态变量并设置一指针变量指向他
newstr 函数 在堆栈上分配新的字符串
now 函数 返回当前的日期和时间
odd 测试参数是否为奇数
onactivate 事件 焦点移到窗体上时触发
onclick 事件 单击窗体空白区域触发
ondblclick 事件 双击窗体空白区域触发
onclosequery 事件 使用者试图关闭窗体触发
onclose 事件 窗体关闭后才触发
oncreate 事件 窗体第一次创建时触发
ondeactivate 事件 用户切换到另一应用程序触发
ondragdrop 事件 鼠标拖放操作结束时触发
ondragover 事件 有其他控件从他上面移过触发
onmousedown 事件 按下鼠标键时触发
onmouseup 事件 释放鼠标键时触发
onmousemove 事件 移动鼠标时触发
onhide 事件 隐藏窗体时触发
onkeydown 事件 按下键盘某键时触发
onkeypress 事件 按下键盘上的单个字符键时触发
onkeyup 事件 释放键盘上的某键时触发
onpaint 事件 窗体上有新部分暴露出来触发
onresize 事件 重新调整窗体大小触发
onshow 事件 在窗体实际显示之前瞬间触发
ord 返回序数类的序数
outlinestyle 属性 类型
outofmemoryerror 引起outofmemory意外
pageindex 属性 页索引
pages 属性 页
paramcount 函数 返回在命令行上传递给程序的参数数量
paramstr 函数 返回指定的命令行参数
pen 属性 画刷设置
pi 函数 返回圆周率pi
picture 属性 显示图象
pictureclosed 属性 设置closed位图
pictureleaf 属性 设置leaf位图
pictureminus 属性 设置minus位图
pictureopen 属性 设置open位图
pictureplus 属性 设置plus位图
pos 函数 在字符串中搜索子串
pred 函数 返回先前的参数
random 函数 返回一随机函数
randomize 函数 用一随机数初始化内置的随机数生成器
read 函数 对有格式的文件,读一文件组件到变量中;
对文本文件,读一个或多个值到一个或多个变量中
readln 函数 执行read过程,然后跳到文件下一行
readonly 属性 只读属性
reallocmem 函数 分配一动态变量
rename 函数 重命名外部文件
renamefile 函数 对文件重命名
reset 函数 打开已有的文件
rewrite 函数 建立并打开一新的文件
rmdir 函数 删除空的子目录
round 函数 将实数值舍入为整型值
runerror 函数 停止程序的执行
scrollbars 属性 滚动条状态
seek 函数 将文件的当前指针移动到指定的组件上
seekeof 函数 返回文件的文件结束状态
seekeoln 函数 返回文件的行结束状态
selectedcolor 属性 选中颜色
setmemorymanager 函数 设置内存管理器的入口点
settextbuf 函数 给文本文件指定i/o缓冲区
shape 属性 显示的形状
showexception 函数 显示意外消息与地址
sin 函数 正弦函数
sizeof 函数 返回参数所占的字节数
smallchange 属性 最小改变值
sorted 属性 是否允许排序
sqr 函数 平方函数
sqrt 函数 平方根函数
startmargin 属性 开始边缘
state 属性 控件当前状态
str 函数 将数值转换为字符串
stralloc 函数 给以null结束的字符串分配最大长度-1的缓冲区
strbufsize 函数 返回存储在由stralloc分配的字符缓冲区的最大字符数
strcat 函数 将一字符串附加到另一字符串尾并返回合并的字符串
strcomp 函数 比较两个字符串
strcopy 函数 将一个字符串复制到另一个字符串中
strdispose 函数 释放堆栈上的字符串
strecopy 函数 将一字符串复制到另一个字符串并返回结果字符串尾部的指针
strend 函数 返回指向字符串尾部的指针
stretch 属性 自动适应控件的大小
strfmt 函数 格式化一系列的参数
stricomp 函数 比较两个字符串(不区分大小写)
stringtowidechar 函数 将ansi字符串转换为unicode字符串
strlcat 函数 将一字符串中的字符附加到另一字符串尾并返回合并的字符串
strlcomp 函数 以最大长度比较两个字符串
strlcopy 函数 将一个字符串中的字符复制到另一个字符串中
strlen 函数 返回字符串中的字符数
strlfmt 函数 格式化一系列的参数,其结果中包含有指向目标缓冲区的指针
strlicomp 函数 以最大长度比较两个字符串(不区分大小写)
strlower 函数 将字符串中的字符转换为小写
strmove 函数 将一个字符串中的字符复制到另一个字符串中
strnew 函数 在堆栈上分配一个字符串
strpas 函数 将以null结束的字符串转换为pascal类的字符串
strpcopy 函数 将pascal类的字符串复制为以null结束的字符串
strplcopy 函数 从pascal类的最大长度字符串复制为以null结束的字符串
strpos 函数 返回一个字符串在另一个字符串中首次出现指针
strrscan 函数 返回字符串中最后出现字符的指针
strscan 函数 返回字符串中出现首字符的指针
strtodate 函数 将字符串转换为日期格式
strtodatetime 函数 将字符串转换为日期/时间格式
strtofloat 函数 将给定的字符串转换为浮点数
strtoint 函数 将字符串转换为整型
strtointdef 函数 将字符串转换为整型或默认值
strtotime 函数 将字符串转换为时间格式
strupper 函数 将字符串中的字符转换为大写
style 属性 类型选择
suce 函数 返回后继的参数
swap 函数 交换参数的高低地址位
tabs 属性 标记每一项的内容
tabindex 属性 标记索引
text 属性 显示的文本
texttofloat 函数 将字符串(以null结束的格式)转换为浮点数
time 函数 返回当前的时间
timetostr 函数 将时间格式转换为字符串
trim 函数 从给定的字符串中删除前导和尾部的空格及控制字符
trimleft 函数 从给定的字符串中删除首部的空格及控制字符
trimright 函数 从给定的字符串中删除尾部的空格及控制字符
trunc 函数 将实型值截取为整型值
truncate 函数 截去当前文件位置后的内容
unselectedcolor 属性 未选中颜色
upcase 将字符转换为大写
uppercase 将给定的字符串变为大写
val 函数 将字符串转换为整型值
vararraycreate 函数 以给定的界限和维数建立变体数组
vararraydimcount 函数 返回给定变体的维数
vararrayhighbound 函数 返回给定变体数组维数的上界
vararraylock 函数 锁定给定的变体数组
vararraylowbound 函数 返回给定变体数组维数的下界
vararrayof 函数 返回指定变体的数组元素
vararrayredim 函数 通过改变上限来调整变体的大小
vararrayunlock 函数 解锁指定的变体数组
varastype 函数 将变体转换为指定的类型
varcase 函数 将变体转换为指定的类型并保存他
varclear 函数 清除指定的变体
varcopy 函数 将指定的变体复制为指定的变体
varformdatetime 函数 返回包含日期时间的变体
varisarray 函数 测试变体是否为数组
varisempty 函数 测试变体是否为unassigned
varisnull 函数 测试变体是否为null
vartodatetime 函数 将给定的变体转换为日期时间
vartype 函数 将变体转换为指定的类型并保存他
visible 属性 控件的可见性
wantreturns 属性 为true时,按回车键产生一个回车符;
为false时,按下ctrl+enter才产生回车符
write 命令 对有格式的文件,写一变量到文件组件中;
对文本文件,写一个或多个值到文件中
writeln 命令 执行write过程,然后输出一行结束标志
widecharlentostring 函数 将ansi字符串转换为unicode字符串
widecharlentostrwar 函数 将unicode字符串转换为ansi字符串变量
widechartostring 函数 将unicode字符串转换为ansi字符串
widechartostrvar 函数 将unicode字符串转换为ansi字符串变量
相关文章:
Delphi控件杂项
Delphi 插件(Plug-ins)创建、调试与使用应用程序扩展
有没有使用过Adobe Photoshop?如果用过,你就会对插件的概念比较熟悉。
对外行人来说,插件仅仅是从外部提供给应用程序的代码块而已(举个例子来说,在
一个DLL中)。一个插件和一个普通DLL之间的差异在于插件具有扩展父应用程序功能
的能力。例如,Photoshop本身并不具备进行大量的图像处理功能。插件的加入使其获
得了产生诸如模糊、斑点,以及其他所有风格的奇怪效果,而其中任何一项功能都不
是父应用程序自身所具有的。
对于图像处理程序来说这很不错,可是为什么要花偌大的力气去完成支持插件的商业
应用程序呢?假设,我们举个例子,你的应用程序要产生一些报表。你的客户肯定会
一直要求更新或者增加新的报表。你可以使用一个诸如Report Smith的外部报表生成
器,这是个不怎么样的解决方案,需要发布附加的文件,要对用户进行额外的培训,
等等。你也可以使用QuickReport,不过这会使你身处版本控制的噩梦之中——如果每
改变一次字体你就要Rebuild你的应用程序的话。
然而,只要你把报表做到插件中,你就可以使用它。需要一个新的报表吗?
没问题,只要安装一个DLL,下次应用程序启动时就会看见它了。另外一个例子是处理
来自外部设备(比如条形码扫描器)的数据的应用程序,为了给用户更多的选择,你
不得不支持半打的各种设备。通过将每种设备接口处理例程写成插件,不用对父应用
程序作任何变动就可以获得最大程度的可伸缩性。
入门
在开始写代码之前最重要的事情就是搞清楚你的应用程序到底需要扩展哪些功
能。这是因为插件是通过一个特定的接口与父应用程序交互的,而这个接口将根据你的
需要来定义。在本文中,我们将建立3个插件,以便展示插件与父应用程序相交互的几
种方式。
我们将把插件制作成DLL。不过,在做这项工作之前,我们得先制作一个外壳程
序来载入和测试它们。图1显示的是加载了第一个插件以后的测试程序。第一个插件没有
完成什么大不了的功能,实际上,它所做的只是返回一个描述自己的字符串。不过,它
证明了很重要的一点——不管有没有插件应用程序都可以正常运行。如果没有插件,它
就不会出现在已安装的插件列表中,但是应用程序仍然可以正常的行使功能。
我们的插件外壳程序与普通应用程序之间的唯一不同就在于工程源文件中出现
在uses子句中的Sharemem单元和加载插件文件的代码。任何在自身与子DLL之间传递字符
串参数的应用程序都需要Sharemem单元,它是DelphiMM.dll(Delphi提供该文件)的接
口。要测试这个外壳,需要将DelphiMM.dll文件从DelphiBin目录复制到path环境变量
所包含的路径或者应用程序所在目录中。发布最终版本时也需要同时分发该文件。
插件通过LoadPlugins过程载入到这个测试外壳中,这个过程在主窗口的
FormCreate事件中调用,见图2。该过程使用FindFirst和FindNext函数在应用程序所在
目录中查找插件文件。找到一个文件以后,就使用图3所示的LoadPlugins过程将其载入。
{ 在应用程序目录下查找插件文件 }
procedure TfrmMain.LoadPlugins;
var
sr: TSearchRec;
path: string;
Found: Integer;
begin
path := ExtractFilePath(Application.Exename);
try
Found := FindFirst(path + cPLUGIN_MASK, 0, sr);
while Found = 0 do begin
LoadPlugin(sr);
Found := FindNext(sr);
end;
finally
FindClose(sr);
end;
end;
{ 加载指定的插件 DLL. }
procedure TfrmMain.LoadPlugin(sr: TSearchRec);
var
Description: string;
LibHandle: Integer;
DescribeProc: TPluginDescribe;
begin
LibHandle := LoadLibrary(Pchar(sr.Name));
if LibHandle <> 0 then
begin
DescribeProc := GetProcAddress(LibHandle,
cPLUGIN_DESCRIBE);
if Assigned(DescribeProc) then
begin
DescribeProc(Description);
memPlugins.Lines.Add(Description);
end
else
begin
MessageDlg('File “' + sr.Name + '” is not a valid plug-in.',
mtInformation, [mbOK], 0);
end;
end
else
MessageDlg('An error occurred loading the plug-in “' +
sr.Name + '”.', mtError, [mbOK], 0);
end;
LoadPlugin方法展示了插件机制的核心。首先,插件被写成DLL。其次,通过
LoadLibrary API它被动态的加载。一旦DLL被加载,我们就需要一个访问它所包含的过
程和函数的途径。API调用GetProcAddress提供这种机制,它返回一个指向所需例程的
指针。在我们这个简单的演示中,插件仅仅包含一个名为DescribePlugin的过程,由常数
cPLUGIN_DESCRIBE指定(过程名的大小写非常重要,传递到GetProcAddress的名称必须
与包含在DLL中的例程名称完全一致)。如果在DLL中没有找到请求的例程,
GetProcAddree将返回nil,这样就允许使用Assigned函数测定返回值。
为了以一种易用的方式存储指向一个函数的指针,有必要为用到的变量创建一个
特定的类型。注意,GetProcAddress的返回值被存储在一个变量中,DescribeProc,属于
TpluginDescribe类型。下面是它的声明:
type
TPluginDescribe = procedure(var Desc: string); stdcall;
由于过程存在于DLL内部,它通过标准调用转换编译所有导出例程,因此需要使
用stdcall指示字。这个过程使用一个var参数,当过程返回的时候它包含插件的描述。
要调用刚刚获得的过程,只需要使用保存地址的变量作为过程名,后面跟上任何
参数。就我们的例子而言,声明:
DescribeProc(Description)
将会调用在插件中获得的描述过程,并且用描述插件功能的字符串填充Description变量。
构造插件
我们已经创建好了父应用程序,现在该轮到创建我们希望加载的插件了。插件
文件是一个标准的Delphi DLL,所以我们从Delphi IDE中创建一个新DLL工程,保存它。
由于导出的插件函数将用到字符串参数,所以要在工程的uses子句中把Sharemen单元放
在最前面。图4列出的就是我们这个简单插件的工程源文件。
uses
Sharemem, SysUtils, Classes,
main in 'main.pas';
{$E plg.}
exports
DescribePlugin;
begin
end.
虽然插件是一个DLL文件,但是没有必要一定要给它一个.DLL的扩展名。实际上,
一个原因就足以让我们有理由改变扩展名:当父应用程序寻找要加载的文件时,新的扩展
名可以作为特定的文件掩模。通过使用别的扩展名(我们的例子使用了*.plg),你可以
在一定程度上确信应用程序只会载入相应的文件。编译指示字$X可以实现这个改变,也可
以通过Project Options对话框的Application页来设置扩展名。
第一个例子插件的代码是很简单的。图5显示了包含在一个新单元中的代码。注
意,DescribePlugin原型与外壳应用程序中的TpluginDescribe类型相一致,使用附加的
export保留字指定该过程将被导出。被导出的过程名称也将会出现在主工程源代码的
exports段中(在图4中列出)。
unit main;
interface
procedure DescribePlugin(var Desc: string);
export; stdcall;
implementation
procedure DescribePlugin(var Desc: string);
begin
Desc := 'Test plugin v1.00';
end;
end.
在测试这个插件之前,要先把它复制到主应用程序的路径下。最简单的办法就是
在主目录的子目录下创建插件,然后把输出路径设置为主路径(Project Options对话框
的Directories/Conditionals也可以作这个设置)。
调试
现在介绍一下Delphi 3中一个较好的功能:从IDE中调试DLL的能力。在DLL工程
中可以通过Run paramaters对话框指定某程序为宿主应用程序,这就是指向将调用DLL的
应用程序的路径(在我们这个例子中,就是刚刚创建的测试外壳程序)。然后你就可以
在DLL代码中设置断点并且按F9运行它——就像在一个普通应用程序中做的那样。Delphi
会运行指定的宿主程序,并且,通过编译带有调试信息的DLL,把你指引到DLL代码内的
断点处。
—
Delphi 插件(Plug-ins)创建、调试与使用应用程序扩展(续)
关键词:Delphi控件杂项
延伸父应用
这个简单的插件不错,不过它不能做什么有用的事情。第二个例子就是纠正这个问题。
这个插件的目标就是在父应用程序的主菜单中加入一个项目。这个菜单项目,当被单击
时,就会执行插件内的一些代码。图6显示外壳程序的改进版,两个插件都已经加载。在
这个版本的外壳程序中,一个名为Plug-in的新菜单项目,被添加到主菜单中。插件会在
运行时加入一个菜单项。
为了实现这个目的,我们必须在插件DLL中定义第二个接口。现有的DLL只导出了一个过
程,DescribePlugin。第二个插件将声明一个叫做InitPlugin的过程。不过,在这个过程
可以在主应用程序中看到以前,必须修改LoadPlugin来配合它。
图7所示的代码展示了改进的过程。
procedure TfrmMain.LoadPlugin(sr: TSearchRec);
var
Description: string;
LibHandle: Integer;
DescribeProc: TPluginDescribe;
InitProc: TPluginInit;
begin
LibHandle := LoadLibrary(Pchar(sr.Name));
if LibHandle <> 0 then
begin
// 查找 DescribePlugin.
DescribeProc := GetProcAddress(LibHandle,
cPLUGIN_DESCRIBE);
if Assigned(DescribeProc) then
begin
// 调用 DescribePlugin.
DescribeProc(Description);
memPlugins.Lines.Add(Description);
// 查找 InitPlugin.
InitProc := GetProcAddress(LibHandle, cPLUGIN_INIT);
if Assigned(InitProc) then
begin
// 调用 InitPlugin.
InitProc(mnuMain);
end;
end
else
begin
MessageDlg('File “' + sr.Name + '” is not a valid plugin.',
mtInformation, [mbOK], 0);
end;
end
else
begin
MessageDlg('An error occurred loading the plugin “' +
sr.Name + '”.', mtInformation, [mbOK], 0);
end;
end;
如你所见,当GetProcAddress第一次查找调用描述过程之后,又调用了一次
GetProcAddress。这一次,我们要寻找的是常量cPLUGIN_INIT,定义如下:
const
cPLUGIN_INIT = 'InitPlugin';
返回值存储在TpluginInit类型的变量中,定义如下:
type
TPluginInit = procedure(ParentMenu: TMainMenu); stdcall;
当InitPlugin方法被执行时,父应用程序的主菜单被当作一个参数传递给它。这个过程
可以按照自己的意愿修改菜单。由于所有GetProcAddress的返回值都用assigned测试,
新版本的LoadPlugin过程仍然会加载不包含InitPlugin过程的第一个插件。在这个过程
中第一次调用寻找DescribePlugin方法会通过,第二次寻找InitPlugin会无响应失败。
现在新的接口已经定义好了,可以为新的InitPlugin方法编写代码了。像原先一样,
新插件的实现代码存在于一个单独的单元中。图8显示了修改过的包含InitPlugin方法
的main.pas。
unit main;
interface
uses Dialogs, Menus;
type
THolder = class
public
procedure ClickHandler(Sender: TObject);
end;
procedure DescribePlugin(var Desc: string);
export; stdcall;
procedure InitPlugin(ParentMenu: TMainMenu);
export; stdcall;
var
Holder: THolder;
implementation
procedure DescribePlugin(var Desc: string);
begin
Desc := 'Test plugin 2 – Menu test';
end;
procedure InitPlugin(ParentMenu: TMainMenu);
var
i: TMenuItem;
begin
// 创建新菜单项.
i := NewItem('Plugin &Test', scNone, False, True,
Holder.ClickHandler, 0, 'mnuTest');
ParentMenu.Items[1].Add(i);
end;
procedure THolder.ClickHandler;
begin
ShowMessage('Clicked!');
end;
initialization
Holder := THolder.Create;
finalization
Holder.Free;
end.
很明显,对原始插件的第一个改变就是增加了InitPlugin过程。像原先一样,带有
export关键字的原型被加入到单元顶端的列表中,过程名也被加入到工程源代码的
exports子句列表中。这个过程使用NewItem函数创建一个新的菜单项,返回值是TmenuItem
对象。新菜单项通过下列语句被加入到应用程序主菜单中:
ParentMenu.Items[1].Add(I);
在测试外壳主菜单上的Items[1]是菜单项Plug-in,所以这个语句在Plugin菜单条上添
加一个叫Plug-in Test的菜单项。
为了处理对新菜单项的响应,作为它的第五个参数,NewItem可以接受一个TNotifyEvent
类型的过程,这个过程将在菜单项被点击时调用。不幸的是,按照定义,这种类型的过程
是一个对象方法,然而在我们的插件中并没有对象。如果我们想用通常的指针来指向函数,
那么得到的将只会是Delphi编译器的抱怨。所以,唯一的解决办法就是创建一个处理菜单
点击的对象。这就是Tholder类的用处。它只有一个方法,是一个叫做ClickHandler的过程。
一个叫做Holder的全局变量,在修改过的main.pas的var段中被声明为Tholder类型,并且
在单元的initialization段中被创建。现在我们就有一个对象了,我们可以拿它的方法
(Holder.ClickHandler)当作NewItem函数的参数。
搞了这一通,ClickHandler除了显示一个“Clicked!”消息对话框以外什么以没干。也
许这不怎么有趣,不过它仍然证明了一点:插件DLL成功的修改了父应用的主菜单,表现
了它的新用途。并且如同第一个例子一样,不管这个插件在不在应用程序都能执行。
由于我们创建了一个对象来处理菜单点击,那么在不再需要这个插件时,就要释放这个
对象。修改后的单元中会在finalization段中处理这件事情。Finalization端时与
initialization段相对应的,如果前面有一个initialization段,那么在应用程序终止时
finalization段一定会得到执行。把下面的语句
Holder.Free
加到finalization段中,以确保Holder对象会被正确的释放。
显而易见,虽然这个插件只是修改了外壳应用的主菜单,但是它可以轻易地操纵传递
到InitPlugin过程中的任何其他对象。如果有必要,插件也可以打开自己的对话框,向
列表框(List boxes)和树状视图(tree views)中添加项目,或者在画布(canvas)
中绘画。
事件驱动的插件
到现在为止我们所描述的技术可以产生一种通用的扩展应用程序的方法。通过增加新菜
单、窗体和对话框,就可以实现全新的功能而不必对父应用做任何修改。不过仍然有一个
限制:这只是一种单侧(one-sided)机制。正如所看到的,系统依赖用户的某些操作才
能启动插件代码,比如点击菜单或者类似的动作。代码运行起来以后,又要依靠另外一个
用户动作来停止它,例如,关闭插件可能已经打开的窗体。克服这种缺陷的一种可行的方
法就是使插件可以响应父应用中的动作——模仿在Delphi中工作地很好的事件驱动编程模
型的确有效。
在最后一个例子插件中,我们将创建一种机制,插件可以藉此响应父应用中产生的事件。
通常情况下,可以通过判定需要触发哪些事件、在父应用中为每个事件创建一个Tlist对象
来实现。然后每个Tlist对象都被传递到插件的初始化过程中,如果插件想在某个事件中
执行动作,它就把负责执行的函数地址加入到对应的TList中。父应用在适当的时刻循环
这些函数指针的列表,按次序调用每个函数。通过这种方法,就为多个插件在同一事件中
执行动作提供了可能。
应用程序产生的事件完全依赖于程序已确定的功能。例如,一个TCP/IP网络应用程序可能
希望通过TclientSocket的onRead事件通知插件数据抵达,而一个图形应用程序可能对调
色板的变化更感兴趣。
为了说明事件驱动的插件应答的概念,我们将创建一个用于限制主窗口最小尺寸的插件。
这个例子有点儿造作,因为把这个功能做到应用程序里边会比这简单的多。不过这个例子
的优点在语容易编码而且易于理解,而这正是本文想要做到的。
很明显,我们要做的第一件事情就是决定到底要产生哪些事件。在本例中,答案很简单:
要限制一个应用程序窗口的尺寸,有必要捕获并且修改Windows消息WM_GETMINMAXSINFO。
因此,要创建一个完成这项功能的插件,我们必须捕获这个消息并且在这个消息处理器中
调用插件例程。这就是我们要创建的事件。
接下来我们要创建一个TList来处理这个事件。在主窗体的initialization段中将会创建
lstMinMax对象,然后,创建一个消息处理器来捕获Windows消息WM_GETMINMAXINFO。图9中
的代码显示了这个消息处理器。
{ 捕获 WM_GETMINMAXINFO. 为每个消息调用插件例程. }
procedure TfrmMain.MinMaxInfo(var msg: TMessage);
var
m: PMinMaxInfo; file://在 Windows.pas 中定义.
i: Integer;
begin
m := pointer(msg.Lparam);
for i := 0 to lstMinMax.count -1 do begin
TResizeProc(lstMinMax)(m.ptMinTrackSize.x,
m.ptMinTrackSize.y);
end;
end;
外壳应用的LoadPlugin过程必须再次修改以便调用初始化例程。这个新初始化函数把
我们的TList当作参数接受,在其中加入修改消息参数的函数地址。图10显示了LoadPlugin
过程的最终版本,它可以执行到目前为止所讨论的全部几个插件的初始化工作。
{ 加载指定的插件DLL. }
procedure TfrmMain.LoadPlugin(sr: TSearchRec);
var
Description: string;
LibHandle: Integer;
DescribeProc: TPluginDescribe;
InitProc: TPluginInit;
InitEvents:TInitPluginEvents;
begin
LibHandle:=LoadLibrary(Pchar(sr.Name));
ifLibHandle<>0then
begin
//查找DescribePlugin.
DescribeProc:=GetProcAddress(LibHandle, cPLUGIN_DESCRIBE);
if Assigned(DescribeProc) then
begin
// 调用 DescribePlugin.
DescribeProc(Description);
memPlugins.Lines.Add(Description);
file://查找InitPlugin.
InitProc := GetProcAddress(LibHandle, cPLUGIN_INIT);
if Assigned(InitProc) then
begin
file://调用InitPlugin.
InitProc(mnuMain);
end;
// 为第三方插件查找 InitPluginEvents
InitEvents := GetProcAddress(LibHandle,
cPLUGIN_INITEVENTS);
if Assigned(InitEvents) then
begin
// 调用 InitPlugin.
InitEvents(lstMinMax);
end;
end
else
begin
MessageDlg('File “' + sr.Name +
'” is not a valid plugin.',
mtInformation, [mbOK], 0);
end;
end
else
begin
MessageDlg('An error occurred loading the plugin “' +
sr.Name + '”.', mtInformation, [mbOK], 0);
end;
end;
图 10: LoadPlugin 的最终版本
最后一步是创建插件自身。如同前面的几个例子,插件展示一个标志自身的描述过程。
它也带有一个初始化例程,在本例中只是接受一个TList作为参数。最后,它还包含一个
没有引出(Export)的历程,叫做AlterMinTrackSize,它将修改传递给它的数值。图11
显示了最终插件的完整代码。
unit main;
interface
uses Dialogs, Menus, classes;
procedure DescribePlugin(var Desc: string);
export; stdcall;
procedure InitPluginEvents(lstResize: TList);
export; stdcall;
procedure AlterMinTrackSize(var x, y: Integer); stdcall;
implementation
procedure DescribePlugin(var Desc: string);
begin
Desc := 'Test plugin 3 – MinMax';
end;
procedure InitPluginEvents(lstResize: TList);
begin
lstResize.Add(@AlterMinTrackSize);
end;
procedure AlterMinTrackSize(var x, y: Integer);
begin
x := 270;
y := 220;
end;
end.
InitPluginEvents过程是这个插件的初始化例程。它接受一个TList作为参数。这个
TList就是在父应用程序中创建的保存相应函数地址的列表。下面的语句:
lstResize.Add(@AlterMinTrackSize);
把AlterMinTrackSize函数的地址加入到了这个列表中。它被声明为类型stdcall以便
与其他过程相配,不过用不着export指示字。由于函数被直接通过它的地址调用,所以也
就没有必要按照通常的方式把它从DLL中引出。
所以,事件序列如下所列:
1、 在应用程序初始化时,创建一个TList对象。
2、 在启动时这个列表被传递到插件的初始化过程InitPluginEvents中。
3、 插件过程把一个过程的地址加入到列表中。
4、 每次窗口大小改变时所产生的Windows消息WM_GETMINMAXINFO被我们的应用程序所捕获。
5、 该消息被我们的消息处理器TfrmMain.MainMaxInfo所处理,见图10。
6、 消息处理器遍历列表并调用它所包含的函数,把当前的X和Y最小窗口尺寸作为参数传递
。要注意,TList类只是存储指针,所以如果想用保存的地址做些什么事情的话,我们必须
把指针转换成所需要的类型——在本例中,要转换成TresizeProc。
TResizeProc = procedure (var x, y: Integer); stdcall;
7、 插件过程AlterMinTrackSize(列表中的指针所指向的),接受X和Y值作为可变的var
参数并且修改它们。
8、 控制权返回到父应用的消息处理器,按照最小窗口尺寸的新值继续运行下去。
9、 应用程序退出时TList会在主代码的finalization段被释放。
结论
使用该体系结构时,可能利用Delphi提供的package功能是个不错的主意。在通常情况
下,我不是一个分割运行时模块的狂热爱好者,但是当你认为任一包含大量代码的Delphi
DLL超过200KB时,它就开始变得有意义了。
这篇文章应该还是有些用处的,至少它可以让你思考一些程序设计方面的问题,比如
如何让它变得更加灵活。我知道如果我在以前的应用程序中使用一些这种技术的话,我就
可以省掉在修改程序方面的好多工作。我并不想把插件作为一种通用的解决方案。很明显,
有些情况下额外的复杂度无法验证其正确性,或者应用程序压根儿就不打算把自身搞成
几块可扩展的单元。还有一些其它的方法也可以达成同样的效果。Delphi自身提供了一个
接口来创作能集成到IDE中的模块,比起我所说明的技术这种方法更加面向对象(或者说
更“干净”),而我也确信你可以在自己的应用中模仿这一技术。在运行时加载Delphi包
也不是做不到的。探索一下这种可能性吧。
相关文章:
Delphi 包
第一部分:有关包的介绍
一般我们编写编译一个DELPHI应用程序时,会产生一个EXE文件,也就是一个独立的WINDOWS应用程序。很重要的一点:区别于Visual Basic,DELPHI产生的是预先包裹的应用程序是不需要大量的运行库(DLL's)。
假设:打开Delphi默认的工程(只有一个空白form),F9她将编译生成一个大约295 KB (Delphi 5)的可执行文件。然后打开Project | Options,把‘Build with runtime packages’选上再编译一下,EXE文件大小就只有15 KB左右了。
我们编译一个DELPHI应用程序时默认地没有选择'Build with runtime packages',编译器将把程序运行所需要的代码直接写入你的EXE文件中,因此产生的程序是一个相对独立的程序,并不需要任何附属的支持文件(例如动态运行库文件DLL),这也就知道了为什么DELPHI产生的应用程序为什么都那么大。
要建立尽可能小的DELPHI程序,方法之一就要充分发挥Borland package libraries的作用,简称BPL。
先说什么是包?
简而言之,一个包就是一个在DELPHI的IDE环境中被DELPHI应用程序共享的特殊的动态链接库。包允许我们通过多级应用将我们的程序的一部分当做一个分离的模块供其他应用程序来共享。
包大致可分为运行期包(Run-time packages)和设计期包(Design-time packages):
运行期包-当运行程序时提供VCL和库函数的支持,操作上很类似标准的动态链接库。
设计期包-用来在DELPHI的IDE环境安装控件和为控件建立特殊的属性编辑器。设计期包允许包含控件、属性和控件编辑器等等,在IDE环境中,这类包是程序设计所必需的,也仅仅是DELPHI使用,并不和开发的应用程序一起分发。
知道这些包的运用,我们也就知道了运行期包是如何做处理和它们对DELPHI程序员有什么帮助了。
有一点必须说明:想很好地运用包并不要求你先成为一个成熟的控件编写者。DELPHI编程初学者也可以和应该尝试去接触包的概念,这将有利于你更好地理解包和DELPHI的工作关系。
第二部分:适时运用包裹和DLL
一般都认为加入WINDOWS操作系统中的动态运行库是一种最有用最高效的应用。在WINDOWS系统中,很多应用程序同时运行可能会引起了内存方面的问题,很多程序执行相似的操作任务,但各自又由不同的代码来控制并完成任务,动态运行库的作用就是将你的执行程序中的这些代码放到一个系统共享环境下的DLL中去。可能最为直观的动态链接库例子就是WINDOWS操作系统自己和它本身所带的API了。
动态链接库通常都是用来集合过程(procedure)和函数(function)以供程序调用。当然我们在编写动态链接库的同时,也可以把一个DELPHI FORM放到一个DLL中去(例如一个AboutBox FORM),此外我们也可以在DLL中存储程序所需要的资源(resources)。更多关于DELPHI如何操作使用动态链接库,请参考相关书籍,不再赘述。
在比较DLLs 和BPLs之前,我们先要知道可执行文件的2种代码链接的方式:静态链接和动态链接。
静态链接就是当一个DELPHI工程被编译的时候,工程所需要的所有代码将被直接链接入你的程序执行文件。结果就是执行文件将包含程序所需要使用到的所有单元(units),你也许会说这样代码有点冗长,因为在通常默认情况下,一个FORM单元的uses子句列举了至少5个基本单元(如:Windows, Messages, SysUtils,…),尽管如此,DELPHI还是能够智能地自动链接单元中真正要用到的代码到工程代码中,从而尽可能地减少了执行文件的大小。使用静态链接,我们的应用程序就是一个相对独立的程序,不需要任何额外的支持文件或动态链接库(暂时不考虑BDE和ActiveX构件)。DELPHI中默认使用的就是静态链接方式。
动态链接就是应用程序将和标准的动态链接库(DLLs)一起运行。动态链接方式不需要将代码直接建立到每个应用程序中去,单独为多个应用程序提供多线程的库函数支持,任何程序运行期间才需用到的包才将被加载,更值得一提的是:程序在动态方式需要调用的包是自动加载的,因此你不需要专门写加载包的代码。
方法:简单地选中在Project | Options 对话框中'Build with runtime packages'复选框后,再次编译你的程序,你的程序代码将自动链接到动态运行包,而不是将引用单元都静态链接入你的工程执行文件。
是选择BPL 还是 DLL?区别又在哪里?
你可能很奇怪为什么要选择使用运行期包,而不是DLL,或者还有其他什么方法。
相对于DLL而言,包裹的概念是DELPHI开发中所特有的,就是说其他语言编写的应用程序不能引用DELPHI建立的包裹。即使包是一种被DELPHI编写的应用程序所使用的动态链接库,它也同时提供给了DELPHI程序员更多的库函数支持。
通常我们在DELPHI中建立动态链接库(DLLs)是用来存储不同环境下应用程序所需要使用到的过程和函数,而包不仅能够包含代码单元(untits)、构件和FORMs,还能包含DELPHI中的类(classes)-这就使我们能够在其中引用对象向导编码(object oriented code)。在包裹中,我们可以保存完整的通用DELPHI构件,而动态运行库(DLL's)对此则无能为力了。
此外,在缩减程序代码上,DLLs和BPLs扮演着同样重要的角色,其主要原因就是在使用包裹或动态链接库技术后,都直接地减少了程序的文件大小。当然,还要说明的是:执行程序需要加载的DLLs或BPLs也可能会是很庞大的。例如如果需要分发你的包裹文件(主要是VCL包,vcl50.BPL)至少有2MB左右。
尽管如此,如果你是要分发共享同个包的多个应用程序,你就可以省很多事了。当用户方系统中已经存在程序运行需要的部分文件(如:标准的DELPHI BPLs)后,就只需要下载程序的最小执行文件了。如果你的程序工程主要是通过INTERNET等方式分发和开展,那效率显然有很大的提高。
同时,包的应用也节省系统内存,因为动态链接的结果就是:只有一个VCL被读入内存供所有使用运行期包的DLEPHI应用程序使用。
包裹的版本问题
当你想升级你的动态链接库时(改变其中一些执行函数),你可以简单地编译产生新的程序文件,并上载新版本文件,所有正在使用该动态链接库的应用程序仍将工作(除非你已经将存在的旧版本程序去除)。
换个角度来讲,在升级新包裹文件的同时,不要忘记升级程序的执行文件。正如你所了解的,包裹文件就是一个单元文件(units)的集合,所有编译过的单元文件(DCU)都含有版本信息,因此,除非我们有单元文件的源码(source),否则我们不能在DELPHI4或5中使用编译过的单元,所以一旦我们改变了单元文件中接口部分uses子句中列举出的任一单元文件,该文件就需要重新编译。编译器将检查DCU文件的版本信息,并决定单元是否需要重新编译。因此我们不能在DELPHI5编译的应用程序中使用在DELPHI6下编译的包,任何为你的应用程序服务的包和你的应用程序必须在相同环境下编译。
因此,当给包裹命名的时要保留包裹名中包含有DELPHI的版本信息(如'AboutDP50',其中50就代表Delphi 5)。这可以有效防止文件版本的冲突问题,也可以避免很多不必要的麻烦,包使用者可以更清楚包的版本和包裹适用于哪个DELPHI编译器。
如果你要分发运行期或设计期包给其他DELPHI程序员,建议同时提供了.DCP(含有包的头信息和各个单元文件)和.BPL文件,还有包中所包含的所有单元文件的.DCU文件。
第三部分:建立和使用运行期包
建立一个包裹
建立一个包很简单,但在建包之前要做一些准备工作。首先,你需要知道你准备建立哪种类型的包文件:运行期包还是设计期包,或两者都是;其次是,建立、调试,反复地测试你想放置到包中去的单元文件;最后,为建立的包裹文件命名,还有就是选择一个合适的地方来存放文件。
建立一个新的运行期包,按照以下步骤:
1.启动DELPHI,并选择File | Close All关闭默认的工程。
2.选择File | New…,在”New items”对话框中的”new”页面中双击Package图标(如图),就会出现包裹编辑器(如图):包裹编辑器包含2个文件夹:Contains和Requires。
3.点击Add按钮,可以增加一个单元文件(构件或是一个简单的代码单元文件)。注意:你添加的是PAS源码文件而不是编译后的DCU文件。当你添加单元文件的同时,包中的单元的名字就显示在包裹编辑器的Contains文件夹中了。如图中添加了FindFile和PictureClip的单元文件。
4.打开Requires文件夹,展开的列表表示包裹所需要的包的DCP文件,包裹文件最基本的就需要引用含有绝大部分标准可视控件的vcl50.dcp文件。
5.当你添加完单元文件,单击Options按钮,在Description面板中的Usage options组中你需要选择包裹种类:是设计期包,还是运行期包,或者两者都是。如果选择Runtime only(仅运行期包),其他包的使用者将无法将图示2个构件安装到IDE环境中去。
6.使用File | Save保存包工程文件(DPK),然后保存包文件,如AboutDP50,包裹文件的命名将很重要。
7.在包裹器中,单击Compile按钮来编译包。
8.如果不出什么意外,编译包后将建立一个包裹文件(BPL文件),期间你可能还要确定你必须增加的其他包裹(例如VCLX50),这些包都将在Requires文件夹中列出。
9.完成,Borland package library文件已经成功建立,就等着使用了。
在包裹编辑器中有一个Install按钮,就是用来将当前包裹安装成一个设计期包的。如果包裹是run-time only(仅运行期包),那Install按钮将无法使用。
关于所建立的这些文件
除了DPK文件和那些单元源码文件,DELPHI还使用包裹的动态链接版本产生一个BPL文件和一个含有包内标识信息DCP文件,DCP文件就是包中所包含单元文件的编译文件(DCU)的标识信息的集合。
使用运行期包设计程序
开始使用动态链接编写应用程序时,不需要写代码去加载运行期包裹,只需要在Project | Options中做相关设置,选择在Packages页的Runtime Packages编辑框中的包裹列表,编译程序时将自动链接。应用程序要使用到一个运行期包时,使用ADD按钮来增加包裹文件。
注意:尽管一个应用程序被链接到运行期包,程序的USES子句所列出的单元文件也必须都是存在的,编译运行期包裹只是告诉应用程序哪里可以找到构件代码而已。
当配置一个使用到运行期包裹的应用程序时,确定用户拥有可执行文件和程序所需的库文件(.BPL或.DLL)。如果库文件在和EXE文件不同的目录下,必须将其指定到系统所能到达的目录。因此,最好的选择就是WindowsSystem系统目录。
总而言之
包裹使你能够有弹性地选择应用程序的分发方式,也使构件的安装变简单了,此外,使用包裹也减少了应用程序的文件大小,因此,使用包裹的开发方式还是具有不小的意义的。
相关文章:
http://blog.katesoft.com
blog 的域名改为 http://blog.katesoft.com 以前的地址也可以访问。
相关文章:
24 season 5 (12:00 -13:00) Episode 6

12:00 P.M.
Buchanan and McGill are hesitant to arrest Cummings. Jack intends to go directly to Novick, who can be trusted. Since Jack no longer works there, the plan won’t backfire on CTU. McGill gives in with the stipulation that Jack doesn’t make this revenge for Palmer’s death.
12:02 P.M.
Audrey apologizes to Jack for being so distant. It will take time for her to get used to seeing him alive.
12:03 P.M.
Cummings cannot confirm whether Jack is dead, but Nathanson says that the nerve gas is on its way to the port.
12:04 P.M.
The yellow tie man and an accomplice named Schaeffer arrange shipping the canisters to Moscow.
12:05 P.M.
Logan is furious that Martha hasn’t been found yet. He is shown a video made by the terrorists to show how the nerve gas causes permanent nerve damage within minutes. Yet the nerve gas stolen from the airport is far more lethal than the one in the video. Novick excuses himself when he gets a text message from Jack. Cummings watches him nervously, wondering if it’s news of Jack’s death.
12:06 P.M.
Novick calls back Jack, who says he has a lead on the nerve gas but that he wants it kept secret from the President. Novick is alarmed when Jack adds that it concerns Cummings. Novick agrees to meet him.
12:07 P.M.
Jack tells Diane and Derek that he needs to stay on to help CTU. Diane knows that Jack isn’t coming back to her, and she asks if it’s because of Audrey. Jack says that he is still in love with Audrey even though he doesn’t know if she feels the same way. He kisses Diane goodbye.
12:09 P.M.
Cummings and Nathanson listen to the playback of Jack and Novick’s phone conversation. Nathanson blames Cummings for not getting the job done inside CTU. He orders Cummings to kill Jack when he comes to the retreat.
12:14 P.M.
Secret Service Agent Pierce finds Martha in the stables on the property. She pleads with him to help her because they are setting her up. She says that someone inside the Administration is trying to shut her up because she knows the truth. The other agents come in to apprehend her.
12:17 P.M.
Inside the freight unit container, Schaeffer secretly attaches a handheld device to the canisters and triggers an unlock code. He exits the container and bumps into the yellow tie man. Schaeffer tells him that he only was securing the canisters, but yellow tie man is suspicious.
12:18 P.M.
Diane asks Audrey if she still has feelings for Jack. Audrey is shocked to learn that Jack still loves her. “If you don’t love him, let him go,” Diane cautions.
12:19 P.M.
Audrey calls Jack. She wants to know if he is coming back to her. Jack doesn’t know what he will do next. “I never stopped loving you, not for one second,” he says.
12:20 P.M.
Agent Pierce lets Logan know that they found Martha. Pierce tries to tell the President about Martha’s claims. Logan brushes this off as “conspiracy theories.”
12:21 P.M.
Logan wonders whether sending Martha away is the right solution. Cummings lets him know that Jack is coming to the retreat to meet with Novick. Jack plans to accuse Cummings of helping the terrorists acquire the nerve gas. Cummings then confesses to the President that he leaked information to the terrorists about the location of the nerve gas. Logan is outraged, but Cummings’ intent was to make the separatists think they will use it against the Russians. The nerve gas will never reach Russian soil because detonators will be triggered once the terrorists landed at their home base. This would prove the existence of weapons of mass destruction in Central Asia. It will allow America to increase its military presence in the area and guarantee the flow of oil.
12:23 P.M.
Logan calls Cummings a traitor for jeopardizing the country and going behind his back. He then realizes that Cummings gave the order to have Palmer killed. “That was an unfortunate, but necessary intervention,” Cummings explains. Logan demands that the operation be stopped, but it is too late because the man Cummings has working inside went dark. Cummings charges that if things don’t play out, Logan will be implicated and his Presidency will be destroyed. Logan is trapped.
12:29 P.M.
Novick meets Jack in secrecy, but a helicopter appears overhead and the agents order Jack to surrender. Novick swears that he didn’t tell anyone, and he yells to the Secret Service to stand down. The agents are under order from the President to arrest Jack. They handcuff him.
12:31 P.M.
With Jack now in custody, he was prevented from telling Novick anything. Cummings will make it look like Jack was leaking information of national security to Novick. Logan considers that others at CTU are aware of what Jack knows, but Cummings covered his bases so that the nerve gas explosion can’t be traced back to them. Logan demands assurance that the canisters will be destroyed before reaching Russian soil. Cummings wants the President to grant him the authority to remove CTU from the investigation. Logan helplessly gives him the power.
12:33 P.M.
Martha tries contacting Logan, but he ignores her.
The Secret Service brings Jack and Novick to the main building of the retreat. Agent Pierce makes eye contact with Jack, and questions an underling why Jack was arrested. The agent says that Cummings directed it.
12:34 P.M.
CTU is confused when it is pulled off the terrorist investigation. The President won’t take McGill’s call, and both Jack and Novick are unreachable. Buchanan senses that something is wrong and he suggests they disregard the order. McGill refuses, and Buchanan demeans his experience and says that is because he doesn’t know any better. McGill calmly asks Buchanan to step outside. Buchanan apologies to McGill for being out of line, but he still stands by his recommendation. Buchanan advises him to make decisions faster. They need to do everything they can to stop the terrorists. McGill agrees to disregard the White House order.
12:35 P.M.
Evelyn packs for the First Lady. Martha wonders aloud what happened with her relationship with Logan. She used to be his closest confidante.
12:36 P.M.
Agent Pierce comes in the holding room to move Jack to a detention facility. Jack tries appealing to Pierce’s friendship with Palmer. He explains that Palmer was killed because he was about to expose Cummings of helping the terrorists attack. It was Cummings who ordered the assassination of Palmer. Pierce says that the First Lady also believes someone inside the Administration was involved. Jack implores him to protect the President because a coup d’etat is going on. Jack begs Pierce for help.
12:43 P.M.
Pierce has a subordinate agent radio in that Jack has escaped.
12:44 P.M.
Cummings gets word that CTU hasn’t stopped working on the terrorist crisis. He urges the President to call McGill off. Suddenly, Pierce enters with Jack. Jack accuses Cummings of working against the country. Cummings tries to flee but Jack pummels him. Logan urges Pierce to intervene, but Pierce says he is only protecting the President. Jack lays out all of Cummings’ crimes, including leaking the nerve gas and the killing of Palmer. “I know about that,” Logan explains to Jack’s horror. Jack draws a knife to Cummings’ face and threatens to cut out each eye in order to get him to confess where the nerve gas is. Knowing Jack’s penchant for torture, Cummings gives up that the nerve gas is hidden on a boat from Long Beach.
12:45 P.M.
Jack calls Buchanan and puts Logan on speaker phone. He lays out the details of the shipment. Logan confirms for Buchanan that CTU should take lead on the investigation.
12:46 P.M.
Jack places his badge on the table and offers to turn himself in to the authorities. Pierce does the same. Logan orders Pierce to take back his shield and get Cummings out of his sight.
12:47 P.M.
Logan explains to Jack how he was coerced. Cummings had lied to him and said it was too late. Yet the international issues from the previous year are still pressing. “The fact that you’re alive presents problems for both of us,” Logan says. Jack’s only intention was to find Palmer’s killer. He wants to see the terrorist threat through, but promises to disappear once it’s done. Logan is satisfied, and then shakes his hand, thanking him.
12:53 P.M.
Evelyn puts Martha in a car, but a Secret Service agent stops her before she can drive off. Logan comes to retrieve her, and tells her that she was right about the conspiracy. He explains that Cummings lied to him and convinced him to send her to the clinic. She is still angry that Logan went along with it. Logan is pulled away by an aide, and he kisses his wife softly on the cheek.
12:55 P.M.
Chloe finds information on the only ship leaving for Central Asia. Edgar narrows down which container the nerve gas could be in.
12:56 P.M.
Buchanan sends Jack an image of the yellow tie man, whose real name is Ivan Erwich. He was a chemical engineer who joined his country’s separatist movement. Buchanan wants Jack to ID him for the strike team.
12:57 P.M.
CTU and the President watch the feed from the strike team at the port. The gas mask-wearing agents raid the container. They find a dead Schaeffer. The canisters are gone from their holding bins.
12:58 P.M.
Jack has Cummings brought back in to see the video. Cummings swears that he doesn’t know what happened to the canisters. Cummings identifies Schaeffer as his inside man. “They must know,” Cummings says.
12:59 P.M.
Cummings’ cell phone rings, and he sees that it’s Schaeffer’s number. Jack has CTU monitor the call and he makes Cummings answer. It’s Erwich, the yellow tie man, who says that Schaeffer confessed everything. Cummings tells Erwich that this was an unsanctioned act and that no one else, including the President, was involved. “Your country is about to pay a very steep price,” Erwich warns.

相关文章:
春节去金沙江玩(2.1-2.3)
今天回来了!
来回坐火车,共3天,玩的好累,但是很愉快,等整理完照片就发上来。
相关文章:
新年好!
关注我的BLOG的朋友,祝您新春快乐,合家幸福!


相关文章:
24 season 5 (11:00 -12:00) Episode 5

11:00 A.M.
The yellow tie man and his team transfer the canisters into a fake police SWAT van. They pull out of the hangar and exit the highly guarded airport.
11:02 A.M.
As Jack is being driven to CTU, he gets a call from Curtis who inquires about the yellow tie man’s possible location for escape.
11:03 A.M.
Evelyn is alarmed to find Martha passed out on the bed.
11:04 A.M.
Curtis pulls up security footage from outside the terminal and he sees the yellow tie man fleeing to a hangar outside the security zone. He goes there.
11:06 A.M.
When Curtis enters the hangar, no one’s there. He sees the hole left by the canisters. Curtis finds dead rats on the ground and he calls for forensics and biohazards to come in and inspect the premises.
11:07 A.M.
The yellow tie man moves the canisters to another truck. He tells his cohort Hank that “the Russians will finally understand the consequences of occupying our homeland.” The plan is to bomb Moscow.
11:08 A.M.
Logan comes to see his wife, who is groggy. She tries to explain to the doctor and Logan that someone knocked her out. Martha tells Logan that she had proof that Palmer called her to warn her about the day’s events. The document was hidden inside her blouse but it was stolen. The President still doesn’t believe her.
11:10 A.M.
Cummings advises Logan to send Martha back to a treatment facility in Vermont. Her conspiracy theories may leak to the media. Logan agrees to have her committed.
11:11 A.M.
Cummings assures Nathanson that Jack is en route to CTU. Cummings will take care of killing Jack because he has a mole on the inside.
11:16 A.M.
After getting confirmation from Curtis, Edgar lets Buchanan know that traces of weaponized nerve gas were found at the hangar. McGill orders forensics to figure out who manufactured it.
11:17 A.M.
Martha’s doctor tells Logan that he has no idea why she blacked out.
11:18 A.M.
Novick lets the President know that a second team of terrorists escaped from the airport with nerve gas.
11:20 A.M.
After seeing Chloe and Spenser argue, Edgar approaches her. He is upset that she has been keeping secrets from him about Jack and about her relationship with Spenser.
11:21 A.M.
Spenser returns a page from Cummings, who wants to know when Jack will arrive at CTU.
11:22 A.M.
McGill has Audrey question Diane Huxley because CTU is overextended. He is aware that the two women have something in common.
11:23 A.M.
Diane and Derek arrive at CTU. Audrey sends Derek to medical to be checked out. Diane is impressed by Jack’s former office. She asks Audrey if she knew Jack before.
11:28 A.M.
Everyone at CTU stops in their tracks when Jack walks in. He thanks Chloe for her help. McGill gives Jack a level two clearance and says that he is no longer a suspect in Palmer’s murder. He also updates him on the nerve gas discovery. McGill agrees with Jack that Palmer knew about the terrorist plot and was killed because of it.
11:30 A.M.
Buchanan tells Jack that Audrey is interviewing Diane.
11:31 A.M.
Audrey questions Diane on her personal relationship with Jack. Diane knew that Jack had secrets, but she “accepted him for who he was.” They stop talking when they see Jack outside. He and Audrey share a look.
11:33 A.M.
Audrey goes out of the office to see Jack for the first time. He says that he kept her in the dark for her own protection. Audrey explains that she was angry at first, but that she doesn’t blame him for Paul’s death anymore.
11:34 A.M.
Evelyn is concerned when Cummings has her pack Martha’s belongings. Cummings refuses to tell her where she is going.
11:35 A.M.
From the tech room’s monitors, Spenser sees Jack in the CTU hallway. Chloe comes in to explain to Spenser why she was abrupt. Spenser walks out annoyed. Chloe sees that Spenser had been logged in at a level five security clearance. She senses something isn’t right. Edgar confirms that Spenser only has a level three clearance. She asks Edgar to notify Buchanan immediately.
11:37 A.M.
Hank, the accomplice of yellow tie man, arrives at CTU posing as a computer repairman. Spenser runs out and apologizes to the guard that he was supposed to clear Hank in. Hank’s bag goes through x-ray. It has tools in it.
11:38 A.M.
Spenser leads Hank into the tech room, and shows him where the classified material on Jack is held. Hank gets to work assembling a gun out of the various pieces in his bag.
11:43 A.M.
Evelyn tells Martha that Cummings ordered her to pack her things because she’s going somewhere. Martha realizes that her husband is having her committed.
11:45 A.M.
Spenser is alarmed when his system is locked. Edgar watches smugly as two security guards apprehend Spenser.
11:46 A.M.
Spenser is brought to the situation room where Chloe and Buchanan are waiting. Buchanan accuses him of unauthorized access of classified files. Chloe wants to know why he seduced her. Spenser tells Buchanan that he was careless with Chloe and now she is trying to get back at him. Buchanan doesn’t buy it.
11:47 A.M.
Logan and Cummings go to Martha’s room, but she has disappeared out the bathroom window. Agent Pierce radios to the other agents to look for her.
11:53 A.M.
Jack confirms to McGill that no one other than Palmer, Tony, Michelle and Chloe knew that he was alive. He explains that he faked his own death because Palmer warned him that someone inside Logan’s Administration was targeting him. Jack thinks that whoever tried to kill him eighteen months ago is after him again. McGill notes that it would take months to weed out someone in the Administration. They are interrupted by a call from medical. Tony is conscious and wants to speak to Jack.
11:54 A.M.
Derek stops Jack as he’s heading to medical and apologizes for the way he has treated him. Jack knows that Derek was only protecting his mother. Jack promises to talk to him once this is all over.
11:55 A.M.
Spenser refuses to confess how he got a higher security clearance. Edgar pulls up Spenser’s system and sees that he was tracking Jack inside CTU. Spenser says that he was only following orders.
11:56 A.M.
As Tony lies in the medical bed, Jack leans down to speak to him. In the glare of the heart monitor, he sees an armed Hank behind him. Jack reacts and is able to knock the gun down. They fight, and Jack forces a pair of scissors into Hank’s throat.
11:57 A.M.
Hearing gunshots, Buchanan rushes in with the guards. Jack knows that this hit man was a professional. Buchanan tells him about Spenser, and Jack orders someone to monitor Tony.
11:58 A.M.
Jack goes to the situation room and pulls up surveillance from the medical wing. He makes Spenser see the image of a dead Hank. Jack demands to know if Spenser let him into CTU. Spenser says he was part of an internal affairs investigation and Hank was supposed to put taps on the servers. He seems confused to hear that Jack was to be assassinated. “Who told you to let that man into CTU?” Jack sneers. Spenser answers that Cummings from the White House recruited him to monitor whether CTU was working within the rules. Spenser was under the impression that he was serving the President.
11:59 A.M.
Jack, McGill and Buchanan decipher that Cummings was responsible for Palmer and is now after Jack. McGill warns that CTU cannot touch the President’s chief of staff. “I’m not CTU,” Jack says. “I’ll go get Walt Cummings myself.”

相关文章:
【论坛文章】中联论坛-其他公司HIS产品交流-云南凯特
论坛帖子:
以下是引用郭扬帆在2006-1-21 8:36:10的发言:
谢谢郭扬帆,凯特公司做HIS的就我一个人,原来我是用UNIX和C的,因为凯特公司以前给这些医院用的HIS系统很差,医院要换系统,公司又不想失去这些用户,我才来开发一套新的HIS,做出的产品虽是就急之作,也做到了灵活行较强,能在多家医院运行的HIS软件,等系统稳定了,采取市场运作模式推向国内市场。但是公司并没有这方面的发展意图,公司管理者也有很多问题。为用户着想,到现在才停止提供技术支持。
目前云南本土的HIS公司也有几家,都没有做成规模,大多都是为某个医院定制,模块也只有几个,公司实力和技术力量也薄弱,成不了气候。一年前和谭艺强谈过云南市场的问题,现在看来就是这样了。