Техническая статья

Динамическое создание и освобождение компонента HotPDF в C++Builder

В большинстве примеров 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()и не сохраняйте указатель в более широкой области, если другая часть формы действительно не владеет жизненным циклом компонента. Для разового экспорта PDF локальная переменная обычно проще всего.

Заметки по настройке проекта

Проект должен находить заголовки, библиотеки и design/runtime-пакеты HotPDF. Добавьте каталог include HotPDF в путь include C++ и каталог библиотек в путь поиска компоновщика. Если проект связывает HPDFDocоставьте имена пакета и модулей без изменений, чтобы C++Builder мог разрешить сгенерированные заголовки.

Перед выпуском

  • Используйте абсолютный или проверенный выходной путь при создании файлов за пределами демонстрационной папки.
  • Вызывайте BeginDoc и EndDoc сбалансированными парами.
  • Открывайте сгенерированный PDF хотя бы в одном внешнем просмотрщике, а не только через AutoLaunch.
  • Записывайте ошибки генерации в журнал, чтобы поддержка могла различать проблемы пути, прав, шрифтов и отрисовки PDF.

Структура, безопасная при исключениях

Пример оставляет код компактным, но реальная процедура экспорта должна обрабатывать исключения между выделением и очисткой. Генерация PDF может не удаться, если выходная папка доступна только для чтения, шрифт не найден, поток закрыт слишком рано или пользовательские данные содержат неожиданное значение. Путь очистки не должен зависеть от успешности каждого вызова рисования.

Практичный подход — создать компонент непосредственно перед экспортом и освободить его в гарантированном блоке очистки. Так срок жизни компонента привязан к одной задаче PDF. Если приложение создает много документов подряд, этот шаблон также снижает риск утечки состояния из одного документа в следующий.

Компоненты времени проектирования и выполнения

Компонент времени проектирования проще, когда одна форма владеет одним предсказуемым потоком экспорта. Компонент времени выполнения лучше, когда приложению нужны несколько временных экспортеров, динамический выбор настроек или запуск кода экспорта из вспомогательного класса, а не из формы. Вызовы API одинаковы; различается только владелец объекта и длительность его жизни.

В серверном или пакетном коде не полагайтесь на AutoLaunchСгенерируйте файл, проверьте его наличие, запишите выходной путь и позвольте вызывающему процессу решить, открывать ли просмотрщик.