Net-Base Magazine

19.04.2026

Unicode-migratie van oude Delphi-projecten: valkuilen, strategie en zorgvuldige uitvoering

Veel Delphi-bestaande toepassingen werken nog met ANSI-strings. Een Unicode-migratie is dan meer dan een compiler-schakelaar: het raakt de toegang tot gegevens, interfaces, rapporten, bibliotheken van derden en tests. Dit artikel toont een in de praktijk toepasbaar migratiepad – incl...

19.04.2026

De Unicode-migratie van oude Delphi-projecten is in veel bedrijven een noodzakelijke stap, omdat bestaande applicaties anders bij internationale gegevens, moderne besturingssystemen, integraties en nieuwe interfaces steeds vaker tegen grenzen aanlopen. In de praktijk is het zelden „Recompile und fertig“. Delphi heeft sinds de Unicode-versies (vanaf Delphi 2009) fundamentele wijzigingen aan de standaard string-types doorgevoerd. Daardoor veranderen aannames over tekenencodering, geheugenlayout en API-signaturen. Wie dat onderschat, veroorzaakt sluipende datafouten, kapotte exports, onduidelijke supportgevallen en veiligheidsrisico’s.

Dit artikel biedt een technisch onderbouwde werkwijze: hoe u de bestaande code analyseert, scope verstandig afbakent, risico’s bij hotspots (databases, bestanden, Windows-API’s, COM, REST-services) verkleint en de migratie zo afdicht dat exploitatie en verdere ontwikkeling parallel mogelijk blijven. De focus ligt op Delphi-typische valkuilen in VCL-applicaties, services en interfaces – met het oog op moderniseringspaden waarin later ook onderwerpen als BDE-vervanging met native koppeling, REST-servers of multiplatform ingepast kunnen worden.

Waarom de Unicode-omstelling in Delphi zo vaak „groter dan gedacht“ is

In klassieke Delphi-versies was string een ANSI-string (afhankelijk van de systeemcodepage). Sinds Delphi 2009 is string standaard een UnicodeString (UTF-16). Tegelijkertijd werden veel bibliotheken en VCL-klassen op Wide-API’s aangepast. Dat is in wezen positief omdat het internationale tekens robuust ondersteunt. Maar: legacy-code is vaak over jaren gebouwd rond de aannames „1 teken = 1 byte“, „PChar is PAnsiChar“ of „Length() komt overeen met byte-aantal“.

De typische oorzaken waarom migraties ingrijpender worden:

  • Implicitte conversies werken wel, maar veranderen data (vooral bij bestanden, interfaces of database BLOB-/tekstvelden).
  • Byte-georiënteerde code (streams, buffers, hashing, encryptie) wordt ongemerkt fout als string-inhoud als bytes geïnterpreteerd wordt.
  • Derde partijen zijn soms ANSI-only of gebruiken eigen string-typen en callbacks.
  • Externe omgeving (Windows-API’s, COM, print/reporting, EDI, CSV, XML/JSON) verwacht bepaalde encodings.

Het doel moet daarom niet zijn om „zoveel mogelijk ongewijzigd te laten“, maar om doelgericht te veranderen waar dat nodig is: waar datastromen en encodings gedefinieerd moeten worden. Een nette Unicode-migratie is ook een kans om onduidelijke coderingsgrenzen eindelijk te documenteren en te testen.

Technische basis: Delphi-stringtypen, encodings en bijeffecten

string, UnicodeString, AnsiString, WideString – wat in het project echt telt

Voor de migratie is het cruciaal welke types aan interfaces en in kernfuncties gebruikt worden:

  • string: Sinds Delphi 2009 een UnicodeString (UTF-16, reference-counted, immutable semantics via Copy-on-Write).
  • AnsiString: Byte-string met gekoppelde codepage (afhankelijk van Delphi-versie kan een codepage bewaard worden). Geschikt als een externe interface expliciet een bepaalde 8-bit codering verlangt.
  • UTF8String: In nieuwere Delphi-versies vaak alias/AnsiString met UTF-8-codepage; praktisch voor REST/JSON en veel protocollen.
  • WideString: BSTR (COM), geheugen beheerd via SysAllocString; tegenwoordig meestal alleen nodig voor specifieke COM-interops.
  • PChar: Sinds Unicode-Delphi PWideChar. Dit is één van de meest voorkomende breekpunten bij Windows-API-calls.

