2025年12月11日

Skia4Delphiでリソースとして埋め込まれたフォントを使用する

このアーティクルはDelphi Advent Calendar 2025の11日目の記事です。

ここまでリソースとして埋め込まれたフォントをVCL(GDI)で使用する方法を見てきました。ところで埋め込んだフォントをSkia4DelphiTSkLabelISkCanvasでも使用したいときは、少し違う方法が必要になります。
Skia4Delphiで描画に使用するフォントはTSkDefaultProviders.RegisterTypeface(かIFMXFontManagerService.AddCustomFontFromFile)で登録するのですが、このときのリソースタイプは(FONTではなく)RCDATAになっている必要があります。しかしフォント以外のリソースもリソースタイプRCDATAとして登録されるため、Win32APIのEnumResourceNames関数でプログラムに含まれるRT_RCDATAのリソースを列挙し、コールバック関数でリソースを読み出したら先頭4バイトでフォントデータかどうかを判別してからWin32APIのAddFontMemResourceEx関数とTSkDefaultProviders.RegisterTypefaceに渡すようにします。

まずプロジェクトにフォントをリソースとして追加します。Delphi IDEの"メインメニュー"→"プロジェクト"→"リソースと画像"で"<プロジェクト名>のリソース"ダイアログで、フォントをリソースとして追加します。このときリソースタイプを"RCDATA"に変更しておきます。
次にプログラムのなるべく早い時点でこのフォントを読み出して登録します。
unit LoadResFontsForSkia;

{$IFNDEF SKIA}
{$MESSAGE ERROR 'Enable Skia4Delphi.'}
{$ENDIF}

interface

uses
  Winapi.Windows,
  System.SysUtils, System.Classes,
  Vcl.Skia;

implementation

type
  TFontType = (ftNotFont, ftGDIFont, ftWebFont);

function CheckFontData(Stream: TStream): TFontType;
var
  Signature: DWORD;
begin
  Result := TFontType.ftNotFont;

  Stream.Position := 0;
  try
    if Stream.Read(Signature,SizeOf(Signature)) <> SizeOf(Signature) then
    begin
      Exit;
    end;

    case Signature of
      $00000100,  // TrueType
      $4F45454F,  // 'OTTO' OpenType
      $66637474:  // 'ttcf' TrueType Collection
      begin
        Result := TFontType.ftGDIFont;
      end;

      $46464F77,  // 'wOFF' Web Open Font
      $32464F77:  // 'wOF2' Web Open Font 2
      begin
        Result := TFontType.ftWebFont;
      end;
    end;

  finally
    Stream.Position := 0;
  end;
end;

function EnumResNameProc(hModule: HMODULE; lpszType: PChar; lpszName: PChar; lParam: LONG_PTR): BOOL; stdcall;
var
  RS: TResourceStream;
  NumFonts: DWORD;
  FontType: TFontType;
begin
  { Load resource }
  if Is_IntResource(lpszName) = False then
  begin
    { By name }
    RS := TResourceStream.Create(HInstance,String(lpszName),RT_RCDATA);
  end
  else
  begin
    { By index }
    RS := TResourceStream.CreateFromID(HInstance,NativeUInt(lpszName),RT_RCDATA);
  end;

  try
    FontType := CheckFontData(RS);
    if FontType in [TFontType.ftGDIFont] then
    begin
      { Regsiter font to GDI }
      if AddFontMemResourceEx(RS.Memory,RS.Size,nil,@NumFonts) = 0 then
      begin
        RaiseLastOSError;
      end;
    end;

    if FontType in [TFontType.ftGDIFont, TFontType.ftWebFont] then
    begin
      { Register font to Skia4Delphi }
      TSkDefaultProviders.RegisterTypeface(RS);
    end;

  finally
    RS.Free;
  end;

  Result := True;
end;

procedure LoadResourceFonts;
begin
  if EnumResourceNames(HInstance,RT_RCDATA,@EnumResNameProc,0) = False then
  begin
    RaiseLastOSError;
  end;
