Страницы: 1 2 След.
RSS
Обеспечение совместимости Excel VBA приложения для систем разной разрядности и с разными региональными установками.
 

   Сообщение посвящено проблеме обеспечения корректной работы приложения для Excel VBA в системах с различными версиями MS Windows (в том числе, с другими кодовыми страницами и/или региональными настройками) и Excel (2007+). Под Приложением понимается совокупность надстроек и книг Excel, объединенных определенной функциональностью.

   Приложение не должно требовать предварительной перенастройки параметров Windows и/или Excel и не должно само вносить изменения в параметры.

   Сообщение основано на практическом опыте автора и является (лаконичным) путеводителем по возможным "подводным камням". Не обсуждаются (хотя это возможно при наличии общественного интереса) проблемы поддержки мультиязычных интерфейсов. Для иллюстрации тезисов к сообщению приложен файл (далее - Пример).
   

   Основная часть проблем, разумеется, связана с кодировками текстов.
   

    Назовем символ юникода "нерелевантным" для текущего экземпляра Windows, если для него не "забронировано" место в кодовой странице по умолчанию. Для (нашей родной) кодировки windows-1251 нерелевантными являются буквы греческого, армянского, грузинского алфавитов, расширенной латиницы, китайские иероглифы и пр. Для кодировки windows-1252 (США и часть западноевропейских стран) нерелевантными являются, в том числе, буквы кириллицы.

  1. Использование API Windows

   Понятно, что при наличии ANSI (*A) и Unicode (*W) версий API следует использовать Unicode-версию. В противном случае, все нерелевантные символы во входных параметрах будут заменены на символ "?" (вопросительный знак).
   

   К сожалению, Microsoft (по инерции?) публикует описания заголовков именно ANSI-версий. Обычно переход к Unicode-версии не сложен: меняем в формальном параметре Byval xxx as String на Byval xxx as LongPtr (Long для Excel 2007), фактический параметр yyy меняем на StrPtr(yyy).

   2. Объекты Excel и MSO.

   Замеченных проблем не много.

   2.1. Именование объектов VBE-проекта.

   Как уже неоднократно отмечалось на форуме, не следует использовать потенциально нерелевантные символы для внутренних (Codename) имен листов, книги, модулей. Только латынь, цифры, знак подчеркивания. Нарушение этого простого правила может привести к разнообразным проблемам в системах с иной кодировкой: от неправильной работы отдельных макросов до "вырубания" Excel.
   

   2.2. Проблемы с Userform.Caption

   Заголовок окна Userform вплоть до версии Office 2016 не поддерживает Unicode (а с заголовками элементов управления все хорошо). Для иллюстрации можно выполнить макрос  i_UserformCaption в Примере.

   Лечение. Если в Приложении заголовок формы имеет смысловую нагрузку и содержит потенциально нерелевантные символы, то для требуемого текста можно вместо заголовка формы можно использовать "яркий" элемент управления Label в верхней части формы.

   2.3. Проблемы с Application.Caption

   Замечены только для Windows XP. Не критично.

   2.4. Функция рабочего листа TEXT (ТЕКСТ)

   Второй параметр (Format) функции TEXT задается с учетом региональных настроек. В каких-то случаях можно заменить указанную функцию на FIXED  (ФИКСИРОВАННЫЙ), у которой, кстати, можно узнать без макросов региональные разделители дробных долей и тысяч (FIXED(1234)). Можно необходимый формат для TEXT хранить в ячейке и извлекать из нее через Range.NumberFormatLocal. Наконец, свойство Application.International дает весь спектр региональных настроек.
   

   3. Проблемы с VBA.

   На субботнике разработчиков по переводу Windows в Unicode на VBA времени явно не хватило...

   3.1. Проблемы с текстовыми литералами.

   К сожалению, Excel не хранит тексты модулей в юникоде. Для иллюстрации - см. ячейки A3 и B3 Примера. И если комментариями (например, на русском языке) можно пожертвовать, то с текстовыми (строковыми) литералами,  содержащими потенциально нерелевантные символы, шутки плохи.

   Разумный выход - перенести соответствующие тексты в ячейки листов надстройки (скрытых листов книги) или в пользовательские свойства надстройки (книги). На такую модификацию в больших приложениях потребуется определенное время. Полезно иметь макрос, который будет отлавливать "нехорошие" литералы. Литералы, содержащие имена (внешние) листов книги, можно вообще исключить, применяя внутренние имена листов (см. п. 2.1.) в соответствующих конструкциях.

   3.2. Функция Msgbox.

   Не поддерживает Unicode - выполните  i_msgbox в Примере. Явно базируется на ANSI-версии API MessageBoxA.
   

   Лечение - перейти к Unicode-версии (см. модуль ModMessage).

   Теоретически, можно перенакрыть Msgbox cвоей функцией с тем же  именем, чтобы не менять (в этой части) код приложения. Это относится и к  пунктам 3.3 - 3.4

   3.3. Функция InputBox.

   Не поддерживает Unicode - выполните i_inputbox в Примере.

   Штатный заменитель  - Application.Inputbox имеет два недостатка: странную реакцию на нажатие стрелочек (на форуме научили с этим бороться с помощью F2) и (существенно!) ограничение в 255 символов на длину параметра Prompt. Оптимальный выход - написать собственную форму с переменным размером окна для приглашения. Заодно можно добавить полезный сервис: подсказки для ввода, контроль введенных значений и т.п.

   3.4. Операторы и функции для работы с файловой системой (dir, kill, ...)

   Нельзя использовать, если обрабатываемые файлы содержат потенциально нерелевантные символы в пути (Path). Заменители: FileSystemObject.Scripting (FSO), Shell.Application, Win API (Unicode-версии).

   3.5. Чтение и запись текстовых файлов

   Нельзя использовать "штатные" конструкции, если текстовые файлы содержат потенциально нерелевантные символы. Заменители: FSO (умеет читать и писать в UTF16), ADODB.Stream (читает и пишет в любой кодировке, способен быстро изменить кодировку файла).

   3.6. Функции VBA, учитывающие региональные настройки

