Unicode-migracija starih Delphi-projekata u mnogim je poduzećima nužan korak, jer bi inače postojeće aplikacije kod međunarodnih podataka, modernih operacijskih sustava, integracija i novih sučelja sve više naletale na ograničenja. U praksi to rijetko znači „recompile i gotovo“. Delphi je od uvođenja Unicode-a (od Delphi 2009) izvršio temeljite promjene u standardnim tipovima stringova. Time se pomiču pretpostavke o kodiranju znakova, rasporedu u memoriji i API-signaturama. Tko to potcijeni, stvara prikrivene pogreške u podacima, pokvarene exporte, nejasne support-slučajeve i sigurnosne rizike.
Ovaj članak donosi tehnički utemeljenu proceduru: kako analizirati postojeći sustav, logično odrediti scope, smanjiti rizike na hotspotovima (baze podataka, datoteke, Windows-APIji, COM, REST-servisi) i osigurati migraciju tako da rad i daljnji razvoj mogu teći paralelno. Fokus je na tipičnim zamkama u Delphi-projektima s VCL-aplikacijama, servisima i sučeljima – s pogledom na modernizacijske putove u koje se kasnije mogu uklopiti teme poput BDE-zamjene s nativnom vezom, REST-servera ili multiplatformskih rješenja.
Zašto je prelazak na Unicode u Delphi često „veći nego što se misli“
U klasičnim verzijama Delphi tip string bio je ANSI-string (ovisno o system codepage). Od Delphi 2009 string je po defaultu UnicodeString (UTF-16). Istovremeno su mnoge biblioteke i VCL-klase prešle na Wide-APIje. To je po sebi pozitivno jer omogućuje robusnu podršku za međunarodne znakove. Međutim: legacy-kod je često godinama građen oko pretpostavki „1 znak = 1 bajt“, „PChar je PAnsiChar“ ili „Length() odgovara broju bajtova“.
Tipični razlozi zbog kojih migracije postaju zahtjevnije:
- Implicitne konverzije prolaze, ali mijenjaju podatke (posebice kod datoteka, sučelja ili BLOB/TEXT polja u bazama).
- Bajtno orijentirani kod (streamovi, bufferi, hashing, enkripcija) postaje neispravan ako se sadržaj stringova tumači kao sirovi bajtovi.
- Komponente trećih strana ponekad su samo ANSI ili koriste vlastite string-tipove i callbacke.
- Vanjsko okruženje (Windows-APIji, COM, ispis/reporting, EDI, CSV, XML/JSON) očekuje određena kodiranja.
Stoga cilj ne bi trebao biti „što manje mijenjati“, nego ciljano mijenjati tamo gdje se definiraju tokovi podataka i kodiranja. Ispravna Unicode-migracija je također prilika da se nejasne granice kodiranja konačno dokumentiraju i testiraju.
Tehničke osnove: Delphi-stringtipovi, encodinzi i njihove posljedice
string, UnicodeString, AnsiString, WideString – što je za projekt stvarno važno
Za migraciju je presudno koji se tipovi koriste na sučeljima i u ključnim funkcijama:
- string: od Delphi 2009 UnicodeString (UTF-16, reference-counted, immutable-semantika preko Copy-on-Write).
- AnsiString: bajt-string s pridruženom codepageom (ovisno o verziji Delphi codepage se može nositi uz vrijednost). Prikladan kad vanjsko sučelje eksplicitno zahtijeva 8-bitno kodiranje.
- UTF8String: u novijim verzijama Delphi često alias/AnsiString s UTF-8 codepageom; praktično za REST/JSON i mnoge protokole.
- WideString: BSTR (COM), memorijski upravljano preko SysAllocString; danas se uglavnom koristi samo za specifične COM-interope.
- PChar: od Unicode-Delphi PWideChar. To je jedna od najčešćih točaka prijeloma kod Windows-poziva.
Ako se ti tipovi miješaju, nastaju konverzije. Neke su ispravne, neke iznenađujuće: konverzija je „točna“ samo ako znate koja codepage dolazi iz izvora i koja se očekuje na odredištu.
Interno UTF-16, eksterno UTF-8: praktično vodilo
U Delphi-VCL-aplikacijama često je smisleno interno dosljedno raditi s string (UTF-16). Eksterno (REST, datoteke, messaging) u praksi prevladava UTF-8. Robusna linija je stoga:
- Interno: string/UnicodeString kao standard.
- Granice: pri ulazu/izlazu eksplicitno konvertirati preko TEncoding.UTF8 (ili definirane ANSI-codepageove).
- Bajtno bazirana obrada: TBytes umjesto stringova.
To smanjuje implicitne konverzije i čini odgovornosti provjerljivima: „Gdje bajtovi postaju tekst i s kojim encodingom?“
Inventura stanja: gdje Unicode u starim Delphi-projektima obično puca
Prije nego što zasučete rukave oko koda, isplati se strukturirana inventura. U Unicode-migraciji starih Delphi-projekata izvori pogrešaka rijetko su ravnomjerno raspoređeni, nego se koncentriraju na određene hotspotove.
1) Pristup bazi podataka i tipovi polja (BDE, ADO, FireDAC)
Mnogi legacy-projekti još koriste BDE ili starije slojeve za pristup podacima. Problemi su ovdje često:
- Poravnanje charset-a baze podataka s Delphi-stringovima (ANSI naspram Unicode polja).
- „Tekst“ u BLOB-ovima ili memo-polјima bez definirane enkodacije.
- SQL-statements kao stringovi koji se pri umlautima/Unicode-znakovima različito tumače.
Ako je ionako planirana modernizacija, Unicode-migracija se dobro može kombinirati s čišćenjem pristupa podacima, npr. prema BDE-Ablosung mit nativer Anbindung i jasnom konfiguracijom charset-a (primjerice za PostgreSQL ili MariaDB). Važno: migracija ne mora automatski značiti migraciju same baze, ali sučelje između DB-a i Delphi mora biti jednoznačno.
2) Datoteke i Stream I/O: CSV, INI, proprietarni formati, import/export
Klasik: datoteke su se ranije čitale/pisale preko AssignFile/ReadLn, TFileStream ili TStringList.LoadFromFile bez specificiranja encodinga. U Unicode-Delphi tada Delphi heuristički odlučuje (BOM) ili koristi default-encoding. To dovodi do:
- pogrešno interpretiranih umlauta (ä, ö) u CSV/log datotekama,
- pogrešnih vrijednosti duljine u proprietarnim formatima,
- nekompatibilnosti s vanjskim partnerima koji očekuju ISO-8859-1 ili Windows-1252.
Čisto rješenje je definirati za svaki format datoteke fiksni encoding i to ugraditi u kod i dokumentaciju. Za CSV/JSON je UTF-8 najčešće ispravan standard, za stare sučelje ponekad Windows-1252. Ključno je eksplicitnost.
3) Windows-API, PChar, veličine buffera i rukovanje porukama
Mnoge Delphi-aplikacije pozivaju WinAPI funkcije ili rade s bufferima. Česte točke prijeloma:
- Upotreba PChar s funkcijama koje imaju ANSI- ili Wide-varijante (…A/…W).
- Veličine buffera računaju se u bajtovima, ali je Char u UTF-16 2 bajta.
- Pointer-aritmetika i layouti zapisa (Record) koji pretpostavljaju 1-bajtne charove.
Ovdje je potrebno precizno refaktoriranje: ili dosljedno koristiti Wide-APIje ili svjesno pozivati ANSI-varijantu i raditi s AnsiString/codepageom. „Nekako se kompajlira“ nije kriterij kvalitete.
4) COM, ActiveX, Office-automacija i biblioteke trećih strana
COM-interfacei često rade s BSTR (WideString). Stare verzije Delphi imale su druge default-stringove pa je kod ponekad „srećom“ radio. U Unicode-Delphi često nastaju dvostruke konverzije ili pogrešne pretpostavke u wrapperima. Biblioteke trećih strana su također kritične: neke daju callbacke kao PAnsiChar, druge očekuju null-terminirane bajt-stringove.
Ovdje se isplati klasificirati ovisnosti: koja je biblioteka Unicode-ready, koja nije i koja se može zamijeniti ili enkapsulirati? Enkapsulacija je često najbrži način da se Unicode-legacy izolira u jasno ograničeno područje.
Strategija: Unicode-migracija starih Delphi-projekata kao kontrolirani program modernizacije
Najsigurniji pristup migraciji je višestupanjski program koji rizike rano čini vidljivima i pritom održava aplikaciju funkcionalnom.
Korak 1: definirati scope i prioritizirati code-hotspote
Ne treba svaku datoteku odmah prilagođavati. Prioritizirajte prema tokovima podataka i riziku:
- Sučelja prema van (REST-API, TCP/IP, datoteke, e-mail, ispis/reporting).
- Pristup podacima (SQL, ORM/Datamodule, BDE/FireDAC-slojevi).
- Utility-funkcije bliske stringovima (parseri, formatteri, encoder/decoderi).
- Integracije (COM, DLL-importi, vezanja na hardver).
Rezultat bi trebao biti popis mjesta na kojima je „encoding specifikacija“. Ta se mjesta kasnije čine testabilnima.
Korak 2: projektne/kompajlerske opcije i upozorenja staviti izrazito
U mnogim projektima su upozorenja bila godinama ugašena. Za Unicode-migraciju to je kontraproduktivno. Smisleno je ponovno uključiti upozorenja i ozbiljno shvatiti konverzijske upozoravajuće poruke. Dodatno pomaže definirati projektne pravila, npr.: bez implicitnih AnsiString-konverzija na I/O-granicama, korištenje TEncoding pri radu s datotekama, nema „PChar-trikova“ bez jasnog konteksta.
Korak 3: uvesti „encoding-granice“ kao tehnički sloj
Praktičan arhitektonski zahvat je uvođenje malih adaptera/helpera koji točno definiraju kako vanjski podaci ulaze i izlaze. Primjeri:
- CSV-reader/-writer: uvijek s TEncoding.UTF8 (ili definiranim codepageom) i jasnim pravilima separatora.
- REST-klijent/server: JSON uvijek kao UTF-8 bajtovi, headeri ispravno postavljeni, body se ne streama kao „string“.
- Windows-API-wrapper: centralizirane funkcije koje Wide/Ansi čisto enkapsuliraju.
Tako sprječavate da se „odluke o encodingu“ razmile po kodnoj bazi.
Tipične kod-zamke i kako ih ispravno popraviti
Length, SizeOf, ByteLength: kad se duljina u znakovima i veličina u bajtovima razdvoje
U ANSI-vremenima se Length(s) često zloupotrebljavao kao broj bajtova. U UTF-16 to je pogrešno. Ako trebate niz bajtova, eksplicitno konvertirajte:
- Za UTF-8: TEncoding.UTF8.GetBytes(s)
- Za definiranu ANSI-codepage: TEncoding.GetEncoding(1252).GetBytes(s) (samo ako je to stručno korektno)
Za veličine buffera u API-pozivima provjerite očekuje li funkcija jedinice u znakovima ili u bajtovima. Mnoge Wide-API funkcije očekuju broj znakova, ne bajtova. Dokumentacija i signatura su mjerodavni, ne intuicija.
PAnsiChar vs. PWideChar: DLL-importi i vanjski protokoli
Kod DLL-importa postoji velika opasnost da signatura u Delphi-kodu više ne odgovara. Odredite što DLL očekuje:
- Očekuje li DLL UTF-8? Tada je uobičajeno prosljeđivanje kao PAnsiChar(UTF8String), ali morate kontrolirati životni vijek i null-terminaciju.
- Očekuje li UTF-16? Tada koristite PWideChar i wide-stringove.
U svakom slučaju importi bi trebali biti enkapsulirani u zasebnu unitu, tako da se string-politika ne razlije po cijelom projektu.
Formatiranje, promjena veličine slova, usporedba: lokal i normalizacija
Unicode donosi i semantička pitanja: velika/mala slova nisu trivijalna u svim jezicima, a znakovi mogu imati različite normalne oblike. U tipičnim enterprise-aplikacijama to je manje kritično nego u obradi teksta za korisnike, ali utječe na:
- sortiranje i filtriranje (npr. u gridovima ili pretraživanjima),
- case-insensitive usporedbe za ključne vrijednosti,
- generiranje naziva datoteka ili identifikatora.
Važno je jasna pravila: što su „ključevi“ (npr. šifrirni brojevi, šifre kupaca) koji trebaju ostati ASCII-bliski, a što su „teksti“ koji moraju biti puni Unicode? Ta podjela smanjuje naknadne pogreške.
GUI/Reporting: fontovi, ispis, PDF i ponašanje komponenti
VCL je od Unicode-verzija osnovno Unicode-sposoban, ali praksa ovisi o komponentama i izlaznim putovima. Rizici se pojavljuju kod:
- starijih report-enginea ili PDF-generatora koji očekuju ANSI,
- barcode/label ispisa koji zahtijevaju određene codepageove,
- hardcodiranih fontova ili skupova znakova.
Planirajte rano testiranje s realnim primjerima podataka (imena, mjesta, posebni znakovi, nedolatinjske abecede ako su relevantne). Vrijednost nije samo u „može Unicode“, nego u dokazivanju: „Ovaj izlaz je u našem kontekstu ispravan.“
Podaci i persistencija: Unicode ne završava u kodu
Ispravno postaviti charset i collation u bazama podataka
Unicode-migracija stabilna je samo ako su baze podataka i driveri pravilno konfigurirani. Primjeri:
- Za PostgreSQL je UTF-8 uglavnom standard; ipak treba provjeriti client-encoding i ponašanje drivera.
- Za SQL Server važna je razlika između VARCHAR i NVARCHAR; pogrešan izbor stupca može uzrokovati gubitak znakova.
- Za MariaDB/MySQL charset/collation (npr. utf8mb4) su presudni da se 4-bajtni Unicode-znakovi ne obrezuju.
U Delphi-kodu parametri i tipovi polja trebaju se koristiti tako da se Unicode ne „konvertira natrag“ na putu. FireDAC obično nudi bolju kontrolu nego vrlo stari pristupni slojevi.
Legacy-formati datoteka: pravila migracije umjesto tihih konverzija
Ako vaša aplikacija godinama proizvodi datoteke (exporti, arhive, proprietarne strukture), morate definirati:
- Koje postojeće datoteke ostaju „kako jesu“ i kako će se pri čitanju ispravno interpretirati?
- Koje se formate podiže na UTF-8?
- Postoje li polja verzije/headeri da se novi i stari formati jasno razlikuju?
Tihi konvertiranje bez oznake je rizično jer se pogreške često otkriju tek kasno. Bolje: verzionirati, jasno prepoznati i ciljano migrirati.
Osiguranje kvalitete: testovi koji zaista pronalaze Unicode-probleme
Unicode-pogreške često ovise o podacima. Zato „happy path“ testovi nisu dovoljni. Korisno je testno pokrivanje koje ciljano adresira problematična mjesta:
- Roundtrip-testovi: import → obrada → export, zatim bajt-po-bajt usporedba (za definirane formate).
- DB-roundtrip: pisanje/čitanje tekstova s umlautima, akcentima i eventualno nedolatinjskim znakovima; provjera jednakosti.
- Sučelni testovi: REST-requesti kao UTF-8, headeri, JSON-escaping, logiranje.
- Regresija: reproducirati stare podatke i tipične korisničke scenarije, osobito kod pretrage, filtriranja, sortiranja.
Za B2B-sustave je također važno da su pogreške promatrive: logiranje ne smije uništavati encodinge. Ako logovi pišu u ANSI, pri grešci ćete izgubiti upravo one informacije koje su potrebne.
Planiranje i napor: što stvarno povećava kompleksnost
Opseg posla Unicode-migracije starih Delphi-projekata manje ovisi o „broju linija koda“, a više o povezivanosti i vanjskim ovisnostima:
- Mnoge integracije (DLLi, COM, uređaji, ERP/DMS/CRM) povećavaju opseg provjera jer je encoding relevantan na svakoj granici.
- Historijski formati (stari exporti, klijentski CSV-ovi) zahtijevaju pravila migracije i strategije kompatibilnosti.
- Miješane verzije Delphi ili više proizvoda iz iste codebase povećavaju potrebu za koordinacijom.
- Stari slojevi pristupa podacima (npr. BDE) mogu Unicode indirektno blokirati i sugerirati modernizaciju.
U praksi se pokazao pristup koji najprije stabilizira Unicode u jezgri i kritičnim tokovima podataka. Nakon toga se modul po modul postupno dovodi u red. To smanjuje rizik i izbjegava duge „big bang“ faze bez izdanja.
Položaj u modernizacijskim putovima: REST, servisi, multiplatforma
Unicode je često temeljna pretpostavka kad se legacy-softver želi modernizirati. Tipična pitanja koja slijede su:
- REST-server ili REST-API kao dodatak (ispravno rukovanje JSON/UTF-8).
- Stabilno upravljanje Windows-servisima ili Linux-servisima (logiranje, konfiguracijske datoteke, protokoli).
- Postupna modernizacija UI-ja u VCL-u, kasnije eventualno multiplatformski klijenti.
Važan je redoslijed: kad gradite nova sučelja, pravila o encodingu trebaju biti dogovorena unaprijed. Unicode-migracija „usput“ tijekom razvoja sučelja inače stvara teško provjerljive greške jer se uzrok i posljedica pomiješaju.
Za internu poveznicu u magazinu korisno je ponuditi povezane teme poput Delphi-modernizacije, FireDAC-pristupa podacima ili arhitekture REST-servera kao produbljujuće članke, kako bi čitatelji mogli ciljano nastaviti na sljedeći tehnički korak.
Zaključak: Unicode-migracija je pitanje rizika – s pravom metodom postaje planirana
Unicode-migracija starih Delphi-projekata nije kozmetički update, nego ispravka temeljnih pretpostavki o tekstu, bajtovima i sučeljima. Tko pristupi strukturirano, dobiva više od „umlauti opet rade“: tokovi podataka postaju jednoznačniji, integracije robusnije, a kasnija modernizacija (npr. REST-serveri, servisi, čišćenje baza) lakša jer se encodinzi više ne događaju implicitno „negdje“.
Ako za svoju Delphi-aplikaciju trebate konkretan plan migracije, analizu rizika hotspotova ili podršku pri provedbi, najbrži sljedeći korak je tehnički početni razgovor o vašim okvirima i ovisnostima: Kontakt aufnehmen.
U stručnom kontekstu Delphi Unicode Migration i Delphi Ansi Zu Unicode također igraju važnu ulogu kad se integracije, tokovi podataka i daljnji razvoj trebaju jasno uskladiti.
Projekt oder Modernisierungsvorhaben mit Net-Base besprechen.