Net-Base Списание

19.04.2026

Миграция към Unicode на стари Delphi проекти: подводни камъни, стратегия и коректна реализация

Много Delphi съществуващи приложения все още работят с ANSI низове. Миграцията към Unicode е повече от просто превключване на компилатора: тя засяга достъпа до данни, интерфейсите, отчетите, библиотеки на трети страни и тестовете. Тази статия показва практически приложим път за миграция – вкл...

19.04.2026

Unicode миграцията на стари Delphi-проекти е в много фирми необходима стъпка, тъй като съществуващите приложения иначе започват да срещат ограничения при международни данни, съвременни операционни системи, интеграции и нови интерфейси. На практика това рядко е „Recompile и готово“. Delphi въведе от версията за Unicode (от Delphi 2009) фундаментални промени в стандартните string-типове. Това променя предположенията относно кодировката на знаците, разпределението в паметта и подписите на API. Който подцени това, създава постепенно появяващи се грешки в данните, повредени експорти, неясни казуси за поддръжка и рискове за сигурността.

Тази статия предоставя технически обоснован подход: как да анализирате състоянието, как да оформите разумно обхвата, как да намалите рисковете в горещите точки (базирани данни, файлове, Windows-API-та, COM, REST-услуги) и как да обезпечите миграцията така, че експлоатацията и по-нататъшната разработка да могат да продължат паралелно. Фокусът е върху типичните капани при Delphi в VCL-приложения, услуги и интерфейси — с оглед на модернизационни пътеки, в които по-късно могат да се включат теми като BDE-замяна с нативно свързване, REST-сървъри или мултиплатформени решения.

Защо преходът към Unicode в Delphi често е „по-голям, отколкото изглежда“

В класическите версии на Delphi string беше ANSI-стринг (в зависимост от системната codepage). От Delphi 2009 string по подразбиране е UnicodeString (UTF-16). Паралелно много библиотеки и VCL-класове бяха преминали към Wide-API-та. Това е положително с оглед на поддръжката на международни знаци. Но: наследен код често е изграждан през годините върху предположенията „1 знак = 1 байт“, „PChar е PAnsiChar“ или „Length() съответства на брой байтове“.

Типичните причини, поради които миграциите се усложняват:

  • Имплицитни конверсии преминават, но променят данните (особено при файлове, интерфейси или DB BLOB/Memo полета).
  • Код, ориентиран към байтове (Streams, буфери, hashing, криптиране) става незабелязано грешен, когато съдържанието на string се тълкува като байтове.
  • Компоненти на трети страни са частично ANSI-only или използват свои собствени string-типове и callbacks.
  • Външна среда (Windows-API-та, COM, печат/репортинг, EDI, CSV, XML/JSON) очаква определени кодировки.

Целта не бива да бъде „да се промени възможно най-малко“, а целенасочено да се промени там, където потокът на данни и кодировките трябва да бъдат ясно дефинирани. Чиста Unicode миграция е и възможност да се документират и тестват неясни граници на кодировките.

Технически основи: Delphi-string-типове, кодировки и странични ефекти

string, UnicodeString, AnsiString, WideString – кои типове имат реално значение в проекта

За миграцията е важно кои типове се използват на интерфейсите и в ключовите функции:

  • string: От Delphi 2009 е UnicodeString (UTF-16, reference-counted, поведение copy-on-write).
  • AnsiString: Байт-стринг с асоциирана кодова страница (в зависимост от версията на Delphi може да съдържа информация за codepage). Подходящ, когато външен интерфейс изрично изисква определена 8-битова кодировка.
  • UTF8String: В по-новите версии на Delphi често е алиас/AnsiString с UTF-8 codepage; удобен за REST/JSON и много протоколи.
  • WideString: BSTR (COM), управляван въвеждащо чрез SysAllocString; днес обикновено нужен само за специфични COM-интеропи.
  • PChar: След Unicode-версиите на Delphi е PWideChar. Това е една от най-честите точки на счупване при Windows-API извиквания.

При смесване на тези типове възникват конверсии. Някои са коректни, други могат да бъдат изненадващи: конверсията е „правилна“ само ако знаете коя codepage е в източника и коя се очаква в целта.

UTF-16 вътрешно, UTF-8 външно: практичен принцип

В VCL-приложения на Delphi често е разумно вътрешно последователно да се работи с string (UTF-16). Външно (REST, файлове, messaging) в реалността доминира UTF-8. Робустната линия е следната:

  • Вътрешно: string/UnicodeString като стандарт.
  • Граници: при вход/изход изрично конвертиране чрез TEncoding.UTF8 (или дефинирани ANSI-codepages).
  • Обработка, базирана на байтове: TBytes вместо Strings.

