Delphi Programming / Object Pascal
[掲載 2017年11月24日] [更新 2017年12月01日] Delphi サンプルプログラム集
907_リソースのビットマップを取得
動作確認等
Windows 7 U64(SP1) + Delphi XE(UP1) Pro
907_GetResourceBitmap.zip [2,407 KB] 2017年12月01日版 (EXE 同梱)
DLL や EXE ファイル等,リソースとしてビットマップ画像が格納されているファイルから,そのビットマップを取得するサンプルです.
以下の参考リンクに,リソースのアイコンを取得するサンプルがありますが,ヒットマップの場合はリソースを含むファイルを LoadLibraryEx( 関数で読み込み,モジュールとしてのハンドルを取得します.そのハンドルを使用してリソースを取得します.
01_ リソースの IDを指定してビットマップを取得
Delphi XE Pro のコンパイル済みパッケージ dclstd150.bpl からリソースのビットマップを取得する例です.このビットマップは,このパッケージに登録されているコンポーネントのアイコン (ビットマップ) となっています.
モジュールとしてのハンドルを取得した後,TBitmap.LoadFromResourceName
メソッドでビットマップを取得します.ここではリソース名が TMEMO32 のビットマップを取得します.
[備考]
Delphi ではコンポーネントのアイコン (実際にはビットマップ) を作成して,リソースコンパイラで .dcr というファイルを生成してそこに格納します.コンポーネントの登録先のパッケージをコンパイルすると,そのパッケージが再構築されて,コンポーネントのアイコンとしてのビットマップが,そのコンパイル済みのパッケージにリソースとして保存されます.
コンパイル済みパッケージの拡張子は .bpl です.
図1
ビットマップの取得結果
リスト1
LoadFromResourceName を使用して,リソース名からビットマップを取得
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Button1: TButton;
Image1: TImage;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := 'TMEMO32' ;
Image1.AutoSize := True;
end ;
// =============================================================================
// コンパイル済みパッケージファイルから指定名前のビットマップを取得
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LResouceFile : string ;
LdwFlag : Cardinal;
LhModule : THandle;
LBitmap : TBitmap;
begin
Image1.Picture.Assign(nil );
LResouceFile := 'C:\Program Files (x86)\Embarcadero\RAD Studio\8.0\bin\dclstd150.bpl' ;
LdwFlag := LOAD_LIBRARY_AS_DATAFILE or LOAD_WITH_ALTERED_SEARCH_PATH;
LhModule := LoadLibraryEx(PChar(LResouceFile), 0 , LdwFlag);
try
if LhModule <> 0 then begin
LBitmap := TBitmap.Create;
try
LBitmap.LoadFromResourceName(LhModule, Trim(Edit1.Text));
Image1.Picture.Bitmap.Assign(LBitmap);
finally
FreeAndNil(LBitmap);
end ;
end ;
finally
FreeLibrary(LhModule);
end ;
end ;
end .
下図は imageres.dll 内のリソース ID が 5004 のビットマップを取得する例です.
このリソース ID は数値です.そこで LoadFromResourceID 関数でビットマップを取得しています.
imageres.dll にはシステム的にパスが通っていますからディレクトリ名を省略できます.
図2
imageres.dll 内の 5004 のビットマップ
リスト2
LoadFromResourceID を使用して,リソース名からビットマップを取得
copy code
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := '5004' ;
Image1.AutoSize := True;
end ;
// =============================================================================
// DLLのリソースからビットマップを取得
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LResouceFile : string ;
LdwFlag : Cardinal;
LhModule : THandle;
LBitmap : TBitmap;
begin
Image1.Picture.Assign(nil );
LResouceFile := 'imageres.dll' ;
LdwFlag := LOAD_LIBRARY_AS_DATAFILE or LOAD_WITH_ALTERED_SEARCH_PATH;
LhModule := LoadLibraryEx(PChar(LResouceFile), 0 , LdwFlag);
try
if LhModule <> 0 then begin
LBitmap := TBitmap.Create;
try
LBitmap.LoadFromResourceID(LhModule, StrToInt(Trim(Edit1.Text)));
Image1.Picture.Bitmap.Assign(LBitmap);
finally
FreeAndNil(LBitmap);
end ;
end ;
finally
FreeLibrary(LhModule);
end ;
end ;
リソースのビットマップを列挙する例です.実際にはリソースの ID の一覧を表示します.一覧表示したリソース ID を選択すると,そのビットマップをリソースから取得して表示します.
参考リンクのサンプルではマルチアイコンを取得するため,処理コードが長く複雑ですが,ビットマップの場合は単純です.ただし,参考リンクのサンプルと同じように,リソース ID には数値と文字列があることに注意します.
下図は Shell32.dll 内と ResourceHacker.exe 内のビットマップリソースを取得した結果です.
Shell32.dll 以外にも compstui.dll, mmcndmgr.dll,
netshell.dll, wmploc.dll, inetcpl.cpl 等にもビットマップ画像が格納されています.
図3
設計時の画面
リソース ID 一覧表示用の TListBoxと画像表示用の TImage を配置
図4
Shell32.dll 内のビットマップを取得
リソース ID を TList に一覧表示
リソース ID は数値と文字列の両方ある
クリックするとその ID のビットマップを取得して表示
図5
ResourceHacker.exe 内のビットマップを取得
下図は前項と同じ Delphi XE Pro のコンパイル済みパッケージ dclstd150.bpl からリソースのビットマップを取得した結果です.286 個あります.このファイルのビットマップのリソース ID は null 終端文字列となっています.
その下の図は Delphi 6 Pro の標準コンポーネントのアイコンですが,77 個しかありません.
図6
Delphi XE の dclstd150.bpl ファイル内のビットマップリソースの列挙
図7
Delphi 6 の dclstd60.bpl ファイル内のビットマップリソースの列挙
リスト3
ビットマップリソースのリソース ID を列挙
LoadFromResourceName または LoadImage を使用して,リソース ID からビットマップを取得
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Button1: TButton;
Edit1: TEdit;
ListBox1: TListBox;
Image1: TImage;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
{ Private 宣言 }
FResouceFile : string ;
public
{ Public 宣言 }
end ;
function EnumResNameProc(hModule: HWND; lpszType: PChar; lpszName:PChar;
AIndex: LPARAM): LongBool; stdcall ;
var
Form1: TForm1;
implementation
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := 'C:\Program Files (x86)\Embarcadero\RAD Studio\8.0\bin\dclstd150.bpl' ;
Image1.AutoSize :=True;
end ;
// =============================================================================
// リソースの列挙
// ここでは RT_BITMAP とする(つまりビットマップ)
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LhModule : THandle;
LdwFlag : Cardinal;
begin
Image1.Picture.Assign(nil );
ListBox1.Items.Clear;
ListBox1.Items.BeginUpdate;
// リソースファイルを指定してモジュールのハンドルを取得
FResouceFile := Trim(Edit1.Text);
LdwFlag := LOAD_LIBRARY_AS_DATAFILE or LOAD_WITH_ALTERED_SEARCH_PATH;
LhModule := LoadLibraryEx(PChar(FResouceFile), 0 , LdwFlag);
try
if LhModule <> 0 then begin
// リソースIDを列挙
EnumResourceNames(LhModule, RT_BITMAP, @EnumResNameProc, -1 );
end ;
Label1.Caption := IntToStr(ListBox1.Items.Count);
finally
FreeLibrary(LhModule);
ListBox1.Items.EndUpdate;
end ;
end ;
// =============================================================================
// ListBox1のOnClickイベント
// リストボックスのItemをクリックしたらそのリソースを読み出してTImageに表示
// =============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
LdwFlag : Cardinal;
LhModule : THandle;
LItemStr : string ;
LItemInt : Integer;
LBitmap : TBitmap;
begin
Image1.Picture.Assign(nil );
if ListBox1.ItemIndex =-1 then Exit;
// リソースファイルを指定してモジュールのハンドルを取得
LdwFlag := LOAD_LIBRARY_AS_DATAFILE or LOAD_WITH_ALTERED_SEARCH_PATH;
LhModule := LoadLibraryEx(PChar(FResouceFile), 0 , LdwFlag);
try
if LhModule <> 0 then begin
LBitmap := TBitmap.Create;
try
LItemStr := ListBox1.Items[ListBox1.ItemIndex];
LItemInt := StrToIntDef(LItemStr, -1 );
// リソースIDが数値の時と文字列の時で処理を分岐
// 文字列が数字だけで構成されていると数値と判定してしまう
if LItemInt < 0 then begin
LBitmap.LoadFromResourceName(LhModule, LItemStr);;
end else begin
LBitmap.LoadFromResourceID(LhModule, LItemInt);
end ;
Image1.Picture.Bitmap.Assign(LBitmap);
finally
// LBitmap.HandleにHBitmapを代入しているのでDeleteObject(LhBitmap)は不要
FreeAndNil(LBitmap);
end ;
end ;
finally
FreeLibrary(LhModule);
end ;
end ;
// -----------------------------------------------------------------------------
// EnumResourceNamesのコールバック関数
// リソースの列挙
// -----------------------------------------------------------------------------
function EnumResNameProc(hModule: HWND; lpszType: PChar; lpszName: PChar;
AIndex: LPARAM): LongBool;
var
LhBitmap : HBitmap;
LResIDStr : string ;
begin
Result := True;
if AIndex = -1 then begin
// リソースの取得
LhBitmap := LoadImage(hModule, MakeIntResource(lpszName), IMAGE_BITMAP, 0 , 0 , 0 );
try
if LhBitmap <> 0 then begin
// リソース名のチェック
// 上位WORD(2バイト)が 0ならIDは数値.それ以外は文字列のポインタ
if HiWord(Cardinal(lpszName)) = 0 then begin
LResIDStr := IntToStr(Cardinal(lpszName));
end else begin
LResIDStr := lpszName;
end ;
// リソースのIDをリストに追加
Form1.ListBox1.Items.Add(LResIDStr);
end ;
finally
DeleteObject(LhBitmap);
end ;
end ;
end ;
end .
03_ .dcr ( コンポーネントのアイコンリソース ) からビットマップ取得
Delphi のコンポーネントのアイコンのリソースファイル
.dcr は拡張子は違いまが .res ファイルと構造は同じです..dcr ファイルは Delphi のコンポーネントのアイコン専用のリソースファイルということになります.
.dcr あるいは .res ファイルを LoadLibraryEx 関数で読み込んでもモジュールとしてのハンドルは取得できません..dcr には [リソース ID] [ビットマップヘッダ] [ビットマップ] データの順にリソースとしての情報が格納されていますから,これを順番に取り出していけばビットマップが取得できることになります.
もう 1 つの方法は,.dcr をリソースとした実行可能なモジュールを作成してしまう方法です.
例えば plPrevReg.dcr を dll 内にリソースとして埋め込むには以下のようなプロジェクトを作成してコンパイルします.このコードではリソースの名前を plPrevReg.res
としていますが,plPrevReg.dcr でも同じです.
リソースの名前を plPrevReg.dcr にした場合は,コンパイルすると plPrevReg.res ファイルが自動的に作成されます.
リスト4
plPevReg.res をリソースとして埋め込む DLL を作成するプロジェクトのコード
library plPrevReg;
uses Windows;
{$R plPrevReg.res}
begin
end .
以下は添付の plPrevReg.dcr をリソースとした DLL を作成するサンプルです.作成した DLL を読み込んでリソースとしてのビットマップを取得します.DLL を作成するコードと,LoadLibraryEx 関数で読み込むファイルがその DLL であること以外は前項のサンプルとほとんど同じです.
当然ですが,このサンプルは
Delphi のコマンドラインコンパイラを使用します.したがって,実行環境に Delphi がインストールされていないと正常に動作しません.
[備考]
Delphi が標準で提供しているコンポーネント類には .dcr ファイルはありません.また.パッケージの定義ファイル .dpk もありません.
Delphi が標準で提供しているコンポーネントのアイコン (ビットマップ) は,コンパイル済みパッケージファイル .bpl にリソースとして格納されています.
図8
実行結果
リスト5
dcr ファイル (コンポーネントのアイコンのリソースファイル) からビットマップを取得する例
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Button1: TButton;
Edit1: TEdit;
ListBox1: TListBox;
Image1: TImage;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private 宣言 }
FdcrDllFile : string ;
function dcrToDllFile(AdcrFilePath: string ): string ;
public
{ Public 宣言 }
end ;
function EnumResNameProc(hModule: HWND; lpszType: PChar; lpszName:PChar;
AIndex: LPARAM): LongBool; stdcall ;
var
Form1: TForm1;
implementation
uses
ShellAPI,
StrUtils;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := ExpandFileName('.\plPrevReg.dcr' );
Image1.AutoSize :=True;
end ;
// =============================================================================
// フォーム破棄時の処理
// =============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
var
LdprFile : string ;
LresFile : string ;
begin
LdprFile := ChangeFileExt(FdcrDllFile, '.dpr' );
LresFile := ChangeFileExt(FdcrDllFile, '.res' );
DeleteFile(FdcrDllFile);
DeleteFile(LdprFile);
DeleteFile(LresFile);
end ;
// =============================================================================
// リソースの列挙
// ここでは RT_BITMAP とする(つまりビットマップ)
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LdcrFilePath : string ;
LhModule : THandle;
LdwFlag : Cardinal;
begin
Image1.Picture.Assign(nil );
if FdcrDllFile <> '' then FormDestroy(nil );
LdcrFilePath := Trim(Edit1.Text);
FdcrDllFile := dcrToDllFile(LdcrFilePath);
ListBox1.Items.Clear;
ListBox1.Items.BeginUpdate;
if FdcrDllFile <> '' then begin
// DLLファイルを指定してモジュールのハンドルを取得
LdwFlag := LOAD_LIBRARY_AS_DATAFILE or LOAD_WITH_ALTERED_SEARCH_PATH;
LhModule := LoadLibraryEx(PChar(FdcrDllFile), 0 , LdwFlag);
try
if LhModule <> 0 then begin
// リソースIDを列挙
EnumResourceNames(LhModule, RT_BITMAP, @EnumResNameProc, -1 );
end ;
Label1.Caption := IntToStr(ListBox1.Items.Count);
finally
FreeLibrary(LhModule);
end ;
end ;
ListBox1.Items.EndUpdate;
end ;
// =============================================================================
// ListBox1のOnClickイベント
// リストボックスのItemをクリックしたらそのリソースを読み出してTImageに表示
// =============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
LdwFlag : Cardinal;
LhModule : THandle;
LItemStr : string ;
LItemInt : Integer;
LBitmap : TBitmap;
begin
Image1.Picture.Assign(nil );
if ListBox1.ItemIndex =-1 then Exit;
// リソースファイルを指定してモジュールのハンドルを取得
LdwFlag := LOAD_LIBRARY_AS_DATAFILE or LOAD_WITH_ALTERED_SEARCH_PATH;
LhModule := LoadLibraryEx(PChar(FdcrDllFile), 0 , LdwFlag);
try
if LhModule <> 0 then begin
LBitmap := TBitmap.Create;
try
LItemStr := ListBox1.Items[ListBox1.ItemIndex];
LItemInt := StrToIntDef(LItemStr, -1 );
// リソースIDが数値の時と文字列の時で処理を分岐
// 文字列が数字だけで構成されていると数値と判定してしまう
if LItemInt < 0 then begin
LBitmap.LoadFromResourceName(LhModule, LItemStr);;
end else begin
LBitmap.LoadFromResourceID(LhModule, LItemInt);
end ;
Image1.Picture.Bitmap.Assign(LBitmap);
finally
// LBitmap.HandleにHBitmapを代入しているのでDeleteObject(LhBitmap)は不要
FreeAndNil(LBitmap);
end ;
end ;
finally
FreeLibrary(LhModule);
end ;
end ;
// -----------------------------------------------------------------------------
// EnumResourceNamesのコールバック関数
// リソースの列挙
// -----------------------------------------------------------------------------
function EnumResNameProc(hModule: HWND; lpszType: PChar; lpszName: PChar;
AIndex: LPARAM): LongBool;
var
LhBitmap : HBitmap;
LResIDStr : string ;
begin
Result := True;
if AIndex = -1 then begin
// リソースの取得
LhBitmap := LoadImage(hModule, MakeIntResource(lpszName), IMAGE_BITMAP, 0 , 0 , 0 );
try
if LhBitmap <> 0 then begin
// リソース名のチェック
// 上位WORD(2バイト)が 0ならIDは数値.それ以外は文字列のポインタ
if HiWord(Cardinal(lpszName)) = 0 then begin
LResIDStr := IntToStr(Cardinal(lpszName));
end else begin
LResIDStr := lpszName;
end ;
// リソースのIDをリストに追加
Form1.ListBox1.Items.Add(LResIDStr);
end ;
finally
DeleteObject(LhBitmap);
end ;
end ;
end ;
// -----------------------------------------------------------------------------
// 拡張子がdcrのファイルからdllファイルを作成する関数
// 実行環境にDelphiがインストールされている必要がある
//
// AdcrFilePath : 対象のdcrファイルのフルパス
// 戻り値はdllのパス名.失敗すると空文字を返す
// グローバルな変数は使用していない
//
// usesに ShellAPI,StrUtilsが必要
// -----------------------------------------------------------------------------
function TForm1.dcrToDllFile(AdcrFilePath: string ): string ;
var
LSelfAppPath : string ;
LResFilePath : string ;
LdprFilePath : string ;
LdprCodeList : TStringList;
Lpdcc32ExePath : PChar;
Ldcc32ExePath : string ;
LCompilerName : string ;
LCmdLineStr : string ;
LStartInfo : TStartupInfo;
LProcessInfo : TProcessInformation;
begin
Result := '' ;
// res,dprのパス名を生成
LSelfAppPath := ExtractFilePath(Application.ExeName);
LResFilePath := LSelfAppPath + ChangeFileExt(ExtractFileName(AdcrFilePath), '.res' );
LdprFilePath := LSelfAppPath + ChangeFileExt(ExtractFileName(AdcrFilePath), '.dpr' );
DeleteFile(LResFilePath);
DeleteFile(LdprFilePath);
// resファイル保存
CopyFile(PChar(AdcrFilePath), PChar(LResFilePath), False);
// DLL作成用のプロジェクトコードを作成して保存
LdprCodeList := TStringList.Create;
try
LdprCodeList.Add('library ' + ChangeFileExt(ExtractFileName(LdprFilePath), '' ) + ';' );
LdprCodeList.Add('uses Windows;' );
LdprCodeList.Add('{$R ' + ExtractFileName(LResFilePath) + '}' );
LdprCodeList.Add('begin' );
LdprCodeList.Add('end.' );
LdprCodeList.SaveToFile(LdprFilePath);
finally
FreeAndNil(LdprCodeList);
end ;
// コマンドラインコンパイラ(dcc32.exe)のフルパスを取得
Lpdcc32ExePath := StrAlloc(MAX_PATH + 1 );
try
if FindExecutable(PChar(LdprFilePath), nil , Lpdcc32ExePath) > 32 then begin
Ldcc32ExePath := Lpdcc32ExePath;
if Ldcc32ExePath <> '' then begin
LCompilerName := ExtractFileName(Ldcc32ExePath);
Ldcc32ExePath := ReplaceText(Ldcc32ExePath, LCompilerName, 'dcc32.exe' );
end ;
end else begin
exit;
end ;
finally
StrDispose(Lpdcc32ExePath);
end ;
if LowerCase(ExtractFileName(Ldcc32ExePath)) <> 'dcc32.exe' then exit;
Ldcc32ExePath := AnsiQuotedStr(Trim(Ldcc32ExePath), '"' );
// 作成したプロジェクトファイルをコンパイルしてDLL作成
GetStartupInfo(LStartInfo);
LStartInfo.dwXSize := 0 ;
LStartInfo.dwYSize := 0 ;
LStartInfo.wShowWindow := SW_HIDE;
LCmdLineStr := Ldcc32ExePath + ' ' + AnsiQuotedStr(LdprFilePath,'"' );
UniqueString(LCmdLineStr);
if not CreateProcess(nil ,
PChar(LCmdLineStr),
nil ,
nil ,
False,
0 ,
nil ,
PChar(LSelfAppPath),
LStartInfo,
LProcessInfo) then begin
end else begin
// コンパイルが終了するまで待つ
while WaitForSingleObject(LProcessInfo.hProcess, 0 ) = WAIT_TIMEOUT do begin
Application.ProcessMessages;
Sleep(1 );
end ;
CloseHandle(LProcessInfo.hProcess);
CloseHandle(LProcessInfo.hThread);
Result := ChangeFileExt(LdprFilePath, '.dll' );
end ;
end ;
end .
04_ unitResFile を利用してリソースファイルのビットマップを取得
コマンドラインコンパイラを使用しないでリソースファイルからリソースを取り出す例です.
unitResFile, unitResourceDetails というリソースファイル操作用のユニット類を利用しています.これらのユニットを使用すると,リソースファイルに格納されている各々のリソース ID の値,リソースの型が取得でき,リソースのデータを個別に TMemoryStream に保存できます.
これらのユニットは,リソースエディタ XN Resource Editor の開発者である Colin Wilson 氏が提供していたユニットですが,2017年11月24日現在,Colin Wilson 氏のサイトは存在しません.今回は以下の SourceForge のページからダウンロードしたファイルを使用しました.
ファイル名をクリックして表示されるページにダウンロードのリンクがあります.そこからダウンロードできます.
ビットマップの場合,リソースから取り出した TMemoryStream のデータの先頭部分にビットマップファイルヘッダの情報がない場合はビットマップとして認識してくれません.ない場合は先頭にファイルヘッダ情報を追加します.Delphi の場合は TBitmapFileHeader レコード型の変数に各メンバの値をセットします.
以下が実際のサンプルです.下図では添付のコンポーネントのリソースファイルからコンポーネントのアイコンのビットマップ画像を取得して表示しています.
[備考 1]
JEDI プロジェクトにも同名のユニットファイルがありますが,Delphi XE で利用するには修正が必要です.JEDI プロジェクトの同名の 2 つのファイルは Ansi 版の Delphi 6 であれば使用可能です.ただし,本サンプルのコードは,Delphi 6 では使用できない部分は変更が必要です.
[備考 2]
コンポーネントアイコン用のリソースファイル .dcr を読み込めないリソースエディタがありますが,拡張子を .res にすれば読み込めるリソースエディタもあります.
図9
コンポーネントのアイコンリソースファイルからビットマップ画像を取得
下図は,添付の DlgSetRes.dres というリソースファイルからビットマップ画像を取得して表示しています.このリソースファイルには JPEG 画像も格納されています.その JPEG 画像を取得して表示したのがその次の図です.リソースの型を RT_RCDATA に変更して取得しています.
図10
リソースファイル DlgSetRes.dres からビットマップ画像を取得
図11
上と同じリソースファイルから JPEG 画像を取得
リスト6
unitResFile ユニットを利用してリソースファイルからビットマップを取得
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, StrUtils;
type
TForm1 = class (TForm)
Button1: TButton;
Edit1: TEdit;
ListBox1: TListBox;
Image1: TImage;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
{ Private 宣言 }
FResouceFile : string ;
FResType : string ;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses
unitResFile,
unitResourceDetails;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := 'DlgSetRes.dres' ;
Image1.AutoSize :=True;
end ;
// =============================================================================
// リソースの列挙
// ここでは RT_BITMAP とする(つまりビットマップ)
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LResModule : TResModule;
LResIndex : Integer;
LresIDName : string ;
begin
Image1.Picture.Assign(nil );
FResouceFile := ExpandFileName(Trim(Edit1.Text));
FResType := UIntToStr(Cardinal(RT_BITMAP));
ListBox1.Items.Clear;
ListBox1.Items.BeginUpdate;
LResModule := TResModule.Create;
LResModule. LoadFromFile(FResouceFile);
try
// リソース名の列挙
for LResIndex := 0 to LResModule.ResourceCount - 1 do begin
if LResModule.ResourceDetails[LResIndex].ResourceType = FResType then begin
LresIDName := LResModule.ResourceDetails[LResIndex].ResourceName;
ListBox1.Items.Add(LresIDName);
end ;
end ;
finally
FreeAndNil(LResModule);
end ;
ListBox1.Items.EndUpdate;
Label1.Caption := IntToStr(ListBox1.Items.Count);
end ;
// =============================================================================
// ListBox1のOnClickイベント
// リストボックスのItemをクリックしたらそのリソースを読み出してTImageに表示
// =============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
LIndex : Integer;
LResModule : TResModule;
LResIDName : string ;
LResIndex : Integer;
LresStream : TBytesStream;
LPictStream : TBytesStream;
LBMCheckStr : array [0 ..1 ] of AnsiChar;
LInfoHeaderSize : DWORD;
LresInfoHeader : TBitmapInfoHeader;
LBmpFileHeader : TBitmapFileHeader;
LWICImage : TWICImage;
LFlag : Boolean;
begin
Image1.Picture.Assign(nil );
LIndex := ListBox1.ItemIndex;
if FResouceFile = '' then exit;
if LIndex < 0 then exit;
LresStream := TBytesStream.Create;
LResModule := TResModule.Create;
try
LResModule. LoadFromFile(FResouceFile);
// 指定したリソース名のインデックスを取得
LFlag := False;
for LResIndex := 0 to LResModule.ResourceCount - 1 do begin
if LResModule.ResourceDetails[LResIndex].ResourceType = FResType then begin
LResIDName := LResModule.ResourceDetails[LResIndex].ResourceName;
if LresIDName = ListBox1.Items[LIndex] then begin
LIndex := LResIndex;
LFlag := True;
Break;
end ;
end ;
end ;
if LFlag = False then exit;
// そのインデックスのリソースをTMemoryStreamに保存
LresStream.Clear;
LResModule.ResourceDetails[LIndex].Data.SaveToStream(LresStream);
LresStream.Position := 0 ;
LresStream.ReadBuffer(LInfoHeaderSize, 4 );
// ビットマップのファイルヘッダ部が付いているビットマップリソースもある
// そのチェック
LresStream.Position := 0 ;
LresStream.Read (LBMCheckStr, 2 );
if LBMCheckStr <> 'BM' then LBMCheckStr := '' ;
LPictStream := TBytesStream.Create;
LWICImage := TWICImage.Create;
try
// ファイルヘッダ情報がないビットマップデータ
if (LBMCheckStr = '' ) and (LInfoHeaderSize <= SizeOf(TBitmapV5Header)) then begin
// ヘッダ部分を読み出す
LresStream.Position := 0 ;
LresStream.Read (LresInfoHeader, SizeOf(LresInfoHeader));
// TBitmapFileHeaderヘッダに値をセット
// $4D42はBMのASCII文字コード(リトルエンディアンなので$42がB,$4DがM)
LBmpFileHeader.bfType := $4D42 ;
LBmpFileHeader.bfSize := LresStream.Size;
LBmpFileHeader.bfReserved1 := 0 ;
LBmpFileHeader.bfReserved2 := 0 ;
LBmpFileHeader.bfOffBits := SizeOf(TBitmapFileHeader);
// 別のTMemoryStreamにTBitmapFileHeaderの情報を書き込んで
// その後に読み出したリソースのデータを追加
LPictStream.Position := 0 ;
LPictStream.Write (LBmpFileHeader, SizeOf(TBitmapFileHeader));
LresStream.Position := 0 ;
LPictStream.CopyFrom(LresStream, LresStream.Size);
end else begin
// 読み出したデータを別のTMemoryStreamにコピー
LPictStream.Position := 0 ;
LresStream.Position := 0 ;
LPictStream.CopyFrom(LresStream, LresStream.Size);
end ;
// 画像の表示
LWICImage.LoadFromStream(LPictStream);
Image1.Picture.Assign(LWICImage);
finally
FreeAndNil(LPictStream);
FreeAndNil(LWICImage);
end ;
finally
FreeAndNil(LResModule);
FreeAndNil(LresStream);
end ;
end ;
end .
本ページのサンプルのように,EXE, DLL 等の実行形式のファイルからリソースとしてビットマップ等を取り出すには EnumResourceNames 等のリソース操作用の関数を使用しますが,PE ヘッダの情報からも取得できます.
以下の [EXE または DLL 内の...] の記事で紹介しているリソースエディタと呼ばれるプログラムを使用すると,それらのリソースをツリー構造で表示できます.エディタですから編集もできます.
上の参考リンクにある XN Resource Editor は Delphi で開発されていてソースコード付きです.
ResEdit は 32 ビット版と 64 ビット版がありますが,64 ビットの Windows では 32 ビット版は動作しません.起動時に [Wizard] のダイアログが現れますがキャンセルで構いません.[Include Paths] の設定ダイアログはリソース作成に使用する Microsoft SDKs, Microsoft Visual Studio の設定です.これもキャンセルで閉じて構いません.後でも設定できます.
対象のファイルは [File] [Open Project] で開きます.[Options] [Preferences...] のダイアログで [Japanese] を選択して,ResEdit を再起動するとメニューが日本語になります.
Resource Bulider, PE Explorer は Delphi 製です.
リソースエディタと呼べるアプリケーションは他にもあります.