Als deze types gemengd worden, ontstaan conversies. Sommige zijn correct, andere verrassend: een conversie is alleen „juist“ als u weet welke codepage aan de bron ligt en welke aan de bestemming verwacht wordt.

UTF-16 intern, UTF-8 extern: een praktisch leidraad

In Delphi-VCL-applicaties is het vaak zinvol intern consequent met string (UTF-16) te werken. Extern (REST, bestanden, messaging) domineert in de praktijk UTF-8. Een robuuste lijn is dus:

  • Intern: string/UnicodeString als standaard.
  • Grenzen: bij in-/uitgang expliciet converteren via TEncoding.UTF8 (of gedefinieerde ANSI-codepages).
  • Byte-gebaseerde verwerking: TBytes in plaats van strings.

Dat reduceert impliciete conversies en maakt verantwoordelijkheden toetsbaar: „Waar worden bytes tekst, en met welke encoding?“

Inventaris: waar Unicode in oude Delphi-projecten typisch breekt

Voordat u code aanraakt, loont een gestructureerde inventarisatie. In de Unicode-migratie van oude Delphi-projecten zijn de foutbronnen meestal niet gelijkmatig verdeeld, maar geconcentreerd op enkele hotspots.

1) Database-toegang en veldtypes (BDE, ADO, FireDAC)

Veel legacy-projecten gebruiken nog BDE of oudere data-access-lagen. Hier komen de problemen vaak voor:

  • Toewijzing van database-charsets aan Delphi-strings (ANSI vs. Unicode-veldtypes).
  • „Tekst“ in BLOBs of memo-velden zonder gedefinieerde codering.
  • SQL-statements als strings die bij umlauts/Unicode-tekens verschillend geïnterpreteerd worden.

Als er toch al gemoderniseerd wordt, laat een Unicode-migratie zich goed combineren met een opschoning van de data-toegang, bijvoorbeeld richting BDE-Ablosung mit nativer Anbindung en eenduidige charset-configuratie (zoals bij PostgreSQL of MariaDB). Belangrijk: een migratie hoeft niet automatisch een database-migratie te forceren, maar de interface tussen DB en Delphi moet ondubbelzinnig zijn.

2) Bestands- en stream-I/O: CSV, INI, propriëtaire formaten, import/export

Een klassieker: bestanden werden vroeger gelezen/geschreven met AssignFile/ReadLn, TFileStream of TStringList.LoadFromFile zonder encoding in te stellen. In Unicode-Delphi bepaalt dan de runtime heuristisch (BOM) of gebruikt default-encodings. Dat leidt tot:

  • verkeerd geïnterpreteerde umlauts (ä, ö) in CSV/logbestanden,
  • foute lengteaanduidingen in propriëtaire formaten,
  • incompatibiliteiten met externe partners die ISO-8859-1 of Windows-1252 verwachten.

Een nette oplossing is per bestandsformaat een vaste encoding te definiëren en die in code en documentatie vast te leggen. Voor CSV/JSON is UTF-8 meestal de juiste standaard; voor oude interfaces soms Windows-1252. Beslissend is explicietheid.

3) Windows-API, PChar, buffergroottes en message-handling

Veel Delphi-applicaties roepen WinAPI-functies aan of werken met buffers. Veelvoorkomende breekpunten:

  • Gebruik van PChar in combinatie met functies die ANSI- of Wide-varianten hebben (…A/…W).
  • Buffergroottes worden in bytes gerekend, maar Char is in UTF-16 2 byte.
  • Pointer-arithmetic en record-layouts die op 1-byte-chars zijn gebaseerd.

