Unicode-migrasjonen av eldre Delphi-prosjekter er i mange virksomheter et nødvendig skritt, fordi eksisterende applikasjoner ellers i økende grad møter begrensninger ved internasjonale data, moderne operativsystemer, integrasjoner og nye grensesnitt. I praksis er dette sjelden et «recompile og ferdig». Delphi har siden Unicode-versjonene (fra Delphi 2009) innført fundamentale endringer i standard string-typene. Dermed forskyves antakelser om tegnkoding, minnelayout og API-signaturer. Den som undervurderer dette, risikerer gradvise datafeil, ødelagte eksportfiler, uklare supporttilfeller og sikkerhetsproblemer.
Denne artikkelen gir en teknisk underbygd fremgangsmåte: Hvordan dere analyserer beholdningen, avgrenser scope fornuftig, reduserer risiko ved hotspots (databaser, filer, Windows-APIer, COM, REST-tjenester) og sikrer migrasjonen slik at drift og videreutvikling kan foregå parallelt. Fokuset ligger på Delphi-typiske fallgruver i VCL-applikasjoner, tjenester og grensesnitt – med tanke på moderniseringsveier hvor temaer som BDE-utskifting med native tilkobling, REST-servere eller multiplattform senere kan plasseres.
Hvorfor Unicode-omstilling i Delphi ofte er «større enn antatt»
I klassiske Delphi-versjoner var string en ANSI-string (avhengig av systemets codepage). Siden Delphi 2009 er string som standard en UnicodeString (UTF-16). Samtidig ble mange biblioteker og VCL-klasser konvertert til Wide-APIer. Det er i utgangspunktet positivt, fordi det gir robust støtte for internasjonale tegn. Men: Legacy-kode har ofte vokst fram over år rundt antakelsene «1 tegn = 1 byte», «PChar er PAnsiChar» eller «Length() tilsvarer byte-antall».
Typiske årsaker til at migrasjoner blir mer omfattende:
- Implisitte konverteringer kan virke, men endrer data (særlig for filer, grensesnitt eller database-blob-/tekstfelt).
- Byte-orientert kode (streams, buffere, hashing, kryptering) blir usynlig feil hvis string-innhold tolkes som bytes.
- Tredjepartskomponenter er delvis ANSI-only eller bruker egne string-typer og callbacks.
- Eksternt miljø (Windows-APIer, COM, utskrift/reporting, EDI, CSV, XML/JSON) forventer bestemte encodings.
Målet bør derfor ikke være å «endre minst mulig», men å endre målrettet der dataflyt og encoding må defineres. En ryddig Unicode-migrasjon er også en mulighet til endelig å dokumentere og teste uklare kodingsgrenser.
Tekniske grunnprinsipper: Delphi-stringtyper, encodings og bivirkninger
string, UnicodeString, AnsiString, WideString – hva som virkelig betyr noe i prosjektet
For migrasjonen er det avgjørende hvilke typer som brukes i grensesnitt og i kjernefunksjoner:
- string: Siden Delphi 2009 en UnicodeString (UTF-16, reference-counted, immutable-semantikk via Copy-on-Write).
- AnsiString: Byte-string med tilordnet codepage (avhengig av Delphi-versjon kan en codepage være lagret). Egnet når et eksternt grensesnitt eksplisitt krever en bestemt 8-bits koding.
- UTF8String: I nyere Delphi-versjoner ofte alias/AnsiString med UTF-8-codepage; praktisk for REST/JSON og mange protokoller.
- WideString: BSTR (COM), minnehåndtert via SysAllocString; i dag som regel bare nødvendig for spesifikke COM-interoperabiliteter.
- PChar: I Unicode-Delphi er dette PWideChar. Dette er ett av de vanligste brytningspunktene ved Windows-API-kall.
Når disse typene blandes, oppstår konverteringer. Noen er korrekte, andre overraskende: En konvertering er bare «riktig» når du vet hvilken codepage som er ved kilden og hvilken som forventes ved målet.
UTF-16 internt, UTF-8 eksternt: et praktisk prinsipp
I Delphi-VCL-applikasjoner er det ofte fornuftig å jobbe internt konsekvent med string (UTF-16). Eksternt (REST, filer, meldingssystemer) dominerer i praksis UTF-8. En robust linje er derfor:
- Internt: string/UnicodeString som standard.
- Grenser: Ved inn-/utgang konverteres eksplisitt via TEncoding.UTF8 (eller definerte ANSI-codepages).
- Byte-basert behandling: TBytes i stedet for Strings.
Det reduserer implisitte konverteringer og gjør ansvarspunkter målbare: «Hvor blir bytes til tekst, og med hvilken encoding?»
Bestandsanalyse: Hvor Unicode typisk bryter i gamle Delphi-prosjekter
Før dere endrer kode, lønner det seg med en strukturert inventarliste. I Unicode-migrasjoner av eldre Delphi-prosjekter er feilkildene sjelden jevnt fordelt, men konsentrert i enkelte hotspots.
1) Databaseaksess og felttyper (BDE, ADO, FireDAC)
Mange gamle prosjekter bruker fortsatt BDE eller eldre dataaksesslag. Typiske problemer her er:
- Tilhørighet mellom database-charset og Delphi-strings (ANSI vs. Unicode-felttyper).
- «Tekst» i BLOBs eller memo-felt uten definert koding.
- SQL-setninger som Strings, som ved umlauter/Unicode-tegn kan tolkes forskjellig.
Dersom modernisering uansett er planlagt, kan en Unicode-migrasjon kombineres med opprydding i dataaksessen, for eksempel mot BDE-Ablosung mit nativer Anbindung og klar charset-konfigurasjon (for eksempel ved PostgreSQL eller MariaDB). Viktig: En migrasjon bør ikke automatisk tvinge en database-migrasjon, men grensesnittet mellom DB og Delphi må være entydig.
2) Fil- og stream-I/O: CSV, INI, proprietære formater, import/eksport
En klassiker: Filer ble tidligere lest/skrevet med AssignFile/ReadLn, TFileStream eller TStringList.LoadFromFile uten å angi encoding. I Unicode-Delphi vil RTL ofte gjøre heuristiske valg (BOM) eller bruke standard-encodings. Det fører til:
- feiltolkede umlauter (ä, ö) i CSV/loggfiler,
- feil lengdeangivelse i proprietære formater,
- inkompatibilitet med eksterne parter som forventer ISO-8859-1 eller Windows-1252.
En ryddig løsning er å definere et fast encoding per filformat og forankre dette i kode og dokumentasjon. For CSV/JSON er UTF-8 vanligvis riktig standard; for eldre grensesnitt kan Windows-1252 være nødvendig. Det avgjørende er eksplisitthet.
3) Windows-API, PChar, bufferstørrelser og meldinghåndtering
Mange Delphi-applikasjoner kaller WinAPI-funksjoner eller jobber med buffere. Vanlige brytepunkter:
- Bruk av PChar sammen med funksjoner som har ANSI- eller Wide-varianter (…A/…W).
- Bufferstørrelser oppgis i bytes, men Char er i UTF-16 2 byte.
- Pointer-aritmetikk og record-layouts som antar 1-byte-chars.
Her kreves presist refaktorering: enten konsekvent bruke Wide-APIer eller bevisst kalle ANSI-varianten og arbeide med AnsiString/codepage. «Det kompilerer på en eller annen måte» er ikke et kvalitetskriterium.
4) COM, ActiveX, Office-automatisering og tredjbiblioteker
COM-grensesnitt arbeider ofte med BSTR (WideString). Gamle Delphi-versjoner hadde andre standardstrings, slik at kode «tilfeldigvis» fungerte. I Unicode-Delphi oppstår ofte doble konverteringer eller feil typeantagelser i wrappers. Tredjepartsbiblioteker er også kritiske: Noen leverer callbacks som PAnsiChar, andre forventer nullterminerte byte-strings.
Her lønner det seg å klassifisere avhengighetene: Hvilket bibliotek er Unicode-ready, hvilket er det ikke, og hva kan erstattes eller kapsles inn? Innkapsling er ofte den raskeste måten å avgrense Unicode-legacy til et veldefinert område.
Strategi: Unicode-migrasjon av gamle Delphi-prosjekter som kontrollert moderniseringsprogram
Den mest sikre fremgangsmåten er et trinnvis program som gjør risiko synlig tidlig og holder applikasjonen kjørbar underveis.
Trinn 1: Definer scope og prioriter kode-hotspots
Ikke all kildekode trenger umiddelbare endringer. Prioriter etter dataflyt og risiko:
- Grensesnitt utad (REST-API, TCP/IP, filer, e-post, utskrift/reporting).
- Dataaksess (SQL, ORM/Datamoduler, BDE/FireDAC-lag).
- String-nære utility-funksjoner (parser, formatter, encoder/decoder).
- Integrasjoner (COM, DLL-importer, hardware-tilknytninger).
Resultatet bør være en liste over steder hvor «encoding er en spesifikasjon». Disse stedene gjøres senere testbare.
Trinn 2: Skjerp compiler-/prosjektinnstillinger og advarsler
I mange prosjekter har advarsler vært skrudd av i årevis. For en Unicode-migrasjon er det kontraintuitivt. Det er fornuftig å aktivere advarsler igjen og ta konverteringsvarsler alvorlig. I tillegg hjelper det å fastsette prosjektomfattende regler, for eksempel: ingen implisitte AnsiString-konverteringer ved I/O-grenser, bruk av TEncoding ved filoperasjoner, ingen «PChar-triks» uten klar kontekst.
Trinn 3: Innfør «encoding-grenser» som teknisk lag
Et praktisk arkitekturgrep er å introdusere små adaptere/helper-klasser som entydig definerer hvordan ekstern data går inn og ut. Eksempler:
- CSV-leser/-skriver: alltid med TEncoding.UTF8 (eller definert codepage) og klare separatorregler.
- REST-klient/server: JSON alltid som UTF-8-bytes, korrekte header-felt, body ikke „string-basert“ streamet.
- Windows-API-wrapper: sentrale funksjoner som kapsler Wide/Ansi ryddig.
Slik forhindrer dere at «encoding-beslutninger» spres ustrukturert gjennom kodebasen.
Typiske kodefeller og hvordan rette dem korrekt
Length, SizeOf, ByteLength: når tegnlengde og bytestørrelse divergerer
I ANSI-tider ble ofte Length(s) misbrukt som byteantall. I UTF-16 er det feil. Når dere trenger byte-arrays, konverter eksplisitt:
- For UTF-8: TEncoding.UTF8.GetBytes(s)
- For definert ANSI-codepage: TEncoding.GetEncoding(1252).GetBytes(s) (kun når det er faglig korrekt)
For bufferstørrelser ved API-kall gjelder: Undersøk om funksjonen forventer tegn- eller byte-enheter. Mange Wide-APIer forventer antall tegn, ikke bytes. Dokumentasjon og signatur avgjør, ikke intuisjon.
PAnsiChar vs. PWideChar: DLL-importer og eksterne protokoller
Ved DLL-importer er faren stor for at signaturer i Delphi-koden ikke lenger stemmer. Avklar hva DLL-en forventer:
- Forventer DLL-en UTF-8? Da er det vanlig å sende PAnsiChar(UTF8String), men livstid og nullterminering må kontrolleres.
- Forventer den UTF-16? Da bruk PWideChar og wide-strings.
I alle tilfeller bør importene kapsles i en separat unit, slik at string-politikken ikke sprer seg gjennom hele prosjektet.
Formatering, case-konvertering, sammenligning: locale og normalisering
Unicode medfører også semantiske spørsmål: store/små bokstaver er ikke trivielt i alle språk, og tegn kan ha ulike normalformer. I typiske virksomhetsapplikasjoner er dette mindre kritisk enn i forbrukertekstbehandling, men det berører:
- sortering og filtrering (f.eks. i grids eller søkefunksjoner),
- case-insensitive sammenligninger for nøkkelverdier,
- generering av filnavn eller identifikatorer.
Viktig er en entydig regel: Hva er «nøkler» (f.eks. artikkelnummer, kundekoder) som bør holdes ASCII-nære, og hva er «tekst» som må være fullt Unicode-kompatibel? Denne adskillelsen reduserer følgeskader.
GUI/Reporting: fonter, utskrift, PDF og komponentoppførsel
VCL er siden Unicode-innføringen i prinsippet Unicode-kompatibelt, men i praksis avhenger resultatet av komponenter og utgangsveier. Risiko oppstår ved:
- eldre report-engines eller PDF-generatorer som forutsetter ANSI,
- strekkode-/etikettskriver som krever bestemte codepages,
- hardkodede fonter eller tegnsett.
Planlegg tidlige tester med reale eksempeldata (navn, steder, spesialtegn, ikke-latinske skriftsystemer der det er relevant). Verdien ligger mindre i «kan Unicode», og mer i å dokumentere: «Denne outputen er korrekt i vår kontekst.»
Data og persistens: Unicode stopper ikke ved koden
Sett database-charset og collations korrekt
En Unicode-migrasjon er stabil først når databaser og drivere er riktig konfigurert. Eksempler:
- For PostgreSQL er UTF-8 som regel standard; likevel må client-encoding og driveradferd verifiseres.
- For SQL Server er skillet mellom VARCHAR og NVARCHAR relevant; feil kolonnekategori kan miste tegn.
- For MariaDB/MySQL er charset/collation (f.eks. utf8mb4) avgjørende for at 4-byte-tegn ikke blir trunkert.
I Delphi-koden bør parametre og felttyper brukes slik at Unicode ikke blir «konvertert tilbake» på vei. FireDAC gir ofte bedre kontroll enn svært gamle aksesslag.
Legacy-filformater: migrasjonsregler i stedet for stille konvertering
Hvis applikasjonen deres har produsert filer over år (eksportformater, arkivfiler, proprietære strukturer), må dere definere:
- Hvilke eksisterende filer forblir «som de er» og skal leses korrekt?
- Hvilke formater skal oppgraderes til UTF-8?
- Finnes det versjonsfelt/headers for entydig å skille nye og gamle filer?
Stille konvertering uten merking er risikabelt, fordi feil ofte oppdages sent. Bedre: versjoner, gjenkjennelse og målrettet migrasjon.
Kvalitetssikring: tester som virkelig finner Unicode-problemer
Unicode-feil er ofte dataavhengige. Derfor er ikke «happy path»-tester nok. Et passende testsett bør dekke problemområdene:
- Roundtrip-tester: Import → behandling → eksport, deretter byte-nøyaktig sammenligning (for definerte formater).
- DB-roundtrip: skrive/lese tekster med umlauter, aksenter og eventuelt ikke-latinske tegn; sjekk for likhet.
- Grensesnittstester: REST-forespørsler som UTF-8, headers, JSON-escaping, logging.
- Regresjon: reproduser gamle data og typiske brukerflyter, særlig ved søk, filtrering og sortering.
For B2B-systemer er det også viktig at feil blir observerbare: logging må ikke ødelegge encodings. Den som skriver logger som ANSI, mister i feilsituasjoner nettopp den informasjonen man trenger.
Planlegging og omfang: hva som egentlig driver kompleksiteten
Arbeidsmengden ved Unicode-migrasjon av eldre Delphi-prosjekter avhenger mindre av «antall kodelinjer» og mer av koblinger og eksterne avhengigheter:
- Mange integrasjoner (DLLer, COM, enheter, ERP/DMS/CRM) øker testbehovet, fordi encoding ved hver grense er relevant.
- Historiske formater (gamle eksporter, kundespesifikke CSV-er) krever migrasjonsregler og kompatibilitetsstrategier.
- Blandet Delphi-versjoner eller flere produkter fra samme kodebase øker koordinasjonsbehovet.
- Gamle dataaksesslag (f.eks. BDE) kan indirekte blokkere Unicode og gjøre modernisering hensiktsmessig.
I praksis har en tilnærming vist seg effektiv: stabiliser Unicode først i kjernen og i de mest kritiske dataflytene. Deretter kan moduler tas etter hvert. Det reduserer risiko og unngår lange „big bang“-faser uten release.
Plassering i moderniseringsløp: REST, tjenester, multiplattform
Unicode er ofte en grunnpilar når legacy-programvare skal moderniseres. Typiske oppfølgingsspørsmål er:
- REST-servere eller REST-APIer for å ettermontere (sørg for korrekt behandling av JSON/UTF-8).
- Stabil drift av Windows-tjenester eller Linux-tjenester (logging, konfigfiler, protokoller).
- Trinnvis UI-modernisering i VCL, og eventuelt senere multiplattform-klienter.
Rekkefølgen er viktig: Når dere bygger nye grensesnitt, bør encoding-regler være avklart på forhånd. En Unicode-migrasjon «ved siden av» under grensesnittutvikling fører lett til vanskelig testbare feilbilder, fordi årsak og virkning blandes.
For intern linking i magasinet er det naturlig å plassere tilstøtende temaer som Delphi-modernisering, FireDAC-dataaksess eller arkitektur for REST-servere som fordypende artikler, slik at lesere kan gå direkte videre til neste tekniske steg.
Konklusjon: Unicode-migrasjon er et risikotema – med riktig metode blir det planleggbart
Unicode-migrasjonen av eldre Delphi-prosjekter er ikke et kosmetisk oppdateringsløp, men en korrigering av grunnleggende antakelser om tekst, bytes og grensesnitt. Den som arbeider strukturert, oppnår mer enn «at umlautene fungerer igjen»: dataflyter blir entydige, integrasjoner mer robuste, og senere modernisering (f.eks. REST-servere, tjenester, databaseopprydding) blir enklere fordi encodings ikke lenger skjer implisitt «et eller annet sted».
Hvis dere trenger en konkret migrasjonsplan for deres Delphi-applikasjon, en risikoanalyse av hotspots eller støtte i gjennomføringen, er neste raske steg et teknisk innledende møte om rammebetingelser og avhengigheter: ta kontakt.
I det faglige landskapet spiller også Delphi Unicode Migration og Delphi Ansi Zu Unicode en viktig rolle når integrasjoner, dataflyt og videreutvikling skal fungere samlet.
Prosjekt eller moderniseringsprosjekt diskuteres med Net-Base.