Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Конференция «Технологии управления данными 2018»
СУБД, платформы, инструменты, реальные проекты.
29 ноября 2018 г.
2006 г.

WinApi
Лекция из курса «Основы офисного программирования и язык VBA»

Биллиг Владимир Арнольдович
Интернет-Университет Информационных Технологий, INTUIT.ru

Назад Оглавление Вперёд

Два языка: C и VB. Различия при вызове функций

Итак, чтобы корректно вызывать Win32 API функции на VBA, следует разбираться, чем отличаются вызовы функций в языках C и Visual Basic (VBA). Даже, если используется обозреватель API Viewer, который автоматически транслирует типы языка C в типы языка VBA, знание этих различий необходимо во многих ситуациях.

Соответствие между простыми типами данных

Нижеследующая таблица описывает соответствие между некоторыми, простыми типами данных двух языков:

Таблица 6.1. Соответствие между типами языков C и VBA
C/C++ тип данныхВенгерская нотацияОписаниеТип языка VBA
BOOLb8-и битное булево значение. Значение 0 эквивалентно False, ненулевое значение - True Boolean или Long
BYTEch8-и битное целое без знака Byte
HANDLEh32 -х битное целое без знака, задающее описатель Windows -объектов Long
intn2-х байтное целое со знаком Integer
UINTu2-х байтное целое без знака Long
DWORDdw4-х байтное целое без знака Long
longl4-х байтное целое со знаком Long
LPlp32-х битный указатель на C/C++ структуры, строки, функции или другие данные в памяти Long
LPZSTRlpsz32-х битный указатель на 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, - по одному на каждый возможный тип параметра. Тогда в каждой конкретной ситуации будет вызываться соответствующая функция с нужным типом параметра.

Назад Оглавление Вперёд

Новости мира IT:

Архив новостей

Последние комментарии:

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...