Hier is precies refactoren nodig: ofwel consequent Wide-API’s gebruiken of bewust de ANSI-variant aanroepen en met AnsiString/codepage werken. „Het compileert ergens“ is geen kwaliteitscriterium.

4) COM, ActiveX, Office-automatisering en derdebibliotheken

COM-interfaces werken veelal met BSTR (WideString). Oude Delphi-versies hadden andere default-strings, waardoor code „toevallig“ werkte. In Unicode-Delphi ontstaan vaak dubbele conversies of verkeerde type-aannames in wrappers. Derdebibliotheken zijn eveneens kritisch: sommige leveren callbacks als PAnsiChar, andere verwachten null-terminated byte-strings.

Het loont om afhankelijkheden te classificeren: welke bibliotheek is Unicode-ready, welke niet, en welke kan worden vervangen of gekapseld? Kapseling is vaak de snelste manier om Unicode-legacy naar een helder begrensd gebied te verplaatsen.

Strategie: Unicode-migratie van oude Delphi-projecten als gecontroleerd moderniseringsprogramma

De migratie met de minste risico’s is een meerstapsprogramma dat risico’s vroeg zichtbaar maakt en de applicatie gedurende het proces operationeel houdt.

Stap 1: scope definiëren en code-hotspots prioriteren

Niet iedere broncode heeft direct aanpassingen nodig. Prioriteer op basis van datastromen en risico:

  • Interfaces naar buiten (REST-API, TCP/IP, bestanden, e-mail, print/reporting).
  • Data-toegang (SQL, ORM/Datamodule, BDE/FireDAC-lagen).
  • String-nahe utility-functies (parser, formatter, encoder/decoder).
  • Integraties (COM, DLL-imports, hardware-koppelingen).

Het resultaat moet een lijst zijn waar „encoding een specificatie is“. Die plekken worden later testbaar gemaakt.

Stap 2: compiler-/projectopties en waarschuwingen bewust scherper zetten

In veel projecten zijn waarschuwingen jarenlang uitgezet. Voor een Unicode-migratie werkt dat contraproductief. Het is zinvol waarschuwingen weer aan te zetten en conversiewaarschuwingen serieus te nemen. Daarnaast helpt het om projectbreed regels vast te leggen, bijvoorbeeld: geen impliciete AnsiString-conversies bij I/O-grenzen, gebruik van TEncoding bij file-operations, geen „PChar-trucs“ zonder duidelijke context.

Stap 3: „encoding-grenzen“ als technische laag invoeren

Een praktische architectuurgreep is het introduceren van kleine adapters/helpers die precies definiëren hoe externe data naar binnen en naar buiten gaat. Voorbeelden:

  • CSV-reader/-writer: altijd met TEncoding.UTF8 (of gedefinieerde codepage) en duidelijke separatorregels.
  • REST-client/server: JSON altijd als UTF-8-bytes, headers correct zetten, body niet als „string-gebaseerde“ stream behandelen.
  • Windows-API-wrapper: centrale functies die Wide/Ansi netjes kapselen.

Zo voorkomt u dat „encoding-beslissingen“ zich door de hele codebase verspreiden.

Typische code-valkuilen en hoe ze netjes te verhelpen

Length, SizeOf, ByteLength: als tekenlengte en bytegrootte uit elkaar lopen

In ANSI-tijden werd Length(s) vaak misbruikt als byte-aantal. In UTF-16 is dat onjuist. Als u byte-arrays nodig hebt, converteer expliciet:

  • Voor UTF-8: TEncoding.UTF8.GetBytes(s)
  • Voor gedefinieerde ANSI-codepage: TEncoding.GetEncoding(1252).GetBytes(s) (alleen als dat inhoudelijk klopt)

Voor buffergroottes bij API-calls geldt: controleer of de functie teken- of byte-eenheden verwacht. Veel Wide-API’s verwachten aantal tekens, niet bytes. Documentatie en signatuur bepalen, niet intuïtie.

PAnsiChar vs. PWideChar: DLL-imports en externe protocollen

