Глава  6

VB - Това ANSI ли е или Unicode?

Както отбелязах още в глава 1 - "Започване на работа", въпросът дали Visual Basic е ANSI или Unicode е подвеждащ. Единственият отговор, който изобщо може да се даде, е и да, и не, или по-точно отговорът зависи от смисъла на въпроса. Може би, като поровим малко по-дълбоко в историята, ще успеем да осмислим достатъчно въпроса, така че отговорът "зависи" да се възприема поне като малко по-малко незадоволителен.


 
ANSI = ~Unicode = MBCS

Вече бе разгледана една важна дефиниция - когато споменавам тук Unicode, използвам понятието на Microsoft за UCS-2/UTF-16. Друга, която не съм обсъждал, е тази за стрингове, които не са Unicode. Въпреки че те обикновено се отнасят към многобайтовите(които обхващат всички останали кодови таблици, включително кодовите таблици DBCS, които ще използват два байта, и UTF-8, които ще използват 1 - 5 байта, и т.н.), мнозина ги отнасят също така към "ANSI". Това се дължи в голяма степен на исторически причини, но има и съвременна база за този неправилно употребяван термин - всички многобайтови API (съкр. от приложно-програмен интерфейс) на Windows имат наставка "A", като под "A" се подразбира ANSI. Пример може да е API FindWindow, който заема стрингове за клас на прозореца, за заглавие на прозореца или и за двете. API FindWindowA има на всички операционни системи Win32 A и той приема стрингове, които могат да се представят от системната кодова страница по подразбиране. API FindWindowW има само на Windows NT и Windows 2000 и той приема стрингове Unicode. 

Лично аз предпочитам да наричам API с "A" ~Unicode API (което означава "не Unicode" API), но знакът ~ не е от тези, които ще са валидни в идентификатори. Това ще е най-малкото объркващо, да не кажем повече! 

Ще разгледам малко по-късно в тази глава проблема на използване и наричане на API с Unicode или не-Unicode и ще се спра подробно на него в глави 7 -"Възприемане на бариерата на кодовата страница", и 8 - "Работа с VB форми и формати".

Кратка история на продуктите на Microsoft и Unicode

Следващото не е замислено като изчерпателен преглед на темата Unicode или стандарта ISO-10646, който Unicode сега се опитва да спази знак по знак. Целта е да се даде исторически контекст, който да помогне да се обясни къде Visual Basic и други продукти на Microsoft са свързани с Unicode и, надявам се, също и къде са ръководени от Unicode. Тази история ще обхване повечето от основните моменти и може да е повече функционална, отколкото хронологична. Откъде да започнем? Ами разбира се от началото...

16-битови Windows (Windows 3.0, 3.1 и 3.1x)

Windows бе разработена в Съединените американски щати от американската фирма Microsoft. Unicode не беше дори разбираем термин по това време, така че не е учудващо, че нито една от 16-битовите операционни системи Windows не говореше Unicode. В Microsoft имаше няколко предвидливи хора, които насочваха погледите си към международните пазари, особено към пазари като японския. Това накара Microsoft да започне да мисли извън кодовата страница 1252 и да се насочи към японските и други азиатски кодови страници. Стойността на глобализацията и локализацията още не се разбираше много добре, но изискванията на японския пазар бяха много ясни; достатъчно ясни, за да накарат Microsoft да скочи с намерение за локализация.

Обаче локализацията на този етап бе много примитивна и се състоеше в това, че софтуеристите на САЩ "прехвърляха кода си през оградата" на японските софтуеристи и след това им възлагаха да внесат необходимите промени в продукта и да изпробват тези промени. За съжаление тези софтуеристи и изпитатели правеха толкова грешки, колкото и първоначалните им възложители, а тези версии на продуктите не бяха разработки от по-високо ниво, които да могат да работят със всички езици, а производни разработки, които също така често не можеха да обработват данни, които биха работили в оригиналната версия.

И така локализация имаше, но глобализацията бе сравнително непозната. Тъй като всеки локален участник просто държеше на себе си и нямаше изискване за възможност за кръстосано взаимодействие на кодовите страници, това не причиняваше особени проблеми на никого.

COM в 16-битовия свят

COM всъщност не разбираше много по-добре Unicode, главно по същите причини. Всъщност COM наистина изобщо не обхвана значението на език / местност. Той работеше при същото предположение, че е достатъчно добър, за да работи в кодовата страница по подразбиране на текущата система.

