Использование раннего и позднего привязывания в автоматизации

Переводы статьи Переводы статьи
Код статьи: 245115 - Vizualiza?i produsele pentru care se aplic? acest articol.
Развернуть все | Свернуть все

В этой статье

Аннотация

Способ привязывания к серверу автоматизации может влиять на многие аспекты программы, такие как производительность, гибкость и удобство сопровождения.

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

Дополнительная информация

Автоматизация – это процесс взаимодействия одного программного компонента с другим компонентом и/или управления им с помощью модели COM (Component Object Model) Microsoft. Это основа большинства способов межкмпонентного взаимодействия, используемых в таких языках, как Visual Basic или Visual Basic for Applications, ставшая обычной частью большинства программ.

Исторически объект автоматизации – это объект, поддерживающий интерфейс IDispatch. Этот интерфейс позволяет клиентам вызывать методы и свойства во время выполнения без необходимости точно знать объект взаимодействия во время разработки; этот процесс называется поздним привязыванием. Однако сегодня понятие объект автоматизации может относиться практически ко всем COM-объектам, даже к тем, которые не поддерживают интерфейс IDispatch (и поэтому для них не может осуществляться позднее привязывание). В данной статье предполагается, что автоматизируемый объект поддерживает оба метода.

Что такое привязывание?

Привязывание – это процесс вызова соответствующей функцией, написанной программистом, фактического кода (внутреннего или внешнего), реализующего функцию. Это осуществляется при компиляции приложения, и все вызываемые в коде функции должны быть привязаны до выполнения кода.

Для понимания процесса «привязывание» можно представить как публикацию книги. Представьте, что ваш код – это текст книги, в определенном параграфе которой вы написали «дополнительные сведения см. на странице x в главе 12». Вы не знаете точный номер страницы, пока книга не будет написана полностью, поэтому для того, чтобы в параграфе содержались верные сведения, все страницы книги должны быть переплетены, а в этот параграф вставлен правильный номер страницы. Вставка ссылок на другие части книги возможна только после того, как она будет «переплетена».

Привязывание программного обеспечения – схожий процесс. Ваш код состоит из отдельных частей, которые должны быть объединены, чтобы код мог быть «прочитан». Привязывание – это замена имен функций адресами памяти (смещениями памяти, если быть более точным), в которые «перейдет» код при вызове функции. Для COM-объектов адрес – это смещение памяти в таблице указателей (называемой таблицей v-table) объекта. Привязка COM-функции осуществляется через таблицу v-table.

Структура COM-объекта простая. Когда в коде содержится ссылка на объект, в нем содержится косвенный указатель на начало таблицы v-table. Таблица v-table – это массив адресов памяти, каждая запись которой представляет отдельную функцию, которая может быть вызвана на этом объекте. Для вызова третьей функции на COM-объекте выполняется переход в таблице на три записи вниз, а затем переход к указанной в записи области памяти. Это вызывает выполнение кода для функции, по завершении чего может быть выполнена следующая строка кода.

+-[Code]------------+  +.................................[COM Object]...+
|                   |  : +-------------+                                :
|Set obj = Nothing -|--->| obj pointer |                                :
|                   |  : +-|-----------+                                :
+-------------------+  :   |   +-----------------+                      :
                       :   +-->| v-table pointer |                      :
                       :       +--|--------------+                      :
                       :          |                                     :
                       :          |  +----------------------------+     :
                       :  (3rd)   |  | Function 1 Address pointer |     :
                       : (Offset) |  +----------------------------+     :
                       :          |  | Function 2 Address pointer |     :
                       :          |  +----------------------------+     :
                       :          +->| Function 3 Address pointer |     :
                       :             +----------------------------+     :
                       +................................................+

				
В приведенном выше пирмере показано освобождение COM-объекта. Поскольку все COM-объекты производны от IUnknown, первые три записи в таблице являются методами, унаследованными от IUnknown. При необходимости освобождения объекта код вызывает третью функцию в таблице v-table (IUnknown::Release).

К счастью, Visual Basic осуществляет это автоматически. Вам, как программисту Visual Basic, никогда не приходилось работать непосредственно с таблицей v-table. Но в этой таблице определяется способ привязывания всех COM-объектов, поэтому для понимания процесса привязки важно быть с ней знакомым.

Ранее привязывание

В приведенном выше примере показано ранее (или таблица v-table) привязывание. Этот вид привязывания осуществляется для всех COM-объектов при каждом вызове интерфейса IUnknown COM-объекта. Но как насчет других функций объекта? Как вызывается его метод Refresh или свойство Parent? Это специальные функции, обычно являющиеся уникальными для объекта. Если расположение этих функций в таблице v-table неизвестно, как найти адреса функций, необходимые для их вызова?

