Teknik Makale

C++Builder ile HotPDF Bileşeni Örneğinin Dinamik Olarak Oluşturulması ve Silinmesi

Tasarım zamanında bir forma THotPDF bırakmak hızlı bir prototip için uygundur, ancak bileşeni formun yaşam döngüsüne bağlar ve bu üretim kodunun nadiren istediği bir şeydir. Düğmeye her tıklandığında bir kez çalışan bir rapor oluşturucu, gece boyunca dışa aktarmaları topluca işleyen bir servis iş parçacığı, formu hiç olmayan bir yardımcı sınıf: tüm bu durumlarda bileşenin tam olarak bir PDF işinin süresi boyunca var olmasını ve ardından kaybolmasını istersiniz. Bu, çalışma zamanı tahsisi anlamına gelir ve ilk satırı yazmadan önce anlaşılması gereken iki şeyi değiştirir: nesneye kimin sahip olduğu ve bir şeyler ters gittiğinde temizliğin nasıl çalışacağı

VCL'de owner semantiği

Her VCL bileşeni yapıcısı, TComponent* türünde bir Owner parametresi alır. this (form) iletmek, yeni nesneyi formun sahip olunan bileşenler listesine kaydeder; böylece form, bileşen hala hayattayken yok edilirse, VCL onu otomatik olarak serbest bırakır. nullptr iletmek, sahibinin olmaması anlamına gelir: göstericinin (pointer) tüm sorumluluğunu siz alırsınız ve siz açıkça delete çağırmadan önce bir istisna (exception) yığını geri sararsa hiçbir şey onu sizin için temizlemez

Tek bir işlev içinde tamamlanan tek seferlik bir dışa aktarma için her iki seçenek de işe yarar, ancak ikisinin farklı hata modları vardır. Sahip olarak this kullanıldığında, form eninde sonunda kapandığı sürece bellek sızıntısı (leak) imkansızdır; nullptr ile ise gösterici (pointer) mutlaka bir __finally bloğuna ulaşmalıdır. Pratikte, kısa ömürlü nesneler için nullptr ve __finally deseni biraz daha temizdir, çünkü yaşam döngüsü sınırını bir bakışta görünür kılar ve formun geçici olması amaçlanan sahip olunan nesneleri biriktirmesini önler

İstisna güvenli yapı (Exception-safe structure)

PDF oluşturma, API ile ilgisi olmayan nedenlerle başarısız olabilir: çıktı dizini salt okunurdur, bir yazı tipi dosyası eksiktir, bir akış (stream) vaktinden önce boşaltılır veya çağıran tarafından sağlanan veriler bir uzunluk sınırına ulaşır. Nedeni ne olursa olsun, temizleme yolu (cleanup path) çalıştırılmalıdır. Bunu garanti etmenin deyimsel C++Builder yolu try/__finally kullanmaktır:

#include <vcl.h>
#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* Pdf = new THotPDF(nullptr);
    try
    {
        Pdf->FileName = "output.pdf";
        Pdf->Compression = cmFlateDecode;
        Pdf->FontEmbedding = true;
        Pdf->BeginDoc();
        Pdf->CurrentPage->SetFont("Arial", TFontStyles(), 12);
        Pdf->CurrentPage->TextOut(72, 720, 0, L"Hello from C++Builder");
        Pdf->EndDoc();
    }
    __finally
    {
        delete Pdf;
    }
}

Bu listedeki birkaç şey belirtilmeye değer. Sahip (owner) nullptr olarak ayarlanmıştır, bu da yaşam döngüsünü açık hale getirir. Compression ve FontEmbedding özellikleri BeginDoc çağrılmadan önce ayarlanır: her ikisi de HotPDF'nin belge açıldığında uyguladığı belge düzeyinde seçeneklerdir ve daha sonra atanmalarının hiçbir etkisi olmaz. TextOut, sayfanın sol alt köşesinden ölçülen puan (points) cinsinden koordinatları alır, Y değeri yukarı doğru artar; 72, 720 çifti metni bir inçlik sol kenar boşluğu ile letter boyutundaki bir sayfanın sol üst köşesine yerleştirir. __finally bloğundaki delete Pdf, BeginDoc, çizim veya EndDoc bir istisna oluşturup oluşturmadığına bakılmaksızın çalışır