Visual Basic в 16-битовия свят

Ранните версии на Visual Basic работеха по същите правила както и другите 16-битови приложения. Обаче към момента на появяване на Visual Basic 3.0 вече бе ясно, че е необходим по-добър подход към софтуера, който да намали разходите и да подобри качеството на продуктите, подлежащи на продажба в други страни. Все пак Visual Basic винаги в голяма степен се е основавал на платформата, на която се намира, и без подкрепа от фундамента къщата изобщо не можеше да се гради в такава посока. Така че VB 3.0 си остана на мястото, но хората гледаха напред, към Новата технология на Windows или Windows NT.

Windows NT

Втората операционна система на David Cutler (първата беше за Digital) бе изградена с оглед на бъдещето и важният за нас аспект бе пълното поддържане на Unicode от Windows NT. Цялата операционна система бе написана из основи с идеята, че ядрото (Kernel) на Unicode и поддържането на Unicode са най-важният метод за постигане на операционната система. Това бе посрещнато със скептицизъм, тъй като повечето хора виждаха просто два пъти по-големи и реални проблеми във времето, когато паметта и пространството на твърдия диск бяха толкова търсени, но г-н Cutler наистина гледаше към бъдещето. Избраният от него "Unicode" бе UCS-2, световният стандарт обхванат от ISO-16046, който определя всеки знак въз основа на два байта. Областта на американския английски все още имаше "позиционното" предимство да е в първите 127 знака, но вече нямаше предимството пред азиатските езици да заема по-малко място.

Същевременно реалността започна да се налага и стана очевидно, че никой не може да премине на платформа, която не поддържаше "стария начин" на правене на нещата. Следователно трябваше да се поддържа ANSI заради обратна съвместимост и за да се даде възможност всички съществуващи приложения да продължат да работят (в по-голямата си част). Всички Win32 API, които вземаха стрингове, сега бяха с две версии: "A" версия за многобайтови знакови системи като английска, холандска, японска и "W" версия за използване на Unicode. По време на компилиране трябваше да изберете кой комплект API да използвате, като изберете дали да компилирате с флага на Unicode, например с решението дали обръщането към GetWindowLong във Вашия код C/C++ ще извиква GetWindowLongA или GetWindowLongW. Винаги можехте да изберете да извиквате изрично единия или другия, но това не Ви се препоръчваше. Теоретично трябваше да е лесно за Вас един ден просто да превключите и да сте в Unicode!

А защо трябваше да постъпват така? Е, първо заради очевидната сила на световните EXE (която дори Windows NT все още нямаше, тъй като много от собствените й базови приложения все още не бяха толкова просветени, колкото ядрото (Kernel), доколкото то може да се разглежда като просветено!). Второ, всеки път, когато имате работа непосредствено с Unicode, всичките Ви операции ще са по-бързи, тъй като няма да има нужда от допълнителни транслирания между ANSI и Unicode. Хората научиха много бързо, че изискванията на SDK документацията бяха точни - функциите MultiByteToWideChar (мултибайт в широк символ) и WideCharToMultiByte (широк символ в мултибайт) можеха да забавят силно дадено приложение.

Една от скритите особености на MultiByteToWideChar и WideCharToMultiByte бе, разбира се, че трябваше да има налице таблици на кодови страници, за да подпомогнат конвертирането на стринговете от Unicode към коя да е друга кодова страница и обратното. Поддържането на даден език в свят, в който повечето приложения в действителност не използваха вътрешно Unicode, означаваше също така поддържане на кодовата страница.

Windows 95

Windows 95 се роди при леко различни принципи - тя бе в много отношения пренос на оригиналната кодова база на Win 3.x (точно такива бяха и повечето приложения, дори под Windows NT). Тя бе предназначена първоначално за пълно поддържане на същите Win32 API, както и Windows NT, въпреки че в повечето случаи "W" версиите на функциите на API просто даваха съобщение за грешка ERROR_CALL_NOT_IMPLEMENTED (грешка, обръщението не се прилага) или E_NOTIMPL. Ограниченият брой обръщения чрез Win32 API, предвидени за поддържане както на Unicode, така и на ANSI под Windows 95/98 са показани в таблица 6.1.