Ответ, разумеется, зависит от того, известна ли вам структура таблицы v-table объекта или нет. Если структура известна, для специальных методов объекта можно выполнить процесс раннего привязывания, аналогичный использовавшемуся для методов IUnknown. Вот то, что обычно подразумевается под термином «ранее привязывание».

Для использования раннего привязывания для объекта необходимо знать, что из себя представляет таблица v-table. В Visual Basic это осуществляется путем добавления ссылки на библиотеку типов, описывающую объект, его интерфейс (v-table) и все функции, которые могут быть вызваны для объекта. После этого можно объявить для объекта определенный тип, а затем установить и использовать этот объект с помощью таблицы v-table. Например, при необходимости автоматизации Microsoft Office Excel с помощью раннего привязывания необходимо добавить ссылку на «библиотеку объектов Microsoft Excel 8.0» в диалоговом окне «Project|References» (Проект|Ссылки), а затем объявить переменную, как имеющую тип «Excel.Application». После этого для всех вызовов объектной переменной будет использоваться ранняя привязка:
' Установка ссылки на библиотеку объектов Microsoft Excel 8.0 в
' диалоговом окне «Project|References» (Проект|Ссылки) (или «Tools|References» (Инструменты|Ссылки) в VB4 или VBA).

' Объявление объекта как объекта с ранней привязкой
  Dim oExcel As Excel.Application

  Set oExcel = CreateObject("Excel.Application")

' Свойство Visible вызывается через таблицу v-table
  oExcel.Visible = True
				
В большинстве случаев этот способ работает замечательно, но что делать, если точный объект, который будет использоваться во время разработки, неизвестен? Например, что делать при необходимости взаимодействия с несколькими версиями Excel или с объектом, который совершенно «неизвестен»?

Позднее привязывание

Модель COM включает интерфейс IDispatch. Объекты, реализующие IDispatch, имеют disp-интерфейс (если это единственный поддерживаемый интерфейс) или dual-интерфейс (при наличии настраиваемого интерфейса, для которого можно выполнить ранее привязывание). Клиенты с привязкой IDispatch называются клиентами с «поздней привязкой», поскольку вызываемое ими точное свойство или метод определяются во время выполнения с помощью методов IDispatch. Возвращаясь к примеру с книгой, представьте это как сноску на содержание, в котором нужно «найти» номер страницы «во время чтения», так как в сноске он не указан.

Магические действия интерфейса вызываются с помощью двух функций: GetIDsOfNames и Invoke. Первая функция сопоставляет имена функций (строки) с идентификатором (который называется dispid), представляющим функцию. После получения сведений об идентификаторе функции, которую необходимо вызвать, она вызывается с помощью функции Invoke. Этот вид вызова метода называется «поздней привязкой».

Опять же, способ привязки объекта в Visual Basic указывается определением объекта. При объявлении объектной переменной как «Object» вы, фактически, указываете Visual Basic на использование IDispatch, и поэтому выполняется позднее привязывание:
' Для использования позднего привязывания ссылка на библиотеку типов не требуется.
' Пока объект поддерживает IDispatch, метод может быть
' динамически размещен и вызван во время выполнения.

' Объявление объекта как объекта с поздней привязкой
  Dim oExcel As Object

  Set oExcel = CreateObject("Excel.Application")

' Свойство Visible вызывается через IDispatch
  oExcel.Visible = True
				
Как вы видите, остальная часть кода совпадает. Единственным различием между ранним и поздним привязыванием (с точки зрения написания кода) является объявление переменной.

Важно отметить, что «позднее привязывание» – это вызываемая функция, а не способ ее вызова. Из предыдущего рассмотрения привязывания в целом вы должны были заметить, что сам IDispatch использует раннюю привязку: т.е. Visual Basic выполняет вызов для установки свойства Visible с помощью записи таблицы v-table (IDispatch::Invoke), так же как и любые вызовы COM. Сам COM-объект отвечает за переадресацию вызова верной функции для отображения Excel. Такое косвенное обращение обеспечивает возможность компиляции клиента Visual Basic (т.е. привязку к действительному адресу функции), но точная функция, фактически выполняющая обработку, все равно неизвестна.

Привязывание Dispid

Некоторые клиенты автоматизации (в большей степени MFC и Visual Basic 3.0, но также и Visual Basic 5.0 и 6.0 в отношении элементов управления ActiveX) используют гибридную форму позднего привязывания, называемую привязыванием dispid. Если COM-объект известен во время разработки, идентификаторы dispid для вызываемых функций могут быть сохранены в кэше и переданы непосредственно IDispatch::Invoke без необходимости вызова GetIDsOfNames во время выполнения. Это может значительно повысить производительность, поскольку вместо двух вызов COM для одной функции необходим только один вызов.