delete işleminden sonra Pdf üzerinde herhangi bir yöntemi (method) çağırmaktan kaçının. Gösterici bir üye değişkende (member variable) saklanıyorsa, silme işleminden hemen sonra onu nullptr olarak ayarlayın, böylece daha sonra yapılacak herhangi bir yanlışlıkla erişim, sessiz bir bozulma (silent corruption) yerine temiz bir çökmeye (crash) neden olur

Proje yapılandırması

C++Builder, THotPDF bileşenini include yolları, kütüphane yolları ve bir pragma yönergesinin birleşimi yoluyla bulur. Üretilen başlık (header) dosyası, HotPDF kaynak dizininde HPDFDoc.pas dosyasının yanında bulunur; bu dizini Project > Options > C++ Compiler > Include path yoluna ekleyin. #pragma link "HPDFDoc" yönergesi, bağlayıcıya (linker) derlenmiş birimi (unit) proje dosyasında manuel olarak listelemeden çekmesini söyler. Statik bağlama yerine çalışma zamanı paketini (runtime package) kullanıyorsanız, önce HotPDF tasarım ve çalışma zamanı paketlerini yükleyin; pragma yönergesi hala geçerlidir

HPDFDoc birim adını değiştirmeden bırakın. C++Builder, başlık adını Pascal birim adından türetir, bu nedenle dosyayı yeniden adlandırmak veya pragma'da bir yol takma adı (path alias) kullanmak, arama işlemini sessizce bozar

Kapsam (Scoping) ve çoklu belge işleri

Kullanıcı eylemi tarafından tetiklenen tek bir dışa aktarma için, düğme işleyicisine (button handler) kapsamı daraltılmış yerel bir değişken doğru cevaptır: tek bir çağrı çerçevesi içinde oluşturulur, kullanılır ve yok edilir ve bu niyet, kodu daha sonra okuyan herkes için açıktır. Kullanıcı bir ayarı değiştirdiğinde belgeyi yeniden oluşturan bir baskı önizleme paneli gibi aynı form sürekli bir iş akışını yönlendirdiğinde, tasarım zamanı alternatifi haklı çıkar; bu durumda, bileşeni canlı tutmak ve BeginDoc/EndDoc metotlarını tekrar tekrar çağırmak, yığın (heap) nesnelerini tekrar tekrar ayırmaktan ve serbest bırakmaktan daha az yıkıcıdır

Sırayla birçok belge üreten toplu (batch) işler için, her belge başına bir THotPDF kapsamlandırmak ayırma yüküne (allocation overhead) değer. Eğer durumu taşıyacak bir nesne yoksa durum (state) belgeler arasında taşınmaz ve bu, asla hata ayıklamanız gerekmeyecek aralıklı bir hata sınıfıdır. Ayır, oluştur, sil, tekrarla

Birkaç HotPDF demosunda görünen özelliklerden biri de, EndDoc çağrısından hemen sonra oluşturulan dosyayı sistemin PDF görüntüleyicisinde açan AutoLaunch özelliğidir. Bir düzenin (layout) ilk taslağını yazarken faydalıdır. Üretim ortamında bunu atlayın: çıktı yolunu açıkça açın, dosyanın var olduğunu ve boyutunun sıfırdan büyük olduğunu doğrulayın, sonucu günlüğe (log) kaydedin ve çağrı yapan iş akışının bir görüntüleyicinin uygun olup olmadığına karar vermesine izin verin. Toplu (batch) bir işte, AutoLaunch her belge için bir görüntüleyici penceresi başlatır ve bazı sistemlerde görüntüleyicinin kapanmasını beklerken işlemi engeller

THotPDF bileşeni ve burada gösterilen tüm çizim çağrıları, Delphi ve C++Builder için HotPDF Bileşeni'nin bir parçasıdır