Сообщение посвящено проблеме обеспечения корректной работы приложения для 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)
В заключение выскажу (оптимистическое) мнение, что даже объемное Приложение можно за относительно короткое время превратить в переносимое.
Автор выражает глубокую благодарность Владимиру (