Таблица 6.1 Обръщения чрез Win32 API, които поддържат Unicode на всички платформи


 
Обръщение чрез  API 
Какво прави
EnumResourceLanguages
Изрежда езиците, поддържани от определеното име / вид ресурс в даден модул.
EnumResourceNames
Изрежда всички ресурси от определен вид в даден модул.
EnumResourceTypes
Изрежда всички видове ресурси в даден модул.
ExtTextOut
Изписва стринг знаци в определено място, като по избор позволява параметри извън поддържаните от TextOut.
FindResource
Намира ресурс с определено име и заглавие.
FindResourceEx
Намира ресурс с определено име и заглавие, като позволява да се уточни езика.
GetCharWidth
Извлича широчината на определени знаци.
GetCommandLine
Извлича стринга на командния ред за текущия процес.
GetTextExtentPoint
Изчислява широчината и височината на даден текстов стринг (с оглед на обратна съвместимост се препоръчва GetTextExtentPoint32).
GetTextExtentPoint32
Изчислява широчината и височината на даден текстов стринг.
lstrlen
Дава дължината на завършващ на нула стринг.
MessageBox
Създава, показва и управлява диалогова кутия.
MessageBoxEx
Създава, показва и управлява диалогова кутия, като позволява на потребителя да уточни езика за предварително определени бутони.
MultiByteToWideChar
Конвертира многобайтов стринг в такъв на Unicode при дадена кодова страница, с която  да се извърши конверсията.
TextOut
Изписва знаков стринг в определено място.
WideCharToMultiByte
Конвертира стринг на Unicode в многобайтов при дадена кодова страница, с която  да се извърши конверсията.

Разбира се, може да е предизвикателство да се пише Unicode приложение за Windows 95 или 98 с толкова немногоброен комплект инструменти. Все пак отначало идеята бе, че по-късно просто бихте компилирали Unicode приложение за Windows NT и това ще е всичко; само по-късно се изясни необходимостта от поддържане на Unicode приложения за Windows 95/98.

Единственото голямо изключение от всичко това е 32-битовия COM.

COM в 32-битовия свят

COM направи интересен пробив с двете операционни системи - той поддържа само Unicode, а ANSI просто е оставен настрана. Ако не можете да говорите Unicode  на известно ниво (дори ако това само означава поддържане на обръщения MultiByteToWideChar и WideCharToMultiByte, за да го конвертирате), не можете да говорите на COM. С толкова много от дори базовата функционалност в 32-битовата програмна обвивка на Windows, изискваща Unicode, всяко приложение трябва да свършва поне малко работа в Unicode. Стринговете в 32-битовия COM (OLESTR и BSTR) са винаги Unicode. Разбира се, повечето приложения го поддържат минимално чрез манипулиране на конвертиращите функции и използване на кодовата страница по подразбиране на системата (CP_ACP), единствената кодова страница, която гарантирано се поддържа винаги.

Windows 98

Базовата операционна система само добави няколко обръщения чрез API към списъка, който поддържа както Unicode, така и ANSI (показани в табл. 6.2).

Таблица 6.2 Обръщения чрез Win32 API, за които Windows 98 добави поддържане на Unicode


 
Обръщение чрез API
Какво прави
lstrcat
Прилага един стринг към друг.
lstrcpy
Копира стринг в буфера.

Все пак бяха добавени много нови интерфейси, като нови разширения на обвивката (shell) и интегрирани подобрения на прелистването (browsing). Всички те са COM интерфейси и следователно поддържат само Unicode.

Windows Millennium Edition (Windows Me)

Windows Me всъщност не добави много в уравнението. Според Microsoft, това е последната версия на кодовата основа Win9x, която изобщо ще се пуска на пазара, но, честно казано, компанията разправя това още от издаването на версията OSR2 на Windows 95. Основните проблеми, които отбелязах във връзка с Windows 95 и 98, се отнасят и за Windows Me.

Двата добавени в Millennium комплекта API, които имат поддържане на Unicode, са свързани с API на Input Method Manager (Управление на метода на въвеждане - IMM), който разглеждам по-нататък в глава 8, и API на Geographical Information Management (Управление на географската информация - Geo). Geo се използва от много компоненти на Windows Me, които отразяват местна информация в географска позиция.

Изчислителни машини за съхранение на данни

