プログラムのUIや印刷などで、標準でWindowsに含まれないフォントを使用したいようなことがあります。もちろんインストーラなどを使って実行環境に(ライセンスに従って)フォントをインストールすることができればそれでよいのですが、状況によってはフォントのインストールが難しい、ということもあります。このような場合にプログラムにフォントをリソースとして埋め込み、これを実行時にWindowsに登録して使用する、という方法があります。
まずプロジェクトにフォントをリソースとして追加します。Delphi IDEの"メインメニュー"→"プロジェクト"→"リソースと画像"→"<プロジェクト名>のリソース"ダイアログで、フォント(.ttfなど)をリソースとして追加します。このときリソースタイプはFONT、リソース識別子は(デフォルトの)1からの整数とします(一意であれば整数値でも文字列でも構いません)。これでリソーススクリプトファイル <プロジェクト名>Resource.rc が用意されて、コンパイル時にリソースコンパイラでリソースファイル <プロジェクト名>.dres が作られます。またプロジェクトソースの "program <プロジェクト名>;" の次に "{$R *.dres}" の行が自動的に追加されることでこのリソースファイルが実行ファイルにリンクされる、ということになります。
プログラム側の対応ですが、プログラムのなるべく早い時点でこのフォントを読み出して登録します。
unit LoadResFontsForGDI;
interface
uses
Winapi.Windows,
System.SysUtils, System.Classes;
implementation
function EnumResNameProc(hModule: HMODULE; lpszType: PChar; lpszName: PChar; lParam: LONG_PTR): BOOL; stdcall;
var
RS: TResourceStream;
NumFonts: DWORD;
begin
{ Load font }
if Is_IntResource(lpszName) = False then
begin
{ By name }
RS := TResourceStream.Create(HInstance,String(lpszName),RT_FONT);
end
else
begin
{ By index }
RS := TResourceStream.CreateFromID(HInstance,NativeUInt(lpszName),RT_FONT);
end;
try
{ Regsiter font to GDI }
if AddFontMemResourceEx(RS.Memory,RS.Size,nil,@NumFonts) = 0 then
begin
RaiseLastOSError;
end;
finally
RS.Free;
end;
Result := True;
end;
procedure LoadResourceFonts;
begin
if EnumResourceNames(HInstance,RT_FONT,@EnumResNameProc,0) = False then
begin
RaiseLastOSError;
end;
end;
initialization
LoadResourceFonts;
end.
ユニットのinitialization部で呼び出しているLoadResourceFonts関数では、Win32APIのEnumResourceNames関数でプログラムに含まれるRT_FONTのリソースを列挙します。コールバック関数EnumResNameProcではパラメータlpszNameに格納されているリソース名が名前かインデックスかをIs_IntResource関数で判定し、名前であればコンストラクタTResourceStream.Createの文字列を取るオーバロードを、インデックスであればインデックスを取るオーバロードを呼び出してフォントをリソースストリームに読み出し、Memoryプロパティの示すアドレスとSizeプロパティの示すサイズ(バイト数)をWin32APIのAddFontMemResourceEx関数に渡して登録します。このようなユニットをプロジェクトに追加することで、プログラムの開始時に埋め込まれているフォントリソースをWindowsに登録して使用することができるようになります。
え?Delphi 12 Athensやそれ以前の環境でコンパイルしようとするとBRCC32 エラーになる?それはMicrosoftのリソースコンパイラ(rc.exe)の不具合が原因です。次のアーティクルではこの問題を解決します。
0 件のコメント:
コメントを投稿