end;

initialization
  LoadResourceFonts;

end.
ユニットのinitialization部で呼び出しているLoadResourceFonts関数では、Win32APIのEnumResourceNames関数でプログラムに含まれるRT_RCDATAのリソースを列挙します。コールバック関数EnumResNameProcではコンストラクタTResourceStream.Createを呼び出してフォントをストリームに読み出し、フォントデータかどうかの判定関数CheckFontDataを呼び出します。CheckFontData関数ではストリームから先頭4バイトを読み出し、TrueType(.ttf)、TrueType Collection(.ttc)OpenType(.otf)、OpenType Collection(.otc)WOFF(.woff)、WOFF2(.woff2)のそれぞれのシグネチャに一致するかどうかでフォントデータかどうかの判定を行います。GDIでは使用できないWOFF/WOFF2形式のフォントもSkia4Delphiでは使用できるので、WOFF/WOFF2形式のときはAddFontMemResourceEx関数に加えてTSkDefaultProviders.RegisterTypefaceも呼び出すようにしています。
これで登録したフォントはSkia4DelphiのFont.Familiesにそのフォント名を指定することで使用できます。TSkLabelならTSkLabel.TextSettings.Font.Families、ISkCanvasに対する描画ならTSkTypeface.MakeFromNameの第1パラメータです。

ん?リソースタイプFONTではなくRCDATAで埋め込んだフォントデータをAddFontMemResourceEx関数に渡せる?じゃあ前回のアーティクルのようにリソースコンパイラを差し替えたりせず、RCDATAでやればいいのでは?と思うかもしれません。その通りで、今回の方法(フォントをRCDATAで埋め込む)を使えば、Delphi 12.3およびそれ以前でもビルド前イベントでresinatorを使って処理する必要はありません。しかしプログラムにフォント以外のRCDATAのリソースが埋め込まれていた場合は、それらもすべて読み出してフォントデータかどうかの判別をする必要があります。このオーバヘッドを許容できるのであれば、今回の方法でも問題ありません。

2025年12月10日

Microsoft Monthly Update 2025/12

今日はMicrosoftのセキュリティアップデートの日です。
2025 年 12 月のセキュリティ更新プログラム - リリース ノート - セキュリティ更新プログラム ガイド - Microsoft
2025 年 12 月のセキュリティ更新プログラム (月例)

Delphi 12.3までの環境でフォントをリソースとして埋め込むとコンパイル時にエラーになる場合の対策

このアーティクルはDelphi Advent Calendar 2025の10日目の記事です。

前回のアーティクルでプログラムにフォントをリソースとして埋め込んで使用する方法を見てきましたが、Delphi 12.3 Athensおよびそれ以前の環境ではコンパイルしようとすると、埋め込もうとしたフォントによっては
[BRCC32 エラー] "brcc32" はコード 1 を伴って終了しました。
とリソースコンパイラでエラーになることがあります。

Delphiのリソースのコンパイルはデフォルトではbrcc32.execgrc.exerc.exeと、最終的にMicrosoftのリソースコンパイラが使われるのですが、このrc.exeに多数の不具合と未定義動作があり、フォントを解析するときの処理の不具合でこのような状況になるようです(下記記事参照)。
一方Delphi 13 Florenceでは新機能ページのIDEツールの改善のリソース コンパイラの項にあるように、Ryan Liptakさんによるrc.exe互換のオープンソース実装であるresinatorをデフォルトで使用するように変更されています。
そこでこのresinatorをDelphi 12.3までの環境で使用する手順を確認していきます。

