La migració a Unicode de projectes antics de Delphi és en moltes empreses un pas necessari, perquè les aplicacions existents, en cas contrari, topen cada vegada més amb límits davant dades internacionals, sistemes operatius moderns, integracions i noves interfícies. A la pràctica això rarament és un «Recompile i llest». Delphi va introduir des de les versions Unicode (a partir de Delphi 2009) canvis fonamentals en els tipus de string estàndard. Això desplaça suposicions sobre l’encoding de caràcters, el layout de memòria i les signatures d’API. Qui subestimi això produeix errors de dades invisibles, exportacions trencades, casos de suport poc clars i riscos de seguretat.
Aquest article ofereix un procediment tècnicament sòlid: com analitzar l’heritat, delimitar el scope de manera raonable, reduir riscos en els punts calents (bases de dades, fitxers, Windows-APIs, COM, serveis REST) i assegurar la migració perquè l’operació i el desenvolupament puguin continuar en paral·lel. El focus està en les trampa típiques de Delphi en aplicacions VCL, serveis i interfícies —amb una perspectiva sobre camins de modernització on més endavant es puguin integrar temes com la sustitució de BDE amb connexió nativa, servidors REST o multiplataforma.
Per què l’adaptació a Unicode en Delphi sovint és «més gran del que es pensava»
En versions clàssiques de Delphi string era un ANSI-String (segons la codepage del sistema). Des de Delphi 2009 string és per defecte un UnicodeString (UTF-16). Al mateix temps moltes llibreries i classes VCL es van passar a APIs Wide. Això és positiu en el fons, perquè dona suport robust a caràcters internacionals. Però: el codi legacy sovint ha crescut durant anys amb les suposicions «1 caràcter = 1 byte», «PChar és PAnsiChar» o «Length() correspon al nombre de bytes».
Les causes típiques per les quals les migracions es fan més costoses:
- Conversions implícites funcionen però alteren dades (especialment en fitxers, interfícies o camps BLOB/Text a bases de dades).
- Codi orientat a bytes (Streams, Buffer, Hashing, xifrat) es trenca sense avisar quan el contingut dels strings s’interpreta com a bytes.
- Components de tercers són sovint ANSI-only, o usen tipus de string i callbacks propis.
- Entorns externs (Windows-APIs, COM, impressió/reporting, EDI, CSV, XML/JSON) esperen determinats encodings.
Per això l’objectiu no hauria de ser «canviar el menys possible», sinó canviar de manera dirigida allà on cal definir fluxos de dades i encodings. Una migració a Unicode ben feta també és una oportunitat per documentar i testejar d’una vegada per totes les fronteres d’encoding que fins ara eren poc clares.
Fundaments tècnics: tipus de string en Delphi, encodings i efectes secundaris
string, UnicodeString, AnsiString, WideString – què compta realment en el projecte
Per a la migració és crucial quins tipus s’utilitzen a les interfícies i en les funcions nuclears:
- string: des de Delphi 2009 un UnicodeString (UTF-16, reference-counted, semàntica immutable via Copy-on-Write).
- AnsiString: string de bytes amb una codepage associada (segons la versió de Delphi es pot portar una codepage). Adequat quan una interfície externa exigeix explícitament una codificació 8-bit concreta.
- UTF8String: en versions més noves de Delphi sovint com a alias/AnsiString amb codepage UTF-8; pràctic per REST/JSON i molts protocols.
- WideString: BSTR (COM), gestionat per SysAllocString; avui dia normalment només necessari per a certs COM-Interops.
- PChar: des de la versió Unicode de Delphi PWideChar. Aquest és un dels punts de ruptura més habituals en crides a Windows-APIs.
Quan aquests tipus es barregen, es produeixen conversions. Algunes són correctes, altres sorprenents: una conversió només és «correcta» si es coneix quina codepage té la font i quina espera el destí.
UTF-16 intern, UTF-8 extern: un paradigma pràctic
En aplicacions VCL amb Delphi sovint és raonable treballar internament de manera consistent amb string (UTF-16). Externament ({{NBML_TERM_7_50780f47}}, fitxers, messaging) domina en la pràctica UTF-8. Una línia robusta és, per tant:
- Intern: string/UnicodeString com a estàndard.
- Fronteres: a l’entrada/sortida convertir de manera explícita amb TEncoding.UTF8 (o codepages ANSI definides).
- Processament basat en bytes: TBytes en lloc de Strings.
Això redueix conversions implícites i fa les responsabilitats comprovables: «On es converteixen bytes en text, i amb quin encoding?»
Inventari: on falla típicament Unicode en projectes antics de Delphi
Abans de tocar el codi val la pena fer una inventariació estructurada. En la migració a Unicode de projectes antics de Delphi les fonts d’errors no estan repartides uniformement, sinó que es concentren en certs punts calents.
1) Accés a base de dades i tipus de camps (BDE, ADO, FireDAC)
Molts projectes antics encara usen BDE o capes d’accés a dades més velles. Aquí els problemes habituals són:
- Mapatge de charsets de la base de dades als strings de Delphi (ANSI vs. tipus de camp Unicode).
- «Text» en BLOBs o camps Memo sense encoding definit.
- Consultes SQL com a Strings, que amb vocals amb dièresi/caràcters Unicode poden interpretar-se de manera diferent.
Si ja es planifica una modernització, una migració a Unicode es pot combinar amb una neteja de l’accés a dades, per exemple cap a BDE-Ablosung mit nativer Anbindung i una configuració clara de charsets (p. ex. en PostgreSQL o MariaDB). Important: una migració no hauria d’imposar automàticament una migració de base de dades, però la interfície entre BD i Delphi ha de ser inequívoca.
2) I/O de fitxers i streams: CSV, INI, formats propietaris, import/export
Un clàssic: fitxers llegits/escrits abans amb AssignFile/ReadLn, TFileStream o TStringList.LoadFromFile sense establir l’encoding. En la versió Unicode de Delphi l’entorn decideix heurísticament (BOM) o usa encodings per defecte. Això causa:
- vocales mal interpretades (ä, ö) en CSV/logfiles,
- errors en longituds en formats propietaris,
- incompatibilitats amb socis externs que esperen ISO-8859-1 o Windows-1252.
Una solució neta és definir un encoding fix per cada format de fitxer i ancorar-ho en el codi i la documentació. Per a CSV/JSON UTF-8 és sovint l’estàndard adequat; per a interfícies antigues de vegades Windows-1252. L’important és l’explicitud.
3) Windows-API, PChar, mides de buffer i maneig de missatges
Moltes aplicacions de Delphi criden funcions WinAPI o treballen amb buffers. Punts de ruptura freqüents:
- Ús de PChar amb funcions que tenen variants ANSI o Wide (…A/…W).
- Les mides de buffer es calculen en bytes, però Char en UTF-16 ocupa 2 bytes.
- Aritmètica de pointers i layouts de records basats en chars d’1 byte.
Aquí cal un refactoring precís: o bé usar estrictament Wide-APIs o bé cridar conscientment la variant ANSI i treballar amb AnsiString/codepage. «Que compili d’alguna manera» no és criteri de qualitat.
4) COM, ActiveX, Office-Automation i biblioteques de tercers
Les interfícies COM sovint treballen amb BSTR (WideString). En versions antigues de Delphi els strings per defecte eren diferents, de manera que el codi encaixava «per casualitat». En la versió Unicode sovint apareixen conversions dobles o supòsits de tipus incorrectes en wrappers. Les biblioteques de tercers també són crítiques: algunes donen callbacks com a PAnsiChar; d’altres esperen strings de bytes amb terminació null.
Val la pena classificar dependències: quina llibreria està preparada per Unicode, quina no, i quina es pot substituir o encapsular? Encapsular sovint és la via més ràpida per confinar la càrrega heretada d’Unicode a una zona ben delimitada.
Estratègia: la migració a Unicode de projectes antics de Delphi com a programa de modernització controlat
L’enfocament més segur per a la migració és un programa per fases que faci visibles els riscos aviat i mantingui la aplicació operativa.
Pas 1: definir l’abast i prioritzar hotspots de codi
No tot el codi font necessita ajust immediat. Prioritzi segons flux de dades i risc:
- Interfícies cap a l’exterior (REST-API, TCP/IP, fitxers, e-mail, impressió/reporting).
- Accés a dades (SQL, ORM/Datamodule, BDE/FireDAC-capas).
- Funcions utilities properes a strings (parsers, formatters, encoder/decoder).
- Integracions (COM, DLL-Imports, connexions a hardware).
El resultat hauria de ser una llista on «encoding és una especificació». Aquestes zones seran posteriorment mesurables amb tests.
Pas 2: opcions del compilador/projekt i advertències, posar-les fortes
En molts projectes les advertències s’han desactivat durant anys. Per a una migració Unicode això és contraproduent. Convé reactivar advertències i prendre seriosament les advertències de conversió. També ajuda establir regles a nivell de projecte, per exemple: no hi ha conversions implícites AnsiString en les fronteres d’I/O, ús de TEncoding en operacions de fitxers, no fer «trucs amb PChar» sense un context clar.
Pas 3: introduir «fronteres d’encoding» com a capa tècnica
Un recurs arquitectònic pràctic és introduir petits adaptadors/helpers que defineixin de manera precisa com entren i surten les dades externes. Exemples:
- CSV-Reader/-Writer: sempre amb TEncoding.UTF8 (o codepage definida) i regles de separador clares.
- REST-Client/Server: JSON sempre com a bytes UTF-8, headers correctament establerts, Body no «streamat» basant-se en strings.
- Windows-API-Wrapper: funcions centrals que encapsulen Wide/Ansi de manera neta.
Així s’impedeix que les «decisions d’encoding» es dispersin per la base de codi.
Caigudes típiques en el codi i com reparar-les netament
Length, SizeOf, ByteLength: quan la longitud de caràcters i la mida en bytes divergeixen
En temps ANSI s’abusava de Length(s) com a nombre de bytes. En UTF-16 això és incorrecte. Si necessita arrays de bytes, converteixi explícitament:
- Per UTF-8: TEncoding.UTF8.GetBytes(s)
- Per una codepage ANSI definida: TEncoding.GetEncoding(1252).GetBytes(s) (només si és correcte des del punt de vista funcional)
Per a mides de buffer en crides d’API cal comprovar si la funció espera unitats de caràcters o de bytes. Moltes Wide-APIs esperen nombre de caràcters, no bytes. La documentació i la signatura decideixen, no la intuïció.
PAnsiChar vs. PWideChar: DLL-Imports i protocols externs
En imports de DLL el risc és gran que les signatures en el codi de Delphi ja no coincideixin. Definiu què espera la DLL:
- La DLL espera UTF-8? Llavors la passada com a PAnsiChar(UTF8String) és habitual, però cal controlar la vida de l’objecte i la terminació null.
- Espera UTF-16? Entonces useu PWideChar i Wide-Strings.
En qualsevol cas, els imports han d’estar encapsulats en una unit separada perquè la política de strings no es propagi per tot el projecte.
Format, canvi de case, comparacions: localització i normalització
Unicode també aporta temes semàntics: majúscules/minúscules no és trivial en totes les llengües, i els caràcters poden tenir diferents formes de normalització. En aplicacions empresarials típiques això és menys crític que en processament de text de consum, però afecta:
- Ordenació i filtratge (p. ex. en grids o funcions de cerca),
- Comparacions case-insensitive per valors clau,
- Generació de noms de fitxer o identificadors.
És important una regla clara: què són «claus» (per ex. números d’article, codis de client) que haurien de romandre ASCII-proximitat, i què són «textos» que han de ser plenament Unicode. Aquesta separació redueix errors derivats.
GUI/Reporting: fonts, impressió, PDF i comportament de components
VCL és des de les versions Unicode fonamentalment compatible amb Unicode, però la pràctica depèn de components i rutes de sortida. Els riscos apareixen amb:
- engines de reporting o generadors de PDF antics que assumeixen ANSI,
- impressió de codi de barres/etiquetes que necessita certes codepages,
- fonts o jocs de caràcters codificats de manera rígida.
Planifiqueu proves primerenques amb dades reals d’exemple (noms, poblacions, caràcters especials, alfabet no llatí si és rellevant). L’interès no és només «pot gestionar Unicode», sinó demostrar: «Aquesta sortida és correcta en el nostre context.»
Dades i persistència: Unicode no acaba en el codi
Definir de manera neta charsets i collations a la base de dades
Una migració a Unicode és estable només si bases de dades i drivers estan configurats correctament. Exemples:
- En PostgreSQL UTF-8 és normalment l’estàndard; tot i així cal verificar client-encoding i el comportament del driver.
- En SQL Server la distinció entre VARCHAR i NVARCHAR és rellevant; una elecció de columna errònia pot fer perdre caràcters.
- En MariaDB/MySQL charset/collation (p. ex. utf8mb4) són crucials perquè caràcters de 4 bytes no siguin truncats.
En el codi de Delphi els paràmetres i tipus de camp s’han d’utilitzar de manera que Unicode no es re-converteixi en el camí de tornada. FireDAC normalment ofereix millor control que capes d’accés molt antigues.
Formats de fitxer legacy: regles de migració en lloc de conversions silencioses
Si la vostra aplicació ha generat fitxers durant anys (formats d’exportació, arxius d’arxiu, estructures propietàries), cal definir:
- Quins fitxers existents es mantenen «tal qual» i es llegeixen interpretant-los correctament?
- Quins formats s’actualitzen a UTF-8?
- Hi ha camps de versió/headers per distingir clarament fitxers nous i antics?
La conversió silenciosa sense marcar és arriscada perquè els errors sovint apareixen tard. Millor: versionar, detectar clarament i migrar de forma dirigida.
Assegurament de qualitat: tests que realment detecten problemes Unicode
Els errors Unicode depenen sovint de dades. Per això els tests «Happy Path» no són suficients. Convé un conjunt de proves que cobreixi les zones problemàtiques:
- Tests de roundtrip: Import → Processament → Export, i després comparació byte-a-byte (per formats definits).
- DB-Roundtrip: escriure/llegir textos amb vocals amb dièresi, accents i, si escau, caràcters no llatins; verificar la igualtat.
- Tests d’interfícies: peticions REST com UTF-8, headers, escapament JSON, logging.
- Regressió: reproduir dades antigues i casos d’usuari típics, especialment en cerca, filtratge i ordenació.
Per a sistemes B2B és també rellevant que els errors siguin observables: el logging no hauria de destruir encodings. Si els logs s’escriuen en ANSI, en cas d’error es perd exactament la informació necessària.
Planificació i esforç: què fa que la complexitat augmenti
L’esforç d’una migració a Unicode en projectes antics de Delphi depèn menys del «nombre de línies» i més de les acoblacions i dependències externes:
- Moltíssimes integracions (DLLs, COM, dispositius, ERP/DMS/CRM) augmenten el treball de verificació perquè a cada frontera l’encoding és rellevant.
- Formats històrics (exports antics, CSVs específics per client) requereixen regles de migració i estratègies de compatibilitat.
- Versions mixtes de Delphi o diversos productes a partir d’un mateix codi incrementen la necessitat de coordinació.
- Capes d’accés a dades antigues (p. ex. BDE) poden bloquejar indirectament Unicode i suggerir una modernització.
En la pràctica funciona un enfocament que estabilitzi primer Unicode en el nucli i en els fluxos de dades més crítics. Després es poden actualitzar mòduls progressivament. Això redueix el risc i evita llargues fases «Big Bang» sense release.
Classificació dins de camins de modernització: REST, serveis, multiplataforma
Unicode sovint és un pilar quan es vol modernitzar software existent. Preguntes típiques són:
- Implantar servidors REST o dotar d’API REST (tractar JSON/UTF-8 amb correcció).
- Mantenir estable serveis Windows o serveis Linux (logging, fitxers de configuració, protocols).
- Modernització progressiva de la IU en VCL, i més endavant clients multiplataforma.
La seqüència és important: si construeix noves interfícies cal que abans s’hagin establert regles d’encoding. Una migració a Unicode «al mateix temps» que el desenvolupament d’interfícies porta normalment a patrons d’error difícils de provar perquè causa confusió entre causa i efecte.
Per a l’enllaç intern al magazín és adequat col·locar articles adjacents sobre modernització de Delphi, accés a dades amb FireDAC o arquitectura de servidors REST perquè el lector pugui seguir el següent pas tècnic.
Conclusió: la migració a Unicode és un tema de risc —amb el mètode correcte es fa planificable
La migració a Unicode de projectes antics de Delphi no és una actualització cosmètica, sinó una correcció de suposicions fonamentals sobre text, bytes i interfícies. Qui actua de manera estructurada però guanya més que «les vocals funcionen de nou»: els fluxos de dades queden més clars, les integracions més robustes i la posterior modernització (per exemple, servidors REST, serveis, neteja de bases de dades) és més senzilla perquè els encodings no passen implícitament «en algun lloc».
Si necessita per la seva aplicació Delphi un pla concret de migració, una anàlisi de riscos dels hotspots o suport en l’execució, el pas següent més ràpid és una reunió tècnica inicial sobre el seu context i les seves dependències: posar-se en contacte.
En l’àmbit tècnic també tenen importància les denominades Delphi Unicode Migration i Delphi Ansi Zu Unicode quan integracions, fluxos de dades i desenvolupament futur han de funcionar conjuntament.
Parlar del projecte o iniciativa de modernització amb Net-Base.