2006 г.
Биллиг Владимир Арнольдович
Интернет-Университет Информационных Технологий, INTUIT.ru
Назад Оглавление Вперёд
Два языка: C и VB. Различия при вызове функций
Итак, чтобы корректно вызывать Win32 API функции на VBA, следует разбираться, чем отличаются вызовы функций в языках C и Visual Basic (VBA). Даже, если используется обозреватель API Viewer, который автоматически транслирует типы языка C в типы языка VBA, знание этих различий необходимо во многих ситуациях.
Соответствие между простыми типами данных
Нижеследующая таблица описывает соответствие между некоторыми, простыми типами данных двух языков:
Таблица 6.1. Соответствие между типами языков C и VBAC/C++ тип данных | Венгерская нотация | Описание | Тип языка VBA |
---|
BOOL | b | 8-и битное булево значение. Значение 0 эквивалентно False , ненулевое значение - True | Boolean или Long |
BYTE | ch | 8-и битное целое без знака | Byte |
HANDLE | h | 32 -х битное целое без знака, задающее описатель Windows -объектов | Long |
int | n | 2-х байтное целое со знаком | Integer |
UINT | u | 2-х байтное целое без знака | Long |
DWORD | dw | 4-х байтное целое без знака | Long |
long | l | 4-х байтное целое со знаком | Long |
LP | lp | 32-х битный указатель на C/C++ структуры, строки, функции или другие данные в памяти | Long |
LPZSTR | lpsz | 32-х битный указатель на C строку, завершаемую нулем | Long |
При преобразовании данных между типами UINT
и DWORD
и типом Long
могут возникнуть проблемы, если заданы некорректные значения этих данных. Понятно, что если параметр функции API объявлен как UINT
, то возникнет ошибка при попытке передать через тип Long
отрицательное значение или длинное целое, превосходящее значение, допустимое для типа UINT
. Конечно, нужно быть или осторожным или ввести собственные типы данных, где все необходимые проверки будут выполняться.
Структуры языка C и тип, определенный пользователем, в языке VBA
В языке C можно определять записи - совокупность данных разного типа. Такие записи в языке C называются структурами. Обычно, вначале определяется соответствующий структурный тип, а затем имя этого типа используется при объявлении конкретных переменных. Структуры могут передаваться в качестве аргументов при вызове функций, в том числе при вызове Win32 API функций. В VBA, как известно, для задания подобного структурного типа используется конструкция Type…End Type
, называемая типом, определенным пользователем. Переменные такого типа передаются вызываемой функции обычным способом: X As T
, где T
- имя пользовательского типа. Позже мы приведем пример вызова функции Win32 API, которой передается структура в качестве аргумента.
Об описателях языка C и объектах Windows
В языке C особенно при работе с объектами Windows, широко используется тип Handle
- задающий описатели объектов. Когда создаются объекты ядра операционной системы и такие основные объекты, как окна, - все они снабжаются описателем, имеющим тип Handle
. Описатель представляет длинное целое и однозначно идентифицирует объект. Всегда, когда в функцию Win32 API необходимо передать такой объект, то реально передается его описатель. При трансляции описателей в тип языка VBA ему ставится в соответствие тип Long
. При этом желательно понимать, что речь все-таки идет об описателях, создаваемых операционной системой, в момент создания соответствующего объекта. Соответствующие примеры будут даны чуть позже.
Void функции языка C
В языке С формально нет процедур, есть только функции. В тех случаях, когда по существу речь идет о процедурах, вычисляющих не один скалярный результат, а имеющих несколько выходных параметров, как правило, используется функция, результат которой говорит об успешности выполнения процедуры. Если результат функции имеет значение True
, то все выходные параметры благополучно вычислены, в противном случае следует проанализировать причину неуспеха. Типично для языка C то, что вызов функций является условием оператора If
, - оператор If
задает упаковку вызова функции, позволяя не только вызвать функцию, но и проверить корректность завершения ее работы. При трансляции заголовков таких функций в язык VBA, они естественно транслируются в функции VBA и для работы с ними можно сохранить стиль языка C.
Однако в языке C используются и функции, не возвращающие результата. Результат таких функций задается описателем Void
, по существу, они являются процедурами. И при трансляции их в VBA их и следует задавать в виде процедур.
Вызов аргументов по ссылке ByRef и по значению ByVal
В языке C++ основным способом передачи параметров является передача их по значению, в VBA - по ссылке. Конечно, в обоих языках применяются оба способа. Тем не менее, нужно понимать, что описатель ByVal
очень часто будет встречаться при вызове Win32 API функций, значительно чаще, чем при вызове обычных VBA функций. Если используется API Viewer, то этот описатель автоматически будет появляться для тех параметров, где необходима подобная форма вызова. Следует обратить внимание на одно обстоятельство. Несмотря на то, что такой описатель может появляться и для строковых аргументов, строки всегда передаются в функции Win32 API по ссылке. Последнее обстоятельство также связано со спецификой работы со строками в функциях языка C, на которых следует остановиться подробнее.
Строковые аргументы при вызове функций Win32 API
Как мы уже говорили, строки передаются по ссылке, даже если у параметра указан описатель ByVal
. Не возникает никаких проблем при передаче строки в функцию Win32 API. Передаваемый аргумент может быть произвольным строковым выражением, в том числе переменной типа String
или строковой константой. Сложнее дело обстоит, если функция должна вернуть строку, в качестве результата. Прежде всего, напомним, что в функциях Win32 API тип возвращаемого значения никогда не является строкой, - это всегда целочисленное значение, чаще всего булево значение, указывающее на то, удачно ли завершилось выполнение функции. Поэтому, если нужно получить строку в качестве результата, то функции передается два параметра - строка и ее длина, описанные чаще всего следующим образом:
ByVal lpResultStr As String, ByVal LenResultString As Long
Поскольку результат будет формироваться непосредственно в области памяти, отведенной строке lpResultStr
, то перед вызовом эта строка должна удовлетворять следующим условиям:
- она должна быть строкой, завершаемой нулем. Чаще всего она вся состоит из нулевых символов.
- Ее длина должна быть достаточной для того, чтобы вместить результирующую строку.
- Параметр
LenResultString
должен указывать максимально допустимое число символов результирующей строки.
С учетом этих требований перед вызовом функций, возвращающих строковые значения, как правило, передаваемая функции строка инициализируется и набивается подходящим количеством нулевых символов. Напомним, нулевой символ задается константой vbNullChar
. Обычно, это делается следующим образом:
Const MaxSize = 255 As Long
lpResultString = String$(MaxSize, vbNullChar)
LenResultString = Len(lpResultString)
После того, как функция благополучно завершит работу, приходится выделять из строки возвращенное значение. Если строка до вызова состояла сплошь из нулевых символов, то результат после вызова представляет ее префикс, заканчивающийся первым нулевым значением. В этом случае результат легко выделяется и это причина того, почему целесообразно строку инициализировать нулевыми символами.
Тип Any
Иногда, параметр функции API может принимать значения различных типов. В этом случае в операторе Declare
нельзя указать один конкретный тип этого параметра. Для решения подобной проблемы и был введен специальный тип Any
. Если параметр имеет этот тип, то в период трансляции не проверяется правильность соответствия типов и аргумент может принимать значения любых типов. Конечно, нужно иметь в виду, что функция может принимать значения хоть и нескольких, но совершенно определенных типов. Поэтому при работе с типом Any
на программиста возлагается вся ответственность за корректную передачу значения функции API. Альтернативой применения типа Any
является задание для одной функции нескольких операторов Declare
, - по одному на каждый возможный тип параметра. Тогда в каждой конкретной ситуации будет вызываться соответствующая функция с нужным типом параметра.
Назад Оглавление Вперёд