同じ環境にDelphi 13 Florence(またはそれ以降のバージョン)がインストールされている場合はパスが通った場所に既にresinatorが配置されているため、別途インストールする必要はありません。そうでない場合は、まずGitHubのリポジトリにアクセスし、最新版のWindows x64のバイナリ(2025/10/23現在ではv0.1.0にあるwindows-x86_64-resinator.zip)をダウンロードし、resinator.exeを(できればパスが通った)適切な場所に展開します(簡単なのはDelphiのインストール先のbinフォルダの下あたりかも)。
次にDelphiのIDEでエラーになるプロジェクトを開き、"メインメニュー"→"プロジェクト"→"リソースと画像"で"<プロジェクト名>のリソース"ダイアログを開いてすべての項目を削除して"OK"で閉じます(<プロジェクト名>Resource.rcファイルは削除されませんので、これをresinatorでコンパイルします)。
"メインメニュー"→"プロジェクト"→"オプション"で"プロジェクトオプション"ダイアログを開き、"ビルド"→"ビルドイベント"のターゲットで"全ての構成 - Windows 32 ビットプラットフォーム"(または"全ての構成 - Windows 64 ビットプラットフォーム")を選択し、"ビルド前イベント"の"コマンド"に
resinator.exe -v $(PROJECTNAME)Resource.rc $(PROJECTNAME).dres
と設定します(もしパスが通っていない場所にresinator.exeを配置した場合は"resinator.exe"を絶対パスで指定してください)。
最後にプロジェクトファイル(*.dpr)の "program プロジェクト名;" の次に "{$R *.dres}" の行を追加します(リソースダイアログで全項目削除すると自動的に削除されてしまうので)。
program Project1;

{$R *.dres}

uses
  Vcl.Forms,
  ...
こんな感じです。これでコンパイルするとビルド前イベントで"(プロジェクト名)を信頼しますか?"という警告ダイアログが表示されるので、"このプロジェクトを常に信頼する"にチェックを入れて"はい"をクリックします。
これによって、プロジェクトをコンパイルするときのビルド前イベントでリソーススクリプトファイル(.rc)をresinatorでコンパイルしてリソースファイル(.dres)を生成しておき、リンカでこのリソースファイルをリンクする、という動作になります。

Skia4Delphiの描画(TSkLabelやISkCanvas)でもリソースとして埋め込んだフォントを使用する方法については次のアーティクルで説明します。

なおMicrosoftのリソースコンパイラrc.exeにどのような不具合があり、resinatorではどのような動作に修正されているのかについてはRyan LiptakさんのblogのEvery bug/quirk of the Windows resource compiler (rc.exe), probably - ryanliptak.comというアーティクルにまとめられています。

2025年12月9日

プログラムにフォントをリソースとして埋め込んで使用する

プログラムにフォントをリソースとして埋め込んで使用する このアーティクルはDelphi Advent Calendar 2025の9日目の記事です。

プログラムの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)の不具合が原因です。次のアーティクルではこの問題を解決します。

2025年12月1日

2025年11月12日

Microsoft Monthly Update 2025/11

今日はMicrosoftのセキュリティアップデートの日です。
2025 年 11 月のセキュリティ更新プログラム - リリース ノート - セキュリティ更新プログラム ガイド - Microsoft
2025 年 11 月のセキュリティ更新プログラム (月例) | MSRC Blog | Microsoft Security Response Center
またESU未適用のWindows 10 22H2にもOOBで更新プログラム(KB5071959)がリリースされています。これはESUの登録でエラーになる問題を修正するとのことです。

2025年11月1日

2025年10月29日

RAD Studio/Delphi/C++Builder 13 Florence October Patch

RAD Studio/Delphi/C++Builder 13 FlorenceのOctober Patchがリリースされています。GetItおよびポータルサイトからダウンロード、インストールできます

RAD Studio 13 October Patch

RAD Studio 13 Florence : October パッチをリリース (en)

2025年10月20日

[書籍]改訂新版 SQL実践入門

紀伊國屋書店新宿本店SQL実践入門の改訂版になる

改訂新版 SQL実践入門 (Amazon)/ミック著/技術評論社/ISBN 978-4-297-15190-4/3,080円

を購入。

2025年9月27日

RAD Studio/Delphi/C++Builder 13 Florence September Patch