Това намалява имплицитните конверсии и прави отговорностите проверими: „Къде се превръщат байтове в текст и с коя кодировка?“

Инвентаризация: къде Unicode в старите Delphi-проекти типично се чупи

Преди да пипнете кода, струва си структурирана инвентаризация. При Unicode миграцията на стари Delphi-проекти източниците на грешки обикновено не са равномерно разпределени, а се концентрират в няколко горещи места.

1) Достъп до бази данни и типове полета (BDE, ADO, FireDAC)

Много стари проекти все още използват BDE или по-старите слоеве за достъп до данни. Проблемите там често са:

  • Съответствие между charset-овете на базата данни и Delphi-стринговете (ANSI срещу Unicode-типове полета).
  • „Текст“ в BLOBs или memo-полета без зададена кодировка.
  • SQL-изрази като Strings, които при умлаут/Unicode знаци се интерпретират различно.

Ако вече планирате модернизация, Unicode миграцията може удобно да се съчетае с почистване на достъпа до данни, например към BDE-Ablosung mit nativer Anbindung и ясна конфигурация на charset (както при PostgreSQL или MariaDB). Важно: миграцията не трябва автоматично да налага миграция на базата данни, но интерфейсът между DB и Delphi трябва да бъде недвусмислен.

2) Файлов I/O и Streams: CSV, INI, proprietäre формати, импорт/експорт

Класика: файлове по-рано се четяха/писаха чрез AssignFile/ReadLn, TFileStream или TStringList.LoadFromFile без зададена кодировка. В Unicode-версиите на Delphi тогава средата често решава хeуристично (BOM) или използва подразбиращите се кодировки. Това води до:

  • грешно интерпретирани умлаути (ä, ö) в CSV/логфайлове,
  • неточни указания за дължина в proprietary формати,
  • несъответствия с външни партньори, които очакват ISO-8859-1 или Windows-1252.

Чисто решение е за всеки файлов формат да бъде дефинирана фиксирана кодировка и това да бъде закрепено в кода и документацията. За CSV/JSON UTF-8 обикновено е правилният стандарт, за стари интерфейси понякога Windows-1252. Решаващ е факторът на експлицитност.

3) Windows-API, PChar, размери на буфера и обработка на съобщения

Много Delphi-приложения извикват WinAPI функции или работят с буфери. Чести точки на счупване:

  • Употреба на PChar с функции, които имат ANSI- и Wide-варианти (…A/…W).
  • Размерите на буферите се изчисляват в байтове, но Char при UTF-16 е 2 байта.
  • Pointer-arithmetik и Record-лайаути, базирани на 1-байтови Char полета.

Тук е нужно прецизно рефакториране: или да се използват последователно Wide-API-та, или съзнателно да се извиква ANSI-вариант и да се работи с AnsiString/codepage. „Иначе компилира“ не е критерий за качество.

4) COM, ActiveX, Office-Automation и библиотеки на трети страни

COM интерфейсите често работят с BSTR (WideString). В стари версии на Delphi имаше други default-стрингове и кодът „случайно“ е работил. В Unicode-версиите често възникват двойни конверсии или неправилни предположения в wrapper-и. Библиотеките на трети страни също са критични: някои подават callbacks като PAnsiChar, други очакват null-terminated byte-стрингове.

Струва си да класифицирате зависимостите: коя библиотека е готова за Unicode, коя не е и коя може да бъде заменена или капсулирана? Капсулирането често е най-бързият начин да се изолират наследени Unicode-проблеми в ясно определена зона.

Стратегия: Unicode миграцията на стари Delphi-проекти като контролирана програма за модернизация

Най-сигурният подход за миграция е многоетапна програма, която рано прави рисковете видими и поддържа приложението работещо.

Стъпка 1: Дефиниране на обхват и приоритизиране на Code-Hotspots

Не всеки източник на код трябва да бъде променян веднага. Приоритизирайте според поток на данни и риск:

  • Интерфейси навън (REST-API, TCP/IP, файлове, e-mail, печат/репортинг).
  • Достъп до данни (SQL, ORM/Datamodul, BDE/FireDAC слоеве).
  • Utility-функции, близки до string (парсери, форматиращи, енкодери/декодери).
  • Интеграции (COM, DLL-импорти, хардуерни свързвания).

Резултатът трябва да бъде списък с местата, където „кодировката е спецификация“. Тези места по-късно се правят тестируеми.

Стъпка 2: Компилаторни/проектни опции и предупреждения – включете ги

