杂记
 


Delphi中资源文件的使用

作者:Cable Fan  2013-12-08 21:14:25     分类:Delphi     标签:blog

本文首次发布在csdn.net,原文请浏览:http://blog.csdn.net/cablefan/article/details/1881268

在Delphi中,生成一个Appliction工程时,会默认生成一个与工程同名的资源文件,即使删除也会再度创建,但是这个资源文件中只有一个图标和一个版本信息。 通常情况下,我们还需要更多的多种多样的资源,虽然可以在IDE中载入并编译到EXE文件中去,但是有时我们需要将资源与EXE分开,以便生成多语言程序或将程序改为其它语言(如汉化)。

Delphi附带的ImageEdit可以编辑资源文件,但只能编辑位图、图标和光标,无法加入字符串资源,而且只持256色的图像。为了将更多种类的资源,只有编写资源脚本或者使用其它资源编辑器,如Visual Stadio 6。不过,Visual Stadio 6编辑的资源文件中包含了C++头文件定义,并且支持的具体资源类型较多,在Delphi中是无法识别的。 只好选择编写资源脚本了,资源脚本文件扩展名为.RC,可以用纯文本编辑器编写。如下面是两个图标与两个字符串的脚本:

/* Delphi中只支持RCDATA类型 */ 
COMPUTER RCDATA "computer.ico" 
WINDOWSXP RCDATA "XP.ico" 

STRINGTABLE 
BEGIN 
  1 "computer(电脑)" 
  2 "Windows XP" 
END 

将其保存为MyRes.rc,需要注意的是,这里包含了两个图标,注意文件名及路径(这里是与文件同一目录)。在命令提示符窗口中将目录切换到MyRes.rc所在的路径,运行brcc32 MyRes.rc,其中brcc32.exe是Delphi附带的资源编译工具。如果想将资源文件生成其它扩展名的文件(如.DLL),可以增加-fo参数,如:brcc32 MyRes.rc –of MyRes.dll。

接下来是对资源的引用,引用方法有静态与动态两种,静态引用就是将资源文件包含到源码中编译到EXE中去;动态引用则是把资源文件当成DLL动态装载。 静态引用资源文件在Delphi中是最简单不过了,只要在工程文件中加入一个编译指令即可,如:

program Multi_Lang; 

uses 
  Forms, 
  TestFormUnit in 'TestFormUnit.pas' {TestForm}; 
  
{$R MyRes.dll} // 包含自定义的资源文件 
{$R *.res} // 包含默认的资源文件 

begin 
  Application.Initialize; 
  Application.CreateForm(TTestForm, TestForm); 
  Application.Run; 
end.

引用时,字符串只要LoadStr(Index)即可,而其它资源用TResourceStream读取,只不过资源句柄就是程序本身,直接用hInstance就可以了。如:

procedure TTestForm.ReadDirect(Index: Integer); 
var 
  Stream: TResourceStream; 
  Icon: TIcon; S: String; 
begin 
  Edit1.Text:= LoadStr(Index); // 在TEdit控件中显示所获取的字符串 
  if Index = 1 then 
    S:= 'COMPUTER' 
  else 
    S:= 'WINDOWSXP'; // Delphi中只支持RT_RCDATA类型读取 
  Stream:= TResourceStream.Create(hInstance, S, RT_RCDATA); // 使用hInstance句柄 
  try 
	Icon:= TIcon.Create; 
	try 
	  Icon.LoadFromStream(Stream); 
	  Image1.Picture.Icon.Assign(Icon); // 是TImage控件中显示所获取的图标 
	finally 
	  Icon.Free; 
	end; 
  finally 
	Stream.Free; 
  end; 
end;

这种引用方式在编译就将资源与EXE文件链接在一起,而编译之后就不再需要资源文件了。

动态引用方式相对更多加灵活,编译时不需要资源文件,而是在运行时动态地入,这样便可以控制载入不同的资源文件,这也是实现多语言程序的一种方法。 动态引用实际上只是将资源文件静态包含到另一个工程(一般为DLL程序)中,如:

library MyResDll; 

uses 
  SysUtils, Classes; 
  
{$R MyRes.dll} // 将资源文件包含到DLL工程中 

ResourceString 
  S1 = '电脑'; 
  S2 = '视窗'; 
  
Begin 

end.

引用时像普通的DLL引用一样,将其装载后得到一个句柄,再用静态引用的方法,使用TResourceStream来读取。如:

procedure TTestForm.ReadDynamic(Index: Integer); 
var 
  Hnd: THandle; Stream: TResourceStream; 
  Icon: TIcon; 
  S: String; 
  Buf: PChar; 
begin 
  Hnd:= LoadLibrary('MyResDll.dll'); // 装载资源文件 
  if Hnd > 0 then 
  begin 
    GetMem(Buf, 255); 
	LoadString(Hnd, Index, Buf, 255); // 使用LoadString装载指定句柄的字符串 
	Edit1.Text:= StrPas(Buf); 
	if Index = 1 then 
	  S:= 'COMPUTER' 
	else 
	  S:= 'WINDOWSXP'; 
    Stream:= TResourceStream.Create(Hnd, S, RT_RCDATA); // 使用装载得到的句柄 
	try 
	  Icon:= TIcon.Create; 
	  try 
	    Icon.LoadFromStream(Stream); 
		Image1.Picture.Icon.Assign(Icon); 
	  finally 
	    Icon.Free; 
	  end; 
	finally 
	  FreeMem(Buf, 255); 
	  Stream.Free; 
	end; 
    FreeLibrary(Hnd); 
  end; 
end; 

这种方法似乎有点复杂。^_^。 将上面的方法变一下,将装载字符串的函数声明在DLL文件中,如:

library MyResDll; 

uses 
  SysUtils, Classes; 
  
{$R MyRes.dll} 

ResourceString 
  S1 = '电脑'; 
  S2 = '视窗'; 
  
const 
  ResStr: array[0..1] of String = (S1, S2); // 将字符串放入数组常量 
  
  { 声明函数获取字符串个数} 
  function GetStrCount: Integer; stdcall; 
  begin 
    Result:= Length(ResStr); 
  end; 
  
  { 声明函数获取指定索引号的字符串 } 
  function GetResStr(Index: Integer): PChar; stdcall; 
  begin 
    if (Index >= Low(ResStr)) and (Index <= High(ResStr)) then 
	  Result:= PChar(ResStr[Index]) 
	else 
	  Result:= ''; 
  end; 
  
exports 
  GetStrCount, GetResStr; 
  
begin 

end. 

引用的方法与一般的函数库引用方法一样。如:

type 
  TGetResStr = function(Index: Integer): PChar; stdcall; 
  
  procedure TTestForm.ReadSourceDef(Index: Integer); 
  var 
    Hnd: THandle; 
	GetResStr: TGetResStr; 
  begin 
    Hnd:= LoadLibrary('MyResDll.dll'); 
	if Hnd > 0 then 
	begin 
	  @GetResStr:= GetProcAddress(Hnd, 'GetResStr'); 
	  Edit1.Text:= GetResStr(Index); 
	  FreeLibrary(Hnd); 
	end; 
  end; 

以上代码在Windows XP Professional + Delphi7下测试通过,如需完整的源码请mail我:fancy105@163.com。

更多
阅读(727)     评论(0)