Самите машини, независимо дали бяха SQL Server, Jet, FoxPro или други, отначало бяха далеч от света на Unicode, като предпочитаха провинциалния свят, където отделната кодова страница е всичко, от което би имало нужда. Въпреки че както Jet, така и SQL Server можеха да извършват собствена нормализация на стринга в много случаи (вж. глава 12 за повече информация по тази тема), това се правеше само с оглед на производителността, а не в подкрепа на понятието за множество кодови страници в един и същи файл. И двата продукта бяха стъпка извън понятието за кодова страница по подразбиране на операционната система. Можехте изрично да изберете да използвате всяка отделна кодова страница, поддържана от OS, но все още бяхте ограничени до отделна кодова страница.

По-неотдавнашните версии на Jet и SQL Server, все пак наистина поддържат Unicode като вроден формат: В Jet, всичко бе прехвърлено в Unicode; в SQL Server, бихте могли да избирате между ANSI и Unicode. Други машини (като FoxPro) нямат вродено поддържане на Unicode на ниво изчислителна машина за бази данни.

Методи за достъп до данни

За разлика от самата изчислителна машина повечето методи за достъп до данни (ADO, OLE DB, DAO и RDO) са компоненти на COM, които поддържат само Unicode. Така че какво правят средствата за форматиране на данни, когато трябва да говорят Unicode, ако базовата изчислителна машина не го прави? Е, просто казано, те конвертират във и от Unicode, като използват или кодовата страница по подразбиране на системата, или в случаите на FoxPro, Jet и SQL Server кодова страница по техен избор. Очевидно тук има много място за грешки при конвертирането.

Преминаването на изчислителните машини за данни към Unicode не само обикновено премахва грешките при конвертирането (ако всичко е в един формат, няма какво да се конвертира неправилно!), но и подобрява ефективността, тъй като изчезват толкова много обръщения за конвертиране! В глава 12 има повече информация за това защо и къде понякога все още има проблеми в тази област.

Microsoft Office

Известният автор Bruce McKinney на Visual Basic веднъж заяви - "Някога ще има Unicode  формати на файлове с данни, но това може и да не се случи през Вашия живот." Колко погрешно излезе това! В първите три 32-битови версии на Office всички по-големи приложения (Word, Excel, Access и PowerPoint) преминаха както на файлови формати Unicode, така и на Unicode изпълними. Дори в света на текстовите файлове (които обикновено се съхраняват в ANSI формат) бяха създадени условия да не се правят предположения за кодовата страница на файла.

За да дадем специфичен пример - самата тази книга бе написана, редактирана и публикувана от издателя с използване на Word 2000. Защо? Защото в много случаи исках да поддържам многоезичен текст. Не исках издателят да използва QuarkXpress, много популярна програма в издателските кръгове, тъй като тя имаше точно същите ограничения, които описах при другите програми. Трябваше с години да се справям с ограниченията на такива пакети при написването на статиите ми (а Quark Inc. определено е стандарт за много издатели), но за тази книга бе важна възможността да се третират равнопоставено всички езици. Като премина на Word 2000, имам възможността да включа текст на хинди като например  "आप यहाँ पर क्यों आना चाहते हैं?" или текст на таи като  "ทำไมคุณถึงต้องเข้ามาชมเว็บไซต์นี้?" , без да е необходимо да използвам специални екранни кадри за всеки бит текст. Ще разгледам това по-нататък в глава 10 - "Обработване на локализирани ресурси със сателитни DLL".

За любознателните в табл. 6.3 е даден преводът на горните текстове на хинди и таи на няколко езика (може би дори и на Вашия!). Тези преводи бяха направени за много от местностите, прилагани в Интернет сайта на trigeminal.com.

Таблица 6.3 Я, няма Bitmap-и! Много начини да се каже една и съща фраза (демонстриране на възможностите на моя издател!)


 
Език
Фраза

Хинди

आप यहाँ पर क्यों आना चाहते हैं?

Таи

ทำไมคุณถึงต้องเข้ามาชมเว็บไซต์นี้?

Български

или защо Ви трябва да идвате тук?

Английски

That is, why would you want to be here?

Опростен китайски

即你来这儿的目的?

Традиционен китайски

即你為什麼要來這裡?

Турски

örneğin; Neden bu sitede olmayı isteyeceginiz gibi?

Немски

d.h. warum lohnt es sich, hier zu sein?

Френски

i.e., pour quelles raisons dé sirez-vous explorer ce site?

Гръцки

δηλαδή, γιατί θέλετε να είστε εδώ;

Иврит

כלוםר למה בכלל תרצה להיות כאן?

Холандски