В много проекти предупрежденията са изключвани с години. За Unicode миграция това е контрапродуктивно. Полезно е да включите предупреждения и да приемете сериозно предупрежденията за конверсии. Допълнително полезно е да зададете проектни правила, напр.: нито една имплицитна AnsiString-конверсия на I/O-граници, използване на TEncoding при файлови операции, никакви „PChar-трикове“ без ясен контекст.

Стъпка 3: Въведете „граници на кодировката“ като технически слой

Практичен архитектурен похват е въвеждането на малки адаптери/хелпъри, които точно дефинират как външните данни влизат и излизат. Примери:

  • CSV-Reader/-Writer: винаги с TEncoding.UTF8 (или дефинирана codepage) и ясни правила за разделители.
  • REST-клиент/сървър: JSON винаги като UTF-8-байтове, коректно зададени header-и, body не се стриймва „като string“.
  • Windows-API-wrapper: централни функции, които чисто капсулират Wide/Ansi.

Така предотвратявате „решения за кодировка“ да се разпростират хаотично из кода.

Типични кодови капани и как да ги отстраните чисто

Length, SizeOf, ByteLength: когато дължина в знаци и размер в байтове се разминават

В ANSI-епохата Length(s) често е използвано като брой байтове. При UTF-16 това е грешно. Ако ви трябват байтови масиви, конвертирайте експлицитно:

  • За UTF-8: TEncoding.UTF8.GetBytes(s)
  • За дефинирана ANSI-codepage: TEncoding.GetEncoding(1252).GetBytes(s) (само когато е технически оправдано)

За размери на буфери при API-извиквания проверявайте дали функцията очаква брой знаци или брой байтове. Много Wide-API-та очакват брой знаци, не байтове. Документацията и подписът решават, не интуицията.

PAnsiChar vs. PWideChar: DLL-Imports и външни протоколи

При DLL-импорти рискът е голям, че подписите в Delphi-кода вече не съвпадат. Уточнете какво очаква DLL:

  • Очаква ли DLL UTF-8? Тогава подаването като PAnsiChar(UTF8String) е обичайна практика, но трябва да контролирате живота на паметта и нул-терминирането.
  • Очаква ли UTF-16? Тогава използвайте PWideChar и wide-стрингове.

Във всеки случай импортите е добре да бъдат капсулирани в отделна unit, за да не се разпростира политиката за string из целия проект.

Форматиране, промяна на регистър, сравнение: Locale и нормализация

Unicode носи и семантични въпроси: големи/малки букви не са тривиални във всички езици и знаци могат да имат различни нормални форми. В типични корпоративни приложения това е по-малко критично от текстообработката за потребители, но засяга:

  • сортиране и филтриране (например в гридове или търсения),
  • case-insensitive сравнения за ключови стойности,
  • генериране на имена на файлове или идентификатори.

Важна е ясната политика: кои са „ключове“ (напр. артикулни номера, клиентски кодове), които трябва да останат близки до ASCII, и кои са „текстове“, които трябва да поддържат пълно Unicode. Това разделение намалява последващи грешки.

GUI/Reporting: Fonts, печат, PDF и поведение на компонентите

VCL от Unicode-версиите е принципно Unicode-способен, но практиката зависи от компоненти и пътищата на изхода. Рискове възникват при:

  • по-стари репорт-енджини или PDF-генератори, които приемат ANSI,
  • barcode/label принтиране, което изисква специфични codepages,
  • твърдо кодирани шрифтове или charset-и.

Планирайте ранен тест с реални примерни данни (имена, населени места, специални знаци, нелатински азбуки, ако са релевантни). Целта не е само „може Unicode“, а доказателство: „Този изход е коректен в нашия контекст.“

Данни и персистентност: Unicode не свършва в кода

Ясно задайте charset и collation в базите данни

Unicode миграцията е стабилна само когато базите данни и драйверите са коректно конфигурирани. Примери:

  • При PostgreSQL UTF-8 обикновено е стандарт; все пак клиентското encoding и поведението на драйвера трябва да бъдат проверени.
  • При SQL Server разграничението между VARCHAR и NVARCHAR е съществено; неправилният избор на колона може да загуби знаци.
  • При MariaDB/MySQL charset/collation (напр. utf8mb4) са критични, за да не се отрежат 4-байтови знаци.

В Delphi-кода параметрите и типовете полета трябва да се използват така, че Unicode да не бъде „обратно конвертиран“ по пътя. FireDAC обикновено дава по-добър контрол в сравнение със силно остарели слоеве за достъп.

Наследени файлови формати: правила за миграция вместо тихи конверсии