Bij DLL-imports is het risico groot dat signaturen in de Delphi-code niet meer passen. Leg vast wat de DLL verwacht:

  • Verwacht de DLL UTF-8? Dan is doorgeven als PAnsiChar(UTF8String) gebruikelijk, maar u moet levensduur en nul-terminatie controleren.
  • Verwacht ze UTF-16? Dan gebruikt u PWideChar en wide-strings.

In alle gevallen moeten de imports in een aparte unit worden gekapseld, zodat de string-policy zich niet door het hele project verspreidt.

Formattering, case-conversie, vergelijking: locale en normalisatie

Unicode brengt ook semantische onderwerpen: hoofd-/kleine letters is niet in alle talen triviaal, en tekens kunnen verschillende normalisatievormen hebben. In typische bedrijfsapplicaties is dat minder kritisch dan in consumer-tekstverwerking, maar het raakt:

  • sortering en filtering (bijv. in grids of zoekfuncties),
  • case-insensitive vergelijkingen voor sleutelwaarden,
  • generatie van bestandsnamen of identifiers.

Belangrijk is een duidelijke regel: wat zijn „sleutels“ (bijv. artikelnummer, klantcodes) die ASCII-achtig moeten blijven, en wat zijn „teksten“ die volledig Unicode-compatibel moeten zijn? Die scheiding reduceert vervolgschade.

GUI/Reporting: fonts, print, PDF en component-gedrag

VCL is sinds de Unicode-versies in principe Unicode-capabel, maar in de praktijk hangt het af van componenten en outputpaden. Risico’s ontstaan bij:

  • oudere report-engines of PDF-generatoren die ANSI verwachten,
  • barcode-/labelprint die specifieke codepages nodig heeft,
  • hardcoded fonts of tekenverzamelingen.

Plan vroeg tests met reële voorbeelddata (namen, plaatsen, speciale tekens, niet-Latijnse schriftsystemen indien relevant). De waarde zit minder in „kan Unicode“ dan in bewijs: „Deze output is in onze context correct.“

Data en persistentie: Unicode eindigt niet bij de code

Database-charsets en collations eenduidig vastleggen

Een Unicode-migratie is alleen stabiel als databases en drivers correct geconfigureerd zijn. Voorbeelden:

  • Bij PostgreSQL is UTF-8 doorgaans standaard; toch moeten client-encoding en drivergedrag gecontroleerd worden.
  • Bij SQL Server is het onderscheid tussen VARCHAR en NVARCHAR relevant; verkeerde kolomkeuze kan tekens verliezen.
  • Bij MariaDB/MySQL zijn charset/collation (bijv. utf8mb4) cruciaal zodat 4-byte-tekens niet afgesneden worden.

In de Delphi-code moeten parameters en veldtypes zo gebruikt worden dat Unicode niet onderweg „terugvertaald“ wordt. FireDAC biedt hier meestal betere controle dan zeer oude toegangslagen.

Legacy-bestandsformaten: migratieregels in plaats van stille conversie

Als uw applicatie over jaren bestanden heeft geproduceerd (exportformaten, archiefbestanden, propriëtaire structuren), moet u definiëren:

  • Welke bestaande bestanden „zoals ze zijn“ blijven en bij het lezen correct geïnterpreteerd worden?
  • Welke formaten naar UTF-8 worden opgewaardeerd?
  • Zijn er versievelden/headers om nieuwe en oude bestanden ondubbelzinnig te onderscheiden?

Stille conversie zonder markering is riskant omdat fouten vaak pas laat opduiken. Beter: versieer, herken duidelijk en migreer doelgericht.

Kwaliteitsborging: tests die Unicode-problemen daadwerkelijk vinden

Unicode-fouten zijn vaak data-afhankelijk. Daarom volstaan „happy path“-tests niet. Een effectief testset dekt de probleemgebieden:

  • Roundtrip-tests: import → verwerking → export, daarna byte-nauwkeurige vergelijking (bij gedefinieerde formaten).
  • DB-roundtrip: schrijven/lezen van teksten met umlauts, accenten en eventueel niet-Latijnse tekens; controle op gelijkheid.
  • Interface-tests: REST-requests als UTF-8, headers, JSON-escaping, logging.
  • Regressie: oude data en typische gebruikersscenario’s reproduceren, vooral bij zoeken, filteren, sorteren.