К таким функциям относятся Format, IsNumeric, IsDate. Для функции Format есть предопределенные форматы и ограниченные в возможностях переносимые заменители (FormatNumber, ...).  См. также п. 2.4.

  3.7 Динамическое занесение формул      

   В некоторых случаях требуется в VBA динамически занести формулу в локализованном виде (условное форматирование, ...). Один из возможных трюков: временно присвоить ячейке свойство Formula (FormulaR1C1) и забрать FormulaLocal. Как всегда, есть и другие способы.

  4. Объекты ActiveX

  Для автора было приятной неожиданностью, что объекты 64-разрядного офиса могут управляться через интерфейсы автоматизации из 32-разрядных приложений.

  4.1 Регулярные выражения

  Не используем потенциально нерелевантные символы (например, русские буквы). Синтаксис регулярных выражений предусматривает символы Unicode (\un)

   В заключение выскажу (оптимистическое) мнение, что даже объемное Приложение можно за относительно короткое время превратить в переносимое.

   Автор выражает глубокую благодарность Владимиру (ZVI), Андрею (Андрей VG) и Михаилу (БМВ) за консультации и проявленное внимание к теме.
   

Изменено: sokol92 - 09.08.2018 17:09:39
Владимир
 
Доброе время суток.
Владимир, большое спасибо! Особенно ценно, что не по частям, а сразу единым справочником.
 
Название заменил, а то
Цитата
О переносимости приложений
как-то уводит в медицинское направление :)

Если замена не полностью соответствует - предлагайте.
 
OFF
модеаоры страдают жуткой непереносимостью к таким названиям тем :-)
По вопросам из тем форума, личку не читаю.
 
Коллеги, спасибо, воодушевлен вашим вниманием! Новое название меня, естественно, устраивает.
Владимир
 
Владимир,  присоединюсь к словам Андрея. Обобщенный и систематизированный материал  будет полезен.

О названии: По идее мы говорим о совместимости кода VBA при использовании в системах с разной битностью и региональными установками.  Мне кажется "разных версий" воспринимается как разных сборок …. .

Обеспечение совместимости  Excel VBA приложения для систем разной разрядности и с разными региональными установками.
По вопросам из тем форума, личку не читаю.
 
Было б интересно расширить список OS . Пингвинячии и огрызочные системы все чаще и чаще встречаются и доставляют хлопоты.
По вопросам из тем форума, личку не читаю.
 
Мне еще не попадались :)  Да и Яндекс, похоже, с ними не знаком.
Изменено: sokol92 - 13.07.2018 00:24:40
Владимир
 
Владимир, пингвинячии и огрызочные :-)
Если для вторых есть типа полноценный вариант, то в первых можно запустить в WINE и PlayOnLinux
По вопросам из тем форума, личку не читаю.
 
