Kesalahan "Please load the document before using BeginDoc" adalah tanda yang hampir pasti bahwa instans THotPDF yang sama sedang digunakan untuk menghasilkan lebih dari satu dokumen tanpa di-reset dengan benar di antaranya. Komponen memiliki mesin state internal yang melacak apakah sesi penulisan aktif, dan mesin itu tidak kembali ke keadaan awal secara otomatis hanya karena EndDoc dipanggil
THotPDF bukan service object yang dapat diputar terus seperti koneksi database. Satu instance memodelkan satu dokumen: BeginDoc membuka alur, EndDoc menserialisasikan hasil ke FileName, lalu instance harus dilepas. Memanggil BeginDoc lagi setelah dokumen selesai berarti meminta state machine masuk kembali ke jalur yang tidak didukung
Model lifecycle
Setiap instans THotPDF mengikuti urutan state ini:
- Create: objek dialokasikan, state internal diinisialisasi, tidak ada dokumen terbuka
- BeginDoc: sesi penulisan dimulai, file output dibuka atau stream dialokasikan, halaman pertama dibuat
- (menggambar halaman, menambahkan halaman)
- EndDoc: semua halaman difinalisasi, struktur PDF ditulis, file ditutup, state kembali ke idle
- Free: objek dibebaskan dari memori
Poin kritis: setelah EndDoc, komponen berada dalam keadaan idle tetapi siap untuk siklus BeginDoc lain jika dan hanya jika tidak ada file yang dimuat ke dalamnya. Jika sebelumnya Anda memanggil LoadFromFile, state internal berisi dokumen yang dimuat dan BeginDoc akan memunculkan kesalahan tersebut karena komponen mengharapkan Anda bekerja dengan dokumen yang ada, bukan membuat dokumen baru
Penyebab umum
Penggunaan ulang setelah LoadFromFile
Jika alur kerja Anda melibatkan pembacaan PDF yang ada dengan LoadFromFile, lalu kemudian mencoba menghasilkan PDF baru dengan BeginDoc pada komponen yang sama, komponen berada dalam state "dokumen dimuat" dan tidak menerima BeginDoc. Solusinya adalah membuat instans terpisah untuk membuat dan memuat, atau memanggil Free dan mengalokasikan ulang komponen sebelum menggunakannya untuk pembuatan
Memanggil BeginDoc dua kali tanpa EndDoc di antaranya
Memanggil BeginDoc saat sesi penulisan sudah aktif memunculkan kesalahan serupa. Ini biasanya terjadi ketika handler event dipanggil dua kali sebelum yang pertama selesai, atau ketika kode iterasi menjalankan ulang blok inisialisasi yang seharusnya berjalan sekali saja
Pola yang aman untuk pembuatan satu dokumen
Cara paling andal adalah mencakup komponen sepenuhnya dalam blok try/finally:
procedure GeneratePDF(const OutputPath: string);
var
PDF: THotPDF;
begin
PDF := THotPDF.Create(nil);
try
PDF.FileName := OutputPath;
PDF.BeginDoc;
// ... rendering ...
PDF.EndDoc;
finally
PDF.Free;
end;
end;
Dengan pola ini tidak ada ambiguitas tentang state. Komponen lahir, melakukan satu pekerjaan, dan dibebaskan. Tidak ada kemungkinan state residual dari panggilan sebelumnya
Penggunaan ulang yang aman untuk pembuatan batch
Jika Anda perlu menghasilkan beberapa dokumen dan ingin menghindari overhead alokasi objek berulang, komponen dapat digunakan kembali hanya jika tidak pernah menerima panggilan LoadFromFile dan setiap siklus BeginDoc/EndDoc selesai dengan bersih:
procedure GenerateBatch(const Files: TStringList);
var
PDF: THotPDF;
I: Integer;
begin
PDF := THotPDF.Create(nil);
try
for I := 0 to Files.Count - 1 do
begin
PDF.FileName := Files[I];
PDF.BeginDoc;
// ... rendering untuk dokumen ke-I ...
PDF.EndDoc;
end;
finally
PDF.Free;
end;
end;
Jika salah satu iterasi memunculkan exception sebelum EndDoc, loop berhenti dan blok finally hanya membebaskan komponen. Dokumen yang sebagian ditulis ditinggalkan di disk. Untuk kode produksi yang memerlukan perilaku atomic, bungkus setiap pasangan BeginDoc/EndDoc dalam blok try/except yang memutuskan apakah akan melanjutkan batch atau menginterupsinya
Masalah file lock setelah LoadFromFile
Satu jebakan terkait yang tidak menampilkan pesan kesalahan yang sama tetapi sering muncul bersamaan: ketika Anda memanggil LoadFromFile pada komponen HotPDF yang dijatuhkan ke form, file tetap terkunci selama instans komponen hidup. Jika Anda kemudian mencoba menulis ke file yang sama dengan instans kedua atau dengan alat eksternal saat form masih terbuka, Anda akan mendapatkan kesalahan akses file. Solusinya adalah memanggil SaveLoadedDocument terlebih dahulu jika Anda perlu mempertahankan modifikasi, lalu Free instans asli sebelum membuka koneksi baru ke file yang sama
Dokumentasi lengkap API tersedia di loslab.com
Contoh kode tambahan
var
Pdf: THotPDF;
PageCount: Integer;
begin
Pdf := THotPDF.Create(nil);
try
PageCount := Pdf.LoadFromFile('contract.pdf');
if PageCount > 0 then
begin
Pdf.CurrentPage.SetFont('Arial', [fsBold], 10);
Pdf.CurrentPage.TextOut(40, 30, 0, 'REVIEWED');
Pdf.SaveLoadedDocument('contract-reviewed.pdf');
end;
finally
Pdf.Free;
end;
end;