Voor B2B-systemen is het verder relevant dat fouten observeerbaar worden: logging mag encodings niet kapotmaken. Wie logs als ANSI wegschrijft, verliest bij een incident precies de informatie die nodig is.

Planning en inspanning: wat de complexiteit echt drijft

De inspanning van de Unicode-migratie van oude Delphi-projecten hangt minder af van „aantal regels code“ en meer van coupling en externe afhankelijkheden:

  • Veel integraties (DLL’s, COM, devices, ERP/DMS/CRM) verhogen de toetslast omdat encodings op elke grens relevant zijn.
  • Historische formaten (oude exports, klant-specifieke CSV’s) vereisen migratieregels en compatibiliteitsstrategieën.
  • Gemengde Delphi-versies of meerdere producten uit een code-stam verhogen coördinatiebehoefte.
  • Oude data-access-lagen (bijv. BDE) kunnen Unicode indirect blokkeren en modernisering noodzakelijk maken.

In de praktijk heeft zich een aanpak bewezen waarbij Unicode eerst in de kern en in de meest kritische datastromen gestabiliseerd wordt. Daarna kunnen modules stapsgewijs worden bijgewerkt. Dat vermindert risico en voorkomt lange „big bang“-fases zonder release.

Inpassing in moderniseringspaden: REST, services, multiplatform

Unicode is vaak een fundament wanneer legacy-software gemoderniseerd moet worden. Typische vervolgvragen zijn:

  • REST-servers of REST-API’s toevoegen (JSON/UTF-8 correct behandelen).
  • Windows-services of Linux-services stabiel exploiteren (logging, configbestanden, protocollen).
  • Stapsgewijze UI-modernisering in VCL, later eventueel multiplatform-clients.

Belangrijk is de volgorde: als u nieuwe interfaces bouwt, moeten encoding-regels vooraf staan. Een Unicode-migratie „ernaast“ tijdens interface-ontwikkeling leidt anders tot moeilijk toetsbare fouten omdat oorzaak en effect verward raken.

Voor interne linking in het magazine is het nuttig verwante onderwerpen als Delphi-modernisering, FireDAC-data-toegang of architectuur van REST-servers als verdiepende artikelen te plaatsen, zodat lezers gericht naar de volgende technische stap kunnen springen.

Conclusie: Unicode-migratie is een risico-onderwerp – met de juiste methode maakbaar

De Unicode-migratie van oude Delphi-projecten is geen cosmetische upgrade, maar een correctie van fundamentele aannames over tekst, bytes en interfaces. Wie gestructureerd te werk gaat, wint echter meer dan „umlauts werken weer“: datastromen worden eenduidiger, integraties robuuster en latere modernisering (bijv. REST-servers, services, database-opruiming) eenvoudiger, omdat encodings niet meer impliciet „ergens“ gebeuren.

Als u voor uw Delphi-applicatie een concreet migratieplan, een risicoanalyse van hotspots of ondersteuning bij de uitvoering nodig heeft, is de snelste volgende stap een technisch eerste gesprek over uw randvoorwaarden en afhankelijkheden: contact opnemen.

In het vakgebied spelen ook Delphi Unicode Migration en Delphi Ansi Zu Unicode een belangrijke rol wanneer integraties, datastromen en verdere ontwikkeling netjes moeten samenwerken.

Projekt oder Modernisierungsvorhaben mit Net-Base besprechen.

Bericht delen

Dit bericht direct delen

LinkedIn, X, XING, Facebook, WhatsApp en e-mail zijn direct beschikbaar. Voor Instagram bereiden we de link en een korte tekst direct voor.

E-mail

Instagram opent in een nieuw tabblad. Link en korte tekst worden van tevoren naar het klembord gekopieerd.