Net-Base Magasin

19.04.2026

Unicode-migrering af ældre Delphi-projekter: faldgruber, strategi og ren implementering

Mange eksisterende Delphi-applikationer arbejder stadig med ANSI-strenge. En Unicode-migrering er mere end et compiler-flag: den omfatter dataadgang, grænseflader, rapporter, tredjepartsbiblioteker og tests. Denne artikel viser en praksisnær migreringsvej – inkl...

19.04.2026

Unicode-migreringen af ældre Delphi-projekter er i mange virksomheder et nødvendigt skridt, fordi eksisterende applikationer ellers støder på begrænsninger ved internationale data, moderne operativsystemer, integrationer og nye interfaces. I praksis er det sjældent et „recompile og færdigt“. Delphi har siden Unicode-versionerne (fra Delphi 2009) foretaget fundamentale ændringer af standard-string-typene. Dermed flyttes antagelser om tegnkodning, hukommelseslayout og API-signaturer. Den, der undervurderer det, producerer snigende datafejl, ødelagte eksporter, uklare supporttilfælde og sikkerhedsrisici.

Denne artikel giver en teknisk holdbar fremgangsmåde: Hvordan I analyserer bestanden, afgrænser scope fornuftigt, reducerer risici ved hotspots (databaser, filer, Windows-APIer, COM, REST-services) og sikrer migreringen, så drift og videreudvikling kan køre parallelt. Fokus er på Delphi-typiske faldgruber i VCL-applikationer, services og grænseflader – med blik for moderniseringsveje, hvori emner som BDE-afløsning med native tilslutning, REST-servere eller multiplatform senere kan placeres.

Hvorfor Unicode-omstillingen i Delphi så ofte er „større end antaget“

I klassiske Delphi-versioner var string en ANSI-string (afhængig af systemcodepage). Siden Delphi 2009 er string som standard en UnicodeString (UTF-16). Samtidig blev mange biblioteker og VCL-klasser omlagt til Wide-APIer. Det er i grunden positivt, fordi det robust understøtter internationale tegn. Men: Legacy-kode er ofte vokset over år omkring antagelserne „1 tegn = 1 byte“, „PChar er PAnsiChar“ eller „Length() svarer til byte-antal“.

De typiske årsager til, at migrationer bliver mere omfangsrige:

  • Implicitte konverteringer gennemføres visse steder, men ændrer data (især ved filer, interfaces eller database-blob-/tekstfelter).
  • Byte-orienteret kode (streams, buffere, hashing, kryptering) bliver ubemærket forkert, når string-indhold behandles som bytes.
  • Tredjepartskomponenter er delvist ANSI-only eller bruger egne string-typer og callbacks.
  • Eksternt miljø (Windows-APIer, COM, print/reporting, EDI, CSV, XML/JSON) forventer bestemte encodninger.

Målet bør derfor ikke være at „ændre så lidt som muligt“, men at ændre målrettet dér, hvor dataflow og encodninger skal defineres. En ordentlig Unicode-migrering er også en mulighed for endeligt at dokumentere og teste uklare kodningsgrænser.

Tekniske grundlag: Delphi-stringtyper, encodninger og deres bivirkninger

string, UnicodeString, AnsiString, WideString – hvad der virkelig betyder noget i projektet

For migreringen er det afgørende, hvilke typer der anvendes ved grænseflader og i kernefunktioner:

  • string: Siden Delphi 2009 en UnicodeString (UTF-16, reference-counted, immutable-semantik via Copy-on-Write).
  • AnsiString: Byte-string med tilknyttet codepage (afhængig af Delphi-version kan en codepage medføres). Velegnet når en ekstern grænseflade eksplicit kræver en bestemt 8-bit-encoding.
  • UTF8String: I nyere Delphi-versioner ofte som alias/AnsiString med UTF-8-codepage; praktisk til REST/JSON og mange protokoller.
  • WideString: BSTR (COM), hukommelsesadministreret via SysAllocString; i dag mest nødvendigt for bestemte COM-interops.
  • PChar: I Unicode-Delphi PWideChar. Det er et af de hyppigste sammenbrudspunkter ved Windows-API-calls.

Når disse typer blandes, opstår konverteringer. Nogle er korrekte, andre overraskende: En konvertering er kun „rigtig“, hvis I ved, hvilken codepage der findes ved kilden, og hvad målet forventer.

UTF-16 internt, UTF-8 eksternt: en praksisorienteret rettesnor

I Delphi-VCL-applikationer giver det ofte mening at arbejde konsekvent internt med string (UTF-16). Eksternt (REST, filer, messaging) dominerer i praksis UTF-8. En robust linje er derfor:

  • Internt: string/UnicodeString som standard.
  • Grænser: Ved input/output eksplicit konvertere via TEncoding.UTF8 (eller definerede ANSI-codepages).
  • Byte-baseret behandling: TBytes i stedet for strings.