d.w.z., waarom wilt u hier zijn?

Японски

すなわち、あなたに必要なもの

Шведски

m.a.o. vad gör du här?

Португалски

porque é que tu queres estar aqui?

Руски

возможно это то, что Вам надо

Испански

ejemplo, ¿Porqué deseas estar aquí?

Италиански

in altre parole, perché potreste voler visitare queste pagine?

Румънски

cu alte cuvinte, de ce sunteti aici?

Тамилски

ஏன்நீ இஙுகு வரவேண்டு?

Windows 2000

Windows 2000, известна докато е разработвана като NT5, просто продължава традицията на NT3.1, 3.51 и 4.0. Тя взе новата обвивка от Windows 98 и получи много оплаквания за използваемостта. Обаче от глобализационна гледна точка тя изцяло се придвижи много по-близо до световния EXE модел - вече нямаше оправяне на бъгове, съществуващи само за специфични езици! Поддържането на MUI (MultiLanguage User Interface - многоезичен потребителски интерфейс) доказа, че Windows 2000 е световна операционна система.

Някои приложения, за съжаление, все още са свързани с ANSI, най-забележимо Internet Information Server, но на тези приложения бе дадена ясна насока за бъдещото развитие - Unicode.

Windows CE

Друг модел бе използван обаче за най-малката операционна система - Windows CE е най-близо до COM с това, че тя поддържа само Unicode на ниво API. Все пак, тъй като има само ограничен брой приложения, които все още наистина поддържат чист Unicode, и само ограничено място на по-малкото устройство за преводните таблици на кодовата страница, приложенията на Windows CE все още се ограничават по брой на кодовите страници, които могат да използват. Ясно е, все пак, че това е стъпка в правилната посока.

Visual Basic в 32-битовия свят

И най-сетне стигнах до най-важното RAD средство от гледна точка на тази книга - 32-битовите версии на Visual Basic! Има много проблеми около поддържането на Unicode във VB:

Разбира се, редът, в който представих тези точки, би накарал всеки да повярва, че окончателният отговор на въпроса "Unicode ли е VB?" ще е "Да, но ...", и може би това е най-добрият отговор, който може да се даде. Visual Basic наистина е Unicode с неговите Unicode съхранение на стрингове и Unicode интерфейси, но, както показаха големите изчислителните машини за обработване на данни и методите за достъп, поддържането на Unicode изисква много повече от осигуряването на поддържането му от входната врата, особено ако искате да използвате предимствата на Unicode. Ако се замислите за това, формите на Visual Basic не печелят нищо от техните Unicode интерфейси, изобщо нищо. Защо е така? Ами, когато те се използват, е необходима една единствена кодова страница. Затова единственото, което дават на VB Unicode интерфейсите на пакета форми е съвместимостта с COM; тук не се разполага с нито едно от предимствата, присъщи на Unicode, като например възможността за поддържане на много езици / местности.

Поглед към бъдещите версии на Visual Basic

Нещо, което трябва да е ясно на колектива на Visual Basic в този момент, е, че VB вече не може да е ANSI приложение. Като представяно от Microsoft RAD средство, важно е VB да може да работи правилно с Office 2000 и Windows 2000, като поддържа всеки изпълняван от тях сценарий.

По времето на написване на тази книга следващата версия на VB дори все още нямаше име (въпреки че мнозина предложиха, ако може да не е VB 7.0!). Обсъждат се много вълнуващи характеристики на продукта, но един въпрос, по който Microsoft учудващо мълчеше, е Unicode и многоезичното поддържане. Едно нещо, за което можем да сме сигурни - колективът на Visual Basic е много наясно с натиска в компанията за докарване на Visual Basic до нивото на повечето други продукти на Microsoft.

Там, откъдето току що тръгнахме...

Понякога най-простият въпрос може да доведе до отговори, които заемат много време за изразяване, и мисля, че тази глава бе наистина един от тях. Започнахме още от далечното минало на 16-битовите Windows и преминахме през някои от важните възлови моменти в развитието на продуктите на Microsoft. Историята и пътя, по който другите продукти израснаха около Visual Basic, могат да ни дадат представа, какво може да се очаква от бъдещите версии на Visual Basic да направят за поддържането на Unicode.

В останалото от част II (следващите две глави) се разглежда как да се заобиколят тези ограничения и да се поддържат езици, които са извън текущата системна кодова страница по подразбиране.