Ако вашето приложение е генерирало файлове през годините (експортни формати, архиви, proprietary структури), трябва да дефинирате:

  • Кои съществуващи файлове остават „както са“ и при четене се интерпретират коректно?
  • Кои формати ще бъдат повишени до UTF-8?
  • Има ли полета за версия/хедъри, за да се различават нови и старите файлове?

Тихата конверсия без маркиране е рискова, защото грешките често се откриват късно. По-добре: версиониране, ясно разпознаване, целенасочена миграция.

Осигуряване на качеството: тестове, които действително откриват Unicode-проблеми

Unicode-грешките често зависят от данните. Затова „happy path“ тестове не са достатъчни. Полезен е набор от тестове, който покрива проблемните места:

  • Roundtrip-тестове: импорт → обработка → експорт, след което байтово точно сравнение (за дефинирани формати).
  • DB-Roundtrip: запис/четене на текстове с умлаути, акценти и евентуално нелатински знаци; проверка за равенство.
  • Интерфейсни тестове: REST заявки като UTF-8, header-и, JSON-escaping, логиране.
  • Регресионни: възпроизвеждане на стари данни и типични потребителски случаи, особено при търсене, филтриране, сортиране.

За B2B системи е също важно грешките да бъдат наблюдаемe: логването не бива да разрушава кодировките. Който пише логове като ANSI, в случай на грешка губи точно информацията, която му трябва.

Планиране и усилие: какво всъщност увеличава сложността

Трудът за Unicode миграция на стари Delphi-проекти зависи по-малко от „редове код“, и повече от свързаностите и външните зависимости:

  • Много интеграции (DLLs, COM, устройства, ERP/DMS/CRM) увеличават работата по проверка, защото кодировките са важни на всяка граница.
  • Исторически формати (стари експорти, клиентски CSV) изискват правила за миграция и стратегии за съвместимост.
  • смесени версии на Delphi или няколко продукта от един кодов клон увеличават нуждата от координация.
  • Остарели слоеве за достъп до данни (напр. BDE) могат индиректно да блокират Unicode и да налагат модернизация.

На практика се е доказал подход, при който Unicode се стабилизира първо в ядрото и в критичните потоци данни. След това модулите се догонват постепенно. Това намалява риска и предотвратява дълги „Big Bang“ фази без release.

Поставяне в модернизационни пътеки: REST, услуги, мултиплатформа

Unicode често е опорен стълб, когато наследен софтуер се модернизира. Типични свързани въпроси са:

  • REST-сървър или REST-API да бъдат добавени (JSON/UTF-8 трябва да се обработват коректно).
  • Windows-услуги или Linux-услуги да се поддържат стабилно (логиране, конфигурационни файлове, протоколи).
  • Постепенна UI-модернизация във VCL, а по-късно евентуално мултиплатформени клиенти.

Важно е редът на изпълнение: когато изграждате нови интерфейси, правилата за кодировка трябва да са вече зададени. Миграцията към Unicode „в крачка“ по време на разработката на интерфейси води до трудно проверими проблеми, защото причина и следствие се смесват.

За вътрешно свързване в изданието на списанието е разумно да се поместят допълнителни статии за съседни теми като Delphi-модернизация, FireDAC-достъп до данни или архитектура на REST-сървъри, за да могат читателите да преминат към следващия технически етап.

Извод: Unicode миграцията е въпрос на риск — с правилния метод тя става планирана

Unicode миграцията на старите Delphi-проекти не е козметичен ъпгрейд, а корекция на основни предположения за текст, байтове и интерфейси. Който действа структурирано, печели повече от „умлаутите отново работят“: потокът на данни става ясен, интеграциите по-робустни, а последващата модернизация (напр. REST-сървъри, услуги, почистване на бази данни) става по-лесна, защото кодировките вече не се случват имплицитно „някъде“.

Ако за вашето Delphi приложение имате нужда от конкретен план за миграция, анализ на риска за горещите точки или подкрепа при изпълнение, най-бързата следваща стъпка е техническа първоначална консултация за вашите рамкови условия и зависимости: свържете се за контакт.

В професионалната среда Delphi Unicode Migration и Delphi Ansi Zu Unicode също играят важна роля, когато интеграции, потоци от данни и бъдещо развитие трябва да работят съвместно.

Проект или модернизационно задание да се обсъдят с Net-Base.

Сподели публикацията

Споделете тази публикация директно

LinkedIn, X, XING, Facebook, WhatsApp и имейл са незабавно достъпни. За Instagram ще подготвим връзка и кратък текст.

Електронна поща

Instagram се отваря в нов раздел. Връзката и краткият текст се копират предварително в клипборда.