Владимир, интересный опыт. Работа с символами вообще интересная тема. К примеру: VBA транслятор (по-моему весь VB) читает и хранит только BSTR строку. На листа Excel символы хранятся в виде юникод-строки и читать через VBA(com) опять же BSTR строку, минуя СОМ оболочку, через API C как сишную строку с нулевым окончанием, так и аналог BSTR без нулевого окончания, с количеством символов в первом элементе этого контейнера. ANSI и другие региональные кодировки используются имхо в устаревших или ещё не допиленных функциях.
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
sokol92 написал:
Назовем символ юникода "нерелевантным" для текущего экземпляра Windows, если для него не "забронировано" место в кодовой странице по умолчанию
Попробую пояснить простым языком: заечание несколько не верно, в кодовой странице символов юникода - есть все символы. Страница символов ANSI - это не символы юникода :) Это какой либо набор региональных символов -256 шт., 128шт. которых всегда совпадает с американским стандартом страницы региональных символов.
Цитата
sokol92 написал:
Для (нашей родной) кодировки windows-1251 нерелевантными являются буквы греческого, армянского, грузинского алфавитов, расширенной латиницы, китайские иероглифы и пр. Для кодировки windows-1252 (США и часть западноевропейских стран) нерелевантными являются, в том числе, буквы кириллицы.
Теперь родная для всех -это одна страница знаков юникода (1-4 байта на символ, поэтому помещаются все символы. примечание:Хотя формы записи UTF-8 и UTF-32 позволяют кодировать до 2^31 (2 147 483 648) кодовых позиций, было принято решение использовать лишь 1 112 064 для совместимости с UTF-16.). Но есть программы, которые используют региональные страницы символов (1 байт на символ), это к примеру в росиии windows-1251, где только 256 символов, а в другой стране тоже 256 символов, но 128 первых - всегда совпадают, а остальные 128 для каждой страны свои.
«Бритва Оккама» или «Принцип Калашникова»?
 
Здравствуйте, Виталий! Спасибо за внимание к теме!
Мне не кажется, что при определении "нерелевантного" символа я отклонился от принятой терминологии. Разумеется, речь идет о кодовой странице Windows по умолчанию. Для РФ это windows-1251, для США и западноевропейских стран - windows-1252 и т.д. Для каждого конкретного экземпляра Windows 256 символов юникода являются, как Вы сами указали, релевантными, все остальные - нет. Понятно, что любой символ, который имеет для конкретного экземпляра Windows код (возвращаемый функцией Asc VBA) больший 127 (за исключением, вероятно, неразрывного пробела и др.), может быть потенциально "нерелевантным" для Windows c другой кодовой страницей по умолчанию.
Изменено: sokol92 - 13.07.2018 16:48:39
Владимир
 
Владимир, не спорю, что есть много кодировок/кодовых страниц, поэтому и придумали одну для всех это юникод (UTF-8, UTF-16, UTF-32 и т.д.)
Цитата
sokol92 написал:
256 символов юникода
- не совсем верно, это просто символы в одной из региональных таблиц (к примеру windows-1251 или windows-1252), . Символы юникода - в таблице юникода, она - одна для всех :)
Но в таблицу символов юникода входят все символы, всех региональных таблиц.
Ваше понятие "нерелевантного" символа - это просто разница между региональными таблицами. Если работать с символами юникода, разницы нет, там все символы "релевантны" (мы же помним про одну таблицу символов для всех).
Причем первые 128 символов (0-127) у всех страниц одинаковые (но кодируется разным количеством байтов).
Изменено: bedvit - 13.07.2018 17:39:17
«Бритва Оккама» или «Принцип Калашникова»?
 
В контексте данной темы "символ"="символ юникода" (символы, не входящие в стандарт юникода, мы вообще не рассматриваем).
"Нерелевантный" символ для экземпляра Windows - это термин, введенный специально для данной темы. Если где-то есть более удачное определение, то можно им воспользоваться.
Изменено: sokol92 - 13.07.2018 18:40:05
Владимир
 
Цитата
sokol92 написал: много полезной информации
Владимир, спасибо, что систематизировали и поделились Вашими знаниями - очень полезная информация! Сохранил себе копию.

Интересно, что в VBA справке MS трактует Unicode несколько по-своему:
- The ChrW function returns a String containing the Unicode character
- The AscW function returns the Unicode character code

Спецификация Unicode достаточно активно развивается.
Интересно посмотреть, например, какие Emoji-символы представлены к включению в новую версию Unicode  2009 г. - Draft Emoji Candidates
Изменено: ZVI - 31.07.2018 00:21:06
 
Здравствуйте, Владимир! Большое спасибо за внимание к теме!
Владимир
 
Цитата
ZVI написал:
Интересно, что в VBA справке MS трактует Unicode несколько по-своему:- The ChrW function returns a String containing the Unicode character …- The AscW function returns the Unicode character code
Владимир, вроде все верно, почему "несколько по-своему", каков альтернативный вариант?