RAD Studio/Delphi/C++Builder 13 FlorenceのSeptember Patchがリリースされています。GetItおよびポータルサイトからダウンロード、インストールできます

RAD Studio 13 September Patch

RAD Studio 13 Florence : 9月パッチがリリースされました (en)

2025年9月11日

RAD Studio/Delphi/C++Builder 13 Florenceリリース

RAD Studio/Delphi/C++Builder 13 Florenceがリリースされています。

RAD Studio 13 Florence ヘルプ (en)
リリース ノート (en)
インストール ノート (en)
新機能 (en)
RAD Studio 13.0 における新機能と修正された顧客から報告された問題 (en)
プラットフォームの状況 (en)

ポータルサイトからダウンロード可能です
RAD Studio, Delphi, C++Builder 13.0 Inline Web Install
RAD Studio, Delphi, C++Builder 13.0 Inline ISO
BDE for RAD Studio 13

RAD Studio 13 Florence 提供開始のお知らせ (en)

RAD Studio 13 で導入予定の新機能:Delphi 言語の条件演算子(三項演算子) (en)
RAD Studio 13 Update: What We Know So Far, And What’s Coming
RAD Studio 13で導入予定の新機能:WebStencils はさらに強力になります (en)
RAD Studio 13で導入予定の新機能:Clang-20ベースのC++Builderコンパイラは、C++23をサポートします (en)
RAD Studio 13で導入予定の新機能:VCL のタイトルバーのスタイルとスクロール可能なアクションメニュー (en)
WebStencils: RAD Studio 13.0 Florence の新機能 (en)
RAD Studio 13: Every New And Enhanced Feature
Watch The Replay: RAD Studio 13 Florence Launch Webinar With Q & A
古い Delphi プロジェクトを診断! Delphiプロジェクトアップグレードアドバイザの登場 (en)
RAD Studio 13 Florence : SmartCore AIコンポーネントパックのご紹介 (en)
RAD Studio 13 Florence で iOS 26とXCode 26 を利用する方法 (en)
RAD Studio 13 FireMonkey の新機能トップ 13 (en)
RAD Studio 13 VCL の新機能トップ 13 (en)

2025年8月12日

[書籍]Web API開発実践ガイド

紀伊國屋書店新宿本店

Web API開発実践ガイド (Amazon)/杉本和也、津郷晶也、太⽥佳敬、武田大輝、宮崎将太、福岡秀一郎、武上将樹、渋川よしき、真野隼記、小谷優空、和田祐汰、浦優太、金井祐樹、内山高広、上原拓也、sumiren、川崎庸市、こたうちさんさん、石川朝久、徳丸浩、松本隆則、川村修平著/技術評論社/ISBN 978-4-297-15062-4/2,420円

を購入。

2025年7月24日

2025年7月14日

[書籍]SQLアンチパターン 第2版

紀伊國屋書店新宿本店SQLアンチパターンの改訂版で、SQL Antipatterns, Volume 1 (Amazon US)の日本語訳である

SQLアンチパターン 第2版 (Amazon)/Bill Karwin著/児島修訳/和田卓人監訳/オライリージャパン/ISBN 978-4-8144-0074-4/4,290円

を購入。

2025年5月20日

RAD Studio/Delphi/C++Builder 12.3 Athens May Patch

RAD Studio/Delphi/C++Builder 12.3 AthensのMay Patchがリリースされています(ネーミングルールが変わったようでPatch 1、Patch 2ではなくApril Patch、May Patchと呼ぶみたい)。April Patchで更新されたソースファイルが含まれていなかった問題、April Patch適用後のWin64デバッグ式評価機能の問題(RSS-3416)、64ビットIDEのバージョン情報の問題(RSS-3173)を修正します。現時点(2025/05/20)ではGetItからのみインストールできます。GetItおよびポータルサイトからダウンロード、インストールできます

RAD Studio 12.3 May Patch

RAD Studio 12.3 May パッチのリリース (en)