Det reducerer implicitte konverteringer og gør ansvarsfordelingen kontrollerbar: „Hvor bliver bytes til tekst, og med hvilken encoding?“

Statusopgørelse: Hvor Unicode typisk bryder i gamle Delphi-projekter

Før I rører ved kode, er en struktureret inventar nyttig. I Unicode-migreringen af ældre Delphi-projekter er fejlene ofte ikke jævnt fordelt, men koncentreret i nogle hotspots.

1) Databaseadgang og felttyper (BDE, ADO, FireDAC)

Mange ældre projekter bruger stadig BDE eller ældre dataadgangslag. Her er problemerne ofte:

  • Tildeling af database-charset til Delphi-strings (ANSI vs. Unicode-felttyper).
  • „Tekst“ i BLOBs eller memo-felter uden defineret kodning.
  • SQL-udtryk som strings, der ved umlauter/Unicode-tegn kan fortolkes forskelligt.

Hvis der alligevel planlægges modernisering, kan en Unicode-migrering kombineres med oprydning af dataadgangen, fx mod BDE-Ablosung mit nativer Anbindung og klar charset-konfiguration (som fx ved PostgreSQL eller MariaDB). Vigtigt: En migrering bør ikke automatisk tvinge en database-migrering, men grænsefladen mellem DB og Delphi skal være entydig.

2) Fil- og stream-I/O: CSV, INI, proprietære formater, import/eksport

En klassiker: Filer blev tidligere læst/skrevet med AssignFile/ReadLn, TFileStream eller TStringList.LoadFromFile uden at sætte encoding. I Unicode-Delphi beslutter så miljøet heuristisk (BOM) eller bruger default-encodings. Det fører til:

  • forkert fortolkede umlauter (ä, ö) i CSV/logfiler,
  • fejl i længdeangivelser i proprietære formater,
  • inkompatibiliteter med eksterne partnere, der forventer ISO-8859-1 eller Windows-1252.

En ren løsning er at definere et fast encoding pr. filformat og forankre det i kode og dokumentation. For CSV/JSON er UTF-8 som regel den rigtige standard; for gamle interfaces nogle gange Windows-1252. Det afgørende er eksplicithed.

3) Windows-API, PChar, bufferstørrelser og message-håndtering

Mange Delphi-applikationer kalder WinAPI-funktioner eller arbejder med buffere. Hyppige brudflader:

  • Brug af PChar sammen med funktioner, der har ANSI- eller Wide-varianter (…A/…W).
  • Bufferstørrelser regnes i bytes, men Char er i UTF-16 2 byte.
  • Pointeraritmetik og record-layouts, der antager 1-byte-chars.

Her kræves præcist refactoring: enten konsekvent bruge Wide-APIer eller bevidst kalde ANSI-varianten og arbejde med AnsiString/codepage. „Det kompilerer på en eller anden måde“ er ikke et kvalitetskriterium.

4) COM, ActiveX, Office-automation og tredjepartsbiblioteker

COM-interfaces arbejder ofte med BSTR (WideString). Ældre Delphi-versioner havde andre default-strings, så kode kunne passe „tilfældigt“. I Unicode-Delphi opstår ofte dobbelte konverteringer eller forkerte typeantagelser i wrappers. Tredjepartsbiblioteker er ligeledes kritiske: Nogle leverer callbacks som PAnsiChar, andre forventer nullterminerede byte-strings.

Her er det nyttigt at klassificere afhængigheder: Hvilket bibliotek er Unicode-ready, hvilket er ikke, og hvilket kan udskiftes eller kapsles ind? En kapsling er ofte den hurtigste vej til at isolere Unicode-legacy i et klart afgrænset område.

Strategi: Unicode-migrering af ældre Delphi-projekter som et kontrolleret moderniseringsprogram

Den migrationssikreste fremgangsmåde er et flertrinsprogram, der gør risici synlige tidligt og holder applikationen kørende.

Trin 1: Definér scope og prioriter kode-hotspots

Ikke al kildekode behøver øjeblikkeligt ændringer. Prioritér efter dataflow og risiko:

  • Eksterne grænseflader (REST-API, TCP/IP, filer, e-mail, print/reporting).
  • Dataadgang (SQL, ORM/datamoduler, BDE/FireDAC-lag).
  • String-nære utilities (parsers, formatters, encoder/decoder).
  • Integrationer (COM, DLL-imports, hardware-tilslutninger).

Resultatet bør være en liste over steder, hvor „encoding er en specifikation“. Disse punkter gøres testbare senere.

Trin 2: Slib compiler-/projektindstillinger og advarsler skarpt

