Delphi
中资源文件使用详解
原文出处:http://blog.51cto.com/
一.编写
RC 脚本文本
用记事本或其它文本编辑器编写一个扩展名为 “.rc” 的文件。格式如下:
AVI 无声动画
BITMAP 位图文件
CURSOR 光标文件
ICON 图标文件
WAVE 声音文件
以上所列均为标准资源类型,也可以给资源自定义一个类型,如: “mytype” 。不过两者在调用方式上有些不同(在后面示例 “ 存取资源文件中的位图 ” 中有详细描述)。
二.根据 RC 脚本文件编译成 RES 资源文件
在命令提示符中输入以下内容:
brcc32 FileName.rc // 注: brcc32.exe 在 DelphiX/Bin 目录中
三.在 Delphi 单元中加入资源文件
将生成的 RES 资源文件复制到相应程序所在的目录中,在单元文件中的 “{$R *DFM}” 后面加上 “{$R FileName.res}” ,编译后资源文件就被包含在可执行文件中了。
说明:如果嫌 2 、 3 两步麻烦,可以采用更简便的做法,即:将 RC 文件直接添加到项目中,在编译 Delphi 项目时,会自动编译该资源文件。
用记事本或其它文本编辑器编写一个扩展名为 “.rc” 的文件。格式如下:
AVI 无声动画
BITMAP 位图文件
CURSOR 光标文件
ICON 图标文件
WAVE 声音文件
以上所列均为标准资源类型,也可以给资源自定义一个类型,如: “mytype” 。不过两者在调用方式上有些不同(在后面示例 “ 存取资源文件中的位图 ” 中有详细描述)。
二.根据 RC 脚本文件编译成 RES 资源文件
在命令提示符中输入以下内容:
brcc32 FileName.rc // 注: brcc32.exe 在 DelphiX/Bin 目录中
三.在 Delphi 单元中加入资源文件
将生成的 RES 资源文件复制到相应程序所在的目录中,在单元文件中的 “{$R *DFM}” 后面加上 “{$R FileName.res}” ,编译后资源文件就被包含在可执行文件中了。
说明:如果嫌 2 、 3 两步麻烦,可以采用更简便的做法,即:将 RC 文件直接添加到项目中,在编译 Delphi 项目时,会自动编译该资源文件。
四.资源文件调用示例
( 1 )存取资源文件中的位图
( 1 )存取资源文件中的位图
//RC: testBmp bitmap res/test.bmp
Image1.Picture.Bitmap.LoadFromResourceName(HInstance, 'res/test.bmp');
//RC: testBmp bmptype res/test.bmp
var
resStream: TResourceStream;
begin
resStream := TResourceStream.Create(HInstance, 'testBmp', 'bmptype');
Image1.Picture.Bitmap.LoadFromStream(resStream);
resStream.Free;
end;
Image1.Picture.Bitmap.LoadFromResourceName(HInstance, 'res/test.bmp');
//RC: testBmp bmptype res/test.bmp
var
resStream: TResourceStream;
begin
resStream := TResourceStream.Create(HInstance, 'testBmp', 'bmptype');
Image1.Picture.Bitmap.LoadFromStream(resStream);
resStream.Free;
end;
请注意上面两种调用方式的不同之处。
( 2 )存取资源文件中的图标
将图标放在资源文件中,可以实现动态改变应用程序的图标。
将图标放在资源文件中,可以实现动态改变应用程序的图标。
//RC: testIcon icon res/test.ico
Application.Icon.Handle := LoadIcon(HInstance, 'testIcon');
Application.Icon.Handle := LoadIcon(HInstance, 'testIcon');
( 3 )存取资源文件中的 AVI 动画
//RC: testAvi avi res/test.avi
Animate1.ResName := 'testAvi';
Animate1.Active := True;
Animate1.ResName := 'testAvi';
Animate1.Active := True;
( 4 )存取资源文件中的 JPEG 图像
为了能够处理 JPEG 图像,必须在 Interface 处引用 JPEG 单元。
为了能够处理 JPEG 图像,必须在 Interface 处引用 JPEG 单元。
Var
jpg: TJPEGImage;
resStream: TResourceStream;
resStream: TResourceStream;
begin
jpg := TJPEGImage.Create;
resStream := TResourceStream.Create(HInstance, 'testJpg', 'jpgtype');
jpg.LoadFromStream(resStream);
Image1.Picture.Assign(jpg);
jpg.Free;
resStream.Free;
end;
jpg := TJPEGImage.Create;
resStream := TResourceStream.Create(HInstance, 'testJpg', 'jpgtype');
jpg.LoadFromStream(resStream);
Image1.Picture.Assign(jpg);
jpg.Free;
resStream.Free;
end;
附: Delphi 编程中资源文件的应用:初级应用篇
资源文件一般为扩展名为 res 的文件 . 在 VC 中资源文件用得非常普遍 , 但 Delphi 在其联机帮助中对资源文件没作什么介绍 , 其实利用其自带的资源编译工具 BRCC32.EXE( 一般位于 /Delphi/BIN 目录下) , 我们完全可以做出跟 VC 一样效果的文件来。
资源文件最大的好处是能将一些在必要时才调用的文件跟可执行文件一起编译 , 生成一个文件 . 这样做最大的好处就是使外部文件免遭破坏 . 例如在一条程序中你要临时调用一幅图片 , 一般作法是把图片放在某一路径下(通常是主程序所在路径) , 但如果用户路径误删你的图片文件 , 则可能使程序找不到相应文件而出错崩溃 . 另外 , 如果你想自己的程序界面美观 , 想用一些自定义光标 , 也要用到资源文件。
资源文件的使用步骤为:
一 . 编写 rc 脚本文本
用记事本或其它文本编辑器编写一个扩展名为 rc 的文件。例如:
mycur cursor move.cur // 加入光标
mypic Bitmap Water.BMP // 加入位图
mywav WAVE happy.wav // 加入声音
myAVI AVI EPOEN.AVI // 加入视频
myIco ICON CJT.ICO // 加入图标
格式分别为在资源文件中的名称 -> 类型 -> 实际文件名称,例如上面第一行定义一个名为 mycur 的光标,实际名称为加入光标 move.cur.
二 . 将 rc 文件编译成 res 资源文件
将脚本文件和实际文件拷到 Brcc32.EXE 所在目录,执行 DOS 命令。格式为: Brcc32 脚本文件 ( 回车 ) ,例如有一名为 myfirst.rc 的脚本文件,则执行 Brcc32 myfirst.rc( 回车 ) 即可。如果你是懒人,也可新建一批处理文件,内容只有一行: Brcc32 mufist.rc.( 因为 Delphi 安装后一般会在自动批处理文件中指明搜索路径的。 ) 如果编译成功,则会生成一个结尾为 res 的文件,这个文件就是我们需要的资源文件。
三 . 在 Delphi 单元中加入资源文件
将生成的 res 资源文件拷贝到你所编程序的路径下,在单元文件 {$R *DFM} 后加上一句 {$R mufirst.res} ,则将 res 文件加入去,编译后资 源文件即已包含在可执行文件中了。若你有多个资源文件,也按上法依次加入。
四 . 在 Delphi 程序中调用资源文件
资源文件在 Delphi 中的关键字为 hinstance. 下面给出具体用法 .
1. 光标的调用
首先在程序中定义一个值大于 0 的常量,因为 Delphi 本身用 0- 负 16 来索引默认的光标,所以我们制定的光标应从表面上 1 开始索引。然后在窗口的 Oncreat 事件中添加以下代码:
资源文件一般为扩展名为 res 的文件 . 在 VC 中资源文件用得非常普遍 , 但 Delphi 在其联机帮助中对资源文件没作什么介绍 , 其实利用其自带的资源编译工具 BRCC32.EXE( 一般位于 /Delphi/BIN 目录下) , 我们完全可以做出跟 VC 一样效果的文件来。
资源文件最大的好处是能将一些在必要时才调用的文件跟可执行文件一起编译 , 生成一个文件 . 这样做最大的好处就是使外部文件免遭破坏 . 例如在一条程序中你要临时调用一幅图片 , 一般作法是把图片放在某一路径下(通常是主程序所在路径) , 但如果用户路径误删你的图片文件 , 则可能使程序找不到相应文件而出错崩溃 . 另外 , 如果你想自己的程序界面美观 , 想用一些自定义光标 , 也要用到资源文件。
资源文件的使用步骤为:
一 . 编写 rc 脚本文本
用记事本或其它文本编辑器编写一个扩展名为 rc 的文件。例如:
mycur cursor move.cur // 加入光标
mypic Bitmap Water.BMP // 加入位图
mywav WAVE happy.wav // 加入声音
myAVI AVI EPOEN.AVI // 加入视频
myIco ICON CJT.ICO // 加入图标
格式分别为在资源文件中的名称 -> 类型 -> 实际文件名称,例如上面第一行定义一个名为 mycur 的光标,实际名称为加入光标 move.cur.
二 . 将 rc 文件编译成 res 资源文件
将脚本文件和实际文件拷到 Brcc32.EXE 所在目录,执行 DOS 命令。格式为: Brcc32 脚本文件 ( 回车 ) ,例如有一名为 myfirst.rc 的脚本文件,则执行 Brcc32 myfirst.rc( 回车 ) 即可。如果你是懒人,也可新建一批处理文件,内容只有一行: Brcc32 mufist.rc.( 因为 Delphi 安装后一般会在自动批处理文件中指明搜索路径的。 ) 如果编译成功,则会生成一个结尾为 res 的文件,这个文件就是我们需要的资源文件。
三 . 在 Delphi 单元中加入资源文件
将生成的 res 资源文件拷贝到你所编程序的路径下,在单元文件 {$R *DFM} 后加上一句 {$R mufirst.res} ,则将 res 文件加入去,编译后资 源文件即已包含在可执行文件中了。若你有多个资源文件,也按上法依次加入。
四 . 在 Delphi 程序中调用资源文件
资源文件在 Delphi 中的关键字为 hinstance. 下面给出具体用法 .
1. 光标的调用
首先在程序中定义一个值大于 0 的常量,因为 Delphi 本身用 0- 负 16 来索引默认的光标,所以我们制定的光标应从表面上 1 开始索引。然后在窗口的 Oncreat 事件中添加以下代码:
screen.cursor[35]:=Loadcursor (hinstance,'mycur');
其中 35 为大于 1 的常量, mycur 为光标在资源文件中的名字。如果希望在其他控件上使用定制光标,例如 Panel 控件,只需在程序的适当处加入以下代码:
Panel1.cursor:=35;
2. 位图的调用
新建一项工程,添加一 Timage 控件,在需要显示的地方写以下代码:
新建一项工程,添加一 Timage 控件,在需要显示的地方写以下代码:
Var mymap:Hbitmap;
begin
mymap:=LoadBitmap(hinstance,'mypic');
Image1.picture.Bitmap.Handle:=mymap ;
end;
mymap:=LoadBitmap(hinstance,'mypic');
Image1.picture.Bitmap.Handle:=mymap ;
end;
其中 "mypic" 为位图资源文件中的名称。
3.AVI 文件的调用
新建一工程,添加一 Animate 控件,在需要的地方加入:
3.AVI 文件的调用
新建一工程,添加一 Animate 控件,在需要的地方加入:
animater1.resname:='myAVI';
animater1.Active:=true;
animater1.Active:=true;
其中 myAVI 为视频文件在资源文件中的名称。
4. 调用 WAV 文件
在 uses 中加入 mmsystm 单元,以便在程序中播放 WAV 文件。播放时 Playsound(pchar('mywav'),hinstance,sndsync or snd_resource); 其中 mywav 为声音文件在资源中的名称。
5. 加入光标
加入光标比较容易,只要将 res 文件加入单元文件中即可。但需注意 , 名称最好取 "W"."WW" 等,使第一个字母尽量靠后,以免与主程序的图标顺序颠倒。这样一来,别人在使用你的程序时如果想选择其它图标就有很多选择了。
补充 :
1. 资源类型除上述类型外,还可以字体文件,字符串文件等。
2. 资源文件不但可以在标准图形界面下使用还可在控制台下使用。
下面我们来试验一下:
新建一工程,将唯一的一个 Form 删除,然后修改工程文件。增加一句 {$Apptype console}, 在 uses 子句中加入 mmsystem, 并将其它引用单元删掉。将 Begin 和 end 之间语句删掉。至此,我们就可和 Turbo PASCAL 下编程序一样,且还可以调用 windows 的 API 和资源。将资源文件 ----{$R myfist.res} 加入。在 Begin 和 end 之间写下:
4. 调用 WAV 文件
在 uses 中加入 mmsystm 单元,以便在程序中播放 WAV 文件。播放时 Playsound(pchar('mywav'),hinstance,sndsync or snd_resource); 其中 mywav 为声音文件在资源中的名称。
5. 加入光标
加入光标比较容易,只要将 res 文件加入单元文件中即可。但需注意 , 名称最好取 "W"."WW" 等,使第一个字母尽量靠后,以免与主程序的图标顺序颠倒。这样一来,别人在使用你的程序时如果想选择其它图标就有很多选择了。
补充 :
1. 资源类型除上述类型外,还可以字体文件,字符串文件等。
2. 资源文件不但可以在标准图形界面下使用还可在控制台下使用。
下面我们来试验一下:
新建一工程,将唯一的一个 Form 删除,然后修改工程文件。增加一句 {$Apptype console}, 在 uses 子句中加入 mmsystem, 并将其它引用单元删掉。将 Begin 和 end 之间语句删掉。至此,我们就可和 Turbo PASCAL 下编程序一样,且还可以调用 windows 的 API 和资源。将资源文件 ----{$R myfist.res} 加入。在 Begin 和 end 之间写下:
writeln('
演示程序,按任意键开始!
');
readln;
playsound(pchar('mywav'),hinstance,snd_sync or snd_resource);
writeln(' 演示结束! ');
readln;
playsound(pchar('mywav'),hinstance,snd_sync or snd_resource);
writeln(' 演示结束! ');
运行程序,将弹出一个标准 DOS 窗口,按任意键播放声音文件。是不是很 COOL 呢 ! 我曾下载过一个播放器,在其安装目录下我发现有一 "DOS 程序 ", 用鼠标双击它便弹出一个 DOS 窗口,显示 DOS 时代特有的画图,并有背景音乐!可能就是用这个方法做的。
3.Delphi 本身自带了一个叫 Image Editor 的工具,同样可以编辑资源文本,但和本文的方法比较,可得出下表:
3.Delphi 本身自带了一个叫 Image Editor 的工具,同样可以编辑资源文本,但和本文的方法比较,可得出下表:
Image
|
Editor
|
Brcc32
|
BMP
|
只支持
16
位色
|
任意色
|
光标
|
黑白两色
|
任意色
|
ICO
|
只支持
16
位色
|
任意色
|
AVI
|
不支持
|
支持
|
WAV
|
不支持
|
支持
|
字符串
|
不支持
|
支持
|
上面说的是直接在程序本身的调用。其实资源文件还有其它用法。比如说在你的程序携带其它文件,要用的时候释放出来。
例如 : myexe exefile 'ha1.exe'// 脚本文件
下面是自定义释放函数 ExtractRes ,本例中使用如下 :
例如 : myexe exefile 'ha1.exe'// 脚本文件
下面是自定义释放函数 ExtractRes ,本例中使用如下 :
ExtractRes('exefile','myexe','c:/new.exe');
就把 ha1.exe 以 new.exe 为名字保存到 C 盘根目录下了 .
function TForm1.ExtractRes(ResType, ResName, ResNewName: string): boolean;
var
Res: TResourceStream;
begin
try
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
try
Res.SavetoFile(ResNewName);
Result := true;
finally
Res.Free;
end;
except
Result := false;
end;
end;
var
Res: TResourceStream;
begin
try
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
try
Res.SavetoFile(ResNewName);
Result := true;
finally
Res.Free;
end;
except
Result := false;
end;
end;
Dephi
资源文件中、高级应用篇
中级应用篇
上面我们已经知道如何把一副 BMP 图像从资源文件里面读出来 , 但是 BMP 文件太大了 ,JPG 文件应用的相对较多 . 那么如何把 JPG 图像读出来呢 ? 用资源文件加流方式即可。具体方法如下 :
1 .MyJpg JPEG My.JPG
2 .
上面我们已经知道如何把一副 BMP 图像从资源文件里面读出来 , 但是 BMP 文件太大了 ,JPG 文件应用的相对较多 . 那么如何把 JPG 图像读出来呢 ? 用资源文件加流方式即可。具体方法如下 :
1 .MyJpg JPEG My.JPG
2 .
Var
Stream:TStream;
MyJpg:TJpegImage;
Begin
Stream := TResourceStream.Cceat(HINSTANCE,'MyJpg','JPEG');
Try
MyJpg:=TJpegImage.Create;
Try
MyJpg.LoadfromStream(Stream);
Image1.Picture.Assignc(MyJpg);
Finally
MyJpg.Free;
end;
Finally
Stream.Free;
end;
end;
Stream:TStream;
MyJpg:TJpegImage;
Begin
Stream := TResourceStream.Cceat(HINSTANCE,'MyJpg','JPEG');
Try
MyJpg:=TJpegImage.Create;
Try
MyJpg.LoadfromStream(Stream);
Image1.Picture.Assignc(MyJpg);
Finally
MyJpg.Free;
end;
Finally
Stream.Free;
end;
end;
读取其它图片文件也是一样的 . 比如说 gif 动画文件,当然前提是你有一个 gif.pas ,这个单元很多站点都有的,可以自己去找找。实际应用中我还发现用上面的代码可以直接显示资源文件中的 ICON 和 BMP 。
说到图形处理 , 实际上还可以用 Delphi 创建、调用纯图标资源的 DLL. 比如说你可以看看超级解霸目录下的 Dll, 很多就是纯图标资源而已。具体方法如下
:
1 : 创建一个 Hicon.RES 文件 , 这里不再重复 .
2 : 新建一文本文件 Icon.dpr, 内容如下 :
1 : 创建一个 Hicon.RES 文件 , 这里不再重复 .
2 : 新建一文本文件 Icon.dpr, 内容如下 :
library Icon;
{$R Icon.RES}
begin
end
{$R Icon.RES}
begin
end
用 Delphi 打开编译即可得到
Icon.dll.
3 : 实际调用方法如下 :
3 : 实际调用方法如下 :
......
Private
Hinst:THANDLE;
......
Var Hicon:THANDLE;
begin
Hinst:=Loadlibrary('Icon.dll');
If Hinst=0 Then Exit ;
Hicon:=Loadicon(Hinst,Pchar(Edit1.Text));
If Hicon<>0 Then Image1.Picture.Icon.Handle:=Hicon;
FreeLibrary(Hinst);
end;
Private
Hinst:THANDLE;
......
Var Hicon:THANDLE;
begin
Hinst:=Loadlibrary('Icon.dll');
If Hinst=0 Then Exit ;
Hicon:=Loadicon(Hinst,Pchar(Edit1.Text));
If Hicon<>0 Then Image1.Picture.Icon.Handle:=Hicon;
FreeLibrary(Hinst);
end;
如果你的程序想在国际上供使用不同语言的人使用的话 , 用 Dll 来存放字符资源将是一个好方法 . 因为 Dll 不象 ini 文件那样可以被人随便修改 , 特别是有时侯如果想保存一些版权信息的话用 Dll 就再好不过了。比如说你准备开发一个 " 汉字简繁体翻译器 " 软件 , 准备提供 Gb32,Big5 码和英文三种语言菜单给用户 , 那么你可以试试用 Dll 来保存字符资源 .
我们需要建立三个 Dll. 第一步当然是写 Rc 文件 , 举 Gb32 码为例 , 内容如下 :
/*MySc.rc*/
#define IDS_MainForm_Caption 1
#define IDS_BtnOpen_Caption 2
#define IDS_BtnSave_Caption 3
#define IDS_BtnBig5_Caption 4
#define IDS_BtnGb32_Caption 5
#define IDS_BtnHelp_Caption 6
#define IDS_Help_Shelp 7
Stringtable
{
IDS_MainForm_Caption," 汉字简繁体翻译器 "
IDS_BtnOpen_Caption," 打开文件 "
IDS_BtnSave_Caption," 保存文件 "
IDS_BtnBig5_Caption," 转换成 Big5"
IDS_BtnGb32_Caption," 转换成 Gb32"
IDS_BtnHelp_Caption," 帮助 "
IDS_Help_Shelp," 输入文字或打开文件后按需要点击按钮即可转换 !"
}
#define IDS_MainForm_Caption 1
#define IDS_BtnOpen_Caption 2
#define IDS_BtnSave_Caption 3
#define IDS_BtnBig5_Caption 4
#define IDS_BtnGb32_Caption 5
#define IDS_BtnHelp_Caption 6
#define IDS_Help_Shelp 7
Stringtable
{
IDS_MainForm_Caption," 汉字简繁体翻译器 "
IDS_BtnOpen_Caption," 打开文件 "
IDS_BtnSave_Caption," 保存文件 "
IDS_BtnBig5_Caption," 转换成 Big5"
IDS_BtnGb32_Caption," 转换成 Gb32"
IDS_BtnHelp_Caption," 帮助 "
IDS_Help_Shelp," 输入文字或打开文件后按需要点击按钮即可转换 !"
}
第二步是 Brcc32 编译为 Res 文件后用上面的方法得到 Dll 文件 , 另外两个 Dll 用同样的方法生成 . 下面来应用一下
:
新建一个工程 , 放上五个 Button:BtnOpen,BtnSave,BtnBig5,BtnGb32 和 BtnHelp. 还有一个 TComboBox:CbSelect 用来选择语言种类的 .
具体代码如下 :
新建一个工程 , 放上五个 Button:BtnOpen,BtnSave,BtnBig5,BtnGb32 和 BtnHelp. 还有一个 TComboBox:CbSelect 用来选择语言种类的 .
具体代码如下 :
unit Unit1;
interface
......
private
SHelp: string;
function SearchLanguagePack: TStrings;
procedure SetActiveLanguage(LanguageName: string);
{ Private declarations }
......
implementation
procedure TForm1.CbSelectChange(Sender: TObject);
begin
SetActiveLanguage(CbSelect.Text);// 调用相应 Dll 文件读取相应字符 .
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
CbSelect.Items.AddStrings(SearchLanguagePack);// 搜索当前目录下所有的 Dll 文件名称
end;
function TForm1.SearchLanguagePack: TStrings;
var
ResultStrings: TStrings;
DosError: integer;
SearchRec: TsearchRec;
begin
ResultStrings := TStringList.Create;
DosError := FindFirst(ExtractFilePath(ParamStr(0)) + '*.dll', faAnyFile, SearchRec);
while DosError = 0 do
begin
ResultStrings.Add(ChangeFileExt(SearchRec.Name, ''));
DosError := FindNext(SearchRec);
end;
FindClose(SearchRec);
Result := ResultStrings;
end;
procedure TForm1.SetActiveLanguage(LanguageName: string);
var
Hdll: Hmodule;
MyChar: array[0..254] of char;
DllFileName: string;
begin
DllFileName := ExtractFilePath(ParamStr(0)) + LanguageName + '.dll';
if not FileExists(DllFileName) then Exit;
Hdll := loadlibrary(Pchar(DllFileName));
Loadstring(hdll, 1, MyChar, 254);
Self.Caption := MyChar;
// 读取字符资源, 1 表示资源文件中定义的 1
Loadstring(hdll, 1, MyChar, 254);
Self.Caption := MyChar;
Loadstring(hdll, 2, MyChar, 254);
BtnOpen.Caption := MyChar;
Loadstring(hdll, 3, MyChar, 254);
BtnSave.Caption := MyChar;
Loadstring(hdll, 4, MyChar, 254);
BtnBig5.Caption := MyChar;
Loadstring(hdll, 5, MyChar, 254);
BtnGb32.Caption := MyChar;
Loadstring(hdll, 6, MyChar, 254);
BtnHelp.Caption := MyChar;
Loadstring(hdll, 7, MyChar, 254);
SHelp := MyChar;
Freelibrary(hdll);
Application.Title := Self.Caption;
//------------------------
BtnOpen.Visible := True;
BtnSave.Visible := True;
BtnBig5.Visible := True;
BtnGb32.Visible := True;
BtnHelp.Visible := True;
//------------------------
end;
procedure TForm1.BtnHelpClick(Sender: TObject);
begin
Application.MessageBox(Pchar(SHelp), 'Http://lovejingtao.126.com', MB_ICONINFORMATION);
end;
end.
interface
......
private
SHelp: string;
function SearchLanguagePack: TStrings;
procedure SetActiveLanguage(LanguageName: string);
{ Private declarations }
......
implementation
procedure TForm1.CbSelectChange(Sender: TObject);
begin
SetActiveLanguage(CbSelect.Text);// 调用相应 Dll 文件读取相应字符 .
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
CbSelect.Items.AddStrings(SearchLanguagePack);// 搜索当前目录下所有的 Dll 文件名称
end;
function TForm1.SearchLanguagePack: TStrings;
var
ResultStrings: TStrings;
DosError: integer;
SearchRec: TsearchRec;
begin
ResultStrings := TStringList.Create;
DosError := FindFirst(ExtractFilePath(ParamStr(0)) + '*.dll', faAnyFile, SearchRec);
while DosError = 0 do
begin
ResultStrings.Add(ChangeFileExt(SearchRec.Name, ''));
DosError := FindNext(SearchRec);
end;
FindClose(SearchRec);
Result := ResultStrings;
end;
procedure TForm1.SetActiveLanguage(LanguageName: string);
var
Hdll: Hmodule;
MyChar: array[0..254] of char;
DllFileName: string;
begin
DllFileName := ExtractFilePath(ParamStr(0)) + LanguageName + '.dll';
if not FileExists(DllFileName) then Exit;
Hdll := loadlibrary(Pchar(DllFileName));
Loadstring(hdll, 1, MyChar, 254);
Self.Caption := MyChar;
// 读取字符资源, 1 表示资源文件中定义的 1
Loadstring(hdll, 1, MyChar, 254);
Self.Caption := MyChar;
Loadstring(hdll, 2, MyChar, 254);
BtnOpen.Caption := MyChar;
Loadstring(hdll, 3, MyChar, 254);
BtnSave.Caption := MyChar;
Loadstring(hdll, 4, MyChar, 254);
BtnBig5.Caption := MyChar;
Loadstring(hdll, 5, MyChar, 254);
BtnGb32.Caption := MyChar;
Loadstring(hdll, 6, MyChar, 254);
BtnHelp.Caption := MyChar;
Loadstring(hdll, 7, MyChar, 254);
SHelp := MyChar;
Freelibrary(hdll);
Application.Title := Self.Caption;
//------------------------
BtnOpen.Visible := True;
BtnSave.Visible := True;
BtnBig5.Visible := True;
BtnGb32.Visible := True;
BtnHelp.Visible := True;
//------------------------
end;
procedure TForm1.BtnHelpClick(Sender: TObject);
begin
Application.MessageBox(Pchar(SHelp), 'Http://lovejingtao.126.com', MB_ICONINFORMATION);
end;
end.
可能你会说 , 这种方法还不如我自己在程序中直接定义三种具体的值来的方便 . 甚至我自己自定义一个结构好了,用不着用 DLL 那么麻烦的。但是如果你的程序要用的字符很多呢 ? 比如说 Windows 操作系统 , 本身就有简体中文 , 繁体中文 , 英文等等版本 , 用 Dll 的话只要直接替换 DLL 即可 , 而不用每发行一个版本就打开代码来修改一次。这样一来可以大大减少工作量和出错的机会 . 说到这里 , 再多说一句 :Windows 系统本身很多 Dll 带有了图片等资源 , 我们可以在程序中直接调用 , 这样一来我们的 EXE 也可以减少不少 ! 当然最小的方法是实时生成技术 . 老外曾经写了一个 67KB 的程序就是利用了这个方法。
高级应用篇
Delphi 是个很有效率的开发工具 , 但是它有一个缺点就是生成的 EXE 文件太大 . 一个程序就算只有一个空窗口体积也有 286KB. 如果直接用 API 来写的话程序体积是小了 , 但是又太繁琐 , 无法立即看到界面效果 , 根本谈不上是可视化开发 . 其实并非 " 鱼与熊掌不可兼得 ", 利用资源文件我们就可以轻松达到这个目的 .
在开始之前 , 我们需要一个可以编辑资源文件的工具 . 这类工具很多 , 比如说 Resource WorkShop 就是非常好的一个 . 如果一时找不到 , 利用 VC 的编辑器来也是可以的 . 下面我们就以 VC 的为例示范如何创建一个窗口资源文件 . 运行 VC, 打开菜单 File-->New, 将出现一个多项选择页 . 我们选择 Files-->ResourceTemplate, 在右边的 File 填上 Demo,Location 选择保存路径 , 然后点击按钮 OK 返回 VC 开发环境 .
选择菜单 Insert-->Resource, 将出现一个资源类型选择框 . 我们把鼠标移到 Dialog 上面 . 不用展开 , 点击右边的 New 即可 , 这时候返回 VC 开发环境并出现一个只有关闭按钮和两个 Button 的窗体 . 将鼠标选定窗体 , 击右键选择最后一项 Properties, 将出现一个设置窗口 , 将 ID 改为 "MAINFORM" 。
注意 : 跟下面添加的其它控件的属性设置方法不同 , 主窗口的 ID 必须把双引号写上去 , 而且名称必须为大写 . 否则程序将找不到资源 . 程序会一运行就退出了。
Caption 改为 " 安装程序 ", 这时候可以立刻看到窗口的标题变成了 " 安装程序 ", 把 Styles 的 Minimize box 选上 ,More Styles 的 Center 勾上使程序运行时的位置居中 . 当然你也可以设置它的坐标 . 其它保留默认值即可 . 回到开发环境 , 在控件框里面分别选择一个 Static Text, 一个 Edit Box, 一个 Button 和一个 Group Box 添加到窗体上面 . 把它们按照自己的爱好排列整齐 . 然后逐个修改它们的属性 . 方法就是按照上面说的选定控件后击右键选择最后一项 Properties, 在出现的属性框里面修改 . 其中属性如下 :Group Box 的 Caption 属性清空 ,Static Text 的 Caption 属性改为 " 请选择安装目录 :",Edit Box 的 ID 改为 10001. 第一个 Button 的 ID 为 10002,Caption 属性为 " 选择 ", 第二个 Button 的 ID 为 10003,Caption 属性为 " 安装 ", 第三个 Button 的 ID 为 10004,Caption 属性为 " 退出 ". 为了使程序更加完美 , 我们为它再添加一个菜单 IDR_MENU1. 选择 Insert-->Resource-->Menu, 我们这里只简单添加一项 " 文件 --> 退出 ", 其中 " 退出 " 的 ID 为 10005. 然后在主窗口的属性 Menu 设定为 IDR_MENU1 即可。
为了使程序更加美观 , 我们再添加一个小图标 , 同时这也将是我们程序的图标 . 选择 Insert-->Resource-->Icon-->Import, 选择一个图标文件 . 并将它的 ID 设置为 "MAINICON"( 注意 : 必须把双引号写上而且字母为大写 ), 为窗口添加一个 Picture 控件并设置它的属性 Type:Icon,Image 下拉选择刚才的图标 MainIcon 即可。
如果你想为程序在鼠标添加一些信息也是可以的 . 选择 Insert-->Resource-->Version 即可。
到这里我们已经完成了一个简单的 " 安装程序 " 的窗体设计 . 实际上我们现在就可以在 Delphi 中调用它了 . 我们先把 " 劳动成果 " 保存起来 . 选择 File-->Save As, 在文件类型里选择 "32-bit Resource File(.res)" 保存为 "Demo.res", 文件大小大约为 2.65KB 。
新建一个扩展名为 dpr 的文本文件 MyDemo.Dpr, 键入如下代码 :
高级应用篇
Delphi 是个很有效率的开发工具 , 但是它有一个缺点就是生成的 EXE 文件太大 . 一个程序就算只有一个空窗口体积也有 286KB. 如果直接用 API 来写的话程序体积是小了 , 但是又太繁琐 , 无法立即看到界面效果 , 根本谈不上是可视化开发 . 其实并非 " 鱼与熊掌不可兼得 ", 利用资源文件我们就可以轻松达到这个目的 .
在开始之前 , 我们需要一个可以编辑资源文件的工具 . 这类工具很多 , 比如说 Resource WorkShop 就是非常好的一个 . 如果一时找不到 , 利用 VC 的编辑器来也是可以的 . 下面我们就以 VC 的为例示范如何创建一个窗口资源文件 . 运行 VC, 打开菜单 File-->New, 将出现一个多项选择页 . 我们选择 Files-->ResourceTemplate, 在右边的 File 填上 Demo,Location 选择保存路径 , 然后点击按钮 OK 返回 VC 开发环境 .
选择菜单 Insert-->Resource, 将出现一个资源类型选择框 . 我们把鼠标移到 Dialog 上面 . 不用展开 , 点击右边的 New 即可 , 这时候返回 VC 开发环境并出现一个只有关闭按钮和两个 Button 的窗体 . 将鼠标选定窗体 , 击右键选择最后一项 Properties, 将出现一个设置窗口 , 将 ID 改为 "MAINFORM" 。
注意 : 跟下面添加的其它控件的属性设置方法不同 , 主窗口的 ID 必须把双引号写上去 , 而且名称必须为大写 . 否则程序将找不到资源 . 程序会一运行就退出了。
Caption 改为 " 安装程序 ", 这时候可以立刻看到窗口的标题变成了 " 安装程序 ", 把 Styles 的 Minimize box 选上 ,More Styles 的 Center 勾上使程序运行时的位置居中 . 当然你也可以设置它的坐标 . 其它保留默认值即可 . 回到开发环境 , 在控件框里面分别选择一个 Static Text, 一个 Edit Box, 一个 Button 和一个 Group Box 添加到窗体上面 . 把它们按照自己的爱好排列整齐 . 然后逐个修改它们的属性 . 方法就是按照上面说的选定控件后击右键选择最后一项 Properties, 在出现的属性框里面修改 . 其中属性如下 :Group Box 的 Caption 属性清空 ,Static Text 的 Caption 属性改为 " 请选择安装目录 :",Edit Box 的 ID 改为 10001. 第一个 Button 的 ID 为 10002,Caption 属性为 " 选择 ", 第二个 Button 的 ID 为 10003,Caption 属性为 " 安装 ", 第三个 Button 的 ID 为 10004,Caption 属性为 " 退出 ". 为了使程序更加完美 , 我们为它再添加一个菜单 IDR_MENU1. 选择 Insert-->Resource-->Menu, 我们这里只简单添加一项 " 文件 --> 退出 ", 其中 " 退出 " 的 ID 为 10005. 然后在主窗口的属性 Menu 设定为 IDR_MENU1 即可。
为了使程序更加美观 , 我们再添加一个小图标 , 同时这也将是我们程序的图标 . 选择 Insert-->Resource-->Icon-->Import, 选择一个图标文件 . 并将它的 ID 设置为 "MAINICON"( 注意 : 必须把双引号写上而且字母为大写 ), 为窗口添加一个 Picture 控件并设置它的属性 Type:Icon,Image 下拉选择刚才的图标 MainIcon 即可。
如果你想为程序在鼠标添加一些信息也是可以的 . 选择 Insert-->Resource-->Version 即可。
到这里我们已经完成了一个简单的 " 安装程序 " 的窗体设计 . 实际上我们现在就可以在 Delphi 中调用它了 . 我们先把 " 劳动成果 " 保存起来 . 选择 File-->Save As, 在文件类型里选择 "32-bit Resource File(.res)" 保存为 "Demo.res", 文件大小大约为 2.65KB 。
新建一个扩展名为 dpr 的文本文件 MyDemo.Dpr, 键入如下代码 :
Uses Windows,Messages;
{$R Demo.Res}
function MainDialogProc(DlgWin:hWnd;DlgMessage:UINT;DlgWParam:WPARAM;DlgLParam:LPARAM):
{$R Demo.Res}
function MainDialogProc(DlgWin:hWnd;DlgMessage:UINT;DlgWParam:WPARAM;DlgLParam:LPARAM):
integer;stdcall;
begin
Result := 0;
case DlgMessage of
WM_Close:
begin
PostQuitMessage(0);
Exit;
end;
end;
end;
begin
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc);
end
begin
Result := 0;
case DlgMessage of
WM_Close:
begin
PostQuitMessage(0);
Exit;
end;
end;
end;
begin
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc);
end
用 Delphi 打开它编译一次即可产生一个大小为 19KB 的 EXE. 是不是很小 ! 实际上 , 你甚至只用一行代码就把它 Show 出来 , 不过程序无法关闭而已 .
Uses Windows;
{$R Demo.Res}
function MainDialogProc: integer;
begin
Result := 0;
end;
begin
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc);
end
{$R Demo.Res}
function MainDialogProc: integer;
begin
Result := 0;
end;
begin
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc);
end
上面的程序只不过是一个空窗口而已 , 现在我们来写代码响应按下相应按钮响应的事件 . 完整代码如下 :
program MyDemo;
uses Windows, Messages, shlobj;
const
ID_Edit = 10001;
ID_Selet = 10002;
ID_Setup = 10003;
ID_Quit = 10004;
ID_Exit = 10005;
{$R Demo.Res}
var
MainWin: HWND;
function My_Gettext: string;
var
Textlength: Integer;
Text: PChar;
s: string;
begin
TextLength := GetWindowTextLength(GetDlgItem(MainWin, ID_Edit));
GetMem(Text, TextLength + 1);
GetWindowText(GetDlgItem(MainWin, ID_Edit), Text, TextLength + 1);
s := text;
FreeMem(Text, TextLength + 1);
Result := s;
end;
function Getmyname: string;
var
i, j: integer;
begin
J := 3;
for i := 1 to length(ParamStr(0)) do
if ParamStr(0)[i] = '/' then J := I;
Result := copy(ParamStr(0), J + 1, length(ParamStr(0)) - J);
end;
function SelectDirectory(handle: hwnd; const Caption: string; const Root:WideString;outDirectory:string): Boolean;
var
lpbi: _browseinfo;
buf: array[0..MAX_PATH] of char;
id: ishellfolder;
eaten, att: cardinal;
rt: pitemidlist;
initdir: pwidechar;
begin
result := false;
lpbi.hwndOwner := handle;
lpbi.lpfn := nil;
lpbi.lpszTitle := pchar(caption);
lpbi.ulFlags := BIF_RETURNONLYFSDIRS + BIF_EDITBOX;
SHGetDesktopFolder(id);
initdir := pwchar(root);
id.ParseDisplayName(0, nil, initdir, eaten, rt, att);
lpbi.pidlRoot := rt;
getmem(lpbi.pszDisplayName, MAX_PATH);
try
result := shgetpathfromidlist(shbrowseforfolder(lpbi), buf);
except
freemem(lpbi.pszDisplayName);
end;
if result then
begin
directory := buf;
if length(directory) <> 3 then directory := directory + '/';
end;
end;
function MainDialogProc(
DlgWin: hWnd;
DlgMessage: UINT;
DlgWParam: WPARAM;
DlgLParam: LPARAM
)
: integer; stdcall;
var
MyIcon: HICON;
Sdir: string;
begin
Result := 0;
case DlgMessage of
WM_INITDIALOG:
begin
MyIcon := LoadIcon(hInstance, 'MainIcon');
SetClassLONG(DlgWin, GCL_HICON, MyIcon);
MainWin := DlgWin;
end;
WM_Close:
begin
PostQuitMessage(0);
Exit;
end;
WM_COMMAND:
case LOWORD(DlgWParam) of
ID_Selet: begin
if SelectDirectory(DlgWin, ' 请选择安装目录 ', '', Sdir)
then SendMessage(GetDlgItem(DlgWin, ID_Edit), WM_SETTEXT, 0, lParam(pChar(Sdir)));
end;
ID_Setup: begin
if My_Gettext = '' then
begin
MessageBox(DlgWin, ' 请先选择安装文件夹 !', ' 信息 ', MB_ICONINFORMATION + MB_OK);
Exit;
end;
CopyFile(pchar(ParamStr(0)), pchar(My_Gettext + Getmyname), false);
MessageBox(DlgWin, ' 安装完毕 !', ' 信息 ', MB_ICONINFORMATION + MB_OK);
PostQuitMessage(0);
Exit;
end;
ID_Quit: begin
PostQuitMessage(0);
EXIT;
end;
ID_Exit: begin
if MessageBox(DlgWin, ' 你点击了菜单 “ 退出 ” ,你确定退出程序吗 ?', ' 信息 ', MB_ICONQUESTION + MB_OKCANCEL) = IDOK then
PostQuitMessage(0);
Exit;
end;
end;
end;
end;
begin
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc);
end
uses Windows, Messages, shlobj;
const
ID_Edit = 10001;
ID_Selet = 10002;
ID_Setup = 10003;
ID_Quit = 10004;
ID_Exit = 10005;
{$R Demo.Res}
var
MainWin: HWND;
function My_Gettext: string;
var
Textlength: Integer;
Text: PChar;
s: string;
begin
TextLength := GetWindowTextLength(GetDlgItem(MainWin, ID_Edit));
GetMem(Text, TextLength + 1);
GetWindowText(GetDlgItem(MainWin, ID_Edit), Text, TextLength + 1);
s := text;
FreeMem(Text, TextLength + 1);
Result := s;
end;
function Getmyname: string;
var
i, j: integer;
begin
J := 3;
for i := 1 to length(ParamStr(0)) do
if ParamStr(0)[i] = '/' then J := I;
Result := copy(ParamStr(0), J + 1, length(ParamStr(0)) - J);
end;
function SelectDirectory(handle: hwnd; const Caption: string; const Root:WideString;outDirectory:string): Boolean;
var
lpbi: _browseinfo;
buf: array[0..MAX_PATH] of char;
id: ishellfolder;
eaten, att: cardinal;
rt: pitemidlist;
initdir: pwidechar;
begin
result := false;
lpbi.hwndOwner := handle;
lpbi.lpfn := nil;
lpbi.lpszTitle := pchar(caption);
lpbi.ulFlags := BIF_RETURNONLYFSDIRS + BIF_EDITBOX;
SHGetDesktopFolder(id);
initdir := pwchar(root);
id.ParseDisplayName(0, nil, initdir, eaten, rt, att);
lpbi.pidlRoot := rt;
getmem(lpbi.pszDisplayName, MAX_PATH);
try
result := shgetpathfromidlist(shbrowseforfolder(lpbi), buf);
except
freemem(lpbi.pszDisplayName);
end;
if result then
begin
directory := buf;
if length(directory) <> 3 then directory := directory + '/';
end;
end;
function MainDialogProc(
DlgWin: hWnd;
DlgMessage: UINT;
DlgWParam: WPARAM;
DlgLParam: LPARAM
)
: integer; stdcall;
var
MyIcon: HICON;
Sdir: string;
begin
Result := 0;
case DlgMessage of
WM_INITDIALOG:
begin
MyIcon := LoadIcon(hInstance, 'MainIcon');
SetClassLONG(DlgWin, GCL_HICON, MyIcon);
MainWin := DlgWin;
end;
WM_Close:
begin
PostQuitMessage(0);
Exit;
end;
WM_COMMAND:
case LOWORD(DlgWParam) of
ID_Selet: begin
if SelectDirectory(DlgWin, ' 请选择安装目录 ', '', Sdir)
then SendMessage(GetDlgItem(DlgWin, ID_Edit), WM_SETTEXT, 0, lParam(pChar(Sdir)));
end;
ID_Setup: begin
if My_Gettext = '' then
begin
MessageBox(DlgWin, ' 请先选择安装文件夹 !', ' 信息 ', MB_ICONINFORMATION + MB_OK);
Exit;
end;
CopyFile(pchar(ParamStr(0)), pchar(My_Gettext + Getmyname), false);
MessageBox(DlgWin, ' 安装完毕 !', ' 信息 ', MB_ICONINFORMATION + MB_OK);
PostQuitMessage(0);
Exit;
end;
ID_Quit: begin
PostQuitMessage(0);
EXIT;
end;
ID_Exit: begin
if MessageBox(DlgWin, ' 你点击了菜单 “ 退出 ” ,你确定退出程序吗 ?', ' 信息 ', MB_ICONQUESTION + MB_OKCANCEL) = IDOK then
PostQuitMessage(0);
Exit;
end;
end;
end;
end;
begin
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc);
end
其中 SelectDirectory 函数的作用是返回一个选择的文件路径 . 然后把自己拷贝到选择的目录下 , 当然很多处理没有写 , 读者可以自行添加 . 文件编译后大小为 22KB, 如果直接用 Delphi 的 VCL 来写的话 , 将为 338KB!