Гергерт Сергей
Оптимизация вызова строковых API
Тип String в VB - это на самом деле WideString, т.е. для хранения каждого символа используется не 1, а 2 байта, как требует стандарт
Unicode. Два байта на символ - это 65535 комбинаций, для земных алфавитов хватает.
API-функции, принимающие параметр
String, как правило, существуют в двух вариантах: A и W (по последней букве). A - функция хочет получить 1-байтовую строку
ANSI. W - функции нужна 2-байтовая строка Unicode. Практически все
OLE-функции являются W, хотя и нет такой буквы в их окончании.
Когда мы объявляем какую-либо функцию через
Declare, и у этой функции есть параметр(ы) String, то в любом случае при вызове этой функции
VB создаёт копию нашей строки при помощи StrConv(str, vbFromUnicode), и в функцию передаётся именно она. Когда функция возвращает результат,
VB проделывает обратную операцию - StrConv(str, vbUnicode).
При этом он никогда не спрашивает нас, нужно ли нам это. В большинстве случаев это действительно удобно (когда мы работает с функциями A), но как быть с W? При передаче им параметра конвертировать из
Unicode не нужно, но нас никто не спрашивает. Один из способов дать W-функции верные данные - перед вызовом сделать
StrConv(str, vbUnicode). Тогда получается:
- мы делаем конверт в Unicode, получается как бы
Double Unicode
- VB перед вызовом функции делает vbFromUnicode, получается нормальный
Unicode
- W-апишка получает свою строку
- на возвращённом результате VB проводит vbUnicode, получается "Double Unicode"
- мы после вызова делаем vbFromUnicode и наконец получаем результат
Страшно, правда? :) Вот был бы у оператора
Declare модификатор Unicode, а? "Но только принца нет, где ж он подевался...". А раз так, обратим свои взоры на то, что именно ожидает увидеть
API-функция в качестве своего параметра. Ожидает она увидеть указатель на массив байт, который, собственно, и является строкой. В результате описанных действий
VB неявно передаёт ей указатель на копию строки, но мы ведь можем и сами. Для того и дадена нам функция
StrPtr, чтобы указатель на строку получать. А раз так, то выводим правило:
- Если функция требует строку ANSI, то её строковые параметры объявляются
As String
- Если функция требует строку Unicode, то её строковые параметры объявляются
As Long, и в качестве значения туда передаётся
StrPtr(str).
В первом случае - два конверта (от них не денешься никуда).
Во втором случае - ни одного. А было четыре.