I mange projekter er advarsler blevet slået fra gennem årene. Til en Unicode-migrering er det kontraproduktivt. Genaktiver advarsler og tag konverteringsadvarsler alvorligt. Derudover hjælper det at fastsætte projektomfattende regler, fx: ingen implicitte AnsiString-konverteringer ved I/O-grænser, brug af TEncoding ved filoperationer, ingen „PChar-tricks“ uden klart kontekst.

Trin 3: Indfør „encoding-grænser“ som en teknisk lag

Et praktisk arkitekturgreb er introduktionen af små adaptere/helpers, der entydigt definerer, hvordan eksterne data kommer ind og ud. Eksempler:

  • CSV-reader/-writer: altid med TEncoding.UTF8 (eller defineret codepage) og klare separatorregler.
  • REST-client/server: JSON altid som UTF-8-bytes, headers sat korrekt, body ikke „stringbaseret“ streamet.
  • Windows-API-wrapper: centrale funktioner, der rent kapsler Wide/Ansi.

Så forhindrer I, at „encoding-beslutninger“ spredes tilfældigt i kodebasen.

Typiske kodefælder og hvordan man retter dem korrekt

Length, SizeOf, ByteLength: når tegnlængde og bytestørrelse adskiller sig

I ANSI-tider blev Length(s) ofte misbrugt som byteantal. I UTF-16 er det forkert. Når I har brug for byte-arrays, så konverter eksplicit:

  • For UTF-8: TEncoding.UTF8.GetBytes(s)
  • For en defineret ANSI-codepage: TEncoding.GetEncoding(1252).GetBytes(s) (kun når det er fagligt korrekt)

For bufferstørrelser ved API-calls gælder: Tjek om funktionen forventer tegn- eller byte-enheder. Mange Wide-APIer forventer tegnantal, ikke bytes. Dokumentation og signatur afgør, ikke intuition.

PAnsiChar vs. PWideChar: DLL-imports og eksterne protokoller

Ved DLL-imports er risikoen stor for, at signaturer i Delphi-koden ikke længere passer. Fastlæg, hvad DLL’en forventer:

  • Forventer DLL’en UTF-8? Så er overlevering som PAnsiChar(UTF8String) almindeligt, men I skal kontrollere levetid og null-terminering.
  • Forventer den UTF-16? Så brug PWideChar og wide-strings.

Under alle omstændigheder bør imports kapsles i en separat unit, så string-politikken ikke spredes gennem hele projektet.

Formatering, case-konvertering, sammenligning: locale og normalisering

Unicode medfører også semantiske emner: store-/småbogstaver er ikke trivialt i alle sprog, og tegn kan have forskellige normalformer. I typiske virksomhedsapplikationer er det mindre kritisk end i consumer-tekstbehandling, men det berører:

  • sortering og filtrering (fx i grids eller søgefunktioner),
  • case-insensitive sammenligninger for nøgleværdier,
  • generering af filnavne eller identifikatorer.

Det er vigtigt at have en klar regel: Hvad er „nøgler“ (fx artikelnumre, kundekoder), som bør holdes ASCII-nære, og hvad er „tekster“, der skal være fuldt Unicode-kompatible? Den adskillelse reducerer efterfølgende fejl.

GUI/reporting: skrifttyper, print, PDF og komponentadfærd

VCL er siden Unicode-versionerne grundlæggende Unicode-kompatibel, men i praksis afhænger det af komponenter og output-paths. Risici opstår ved:

  • ældre rapport-engines eller PDF-generatorer, der antager ANSI,
  • stregkode-/label-printere, der kræver bestemte codepages,
  • hardkodede fonte eller tegnsæt.

Planlæg tidlige tests med realistiske eksempeldata (navne, steder, specialtegn, ikke-latinske skriftsæt hvis relevant). Værdien ligger ikke i „kan Unicode“, men i dokumenteret bevis: „Dette output er korrekt i vores kontekst.“

Data og persistens: Unicode stopper ikke ved koden

Fastlæg database-charsets og collations korrekt

En Unicode-migrering er kun stabil, når databaser og drivere er korrekt konfigureret. Eksempler:

  • Hos PostgreSQL er UTF-8 normalt standard; alligevel skal client-encoding og driveradfærd kontrolleres.
  • Hos SQL Server er sondringen mellem VARCHAR og NVARCHAR relevant; forkerte kolonner kan miste tegn.
  • Hos MariaDB/MySQL er charset/collation (fx utf8mb4) afgørende, så 4-byte-tegn ikke afskæres.

I Delphi-koden bør parameterer og felttyper anvendes, så Unicode ikke „konverteres tilbage“ på vejen. FireDAC giver her ofte bedre kontrol end meget gamle adgangslag.

Legacy-filformater: migrationsregler i stedet for stille konvertering

