技術記事

C++Builder で HotPDF コンポーネントを動的に作成し解放する

· PDFプログラミング

多くの HotPDF サンプルでは、設計時にコンポーネントをフォームへ配置します。デモには便利ですが、実運用コードでは特定のエクスポート操作のためだけに PDF コンポーネントを作成したい場合があります。動的作成は、サービス モジュール、レポート ヘルパー、バッチ ジョブ、コンポーネントをフォームの寿命全体にわたって保持したくないフォームで役立ちます。

基本的な C++Builder のパターンは、 THotPDF インスタンスを割り当て、出力ファイルと文書オプションを設定し、PDF を生成して、操作完了時にコンポーネントを解放することです。下の例は、ボタン ハンドラー内の最小ワークフローを示しています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include
#pragma hdrstop
 
#include "Unit1.h"
#pragma package(smart_init)
#pragma link "HPDFDoc"
#pragma resource "*.dfm"
TForm1 *Form1;
 
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 
    THotPDF* HotPDF1 = new THotPDF(this);
    HotPDF1->FileName = "HelloWorld.pdf";
    HotPDF1->AutoLaunch = true;      
    HotPDF1->BeginDoc(false);
    HotPDF1->CurrentPage->PrintText( 10, 10, 0, "Hello World!" );
    HotPDF1->EndDoc();
    HotPDF1->Free();
}

所有権とクリーンアップ

コンストラクターは所有者として this を受け取るため、コンポーネントが残っていればフォームがクリーンアップできます。この短い例では、 EndDocの後でオブジェクトも明示的に解放しています。実際のコードでは、クリーンアップ経路を例外安全にしてください。PDF 生成が失敗する可能性がある場合は、処理を try/__finally ブロックで囲むか、小さな RAII ヘルパーを使って Free() が必ず実行されるようにします。

コンポーネントを Free()した後にそのメソッドを呼び出さないでください。また、フォームの別の部分が本当にコンポーネントのライフサイクルを所有している場合を除き、ポインターを広いスコープに保存しないでください。1 回限りの PDF エクスポートでは、通常はローカル変数が最も簡単です。

プロジェクト設定の注意

プロジェクトは HotPDF のヘッダー、ライブラリ、設計時/実行時パッケージを見つけられる必要があります。C++ の include パスに HotPDF の include ディレクトリを追加し、リンカー検索パスにライブラリ ディレクトリを追加してください。プロジェクトが HPDFDocをリンクする場合は、C++Builder が生成ヘッダーを解決できるよう、パッケージ名とユニット名を変更しないでください。

出荷前に確認すること

  • デモ フォルダー外へファイルを生成する場合は、絶対パスまたは検証済みの出力パスを使用します。
  • 呼び出すときは BeginDocEndDoc は対応するペアで呼び出します。
  • 生成された PDF は AutoLaunchだけでなく、少なくとも 1 つの外部ビューアーでも開いて確認します。
  • 生成エラーをログに記録し、サポートがパス、権限、フォント、PDF 描画の問題を区別できるようにします。

例外安全な構造

サンプルはコードをコンパクトに保っていますが、実際のエクスポート ルーチンでは割り当てからクリーンアップまでの例外を処理する必要があります。PDF 生成は、出力フォルダーが読み取り専用、フォントを解決できない、ストリームが早すぎる段階で閉じられた、ユーザー データに予期しない値がある、といった理由で失敗することがあります。クリーンアップ経路は、すべての描画呼び出しが成功することに依存すべきではありません。

実用的な方法の 1 つは、エクスポートの直前にコンポーネントを作成し、保証されたクリーンアップ ブロックで解放することです。これによりコンポーネントの寿命は 1 つの PDF ジョブに結び付けられます。アプリケーションが連続して多数の文書を生成する場合も、このパターンにより、ある文書の状態が次の文書へ漏れる可能性を減らせます。

設計時コンポーネントと実行時コンポーネント

1 つのフォームが予測可能な 1 つのエクスポート ワークフローを所有する場合は、設計時コンポーネントの方が簡単です。アプリケーションが複数の一時的なエクスポーターを必要とする場合、設定を動的に選ぶ場合、またはフォームではなくヘルパー クラスからエクスポート コードを実行する場合は、実行時コンポーネントの方が適しています。API 呼び出しは同じで、違いは誰がオブジェクトを所有し、どれだけ長く生存させるかだけです。

サーバー形式やバッチ コードでは、 AutoLaunchに依存しないでください。ファイルを生成し、存在を確認し、出力パスを記録して、ビューアーを開くかどうかは呼び出し側のワークフローに判断させます。