Цитата
ZVI написал:
Emoji-символы
был удивлен, что в Unicode хотят запихнуть Emoji-символы. Зачем? ведь их тысячи (на одни и те же эмоции десятки разных смайлов), все нет смысла вносить, а те которые будут не всем будут нравиться. Судя по ссылке Владимира, какие-то посредственные (мое личное мнение).
«Бритва Оккама» или «Принцип Калашникова»?
 
Здравствуйте, Виталий! Мне кажется, по отношению к суррогатным парам вышеуказанное определение не точно. В последних версиях Excel появились функции UNICODE и UNICHAR.
Владимир
 
Владимир, приветствую! Формально написано, что возвращается символ или код символа (соответственно) в кодировке Юникода. Про возможность чтения четырехбайтовых символов не говорится. А первые два байта возвращаются исправно (как и описано). Хотя нам, со стороны - это кажется недоработкой. Видимо в UNICODE и UNICHAR добавили и возможность чтения четырехбайтвых символов - спец. китайский, музыкальные символы и прочая экзотика (символы не влезающие в 16 бит, в диапазоне 1000016..10FFFF16 и диапазон D80016..DFFF16 для кодирования так называемых суррогатных пар). Не проверял, времени пока нет. Предполагаю.
«Бритва Оккама» или «Принцип Калашникова»?
 
Проверял. На форуме были вопросы об иероглифах, "странных" знаках и пр.
Владимир
 
Плюс родная кодировка для Win это UTF-16LE, т.е. каждый символ кодируется 2 байтами (16 бит). Видимо разработчики первых двух функций не стали заморачиватся по поводу 32 битных символов. Я сам не читал, нужно поднять матчасть и посмотреть, как в кодировке UTF-16LE различаются 2 символа по 2 байта и одна суррогатная пара в 4 байта. Ведь когда читаем байты из байтового массива (строка юникода) мы должны как-то понимать, что вторые два байта могут быть не новый символ, а вторая часть суррогатной пары и это все еще один символ. Возможно есть границы, в которых только 4 байта на символ или как-то еще...
«Бритва Оккама» или «Принцип Калашникова»?
 
Так и различаются, как Вы написали в #19, - по старшим битам.
Владимир
 
Цитата
sokol92 написал:
Проверял
Спасибо за информацию.
Цитата
sokol92 написал:
- по старшим битам.
звучит логично. Думаю вы правы. Вот ещё матчасть:
Диапазон D80016..DFFF16 используется как раз для кодирования так называемых суррогатных пар — символов, которые кодируются двумя 16-битными словами. Символы Unicode до FFFF16 включительно (исключая диапазон для суррогатов) записываются как есть 16-битным словом. Символы же в диапазоне 1000016..10FFFF16 (больше 16 бит) уже кодируются парой 16-битных слов. Для этого их код арифметически сдвигается до нуля (из него вычитается минимальное число 1000016). В результате получится значение от нуля до FFFF16, которое занимает до 20 бит. Старшие 10 бит этого значения идут в лидирующее (первое) слово, а младшие 10 бит — в последующее (второе). При этом в обоих словах старшие 6 бит используются для обозначения суррогата. Биты с 11 по 15 имеют значения 110112, а 10-й бит содержит 0 у лидирующего слова и 1 — у последующего. В связи с этим можно легко определить к чему относится каждое слово.
«Бритва Оккама» или «Принцип Калашникова»?
 
Добавил в #1 раздел 4
Владимир
 
Цитата
bedvit написал: почему "несколько по-своему", каков альтернативный вариант?
Добрый день, Виталий. Здесь уже правильно отмечено, что "по-своему", т.к. отражает старую 16-битную версию стандарта Unicode. Это не удивительно, учитывая возраст Excel и VBA. И в сравнительно новой версии VBA7 не подтянули это к современному уровню, к сожалению.
 
Владимир, приветствую! Ну хоть альтернативу предложили,
Цитата
sokol92 написал:
В последних версиях Excel появились функции UNICODE и UNICHAR.
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
sokol92 написал:
1. Использование API Windows
Скажите пожалуйста откуда у вас такая информация, что с юникодными api-функциями нужно именно так работать? Вы это понимаете или просто нашли в интернете?
 
На всякий случай и на киберфорум закинули?)
«Бритва Оккама» или «Принцип Калашникова»?
 
Вот ещё небольшое обсуждение значимости книги и утверждений Win32 API и Visual Basic (Dan Appleman) :)
 
...
Изменено: Korshi - 16.07.2019 19:52:07
Страницы: 1 2 След.
Наверх