Hvis jeres applikation over år har produceret filer (eksportformater, arkivfiler, proprietære strukturer), skal I definere:

  • Hvilke eksisterende filer forbliver „som de er“ og læses korrekt?
  • Hvilke formater opgraderes til UTF-8?
  • Findes der versionsfelter/headers, så nye og gamle filer tydeligt kan skilles?

Stille konvertering uden markering er risikabelt, fordi fejl ofte først opdages sent. Bedre: versionér, identificér klart og migrér målrettet.

Kvalitetssikring: tests der faktisk finder Unicode-problemer

Unicode-fejl er ofte dataafhængige. Derfor er „happy path“-tests utilstrækkelige. Et testset bør dække de problematiske områder:

  • Roundtrip-tests: Import → behandling → eksport, efterfølgende byte-nøjagtig sammenligning (for definerede formater).
  • DB-roundtrip: Skriv/læs tekster med umlauter, accenter og eventuelt ikke-latinske tegn; test for lighed.
  • Interface-tests: REST-requests som UTF-8, headers, JSON-escaping, logging.
  • Regression: Reproducer gamle data og typiske brugerflows, især ved søgning, filtrering, sortering.

For B2B-systemer er det derudover vigtigt, at fejl er observerbare: Logging bør ikke ødelægge encodninger. Den, der skriver logs som ANSI, mister i fejltilfælde netop den information, man har brug for.

Planlægning og indsats: Hvad der reelt driver kompleksiteten

Indsatsen i Unicode-migreringen af ældre Delphi-projekter afhænger mindre af „linjer kode“ og mere af koblinger og eksterne afhængigheder:

  • Mange integrationer (DLLs, COM, enheder, ERP/DMS/CRM) øger testomfanget, fordi encodinger er relevante ved hver grænse.
  • Historiske formater (gamle eksporter, kundespecifikke CSV’er) kræver migrationsregler og kompatibilitetsstrategier.
  • Blandede Delphi-versioner eller flere produkter fra én kodebase øger koordineringsbehovet.
  • Gamle dataadgangslag (fx BDE) kan indirekte blokere Unicode og pege mod modernisering.

I praksis har en strategi vist sig effektiv, hvor Unicode først stabiliseres i kernen og i de mest kritiske dataflows. Derefter kan moduler gradvist bringes med. Det reducerer risiko og undgår lange „big bang“-faser uden release.

Placering i moderniseringsveje: REST, services, multiplatform

Unicode er ofte en grundpille, når legacy-software skal moderniseres. Typiske opfølgende spørgsmål er:

  • REST-servere eller REST-APIer kan tilføres (JSON/UTF-8 håndteres korrekt).
  • Windows-services eller Linux-services kan drives stabilt (logging, konfigfiler, protokoller).
  • Trinvis UI-modernisering i VCL, senere eventuelt multiplatform-klienter.

Rækkefølgen er vigtig: Når I bygger nye interfaces, bør encoding-regler være fastlagt på forhånd. En Unicode-migrering „ved siden af“ under interfaceudvikling leder ellers til svære at teste fejlbilleder, fordi årsag og virkning blandes sammen.

Til intern linkning i magasinet giver det mening at samle relaterede emner som Delphi-modernisering, FireDAC-dataadgang eller arkitektur for REST-servere som uddybende artikler, så læseren kan gå videre til næste tekniske trin.

Konklusion: Unicode-migrering er et risikoområde – med den rette metode bliver det planlagt

Unicode-migreringen af ældre Delphi-projekter er ikke et kosmetisk upgrade, men en korrektion af grundlæggende antagelser om tekst, bytes og grænseflader. Den, der arbejder struktureret, opnår dog mere end „umlauter virker igen“: Dataflows bliver entydige, integrationer mere robuste, og efterfølgende modernisering (fx REST-servere, services, databaseoprensning) bliver enklere, fordi encodninger ikke længere sker implicit „et eller andet sted“.

Hvis I til jeres Delphi-applikation har brug for en konkret migreringsplan, en risikoanalyse af hotspots eller støtte til implementering, er det hurtigste næste skridt et teknisk indledende møde om jeres rammebetingelser og afhængigheder: Kontakt os.

I det faglige miljø spiller også Delphi Unicode Migration og Delphi Ansi Zu Unicode en vigtig rolle, når integrationer, dataflows og videreudvikling skal spille sammen.

Projekt eller moderniseringsprojekt drøftes med Net-Base.

Del indlæg

Del dette indlæg direkte

LinkedIn, X, XING, Facebook, WhatsApp og e-mail er straks tilgængelige. Til Instagram forbereder vi link og kort tekst med det samme.

E-mail

Instagram åbner i en ny fane. Linket og kortteksten kopieres på forhånd til udklipsholderen.