La migrazione a Unicode di vecchi progetti Delphi è in molte aziende un passo necessario, perché le applicazioni esistenti altrimenti incontrano sempre più limiti con dati internazionali, sistemi operativi moderni, integrazioni e nuove interfacce. Nella pratica non si tratta quasi mai di un semplice “ricompila e finito”. Delphi ha introdotto, a partire dalle versioni Unicode (da Delphi 2009), cambiamenti fondamentali ai tipi stringa standard. Questo sposta le assunzioni su codifica dei caratteri, layout in memoria e firme delle API. Chi lo sottovaluta genera errori di dati silenti, export corrotti, casi di supporto poco chiari e rischi di sicurezza.
Questo articolo fornisce un approccio tecnicamente fondato: come analizzare il codice esistente, delimitare il perimetro in modo sensato, ridurre i rischi nei punti critici (database, file, API Windows, COM, servizi REST) e mettere in sicurezza la migrazione in modo che esercizio e sviluppo possano procedere in parallelo. Il focus è sulle insidie tipiche di Delphi in applicazioni VCL, servizi e interfacce — con uno sguardo ai percorsi di modernizzazione in cui in seguito possono inserirsi temi come la sostituzione di BDE con connettività nativa, server REST o scenari multipiattaforma.
Perché la conversione a Unicode in Delphi è spesso «più grande del previsto»
Nelle versioni classiche di Delphi il string era una stringa ANSI (in base alla codepage di sistema). Da Delphi 2009 string è per default un UnicodeString (UTF-16). Contemporaneamente molte librerie e classi VCL sono state migrate a API Wide. Questo è positivo in quanto supporta in modo robusto i caratteri internazionali. Tuttavia: il codice legacy è spesso cresciuto negli anni intorno alle assunzioni “1 carattere = 1 byte”, “PChar è PAnsiChar” o “Length() corrisponde al numero di byte”.
Le cause tipiche per cui le migrazioni diventano più complesse:
- Conversioni implicite avvengono ma modificano i dati (soprattutto su file, interfacce o campi BLOB/Testo del database).
- Codice orientato ai byte (Stream, buffer, hashing, crittografia) diventa erroneo se i contenuti stringa vengono interpretati come byte.
- Componenti di terze parti sono talvolta solo ANSI o usano tipi stringa e callback propri.
- Ambienti esterni (API Windows, COM, stampa/reporting, EDI, CSV, XML/JSON) si aspettano determinate codifiche.
Lo scopo quindi non dovrebbe essere “cambiare il meno possibile”, ma modificare in modo mirato dove i flussi di dati e le codifiche devono essere definiti. Una migrazione a Unicode ben eseguita è anche un’opportunità per documentare e testare finalmente i confini di codifica poco chiari.
Fondamenti tecnici: tipi stringa di Delphi, encodings e loro effetti collaterali
string, UnicodeString, AnsiString, WideString – cosa conta realmente nel progetto
Per la migrazione è cruciale quali tipi vengono usati alle interfacce e nelle funzioni core:
- string: da Delphi 2009 un UnicodeString (UTF-16, reference-counted, semantica immutabile via Copy-on-Write).
- AnsiString: stringa di byte con codepage associata (a seconda della versione di Delphi può essere trasportata una codepage). Utile quando un’interfaccia esterna richiede esplicitamente una codifica 8-bit.
- UTF8String: in versioni più recenti di Delphi spesso alias/AnsiString con codepage UTF-8; pratico per REST/JSON e molti protocolli.
- WideString: BSTR (COM), gestito in memoria tramite SysAllocString; oggi principalmente per interop COM specifici.
- PChar: dopo le versioni Unicode di Delphi è PWideChar. Questo è uno dei punti di rottura più frequenti nelle chiamate API Windows.
Se questi tipi vengono mescolati si generano conversioni. Alcune sono corrette, altre sorprendenti: una conversione è «giusta» solo se si conosce quale codepage è alla fonte e quale è attesa dal destinatario.
UTF-16 internamente, UTF-8 esternamente: un principio pratico
Nelle applicazioni VCL di Delphi spesso ha senso lavorare internamente in modo coerente con string (UTF-16). Esternamente (REST, file, messaging) nella realtà prevale il UTF-8. Una linea robusta è quindi:
- Interno: string/UnicodeString come standard.
- Confini: alla lettura/scrittura convertire esplicitamente con TEncoding.UTF8 (o codepage ANSI definite).
- Elaborazione basata su byte: usare TBytes invece di stringhe.
Questo riduce le conversioni implicite e rende verificabili le responsabilità: “Dove si convertono byte in testo e con quale encoding?”
Inventario: dove Unicode nei vecchi progetti Delphi tipicamente si rompe
Prima di toccare il codice conviene un inventario strutturato. Nella migrazione a Unicode di vecchi progetti Delphi le fonti di errore non sono distribuite uniformemente, ma si concentrano su alcuni punti critici.
1) Accesso al database e tipi di campo (BDE, ADO, FireDAC)
Molti progetti legacy usano ancora BDE o layer di accesso più vecchi. I problemi comuni sono:
- mappatura dei charset del database verso le stringhe Delphi (campi ANSI vs. Unicode).
- “Testo” in BLOB o campi Memo senza codifica definita.
- istruzioni SQL come stringhe che, in presenza di Umlaut/caratteri Unicode, vengono interpretate in modo diverso.
Se è prevista una modernizzazione, una migrazione a Unicode si può ben combinare con una pulizia dell’accesso ai dati, ad esempio verso BDE-Ablosung mit nativer Anbindung e una configurazione chiara dei charset (come in PostgreSQL o MariaDB). Importante: una migrazione non deve automaticamente forzare una migrazione del database, ma l’interfaccia tra DB e Delphi deve essere univoca.
2) I/O file e stream: CSV, INI, formati proprietari, import/export
Un classico: file letti/scritti in passato con AssignFile/ReadLn, TFileStream o TStringList.LoadFromFile senza impostare l’encoding. In Delphi Unicode il comportamento è poi determinato in modo euristico (BOM) o da encodings di default. Questo porta a:
- interpretazione errata di caratteri accentati (ä, ö) in CSV/logfile,
- errori nelle lunghezze in formati proprietari,
- incompatibilità con partner esterni che si aspettano ISO-8859-1 o Windows-1252.
Una soluzione pulita è definire un encoding fisso per ogni formato di file e fissarlo nel codice e nella documentazione. Per CSV/JSON UTF-8 è di solito lo standard corretto, per interfacce legacy talvolta Windows-1252. L’essenziale è l’esplicitazione.
3) API Windows, PChar, dimensioni buffer e gestione messaggi
Molte applicazioni Delphi chiamano funzioni WinAPI o lavorano con buffer. Punti di rottura frequenti:
- uso di PChar con funzioni che hanno varianti ANSI o Wide (…A/…W).
- le dimensioni dei buffer vengono calcolate in byte, ma Char in UTF-16 occupa 2 byte.
- aritmetica sui puntatori e layout di record basati su char a 1 byte.
Serve un refactoring preciso: o si usano coerentemente le Wide-API o si richiama consapevolmente la variante ANSI e si lavora con AnsiString/codepage. “Compila comunque” non è un criterio di qualità.
4) COM, ActiveX, Office-Automation e librerie di terze parti
Le interfacce COM spesso lavorano con BSTR (WideString). Versioni vecchie di Delphi avevano default stringa diversi, perciò il codice funzionava “per caso”. In Delphi Unicode si osservano spesso doppie conversioni o assunzioni di tipo errate nei wrapper. Le librerie di terze parti sono critiche: alcune forniscono callback come PAnsiChar, altre si aspettano stringhe di byte terminate da null.
Conviene classificare le dipendenze: quali librerie sono Unicode-ready, quali no, e quali possono essere sostituite o incapsulate? L’incapsulamento è spesso il modo più rapido per confinare i debiti Unicode in un’area ben definita.
Strategia: migrazione a Unicode di vecchi progetti Delphi come programma di modernizzazione controllato
L’approccio più sicuro è un programma a più stadi che renda i rischi visibili precocemente e mantenga l’applicazione in esecuzione.
Passo 1: definire il perimetro e prioritizzare i punti caldi nel codice
Non tutto il sorgente richiede adattamenti immediati. Prioritizzate in base ai flussi di dati e al rischio:
- Interfacce verso l’esterno (REST-API, TCP/IP, file, e-mail, stampa/reporting).
- Accesso ai dati (SQL, ORM/Datamodule, BDE/FireDAC-layer).
- Utility vicine alle stringhe (parser, formatter, encoder/decoder).
- Integrazioni (COM, import DLL, connessioni hardware).
Il risultato dovrebbe essere un elenco di punti in cui “l’encoding è una specifica”. Queste aree saranno rese testabili in seguito.
Passo 2: impostare consapevolmente le opzioni del compilatore/progetto e le warning
In molti progetti le warning sono state disattivate per anni. Per una migrazione Unicode questo è controproducente. Riattivate le warning e prendete sul serio gli avvisi di conversione. Aiuta inoltre stabilire regole di progetto, ad es.: nessuna conversione implicita AnsiString ai confini I/O, uso di TEncoding nelle operazioni file, niente “trucchi PChar” senza contesto chiaro.
Passo 3: introdurre i “confini di encoding” come layer tecnico
Un approccio architetturale pratico è introdurre piccoli adapter/helper che definiscano esattamente come entrano e escono i dati esterni. Esempi:
- CSV-Reader/-Writer: sempre con TEncoding.UTF8 (o codepage definita) e regole chiare di separazione.
- REST-Client/Server: JSON sempre come byte UTF-8, header impostati correttamente, body non trasmesso come stream “a base stringa”.
- Wrapper API Windows: funzioni centrali che incapsulano correttamente Wide/Ansi.
Così si evita che decisioni di encoding si disperdano nella codebase.
Trappole di codice tipiche e come risolverle correttamente
Length, SizeOf, ByteLength: quando lunghezza in caratteri e dimensione in byte divergono
In epoca ANSI Length(s) veniva spesso impiegato come numero di byte. In UTF-16 questo è sbagliato. Se servono array di byte, convertite esplicitamente:
- Per UTF-8: TEncoding.UTF8.GetBytes(s)
- Per una codepage ANSI definita: TEncoding.GetEncoding(1252).GetBytes(s) (solo se corretto dal punto di vista funzionale)
Per le dimensioni buffer nelle chiamate API verificate se la funzione si aspetta unità in caratteri o in byte. Molte Wide-API si aspettano il numero di caratteri, non di byte. Decidono documentazione e firma, non l’intuizione.
PAnsiChar vs. PWideChar: import di DLL e protocolli esterni
Negli import di DLL il rischio è che le firme nel codice Delphi non corrispondano più. Stabilite cosa si aspetta la DLL:
- La DLL si aspetta UTF-8? Allora il passaggio come PAnsiChar(UTF8String) è comune, ma dovete controllare la durata e la terminazione null.
- Si aspetta UTF-16? Allora usare PWideChar e wide-strings.
In ogni caso incapsulate gli import in una unit separata, così la politica sulle stringhe non si disperde nel progetto.
Formattazione, conversione case, confronto: localizzazione e normalizzazione
Unicode introduce anche temi semantici: le conversioni maiuscole/minuscole non sono banali in tutte le lingue, e i caratteri possono avere diverse forme di normalizzazione. Nelle applicazioni aziendali tipiche questo è meno critico che in un editor di testi consumer, ma riguarda comunque:
- ordinamento e filtri (es. in grid o funzioni di ricerca),
- confronti case-insensitive per chiavi,
- generazione di nomi file o identificatori.
Stabilite regole chiare: cosa sono le “chiavi” (es. codici articolo, codici cliente) che dovrebbero rimanere ASCII-neutre, e cosa sono i “testi” che devono essere pienamente Unicode. Questa separazione riduce gli errori a cascata.
GUI/Reporting: font, stampa, PDF e comportamento dei componenti
La VCL è Unicode-ready dalle versioni corrispondenti, ma la pratica dipende da componenti e percorsi di output. I rischi emergono con:
- motori di report o generatori PDF datati che assumono ANSI,
- stampa barcode/label che necessita di codepage specifiche,
- font o set di caratteri hardcodati.
Pianificate test precoci con dati di esempio realistici (nomi, località, caratteri speciali, scritture non latine se rilevanti). Il valore non è solo che “può gestire Unicode”, ma la prova: “Questo output è corretto nel nostro contesto.”
Dati e persistenza: Unicode non finisce nel codice
Definire chiaramente charset e collations dei database
Una migrazione a Unicode è stabile solo se database e driver sono configurati correttamente. Esempi:
- In PostgreSQL UTF-8 è di norma lo standard; tuttavia vanno verificati client-encoding e comportamento del driver.
- In SQL Server la distinzione tra VARCHAR e NVARCHAR è rilevante; colonne scelte male possono perdere caratteri.
- In MariaDB/MySQL charset/collation (es. utf8mb4) sono decisivi affinché i caratteri a 4 byte non vengano troncati.
Nel codice Delphi usate parametri e tipi di campo in modo che il testo Unicode non venga “riconvertito indietro” lungo il percorso. FireDAC offre in genere un controllo migliore rispetto ad accessi molto vecchi.
Formati di file legacy: regole di migrazione invece di conversioni silenziose
Se la vostra applicazione ha prodotto file negli anni (export, archivi, strutture proprietarie), dovete definire:
- quali file esistenti rimangono “così come sono” e vengono interpretati correttamente alla lettura?
- quali formati verranno aggiornati a UTF-8?
- esistono campi versione/header per distinguere in modo univoco file nuovi e vecchi?
La conversione silenziosa senza marcatura è rischiosa, perché gli errori emergono tardi. Meglio: versionare, riconoscere chiaramente, migrare intenzionalmente.
Assicurazione qualità: test che individuano realmente i problemi Unicode
Gli errori Unicode dipendono spesso dai dati. Perciò i test “Happy Path” non bastano. È utile un set di test che copra i punti problematici:
- Roundtrip-Tests: Import → Elaborazione → Export e confronto byte-per-byte (per formati definiti).
- DB-Roundtrip: scrittura/lettura di testi con caratteri accentati, accenti e eventualmente scritture non latine; verifica di identità.
- Test delle interfacce: richieste REST come UTF-8, header, escaping JSON, logging.
- Regressione: riprodurre dati legacy e casi utente tipici, specialmente in ricerche, filtri, ordinamenti.
Per i sistemi B2B è inoltre rilevante che gli errori siano osservabili: il logging non deve danneggiare le codifiche. Chi scrive log in ANSI perde, in caso di errore, proprio le informazioni necessarie.
Pianificazione e sforzo: cosa determina realmente la complessità
Lo sforzo per migrare a Unicode vecchi progetti Delphi dipende meno dalle “righe di codice” e più dai coupling e dalle dipendenze esterne:
- Molte integrazioni (DLL, COM, dispositivi, ERP/DMS/CRM) aumentano il lavoro di verifica perché l’encoding è rilevante a ogni confine.
- Formati storici (vecchi export, CSV custom clienti) richiedono regole di migrazione e strategie di compatibilità.
- Versioni Delphi miste o più prodotti derivati dallo stesso codice aumentano il coordinamento.
- Vecchi layer di accesso ai dati (es. BDE) possono indirettamente bloccare Unicode e suggerire una modernizzazione.
Prassi consolidata è stabilizzare Unicode nel core e nei flussi dati critici per primi. Successivamente si aggiornano i moduli in modo graduale. Questo riduce il rischio e evita lunghe fasi “big bang” senza rilascio.
Inquadramento nei percorsi di modernizzazione: REST, servizi, multipiattaforma
Unicode è spesso un requisito fondamentale quando il software legacy viene modernizzato. Domande tipiche collegate sono:
- Aggiornare con server REST o API REST (gestione pulita di JSON/UTF-8).
- Gestire stabilmente servizi [[NBML_TERM_3_aea23489 ]] o Linux-Services (logging, file di configurazione, protocolli).
- Modernizzazione graduale della UI in VCL, con possibili client multipiattaforma successivi.
Importante è l’ordine: se costruite nuove interfacce, le regole di encoding devono essere definite prima. Una migrazione a Unicode “di fianco” allo sviluppo di nuove interfacce genera altrimenti errori difficili da testare, perché causa ed effetto si mescolano.
Per la navigazione interna nel magazine è utile collocare articoli collegati su modernizzazione [[NBML_TERM_5_4c4a218d ]], accesso dati FireDAC o architetture di server REST come approfondimenti, così i lettori possono passare al passo tecnico successivo.
Conclusione: la migrazione a Unicode è un tema di rischio — con il metodo giusto diventa pianificabile
La migrazione a Unicode di vecchi progetti Delphi non è un aggiornamento cosmetico, ma una correzione di assunzioni di base su testo, byte e interfacce. Chi agisce in modo strutturato ottiene però più di “gli umlaut che tornano”: i flussi di dati diventano univoci, le integrazioni più robuste e le successive modernizzazioni (es. server [[NBML_TERM_7_50780f47 ]], servizi, pulizia del database) più semplici, perché le conversioni non avvengono più implicitamente “da qualche parte”.
Se per la vostra applicazione Delphi desiderate un piano di migrazione concreto, un’analisi dei rischi sui punti critici o supporto nell’implementazione, il passo successivo più rapido è un colloquio tecnico iniziale sulle vostre condizioni e dipendenze: contattateci.
Nel contesto specialistico la Delphi Unicode Migration e la Delphi Ansi Zu Unicode giocano un ruolo importante quando integrazioni, flussi di dati e sviluppo devono funzionare in modo coerente.
Discutere il progetto o l’iniziativa di modernizzazione con Net-Base.