Вызов функций и оператор Declare
Элементы ActiveX, COM объекты могут экспонировать свой интерфейс, - свои свойства и методы. Это означает, что они уведомляют, предоставляют информацию клиентам о своем интерфейсе. Технически это обеспечивается тем, что эти объекты, наряду с DLL, сопровождаются TypeLib - библиотекой типов, в которой содержится в требуемом виде информация об интерфейсе объекта. В этом случае, для того чтобы начать работу с объектом, достаточно подключить ссылку на эту библиотеку в меню Tools|References в среде редактора VBE. Эта возможность не раз обсуждалась, когда речь шла о вызове, например, приложения Excel в документах Word. Напомним, что приложения Office 2000 представляют собой ActiveX объекты, построенные на основе COM технологии. Они явно экспонируют свой интерфейс, именно поэтому нет проблем при работе с такими приложениями, вызовами свойств и методов их многочисленных объектов. Библиотеки, составляющие Win32 интерфейс, не сопровождаются библиотеками типов TypeLib. Поэтому необходимо самому программисту уведомить VBA о том, где найти и как следует вызывать ту или иную функцию Win32 API Вызову каждой функции должен предшествовать оператор Declare, описывающий эту функцию. Этот оператор и сама схема вызова библиотечных функций используется при работе с любыми DLL, а не только с теми, которые содержат Win32 API функции. В общем случае в DLL могут храниться как функции, так и процедуры. Два варианта вызова этого оператора соответствуют ссылке на процедуру и на функцию, возвращающую значение. Первый вариант:
[Public | Private] Declare Sub имя Lib "имя-библиотеки" [Alias "псевдоним"] [([параметры])]
Во втором случае его синтаксис:
[Public | Private] Declare Function имя Lib "имя-библиотеки" [Alias "псевдоним"] [([параметры])] [As возвращаемый-тип]
В этих вызовах ключевые слова и параметры имеют следующий смысл:
- Ключевое слово Public используется, чтобы сделать объявляемую процедуру доступной всем модулям проекта; ключевое слово Private ограничивает доступ к объявленной процедуре лишь модулем, в котором она объявлена.
Заметьте, в стандартном модуле можно использовать оба описателя, но в модуле класса разрешается использовать только описатель Private. - Ключевое слово Sub в первом случае означает, что речь идет о процедуре; альтернативный ключ Function во втором случае указывает на функцию, возвращающую значение, которое может быть использовано в выражениях.
- Обязательный параметр имя является именем объявляемой процедуры или функции. Это имя используется при вызовах в VBA программах. Оно может совпадать или отличаться от того имени, под которым процедура (функция) хранится в DLL. Заметьте, для имен функций Win32 API в отличие от Win 16 имеет значение различие между прописными и строчными буквами.
- После обязательного ключевого слова Lib должно следовать в кавычках имя-библиотеки, содержащей объявляемую процедуру.
- Ключ Alias позволяет указать, что процедура имеет в DLL другое имя - "псевдоним", благодаря чему можно избежать коллизии имен в программе. Если первый символ параметра " псевдоним" не является признаком числа ( #), псевдоним понимается как имя входной точки DLL для данной процедуры; если же первый символ псевдонима - ( #), следующие за ним число должно задавать порядковый номер входной точки процедуры в DLL. Дело в том, что процедура может иметь несколько точек входа.
- Необязательный список параметры задает список параметров, передаваемых процедуре при вызове.
- As возвращаемый-тип во втором варианте оператора задает тип значения, возвращаемого функцией; им может быть любой из базисных типов VBA (не допускаются только строки фиксированной длины), тип объекта или определенный пользователем тип.
- Список параметры - это список разделенных запятыми параметров процедуры; каждый элемент этого списка имеет вид:
[Optional] [ByVal | ByRef] [ParamArray] переменная[()] [As тип]
- Здесь ключ Optional означает, что данный параметр необязателен; при этом все следующие в списке параметры должны быть необязательными и сопровождаться этим же ключом Optional. Этот ключ нельзя применять, если среди параметров есть массив параметров ParamArray.
- Ключевые слова ByVal и ByRef указывают на то, что параметр передается по значению или по ссылке; по умолчанию в VBA предполагается передача значения по ссылке (ByRef).
- Ключевое слово ParamArray позволяет задать массив элементов типа Variant; этот параметр должен быть последним в списке и не должен перед собой иметь ключей ByVal, ByRef или Optional; такой массив позволяет передавать в процедуру произвольное (заранее неизвестное) число параметров.
- Переменная - произвольное допустимое в VBA имя переменной; пустые скобки () после имени переменной означают, что соответствующий параметр - массив.
- Необязательное определение As тип задает тип параметра, значения которого могут быть такими же, как и у описанного выше определения возвращаемый-тип.
Задав произвольный тип (As Any), Вы исключите проверку при передаче параметра процедуре.
Вот пример задания оператора Declare для двух функций Win32 API:
Private Declare Function CreateRectRgn Lib "gdi32" Alias "CreateRectRgn" _ (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long Private Declare Function GetTempPath Lib "kernel32" _ Alias "GetTempPathA" (ByVal nBufferLength As Long, _ ByVal lpBuffer As String) As Long
Синтаксически оператор Declare прост и понятен, нужно указать библиотеку, имя функции, под которым она будет вызываться в VBA программе, ее имя (псевдоним) под которым она записана в библиотеке и параметры функции в привычном синтаксисе. Однако реальная жизнь не так проста и в организации вызова функций API есть много подводных камней. Дело в том, что DLL служат средством межязыкового взаимодействия. Сама DLL может быть разработана на одном языке, а вызываться в другом. Тогда возникает проблема правильной передачи параметров, поскольку может не быть точного соответствия между типами данных двух используемых языков. Функции Win32 API разработаны в ориентации на синтаксис языка C и C++. Поэтому при записи оператора Declare требуется корректно указать типы параметров, так чтобы они соответствовали типам, используемым в языке C. Еще одна проблема состоит в том, что помимо оператора Declare, в ряде случаев необходимо предварительно описать требуемые типы данных и константы, необходимые в процессе вызова функции. Так что, прежде чем вызвать функцию из DLL, необходимо корректно задать оператор Declare, описать необходимые типы и константы, - все это может быть не столь простой задачей.