Neredeyse hiçbir şey yapmayan bir işi düşünün: aylık bir çalışma kitabını aç, bugünün tarihini tek bir hücreye yaz, geri kaydet. Bunu bir servis üzerinden yeterince sık çalıştırın, yine de bir şikâyet gelir. Makrolar kaybolmuştur ya da bağlı döviz kurları artık #REF! gösteriyordur ve operasyon ekibi kodunuzun onları sildiğine ikna olmuştur. Kod hiçbir şey silmedi. Genellikle olan şey şudur: makro etkin bir çalışma kitabı düz bir .xlsx adıyla dışarı çıkmıştır ve Excel, ECMA-376 içerik türü kurallarına uymuştur: içerik türü hiçbir VBA bildirmeyen bir paket, baytlar tam orada dursa bile bir VBA projesi yükleyemez. Dosya bozulmadı. Excel'in bir bölümünü yok saymak zorunda olduğu bir duruma yeniden adlandırıldı
Otomasyonun en güvenilir biçimde kaybettiği iki şey makrolar ve dış çalışma kitabı bağlantılarıdır; ikisi de aynı temel nedenle. Her ikisi de düzenleme kodunun gerçekten dokunduğu hücre ızgarasının dışında yaşar; bu yüzden satır ve sütun terimleriyle akıl yürüten bir kod, tek bir silme komutu vermeden onları düşürür. HotXLS, Excel kurulu olmadan XLS ve XLSX okuyup yazan yerel bir Delphi ve C++Builder kütüphanesidir ve her iki varlığı da tesadüfen kopyaladığı veri olarak değil, bilinçli olarak taşıdığı yükler olarak ele alır. Devamında her birinin kaydetme yolunuzdan ne istediği ve güvencelerin nerede bittiği anlatılıyor
Bu iki varlık yeniden yazma sırasında neden farklı davranır
Bir VBA projesi tek bir opak ikili bloktur. Bir OOXML paketinde vbaProject.bin dosyasıdır; eski bir BIFF dosyasında ise bir OLE deposudur. Onu kaybetmenin tam olarak iki yolu vardır: yazıcı onu çıktıya hiç kopyalamaz ya da çıktı, ona izin vermeyen bir dosya türü alır. Her iki başarısızlık da bütünsel ve sessizdir. Proje ya vardır ya yoktur
Bir dış bağlantı ise hiç blok değildir. Küçük bir ilişki grafiğidir: başka bir çalışma kitabını gösteren bir hedef yol ya da URL, o hedefin açtığı sayfa adlarının listesi ve hedef çevrimdışıyken Excel bir şey gösterebilsin diye o sayfalarda en son görülen değerlerin isteğe bağlı bir önbelleği. Bu üç parçanın yeniden yazma altındaki ömürleri farklıdır ve bir kütüphane bazılarını sadakatle korurken diğerlerini sessizce düşürebilir. Kesinleştirmeye değer kısım bu asimetridir; çünkü hücre düzenleme kodundaki hiçbir şey bunu yüzeye çıkarmaz
Bir VBA projesini XLSX yeniden yazımından geçirmek
XLSX tarafında TXLSXWorkbook makro yükünü harfi harfine korur. VbaProject özelliği ham vbaProject.bin baytlarını bir AnsiString içinde tutar ve boş dizge, modelin makro bulunmadığını söyleme biçimidir. Çevresinde üç işlem durur: HasVbaProject bir projenin var olup olmadığını yanıtlar, ClearVbaProject onu bilerek kaldırır ve LoadVbaProjectFromFile bir şablondan çıkarılmış bir projeyi enjekte eder. Bu son çağrı göründüğünden daha değerlidir. Üretilen çalışma kitaplarının, hattan tam bir şablon dosyası sürüklemeden standart bir makro projesi edinmesini sağlar
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Data');
Sheet.Cells[1, 1].Value := 'Refreshed ' + DateTimeToStr(Now);
Book.LoadVbaProjectFromFile('macros\vbaProject.bin');
if not Book.HasVbaProject then
raise Exception.Create('VBA payload failed to load');
// .xlsm uzantısı süs değildir: paket içindeki
// makro etkin içerik türünü seçer.
Book.SaveAs('monthly-report.xlsm');
finally
Book.Free;
end;
end;
Bütün sorunun döndüğü yer kaydetme satırıdır. VBA projesi taşıyan bir çalışma kitabının makro etkin anlambilimle yazılması gerekir ve HotXLS bunu, hedef ad .xlsm ile bittiğinde uygular. Bunun yerine ona .xlsx verirseniz, baytlar fiziksel olarak pakette bulunsa ve sorunsuz çözülecek olsa bile Excel makroları reddeder. Uzantı bir süs değildir; Excel'e bir VBA projesinin var olabileceğini söyleyen içerik türünü seçer. Çoğu zaman yükü yalnızca taşımanız yeterlidir. İçini okumanız gerektiğinde, örneğin bir denetim raporu için modül adlarını listelemek istediğinizde, ParsedVBAProject ayrıştırılmış bir modül modeli sunarken VbaProject özgün ve dokunulmamış baytlar olarak kalır
Eski XLS çalışma kitaplarındaki makroları yeniden kullanmak
BIFF cephesi bu araç setini bir adım fazlasıyla yansıtır. HasVBAProject yüklenmiş bir dosyayı yoklar, SaveVBAProjectToFile proje deposunu diske yazar ve LoadVBAProjectFromFile onu başka bir çalışma kitabına geri okur. Bir dosya üzerinden yapılan bu dolambaç, yaygın bir modernizasyon işini basitleştirir: makroları 2003 dönemine ait bir modelden alıp yeni üretilmiş XLS çıktısına yerleştirmek, çalışma zamanında özgün şablona hiç gerek duymadan
var
Src, Dst: IXLSWorkbook; // arayüz başvuruları: elle Free yok
begin
Src := TXLSWorkbook.Create;
if Src.Open('legacy-model.xls') <= 0 then
raise Exception.Create('Cannot open legacy model');
if Src.HasVBAProject then
Src.SaveVBAProjectToFile('extracted-vba.bin');
Dst := TXLSWorkbook.Create;
Dst.Sheets.Add.Name := 'Report2026';
Dst.LoadVBAProjectFromFile('extracted-vba.bin');
Dst.SaveAs('report-with-macros.xls');
end;
Buradaki tuzak bellek modelidir ve XLSX sınıfının tam tersine işler. TXLSWorkbook, başvuru sayımlı IXLSWorkbook arayüzü üzerinden tutulur; bu yüzden onu elle asla serbest bırakmazsınız. XLSX tarafındaki TXLSXWorkbook ise try..finally içine sarıp serbest bırakmanız gereken düz bir nesnedir. İki geleneği tek bir birimde karıştırın, çifte serbest bırakma çökmeleri gelir. Saygı göstermeye değer bir sınır daha var: çıkarma ve enjekte etme işlerini tek bir dosya biçimi içinde tutun. BIFF proje deposu ile OOXML vbaProject.bin kuzendir, aynı kapsayıcı değil; her iki biçimde de makro üretmesi gereken bir hat her biri için ayrı bir makro şablonu tutmalıdır
Dış bağlantılar: harita hayatta kalır, önbelleklenmiş değerler kalmaz
XLSX çalışma kitapları için HotXLS dış bağlantıları ExternalLinks koleksiyonu üzerinden sunar. Her TXLSXExternalLink bir Target yani uzak çalışma kitabının yolunu ya da URL adresini, ayrıca başvurduğu sayfaları adlandıran bir SheetNames listesini taşır. Her ikisi de bir aç ve kaydet döngüsünü eksiksiz atlatır ve sıfırdan bir bağlantı da kurabilirsiniz:
var
Link: TXLSXExternalLink;
begin
Link := Book.ExternalLinks.Add('\\fileserver\finance\fx-rates-2026.xlsx');
Link.SheetNames.Add('FX');
if Book.ExternalLinks.Count > 0 then
Writeln(Format('%d external link(s): delivery requires reachable targets',
[Book.ExternalLinks.Count]));
end;
Sınır, hedef listesinden bir düzey daha derinde durur. HotXLS bağlantı haritasını, yani hedefi ve sayfa adlarını gidiş dönüş taşır; ancak OOXML'in bağlantının sheetDataSet öğesinde tuttuğu önbelleklenmiş hücre değerlerini ayrıştırmaz ya da yeniden yazmaz. Kaynak dosya çevrimdışıyken Excel'in son bilinen bir sayıyı göstermesini sağlayan şey o önbellektir ve üretilen bir çalışma kitabı onsuz yola çıkar. Sonuç sizin değil, alıcının başına gelir. Böyle bir dosyayı hedefin erişilemez olduğu bir yerde, VPN dışındaki bir dizüstünde ya da adı değişmiş bir paylaşımda açın; bağlantıya bağlı formüller #REF! değerine çözülür ya da bir güncelleme istemi arkasında takılır. Buradan iki kural çıkar. Üretilen bir çalışma kitabının dışarıdan bağlı değerlerini çevrimdışı göstereceğine söz vermeyin. Ve sıfırdan farklı bir ExternalLinks.Count değerini bir özellik olarak değil, bir teslim ön koşulu olarak okuyun: her hedefin, dosyanın gerçekten açılacağı yerden erişilebilir olması gerekir
XLS okuyucusunun bayt bayt koruduğu şeyler
Modellemediği yapılar için BIFF tarafının farklı bir yanıtı var: onları bulduğu gibi bırak. Pivot önbellekleri ve pivot görünümleri (SX* kayıt ailesi), QueryTable tanımları, dış veri bağlantıları, özel görünümler, üst bilgi resimleri ve tema kayıtlarının hepsi bir aç ve kaydet döngüsünden ham kayıt blokları olarak, ayrıştırılmadan ve değiştirilmeden geçer. Dış başvurular ise altta yatan EXTERNSHEET ve SupBook kayıtları üzerinden gidiş dönüş yapar. XLS tarafında bunlar için türlenmiş bir oluşturma API yoktur ama mevcut bir bağlantı düzenlemeye dokunulmadan dayanır
Bayt bayt koruma, keskin bir kenarı olan gerçek bir güvencedir. Korunan bir yapıyı hiçbir şey okumadığı için düzenlemeleriniz onu bozamaz. Aynı nedenle hiçbir şey onu güncellemez de. Korunan bir pivot önbelleğinin ya da sorgu tablosunun işaret ettiği bir bölgeye satır ekleyin; altındaki veri kayarken yapı özgün koordinatlarını tutar. Dosya hâlâ geçerli XML ya da BIFF olur; anlam ise sessizce hizadan çıkmıştır ve bunu size söyleyecek bir hata tetiklenmez. Savunulabilir düzen, üretilen düzenlemeleri korunan yapı barındırmayan sayfalarda tutmaktır; bu, çalışma sayfası koruması ve sayfa yapısı üzerine yazımızda kilitli ve yazdırma için yapılandırılmış sayfaları koruyan disiplinin aynısıdır
Gerçekten yazdığınız dosyayı doğrulamak
Her iki başarısızlık kipi de yazma anında sessizdir; bu yüzden önem taşıyan doğrulama, onu üreten koda güvenmek değil çıktıyı yeniden açmaktır. Üç denetim neredeyse her şeyi kapsar. Dosyayı yeniden açın ve makro beklendiği her durumda HasVbaProject hâlâ true döndürüyor mu bakın; bu tek sınama hem düşmüş bir yükü hem de yanlış bir uzantıyı yakalar. ExternalLinks.Count değerini okuyup yeniden yazmadan önceki sayıyla karşılaştırın. Sonra dosyayı Excel'de makrolar devre dışıyken bir kez açın; çünkü Excel'in içerik türü doğrulaması herhangi bir kütüphaneninkinden katıdır ve müşterilerinizin dosyayı yargılayacağı program Excel'dir
Bunların hiçbiri girişte tam bir ayrıştırma gerektirmez. Çalışma kitapları yığınla geldiğinde ve yalnızca hangilerinin yönetime tabi içerik taşıdığını triyaj etmeniz gerektiğinde, sayfa listeleme ve hafif çalışma kitabı incelemesi üzerine yazımızdaki hafif yoklama, makro taşıyan ve bağlantılı dosyaları ilk yeniden yazma çalışmadan önce daha katı bir hatta yönlendirmenizi sağlar
Birkaç soru doğrudan yanıtlanacak kadar sık geliyor. HotXLS koruduğu makroları asla çalıştırmaz: kütüphanede VBA çalışma zamanı yoktur, yalnızca projeyi veri olarak saklama, kopyalama, çıkarma ve enjekte etme düzeneği vardır. Bir sunucuda bu, belirtmeye değer bir güvenlik özelliğidir; çünkü hattan geçen düşmanca bir makro, bir masaüstü Excel dosyayı açıp bir kullanıcı içeriği etkinleştirene dek atıl kalır. Bir .xlsm dosyasını .xlsx biçimine çevirip makroları korumak mümkün değildir ve bu, kütüphane kısıtı değil biçimin kuralıdır: .xlsx içerik türü makrosuz bir çalışma kitabı bildirir; dolayısıyla dürüst tek sonuçlar .xlsm olarak kalmak ya da ClearVbaProject çağırıp gerçekten makrosuz bir dosya göndermektir. Sessiz yeniden adlandırma ise kimseyi tatmin etmeyen tek seçenektir. Bağlı hücreler yeniden yazmadan sonra #REF! gösterdiğinde neden, yukarıda anlatılan eksik değer önbelleğidir: yeni dosya hedefi taşır ama önbelleklenmiş sayıları taşımaz, bu yüzden Excel kaynağı açılış anında çözmek zorundadır ve erişilemez ya da ortama göreli bir yol bunu boşa çıkarır. Ya hedefin erişilebilir olduğunu garanti edin ya da teslimden önce hesaplanmış değerleri hücrelere yazıp bağımlılığı tümüyle düşürün
Başkalarının çalışma kitaplarını düzenlemek, çoğunlukla yazmadığınız ve tam olarak anlamadığınız şeyleri koruma işidir. Burada anlatılan VBA ve dış bağlantı gidiş dönüş olanakları, Delphi ve C++Builder için HotXLS Delphi Component ile birlikte gelir; yanında da bir dosya gelir gelmez yönetime tabi içeriği saptamanızı sağlayan denetim özellikleri bulunur