Unicode-migreringen av gamla Delphi-projekt är i många företag ett nödvändigt steg eftersom befintliga applikationer annars vid internationella data, moderna operativsystem, integrationer och nya gränssnitt allt mer når sina gränser. I praktiken är det sällan en „kompilera om och klart“-åtgärd. Delphi har sedan Unicode-versionerna (från Delphi 2009) gjort fundamentala förändringar av standardstring-typerna. Det flyttar antaganden om teckenkodning, minneslayout och API-signaturer. Den som underskattar detta skapar gradvisa datafel, trasiga exporter, oklara supportfall och säkerhetsrisker.
Detta inlägg levererar en tekniskt hållbar metodik: hur ni analyserar befintlig kod, avgränsar scope på ett rimligt sätt, reducerar risker vid kritiska punkter (databaser, filer, Windows-API:er, COM, REST-tjänster) och säkrar migrationen så att drift och vidareutveckling kan löpa parallellt. Fokus ligger på Delphi-typiska fallgropar i VCL-applikationer, tjänster och gränssnitt – med blick för moderniseringsvägar där ämnen som BDE-ersättning med nativeranslutning, REST-servrar eller multiplattform senare kan placeras in.
Varför Unicode-omställningen i Delphi så ofta är „större än väntat“
I klassiska Delphi-versioner var string en ANSI-string (beroende på systemets kodsida). Sedan Delphi 2009 är string som standard en UnicodeString (UTF-16). Samtidigt har många bibliotek och VCL-klasser gått över till Wide-API:er. Det är i grunden positivt eftersom det robust stödjer internationella tecken. Men: legacy-kod har ofta vuxit under antaganden som „1 tecken = 1 byte“, „PChar är PAnsiChar“ eller „Length() motsvarar antal bytes“.
Typiska orsaker till att migrationer blir mer omfattande:
- Implicit konvertering sker visserligen, men förändrar data (särskilt för filer, gränssnitt eller databas-BLOB-/textfält).
- Byte-orienterad kod (streams, buffrar, hashing, kryptering) blir omärkligt fel om stringinnehåll tolkas som bytes.
- Tredjepartskomponenter är delvis bara ANSI, eller använder egna string-typer och callbacks.
- Externt sammanhang (Windows-API:er, COM, utskrift/reporting, EDI, CSV, XML/JSON) förväntar sig specifika encodningar.
Målet bör därför inte vara att „ändra så lite som möjligt“, utan att ändra målmedvetet där dataflöden och encodningar måste definieras. En ordnad Unicode-migrering är också en möjlighet att slutgiltigt dokumentera och testa tidigare oklara kodningsgränser.
Teknisk bakgrund: Delphi-stringtyper, encodningar och deras sidoeffekter
string, UnicodeString, AnsiString, WideString – vad som verkligen räknas i projektet
För migrationen är det avgörande vilka typer som används i gränssnitt och i kärnfunktioner:
- string: Sedan Delphi 2009 en UnicodeString (UTF-16, reference-counted, immutable-semantik via copy-on-write).
- AnsiString: Byte-string med tillhörande codepage (beroende på Delphi-version kan en codepage bevaras). Lämplig när ett externt gränssnitt uttryckligen kräver en viss 8-bitarskodning.
- UTF8String: I nyare Delphi-versioner ofta alias/AnsiString med UTF-8-codepage; praktiskt för REST/JSON och många protokoll.
- WideString: BSTR (COM), minneshanterad via SysAllocString; i dag oftast bara nödvändig för vissa COM-interoperabiliteter.
- PChar: Sedan Unicode-Delphi PWideChar. Det är en av de vanligaste brytpunkterna vid Windows-API-anrop.
När dessa typer blandas uppstår konverteringar. Vissa är korrekta, andra överraskande: en konvertering är bara „rätt“ om du vet vilken codepage källan använder och vad målet förväntar sig.
Intern UTF-16, extern UTF-8: en pragmatisk riktlinje
I Delphi-VCL-applikationer är det ofta lämpligt att konsekvent arbeta internt med string (UTF-16). Externt (REST, filer, messaging) dominerar i praktiken UTF-8. En robust linje blir därför:
- Internt: string/UnicodeString som standard.
- Gränser: Vid in-/utgång explicit konvertering via TEncoding.UTF8 (eller definierade ANSI-codepages).
- Byte-baserad bearbetning: TBytes istället för Strings.
Det reducerar implicita konverteringar och gör ansvarsfördelning testbar: „Var blir bytes till text, och med vilken encoding?“
Inventering: Var Unicode i gamla Delphi-projekt typiskt sett brister
Innan ni rör koden lönar sig en strukturerad inventering. I Unicode-migreringar av gamla Delphi-projekt är felkällorna oftast inte jämnt fördelade utan koncentrerade till ett antal kritiska områden.
1) Databasåtkomst och fälttyper (BDE, ADO, FireDAC)
Många äldre projekt använder fortfarande BDE eller äldre dataåtkomstlager. Här uppstår ofta problem som:
- Mappning av databas-charset till Delphi-strings (ANSI vs. Unicode-fälttyper).
- „Text“ i BLOBs eller memo-fält utan definierad kodning.
- SQL-satser som strings där umlauter/Unicode-tecken tolkas olika.
Om modernisering ändå planeras kan en Unicode-migrering väl kombineras med en städning av dataåtkomsten, till exempel mot BDE-Ablosung mit nativer Anbindung och tydlig charset-konfiguration (till exempel för PostgreSQL eller MariaDB). Viktigt: en migration bör inte automatiskt tvinga en databasmigrering, men gränssnittet mellan DB och Delphi måste vara entydigt.
2) Fil- och stream-I/O: CSV, INI, proprietära format, import/export
En klassiker: filer lästes tidigare via AssignFile/ReadLn, TFileStream eller TStringList.LoadFromFile utan att encoding satts. I Unicode-Delphi avgörs det då heuristiskt (BOM) eller via default-encodningar. Det leder till:
- felaktigt tolkade umlauter (ä, ö) i CSV/loggfiler,
- felaktiga längdangivelser i proprietära format,
- inkompatibilitet mot externa parter som förväntar sig ISO-8859-1 eller Windows-1252.
En ren lösning är att per filformat definiera en fast encoding och förankra detta i kod och dokumentation. För CSV/JSON är UTF-8 oftast rätt standard, för gamla gränssnitt ibland Windows-1252. Avgörande är tydlighet och explicithet.
3) Windows-API, PChar, buffertstorlekar och meddelandehantering
Många Delphi-applikationer anropar WinAPI-funktioner eller arbetar med buffrar. Vanliga brytpunkter:
- Användning av PChar ihop med funktioner som har ANSI- eller Wide-varianter (…A/…W).
- Buffertstorlekar beräknas i bytes, men Char i UTF-16 är 2 bytes.
- Pointer-aritmetik och record-layouts byggda på 1-byte-chars.
Här krävs precist refactoring: antingen konsekvent använda Wide-API:er eller medvetet anropa ANSI-varianten och arbeta med AnsiString/codepage. „På något sätt kompilerar“ är inget kvalitetskriterium.
4) COM, ActiveX, Office-automation och tredjepartsbibliotek
COM-gränssnitt arbetar ofta med BSTR (WideString). Gamla Delphi-versioner hade andra default-strings så koden „råkade“ passa. I Unicode-Delphi uppstår ofta dubbla konverteringar eller felaktiga typantaganden i wrappers. Tredjepartsbibliotek är också kritiska: vissa levererar callbacks som PAnsiChar, andra förväntar sig nullterminerade byte-strings.
Här är det värt att klassificera beroenden: vilka bibliotek är Unicode-ready, vilka är det inte, och vilka kan ersättas eller kapslas in? En kapsling är ofta det snabbaste sättet att avgränsa Unicode-legacy till ett väl avgränsat område.
Strategi: Unicode-migrering av gamla Delphi-projekt som ett kontrollerat moderniseringsprogram
Det mest migrationssäkra tillvägagångssättet är ett flerstegsprogram som tidigt synliggör risker och håller applikationen körbar under arbetet.
Steg 1: Definiera scope och prioritera kod-hotspots
Inte all källkod behöver ändras omedelbart. Prioritera efter dataflöde och risk:
- Gränssnitt ut mot omvärlden (REST-API, TCP/IP, filer, e-post, utskrift/reporting).
- Dataåtkomst (SQL, ORM/Datamoduler, BDE/FireDAC-lager).
- String-nära utility-funktioner (parser, formatter, encoder/decoder).
- Integrationer (COM, DLL-importer, hårdvaruanslutningar).
Resultatet bör bli en lista över var „encoding är en specifikation“. Dessa ställen görs senare testbara.
Steg 2: Skärp compiler-/projektinställningar och var uppmärksam på varningar
I många projekt har varningar tystats under årens lopp. För en Unicode-migrering är det kontraproduktivt. Aktivera varningar igen och ta konverteringsvarningar på allvar. Det hjälper också att införa projektregler, exempelvis: inga implicita AnsiString-konverteringar vid I/O-gränser, använd TEncoding vid filoperationer, inga „PChar-tricks“ utan tydlig kontext.
Steg 3: Inför „encoding-gränser“ som teknisk nivå
Ett pragmatiskt arkitekturgrepp är att införa små adapter-/helper-skikt som exakt definierar hur extern data ska tas in och lämnas ut. Exempel:
- CSV-reader/-writer: alltid med TEncoding.UTF8 (eller definierad codepage) och tydliga separatorregler.
- REST-klient/server: JSON alltid som UTF-8-bytes, headers korrekt satta, body inte „string-baserat“ streamad.
- Windows-API-wrapper: centrala funktioner som rent kapslar Wide/Ansi.
Så förhindrar ni att „encoding-beslut“ sprids kors och tvärs i kodbasen.
Typiska kodfällor och hur man rättar dem konsekvent
Length, SizeOf, ByteLength: när teckenlängd och bytestorlek skiljer sig åt
I ANSI-tiden missbrukades ofta Length(s) som byteantal. I UTF-16 är det felaktigt. Om ni behöver byte-arrayer, konvertera explicit:
- För UTF-8: TEncoding.UTF8.GetBytes(s)
- För definierad ANSI-codepage: TEncoding.GetEncoding(1252).GetBytes(s) (endast om det är korrekt utifrån krav)
För buffertstorlekar vid API-anrop gäller: kontrollera om funktionen förväntar sig tecken- eller byte-enheter. Många Wide-API:er förväntar sig antal tecken, inte bytes. Dokumentation och signatur avgör, inte intuition.
PAnsiChar vs. PWideChar: DLL-importer och externa protokoll
Vid DLL-importer är risken stor att signaturerna i Delphi-koden inte längre stämmer. Bestäm vad DLL:en förväntar sig:
- Förväntar DLL:en UTF-8? Då är passering som PAnsiChar(UTF8String) vanligt, men ni måste kontrollera livstid och null-terminering.
- Förväntar den UTF-16? Använd då PWideChar och wide-strings.
I alla fall bör importer kapslas i en separat unit så att string-politiken inte sprids över hela projektet.
Formatering, case-omvandling, jämförelse: locale och normalisering
Unicode medför även semantiska frågor: versaler/gemener är inte trivialt i alla språk, och tecken kan ha olika normalformer. I typiska företagsapplikationer är detta mindre kritiskt än i konsument-textbehandling, men det påverkar:
- sortering och filtrering (t.ex. i grids eller sökfunktioner),
- case-insensitiva jämförelser för nyckelvärden,
- generering av filnamn eller identifierare.
Viktigt är en tydlig regel: vad är „nycklar“ (t.ex. artikelnummer, kundkoder) som bör förbli ASCII-nära, och vad är „texter“ som måste vara fullt Unicode-kompatibla? Denna separation minskar följdfelen.
GUI/Reporting: typsnitt, utskrift, PDF och komponentbeteende
VCL är sedan Unicode-versionerna i grunden Unicode-kompatibelt, men praktiken hänger på komponenter och utdataflöden. Risker uppstår vid:
- äldre rapportmotorer eller PDF-generatorer som antar ANSI,
- streckkod-/etikettskrivning som kräver specifika codepages,
- hårdkodade typsnitt eller teckenuppsättningar.
Planera tidigt tester med verkliga exempeldata (namn, orter, specialtecken, icke-latinska skript om relevant). Värdet ligger inte i att „kan Unicode“, utan i beviset: „Denna output är korrekt i vårt sammanhang.“
Data och persistens: Unicode slutar inte vid koden
Ställ in databas-charset och collations korrekt
En Unicode-migrering är bara stabil om databaser och drivrutiner är korrekt konfigurerade. Exempel:
- För PostgreSQL är UTF-8 i regel standard; ändå måste client-encoding och drivrutinsbeteende kontrolleras.
- För SQL Server är skillnaden mellan VARCHAR och NVARCHAR relevant; fel kolumntyp kan förlora tecken.
- För MariaDB/MySQL är charset/collation (t.ex. utf8mb4) avgörande så att 4-byte-tecken inte trunkeras.
I Delphi-koden bör parametrar och fälttyper användas så att Unicode inte „konverteras tillbaka“ på vägen. FireDAC ger här ofta bättre kontroll än mycket gamla åtkomstlager.
Legacy-filformat: migrationsregler i stället för tysta konverteringar
Om er applikation under åren skapat filer (exportformat, arkivfiler, proprietära strukturer) måste ni definiera:
- Vilka befintliga filer förblir „som de är“ och läses korrekt?
- Vilka format höjs till UTF-8?
- Finns versionsfält/headers för att entydigt skilja nya och gamla filer?
Tyst konvertering utan markering är riskabelt eftersom fel ofta upptäcks sent. Bättre: versionera, upptäck tydligt och migrera målmedvetet.
Kvalitetssäkring: tester som verkligen hittar Unicode-problem
Unicode-fel är ofta databeroende. Därför räcker inte „happy path“-tester. Ett lämpligt testset täcker problematiska områden:
- Roundtrip-tester: import → bearbetning → export, följt av byte-exakt jämförelse (för definierade format).
- DB-roundtrip: skriv/läs texter med umlauter, accenter och eventuellt icke-latinska tecken; kontrollera likhet.
- Gränssnittstester: REST-requests som UTF-8, headers, JSON-escaping, logging.
- Regression: återskapa gammal data och typiska användarfall, särskilt sök, filter och sortering.
För B2B-system är det dessutom viktigt att fel blir observerbara: logging bör inte förstöra encodningar. Att skriva loggar som ANSI innebär att man vid fel tappar precis den information som behövs.
Planering och insats: vad som verkligen driver komplexiteten
Ansträngningen för Unicode-migreringen av gamla Delphi-projekt styrs mindre av „antal rader kod“ än av kopplingar och externa beroenden:
- Många integrationer (DLL:er, COM, enheter, ERP/DMS/CRM) ökar test- och verifieringsarbetet eftersom encodingar är relevanta vid varje gräns.
- Historiska format (gamla exporter, kundspecifika CSV:er) kräver migrationsregler och kompatibilitetsstrategier.
- Blandade Delphi-versioner eller flera produkter ur en kodbas ökar koordineringsbehovet.
- Gamla dataåtkomstlager (t.ex. BDE) kan indirekt blockera Unicode och motivera modernisering.
I praktiken har ett arbetssätt visat sig effektivt där Unicode först stabiliseras i kärnan och i de mest kritiska dataflödena. Därefter dras moduler successivt i takt. Det minskar risken och undviker långa „big bang“-faser utan releaser.
Placering i moderniseringsvägar: REST, tjänster, multiplattform
Unicode är ofta en grundförutsättning när legacy-programvara ska moderniseras. Typiska följdfrågor är:
- REST-servrar eller REST-API:er som eftermonteras (JSON/UTF-8 måste hanteras korrekt).
- Drift av Windows-tjänster eller Linux-tjänster med stabil logging, konfigfiler och protokoll.
- Successiv UI-modernisering i VCL, senare eventuellt multiplattforms-klienter.
Viktig är ordningen: om ni bygger nya gränssnitt bör encoding-regler vara fastställda i förväg. En Unicode-migrering „vid sidan om“ under gränssnittsutveckling leder annars till svårtestade felbilder där orsak och verkan blandas ihop.
För intern länkning i magasinet är det lämpligt att placera närliggande ämnen som Delphi-modernisering, FireDAC-dataåtkomst eller arkitektur för REST-servrar som fördjupande artiklar så att läsaren kan hoppa vidare till nästa tekniska steg.
Slutsats: Unicode-migrering är ett riskämne – med rätt metod blir det planbart
Unicode-migreringen av gamla Delphi-projekt är ingen kosmetisk uppgradering utan en korrigering av grundläggande antaganden om text, bytes och gränssnitt. Den som arbetar strukturerat vinner dock mer än „att umlauter åter fungerar“: dataflöden blir entydigare, integrationer mer robusta och senare modernisering (t.ex. REST-servrar, tjänster, databasrensning) blir enklare eftersom encodningar inte längre händer implicit „någonstans“.
Om ni behöver en konkret migrationsplan för er Delphi-applikation, en riskanalys av hotspots eller stöd vid genomförandet, är nästa snabbaste steg ett tekniskt första samtal om era ramvillkor och beroenden: ta kontakt.
I det professionella sammanhanget spelar även Delphi Unicode Migration och Delphi Ansi Zu Unicode en viktig roll när integrationer, dataflöden och vidareutveckling måste fungera ihop.
Projekt eller moderniseringsprojekt att diskutera med Net-Base.