Delphi, С++Builder и COM: вопросы и ответы

Наталия Елманова
Компьютер Пресс — CD, 1999, N 7
Copyright N.Elmanova & ComputerPress Magazine.

После публикации осенью 1998 г. цикла статей, посвященных C++Builder и COM-технологии, в адрес редакции поступило много вопросов, связанных с проблемами использования COM в приложениях Delphi и C++Builder. Данная статья посвящена ответам на некоторые наиболее часто встречающиеся из них.

Уважаемая Наталия! Я только начал изучать Delphi и не могу решить простые задачи, например, такие как инсталляция новых компонент *.ocx ("Компьютер Пресс CD, 1999, N 3).
Не могли бы Вы помочь в решении этих вопросов?

Установка ActiveX (OCX) в палитру компонентов осуществляется просто: из меню среды разработки нужно выбрать опцию "Component/Import ActiveX Control". Если в полученном списке нужного элемента не окажется, нужно перед этим его зарегистрировать из командной строки: Regsvr32 <имя *.ocx-файла><имя *.ocx-файла>
В документации к Delphi и C++Builder установка элементов управления ActiveX описана довольно подробно.

Уважаемый автор,
Не могли бы Вы подробнее осветить вопрос применения созданных компонентов ActiveX в оболочке Microsoft Word. Процесс создания объекта ActiveX не вызывает столько вопросов, сколько вызывает вопросов проблема его распространения. Как среда внедрения заманчиво выглядит Microsoft Word, в связи с его большей распространенностью. Но созданные компоненты ActiveX не доступны во "вставляемых" объектах Word`а. Буду Вам очень признателен, если вы подскажете пути решения этой проблемы.

Если имеются в виду объекты, вставляемые с помощью пункта меню Word "Вставка/Объект", то обычно таким образом вставляются OLE-объекты, поддерживаемые так называемыми серверами документов. Элементы ActiveX могут и не являться такими серверами. Тем не менее, их можно вставить непосредственно в документ Word 97, используя опцию "Элементы управления" панели инструментов Visual Basic. На диалоговой панели "Элементы управления" следует нажать кнопку "Дополнительные элементы" и выбрать нужный элемент ActiveX. Он должен присутствовать в списке, если он зарегистрирован. Если же нет, его можно зарегистрировать, выбрав опцию "Зарегистрировать элемент управления".
Помимо этого, практически любой ActiveX можно поместить на форму Visual Basic, вызываемую из документа Word. Однако следует заметить, что, если Вы отдаете документ для использования на другом компьютере, следует отдать и библиотеку, содержащую элемент ActiveX — документ Word содержит лишь ссылку на нее (и организовать ее регистрацию). Иными словами, в данном случае мы имеем дело с типичной задачей поставки приложения (или документа — в данном случае это неважно), содержащего библиотеку ActiveX. Ее можно решить, создав обычный дистрибутив (хотя бы с помощью InstallShield Express). Однако более корректным кажется использование для этой цели Internet Explorer , так как он, в отличие от Word, предусматривает автоматическую регистрацию элементов управления ActiveX в составе Web-страницы.

После создания и переноса CAB-файла и Web-страницы на Web-сервер эта страница в браузере открывается, но на месте предполагаемой активной формы появляется только квадратик. Разъясните, в чем может быть проблема

Причин такого поведения может быть несколько. Первая причина связана с тем, что далеко не все браузеры поддерживают отображение ActiveX с помощью тега<OBJECT>. Для отображения ActiveX следует использовать MS Internet Explorer версии 3.0 и выше (отметим, что в комплект поставки некоторых 32-разрядных версий Windows входит более ранняя версия этого браузера) либо Netscape Communicator, оснащенный соответствующим модулем расширения (plug-in). Дело в том, что Netscape Communicator позиционирует себя на рынке как многоплатформенный браузер, поэтому сам по себе он не отображает элементов управления ActiveX, так как ActiveX есть технология, специфичная для Windows.
Вторая причина может быть связана с настройкой уровня безопасности браузера. Пользователь, желающий выполнять элемент управления ActiveX под управлением браузера, должен в общем случае дать разрешение на это — ведь ActiveX содержит исполняемый код, и в общем случае нет никакой гарантии, что он безопасен в использовании. Поэтому, если элемент управления ActiveX не имеет электронной подписи (а в России сейчас получить ее довольно сложно), при использовании настроек браузера по умолчанию он выполняться не будет. При этом некоторые версии Internet Explorer не только не сгружают ActiveX и тем более не выполняют его, но при этом еще и ничего не сообщают пользователю. Чтобы тем не менее осуществить выполнение неподписанного элемента управления ActiveX, в настройках параметров безопасности браузера нужно явным образом указать, что пользователь разрешает выполнять код в элементах управления ActiveX, полученных либо с конкретного Web-сервера, либо с любого сервера в Internet.
Есть и третья возможная причина — настройки операционной системы компьютера пользователя могут быть таковы, что пользователю запрещено изменять реестр, и в этом случае ActiveX в нем, естественно, не зарегистрируется.
И, наконец, еще одна возможная причина может заключаться в том, что приложение может быть разбито на "пакеты" (packages), которые ошибочно не включены в комплект поставки. В этом случае рекомендуется проверить опции проекта и, если необходимо, добавить недостающие файлы.

С удовольствием прочитал вашу статью: "Создание контроллеров автоматизации....", но по ходу дела у меня возник ряд вопросов: Как заставить управляемое приложение остаться активным после завершения контроллера. Пример: некая программа генерирует отчет, управляя редактором Word. Требуется, чтобы после того как отчет создан, окно Word не закрывалось. Я добился этого методом вызова функции AddRef применительно к управляемому объекту, но подозреваю, что этот способ не корректен.

В принципе можно использовать вызов функции AddRef. Но наиболее принятый способ (если используются вариантные переменные, как в примерах из статьи "Создание контроллеров автоматизации...") — поместить вариантную переменную в глобальную область видимости приложения-контроллера. В этом случае данные, содержащиеся в этой переменной, могут существовать, пока запущено приложение-контроллер, а вместе с ними остается активным и сам COM-сервер (если, конечно, из приложения-контроллера не был вызван метод, приводящий к его закрытию, и если этой вариантной переменной не было присвоено другое значение).

Я не понял, как формируется имя сервера, занесенное в реестр (Project1.MyAuto3)? MyAuto3 — мы задаем явно, а откуда берется Project1???

Project1 в данном случае есть имя исполняемого файла COM-сервера. MyAuto3 — это имя COM-объекта, реализованного в данном сервере (COM-объектов в одном сервере может быть и несколько).

Мой вопрос связан с автоматизацией Excel из приложений Delphi. Например, вполне нормально выполняется код, написанный в Delphi:

 var
v:variant;
begin
v := CreateOleObject('Excel.Application.8');
v.Visible:= True;
v.WorkBooks.Add;
v.Range('A2') := 12;
v.ActiveCell.FormulaR1C1 := '=RAND()';
v.ActiveCell.Font.Bold := True;
end;
Почему при этом не выполняется команда:
v.Range('A2').Select;
При этом появляется сообщение об ошибке: Member not found. Точно так же не выполняются и многие другие команды, которые можно найти в макросах Excel.
Я экспериментировал с Visual FoxPro 5.0, и все команды (макросы) из Excel можно переносить в него практически без изменений, подставляя впереди имя переменной, например v.Range('A2').Select

На самом деле в Delphi подобная команда выглядит так:

v.Range['A2'].Select;.

Иными словами, если Вы пользуетесь справкой по Visual Basic for Applications, нужно менять в содержащихся в ней примерах не только кавычки, но и скобки. Дело в том, что получающийся код должен удовлетворять требованиям синтаксиса языка программирования того средства разработки, на котором пишется контроллер Excel. Хотя синтаксис Pascal и позволяет создавать видимость того, что мы вызываем методы вариантной переменной (не все языки программирования позволяют это делать, например, в C++ так с вариантными переменными обращаться нельзя), из этого не следует, что в него можно включать синтаксические конструкции из Visual Basic без изменений. Что касается FoxPro — синтаксис используемого в этом средстве разработки языка с этой точки зрения (я имею в виду именно употребление скобок и кавычек в описании методов переменных, содержащих ссылки на COM-объекты), видимо, более близок к Visual Basic, чем синтаксис Pascal.

Чем с точки зрения синтаксиса может при автоматизации Excel помочь импорт библиотеки типов?

Если рассматривать только проблемы синтаксиса, импорт библиотеки типов полезен, скорее, в случае С++, а не Pascal.
Если мы не импортируем библиотеку типов, то синтаксис С++ будет совсем другим, нежели синтаксис Pascal. Рассмотрим простейший пример:

1) Form1.Show — этот оператор использует настоящий метод класса TForm (аналог на C++ — Form1->Show());

2) Var V:variant;
V:=CreateOleObject('Excel.Application');
.....
V.Visible:=True; —

Здесь используется "метод" для установки "свойства" варианта, но в действительности это инициирование вызова удаленных процедур в Excel (и его внутренних методов). В данном случае внутренний метод Excel, предназначенный для показа его окна, может называться как угодно, и "Show" есть лишь внешнее опубликованное имя этого внутреннего метода.

Аналог на C++ :

Variant V;
V=CreateOleObject("Excel.Application");
V.OlePropertySet("Visible",true);
//!

Итак, мы видим, что на самом деле "Visible" с точки зрения C++ — это просто строка. Иными словами, и Visual Basic, и Delphi, и Visual FoxPro просто совершают некоторые манипуляции со строками, позволяя помещать их в исходный текст без явного указания, что это строки, и тем самым заставляя думать, что мы вызываем методы вариантной переменной. C++ таких вещей делать не позволяет. Зато его код иллюстрирует, что происходит на самом деле при автоматизации Excel в Visual Basic или Delphi. Фактически "Visible" — просто строка, передаваемая в Excel из приложения-контроллера. Импорт же библиотеки типов позволяет создать объекты в адресном пространстве контроллера автоматизации, имеющие те же методы, что и объекты в адресном пространстве Excel. Соответственно можно вызывать настоящие методы этого "своего" объекта, а их реализация на самом деле будет заключаться в вызове удаленных процедур, обращенных к Excel (даже если это локальный Excel), которые инициируют манипуляции уже с внутренними объектами Excel. Соответственно после этого синтаксис на любом языке будет похож (с точностью до скобок, кавычек и указателей) на синтаксис Visual Basic.
То есть код С++

V.Visible=true

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

Есть ли возможность с помощью Delphi или C++Builder создать контроллер автоматизации одновременно для Excel 7 и Excel 97?

Если нужно создать приложение-контроллер, совместимое и с текущей, и с прежней версиями Excel, лучше или не импортировать библиотеку типов, или импортировать, но использовать позднее связывание по изложенным выше причинам (в документации к Delphi подробно описано, как это сделать), и не использовать вызовы методов, отсутствующих в старой версии Excel.
Совместимость со старыми версиями COM-серверов есть требование спецификации COM, и надо полагать, Microsoft следует своей собственной спецификации.
Однако не стоит полагаться на это, не произведя соответствующего тестирования с теми версиями COM-сервера, с которыми предполагается использовать данный контроллер. Дело в том, что в Office 95 в разных языковых версиях (немецкой, французской, английской) некоторые методы назывались по-разному, и с Delphi 2 поставлялся пример, который это иллюстрировал. Поэтому стоит уточнить (или проверить экспериментально), как именно с точки зрения именования методов Excel как COM-сервера локализована версия, которую планируется использовать.