Привязывание Dispid, как правило, нельзя использовать в Visual Basic 5.0 и 6.0. Эта привязка используется для объектов, указанных в библиотеке типов, но для которых отсутствует настраиваемый интерфейс (то есть для объектов только с disp-интерфейсом), и для сводных элементов управления ActiveX, но, как правило, Visual Basic во всех случаях использует раннее привязывание, когда бы вы использовали привязывание dispid.

Какой вид привязывания следует использовать?

Ответ на этот вопрос зависит только от особенностей проекта. Корпорация Майкрософт рекомендует практически всегда использовать ранее привязывание. Однако могут существовать причины для использования позднего привязывания.

Ранее привязывание является предпочтительным способом. Она является наилучшим вариантом с точки зрения производительности, поскольку приложение выполняет привязку непосредственно к адресу вызываемой функции, и поэтому отсутствует дополнительная нагрузка при подстановке во время выполнения. Что касается общей скорости выполнения, она почти в два раза выше, чем при использовании позднего привязывания.

Ранее привязывание также поддерживает безопасность типа. При наличии ссылки на библиотеку типов компонента Visual Basic обеспечивает поддержку IntelliSense, что помогает в правильном написании каждой функции. Visual Basic также отображает предупреждения о наличии недопустимого типа данных параметра или возвращенного значения, позволяя сэкономить время на написание и отладку кода.

Однако позднее привязывание полезно в ситуациях, когда во время разработки точный интерфейс объекта не известен. Если ваше приложение обращается к нескольким неизвестным серверам или для него необходим вызов функций по их именам (например, используя функцию CallByName Visual Basic 6.0), необходимо использовать позднее привязывание. Позднее привязывание также полезно для разрешения проблем совместимости нескольких версий компонента, интерфейс которого в определенных версиях был неправильно изменен или настроен.

Преимущества раннего привязывания делают его лучшим решением, если использование этого вида привязывания возможно.

Обеспечение совместимости нескольких версий

Если при использовании компонента, не распространяемого с пакетом установки, вы не уверены в точной версии, с которой будет осуществляться взаимодействие во время выполнения, следует уделить особое внимание раннему привязыванию к интерфейсу, совместимому со всеми версиями компонента, или (в некоторых случаях) использовать позднее привязывание для вызова метода, существующего в определенной версии, обеспечивая безопасность отказов, если этот метод отсутствует в версии, установленной в клиентской системе.

Хорошими примерами таких серверов COM являются приложения Microsoft Office. Как правило, приложения Office расширяют интерфейсы новыми возможностями или исправляют предыдущие несоответствия версий. При необходимости автоматизации приложения Office рекомендуется использовать ранее привязывание к первой версии продукта, которая, как вы полагаете, может быть установлена в системе клиента. Например, для обеспечения возможности автоматизации Excel 95, Excel 97, Excel 2000 и Excel 2002 необходимо использовать библиотеку типов для Excel 95 (XL5en32.olb), чтобы обеспечить совместимость c тремя другими версиями.

Приложения Office также демонстрируют возможные ограничения маршалинга объектных моделей с большими dual-интерфейсами на некоторых платформах. Для обеспечения правильной работы кода на всех платформах необходимо использовать IDispatch. Дополнительные сведения об обеспечении совместимости при работе с приложениями Office см. в следующей статье базы знаний Майкрософт:
247579 Использование привязывания DISPID для автоматизации приложений Office во всех возможных случаях (Эта ссылка может указывать на содержимое полностью или частично на английском языке)

Ссылки

Дополнительные сведения о моделе COM, таблицах v-table и использовании автоматизации см. в следующих книгах.
Дейл Роджерсон, Inside COM, MSPRESS, ISBN: 1-57231-349-8.

Мэтт Керленд, Advanced Visual Basic 6, DevelopMentor, 0201707128.

Свойства

Код статьи: 245115 - Последний отзыв: 29 декабря 2007 г. - Revision: 7.1
Информация в данной статье относится к следующим продуктам.
  • Microsoft Office Ultimate 2007
  • Microsoft Office Enterprise 2007
  • Microsoft Office Professional 2007
  • Microsoft Office Professional Plus 2007
  • Microsoft Office Standard 2007
  • Microsoft Office Home and Student 2007
  • Microsoft Office Basic 2007
  • Microsoft Office Standard Edition 2003
  • Microsoft Office XP Developer Edition
  • Microsoft Office 2000 Developer Edition
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
Ключевые слова: 
kbinfo kbautomation KB245115

Отправить отзыв

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com