современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран
Скачать 2.24 Mb.
|
388 12. Конструктор модулей для объектов ActiveX Рис. 12.1. Задание типа объекта Таким источником может быть: • сам объект (Automation Object); • библиотека типа, содержащая данные об объекте Автоматизации (Type Library Containing Automation Information); • библиотека типа, содержащая данные о COM-интерфейсе объекта (Type Library Containing COM Interface Information); • библиотека типа, содержащая данные о DLL (Type Library Containing DLL Information); • библиотека DLL, содержащая данные о типе объекта (DLL Containing Type Information). Выбор Automation Object производится, когда информация об объекте предоставляется динамически в процессе исполнения приложения. Такая ситуация встречается сравнительно редко, поскольку Мicrosoft рекомендует, чтобы объекты снабжались библиотекой типа. После выбора Automation Object потребуется ввести имена приложения, объекта и номер версии объекта (рис. 12.2), который, впрочем, может быть опущен. В таком случае будет использована последняя версия, т. е. объект Автоматизации задается в виде application_name.object_name.object_version. 389 О. В. Бартеньев. Современный ФОРТРАН Рис. 12.2. Идентификация объекта Опция Automation Object может быть использована с объектами, обеспечивающими программный идентификатор (ProgID). Он заносится в системный реестр и идентифицирует исполняемый файл, реализующий объект. Нажатие на кнопку Generate обеспечит формирование модулей, позволяющих использовать объект в Фортран-приложении. Заданное без расширения в поле Module Name имя (См. рис. 12.1) будет впоследствии использовано для имени формируемого КМ файла. Формируемые КМ файлы имеют расширение F90. Если выбран другой источник информации о типе, например Type Li- brary Containing Automation Information, то нажатие клавиши Next вызовет появление приведенного на рис. 12.3 экрана. Рис. 12.3. Выбор компонентов из библиотеки типа 390 12. Конструктор модулей для объектов ActiveX Экран позволяет выбрать файл, содержащий библиотеку типа (кнопка Browse), просмотреть состав библиотеки (кнопка Show), выбрать, применив левую кнопку мыши, необходимые или все (кнопка Select All) компоненты. Кнопка Generate обеспечит формирование соответствующих модулей. Файлы, содержащие библиотеки типов, могут иметь разные расширения, например OLB (объектные библиотеки) или OCX (управляющие элементы ActiveX). 12.9. Пример вызова процедур, сгенерированных конструктором модулей Сгенерированный КМ файл содержит один или несколько модулей, характеризующих объект и в общем случае включающих: • определения производных типов данных и констант, обнаруженных в разделе описаний объекта; • интерфейсы процедур, расположенные в разделе описаний объекта; • подпрограммы и функции, используемые при работе с объектом. Имеющиеся в модулях процедуры пригодны для вызова из Фортрана (при наличии соответствующей use-ассоциации). Рассмотрим в качестве примера использования объектов ActiveX написанное на Фортране приложение, выводящее в Excel диаграмму по сформированным в приложении данным. Проект, создающий приложение, входит в состав поставляемых с CVF образцов и находится в ...\DF98\SAMPLES\ADVANCED\COM\AUTODICE. Состав проекта отображен на рис. 12.4. Рис. 12.4. Проект AUTODICE Главная программа, находящаяся в файле autodice.f90, и модуль ADOBJS написаны программистом. Модуль EXCEL97A получен в результате применения КМ. Для его формирования были выполнены такие действия: • на приведенном на рис. 12.1 экране выбран источник Type Library Con- taining Automation Information; • на следующем экране (рис. 12.3) указан файл c:\Program Files\Microsoft Office\Office\Excel8.olb, содержащий библиотеку с компонентами, 391 О. В. Бартеньев. Современный ФОРТРАН обеспечивающими функционирование Excel, и выбраны компоненты _Application, _Chart. _Workbook, _Worksheet, Axes, Charts, Range, Work- books, Worksheets, EnumXIAxisGroup, EnaumXIAxisType, необходимые для работы с Excel. Сгенерированный модуль имеет внушительный объем (около 20'000 строк исходного текста). Ниже приведена его начальная часть, содержащая объявления глобальных констант и одну функцию компонента _Application. ! excel97a.f90 ! This module contains the Automation interfaces of the objects defined in ! c:\Program Files\Microsoft Office\Office\excel8.olb ! Generated by the Fortran Module Wizard on 10/24/98 module excel97a use dfcomty use dfauto implicit none ! CLSIDs type(guid), parameter :: CLSID_Global = & guid(#00020812, #0000, #0000, & char('c0'x)//char('00'x)//char('00'x)//char('00'x)// & char('00'x)//char('00'x)//char('00'x)//char('46'x)) type(guid), parameter :: CLSID_Worksheet = & guid(#00020820, #0000, #0000, & char('c0'x)//char('00'x)//char('00'x)//char('00'x)// & char('00'x)//char('00'x)//char('00'x)//char('46'x)) type(guid), parameter :: CLSID_Chart = & guid(#00020821, #0000, #0000, & char('c0'x)//char('00'x)//char('00'x)//char('00'x)// & char('00'x)//char('00'x)//char('00'x)//char('46'x)) type(guid), parameter :: CLSID_APPLICATION = & guid(#00024500, #0000, #0000, & char('c0'x)//char('00'x)//char('00'x)//char('00'x)// & char('00'x)//char('00'x)//char('00'x)//char('46'x)) ! Enums ! XlAxisGroup integer, parameter :: xlPrimary = 1 integer, parameter :: xlSecondary = 2 ! XlAxisType integer, parameter :: xlCategory = 1 integer, parameter :: xlSeriesAxis = 3 integer, parameter :: xlValue = 2 ! Module Procedures contains function $Application__Evaluate($object, Name, $status) !dec$ attributes dllexport :: $Application__Evaluate implicit none 392 12. Конструктор модулей для объектов ActiveX integer(4), intent(in) :: $object ! Object Pointer !dec$ attributes value :: $object type(variant), intent(in) :: Name !dec$ attributes reference :: Name integer(4), intent(out), optional :: $status ! Method status !dec$ attributes reference :: $status integer(4) $$status integer(4) invokeargs type(variant), volatile :: $return type(variant) $Application__Evaluate invokeargs = AUTOAllocateInvokeArgs( ) call AUTOAddArg(invokeargs, '$return', $return, .true.) call AUTOAddArg(invokeargs, '$arg1', Name, .false.) $$status = AUTOInvoke($object, -5, invokeargs) if(present($status)) $status = $$status $Application__Evaluate = $return call AUTODeallocateInvokeArgs(invokeargs) end function $Application__Evaluate ... ! Далее следуют иные процедуры end module excel97a ! модуля Замечания к результатам работы КМ: 1. КМ использует типы данных, имеющиеся в модуле DFCOMTY (а фактически в модуле DFWINTY), и процедуры модуля DFAUTO. Любая процедура сгенерированного модуля EXCEL97A может быть вызвана из создаваемого Фортран-приложения. 2. Если информация о типе содержит комментарий, описывающий функцию-член, то он размещается перед кодом процедуры. 3. Первый параметр сгенерированных процедур всегда имеет имя $object. Он является указателем на интерфейс объекта. 4. Директива ATTRIBUTE употребляется для задания соглашения о способах передачи параметров. В частности, !dec$ attributes value :: $object обеспечивает передачу параметра $object по значению, а !dec$ attributes reference :: Name говорит о том, что параметр Name передается по ссылке. 5. Почти каждая СОМ-функция-член возвращает статус завершения типа HRESULT, соответствующего типу INTEGER(4). 6. Интерфейс СОМ-функции-члена подобен интерфейсу DLL-функции. Однако в отличие от последней адрес СОМ-функции-члена неизвестен построителю приложения. Поэтому для ее вызова необходимо получить 393 О. В. Бартеньев. Современный ФОРТРАН указатель на интерфейс объекта; адрес соответствующей функции-члена вычисляется по значению этого указателя. Разберем подробнее рассматриваемый пример. Выберем для этого из модулей DFWINTY, DFCOM, OLEAUT32, DFNLS и EXCEL97A код, необходимый для решения поставленной задачи - отображения Фортран- массива в ячейках листа Excel и построения соответствующей диаграммы. Разместим данные, выбранные из модуля DFWINTY, в модуле MYCOMTY, код, взятый из модулей DFCOM, OLEAUT32 и DFNLS, разместим в модуле MYCOM, а код EXCEL97A - в модуле EXCEL97B. Теперь код становится вполне обозримым и пригодным для анализа, выполнить который читателю поможет имеющийся в программе комментарий. В частности, комментарий главной программы включает порядок работы с объектами Excel, придерживаясь которого удается объекты активизировать, задать их свойства и отобразить данные массива cellCounts в виде гистограммы. Для работы приложения необходимо задать имя XLS-файла. В рассмотренном в CVF примере такой файл имеет имя histo.xls и содержит приведенные на рис. 12.5 данные. Рис. 12.5. Состав файла histo.xls module mycomty ! Содержит объявления всех используемых !dec$objcomment lib: "dfcom.lib" ! в приложении autodice данных, !dec$objcomment lib: "oleaut32.lib" ! а также процедур, преобразовывающих implicit none ! строку Фортрана в BSTR и обратно ! Структура variant_union и тип variant взяты из файла dfwinty.f90 structure /variant_union/ union map integer(4) long_val end map map character char_val end map map integer(2) short_val end map map real(4) float_val end map map real(8) double_val end map 394 12. Конструктор модулей для объектов ActiveX map integer(2) bool_val end map map integer(4) scode_val end map map real(8) date_val end map map integer(4) ptr_val ! ptr_val - целочисленный указатель end map end union end structure type variant sequence integer(2) vt integer(2) reserved1, reserved2, reserved3 record /variant_union/ vu end type variant ! Определение типа guid заимствовано из файла dfwinty.f90 type guid sequence integer(4) data1 integer(2) data2, data3 character(8) data4 end type guid ! Константы vt_i4, vt_bstr, vt_dispatch определены в файле dfwinty.f90 integer(2), parameter :: vt_i4 = 3, vt_bstr = 8, vt_dispatch = 9 end module mycomty module mycom ! Содержит интерфейсы из модулей DFCOM, !dec$objcomment lib: "dfcom.lib" ! DFAUTO и OLEAUT32 используемых !dec$objcomment lib: "dfauto.lib" ! в приложении autodice процедур, !dec$objcomment lib: "oleaut32.lib" ! а также процедуры, преобразовывающие !dec$objcomment lib: "dfnls.lib" ! строку Фортрана в BSTR и обратно implicit none ! Родовой интерфейс COMCreateObject взят из модуля DFCOM (файл dfcom.f90) interface COMCreateObject subroutine COMCreateObjectByProgID(prog_id, idispatch, status) !dec$ attributes default :: COMCreateObjectByProgID !dec$ attributes reference :: prog_id !dec$ attributes reference :: idispatch !dec$ attributes reference :: status character(*), intent(in) :: prog_id integer(4), intent(out) :: idispatch, status end subroutine COMCreateObjectByProgID 395 О. В. Бартеньев. Современный ФОРТРАН subroutine COMCreateObjectByGUID(clsid, clsctx, iid, iinterface, status) use mycomty !dec$ attributes default :: COMCreateObjectByGUID !dec$ attributes reference :: clsid !dec$ attributes reference :: clsctx !dec$ attributes reference :: iid !dec$ attributes reference :: iinterface !dec$ attributes reference :: status type(guid), intent(in) :: clsid, clsctx, iid integer(4), intent(out) :: iinterface, status end subroutine COMCreateObjectByGUID end interface COMCreateObject interface ! Интерфейсы COMInitialize и COMUninitialize взяты из модуля DFCOM subroutine COMInitialize(status) !dec$ attributes default :: COMInitialize !dec$ attributes reference :: status integer(4), intent(out) :: status end subroutine COMInitialize subroutine COMUninitialize( ) !dec$ attributes default :: COMUninitialize end subroutine COMUninitialize ! Интерфейс COMReleaseObject заимствован из модуля DFCOM (файл dfcom.f90) integer(4) function COMReleaseObject(iunknown) !dec$ attributes default :: COMReleaseObject !dec$ attributes value :: iunknown integer(4), intent(in) :: iunknown end function COMReleaseObject ! Интерфейсы функций автоматизации взяты из файла dfauto.f90 ! Метод активизации параметра integer(4) function AUTOAllocateInvokeArgs( ) !dec$ attributes default :: AUTOAllocateInvokeArgs end function AUTOAllocateInvokeArgs integer(4) function AUTOSetPropertyByID(idispatch, memid, invoke_args) !dec$ attributes default :: AUTOSetPropertyByID !dec$ attributes value :: idispatch !dec$ attributes value :: memid !dec$ attributes value :: invoke_args integer(4), intent(in) :: idispatch, memid, invoke_args end function AUTOSetPropertyByID integer(4) function AUTOGetPropertyByID(idispatch, memid, invoke_args) !dec$ attributes default :: AUTOGetPropertyByID !dec$ attributes value :: idispatch !dec$ attributes value :: memid !dec$ attributes value :: invoke_args integer(4), intent(in) :: idispatch, memid, invoke_args 396 12. Конструктор модулей для объектов ActiveX end function AUTOGetPropertyByID end interface ! Часть родового интерфейса AUTOSetProperty interface AUTOSetProperty integer(4) function AUTOSetPropertyInteger2Array(idispatch, name, value, type) !dec$ attributes default :: AUTOSetPropertyInteger2Array !dec$ attributes value :: idispatch !dec$ attributes reference :: name !dec$ attributes reference :: value !dec$ attributes reference :: type integer(4), intent(in) :: idispatch character(*), intent(in) :: name integer(2), dimension(:), intent(in) :: value integer(2), intent(in), optional :: type end function AUTOSetPropertyInteger2Array integer(4) function AUTOSetPropertyInteger4(idispatch, name, value, type) !dec$ attributes default :: AUTOSetPropertyInteger4 !dec$ attributes value :: idispatch !dec$ attributes reference :: name !dec$ attributes reference :: value !dec$ attributes reference :: type integer(4), intent(in) :: idispatch, value character(*), intent(in) :: name integer(2), intent(in), optional :: type end function AUTOSetPropertyInteger4 end interface AUTOSetProperty ! Родовой интерфейс AUTOInvoke interface AUTOInvoke integer(4) function AUTOInvokeByName(idispatch, name, invoke_args) !dec$ attributes default :: AUTOInvokeByName !dec$ attributes value :: idispatch !dec$ attributes value :: invoke_args !dec$ attributes reference :: name integer(4), intent(in) :: idispatch, invoke_args character(*), intent(in) :: name end function AUTOInvokeByName ! Замечание. При использовании AUTOInvokeByID для всех вызовов ! AUTOAddArg задается параметр "$ARGnn" integer(4) function AUTOInvokeByID(idispatch, memid, invoke_args) !dec$ attributes default :: AUTOInvokeByID !dec$ attributes value :: idispatch !dec$ attributes value :: memid !dec$ attributes value :: invoke_args integer(4), intent(in) :: idispatch, memid, invoke_args 397 О. В. Бартеньев. Современный ФОРТРАН end function AUTOInvokeByID end interface AUTOInvoke ! Часть родового интерфейса AUTOAddArg interface AUTOAddArg subroutine AUTOAddArgInteger4(invoke_args, name, value, output_arg, type) !dec$ attributes default :: AUTOAddArgInteger4 !dec$ attributes value :: invoke_args !dec$ attributes reference :: name !dec$ attributes reference :: value !dec$ attributes reference :: output_arg !dec$ attributes reference :: type integer(4), intent(in) :: invoke_args, value character(*), intent(in) :: name logical(4), intent(in), optional :: output_arg integer(2), intent(in), optional :: type end subroutine AUTOAddArgInteger4 subroutine AUTOAddArgLogical2(invoke_args, name, value, output_arg, type) !dec$ attributes default :: AUTOAddArgLogical2 integer(4), intent(in) :: invoke_args !dec$ attributes value :: invoke_args !dec$ attributes reference :: name !dec$ attributes reference :: value !dec$ attributes reference :: output_arg !dec$ attributes reference :: type character(*), intent(in) :: name logical(2), intent(in) :: value logical(4), intent(in), optional :: output_arg integer(2), intent(in), optional :: type end subroutine AUTOAddArgLogical2 subroutine AUTOAddArgCharacter(invoke_args, name, value, output_arg, type) !dec$ attributes default :: AUTOAddArgCharacter !dec$ attributes value :: invoke_args !dec$ attributes reference :: name !dec$ attributes reference :: value !dec$ attributes reference :: output_arg !dec$ attributes reference :: type integer(4), intent(in) :: invoke_args character(*), intent(in) :: name, value logical(4), intent(in), optional :: output_arg integer(2), intent(in), optional :: type end subroutine AUTOAddArgCharacter subroutine AUTOAddArgVariant(invoke_args, name, value, output_arg) !dec$ attributes default :: AUTOAddArgVariant !dec$ attributes value :: invoke_args !dec$ attributes reference :: name !dec$ attributes reference :: value 398 12. Конструктор модулей для объектов ActiveX !dec$ attributes reference :: output_arg use mycomty integer(4), intent(in) :: invoke_args character(*), intent(in) :: name type(variant), intent(in) :: value logical, intent(in), optional :: output_arg end subroutine AUTOAddArgVariant end interface AUTOAddArg ! Интерфейсы SysAllocString, SysStringLen и SysFreeString ! взяты из файла oleaut32.f90 interface integer(4) function SysAllocString(unistr) !dec$ attributes default, stdcall, alias : '_SysAllocString@' :: SysAllocString integer(2), intent(in) :: unistr(*) end function SysAllocString integer(4) function SysStringLen(bstr) !dec$ attributes default, stdcall, alias : '_SysStringLen@' :: SysStringLen !dec$ attributes value :: bstr integer(4), intent(in) :: bstr end function SysStringLen subroutine SysFreeString(bstr) !dec$ attributes default, stdcall, alias : '_SysFreeString@' :: SysFreeString !dec$ attributes value :: bstr integer(4), intent(in) :: bstr end subroutine SysFreeString ! Интерфейсы VariantInit и VariantClear взяты из файла oleaut32.f90 subroutine VariantInit(pvarg) !dec$ attributes default, stdcall, alias : '_VariantInit@' :: VariantInit !dec$ attributes reference :: pvarg use mycomty ! Взамен use dfwinty type(variant), intent(out) :: pvarg end subroutine VariantInit integer(4) function VariantClear(pvarg) !dec$ attributes default, stdcall, alias : '_VariantClear@' :: VariantClear !dec$ attributes reference :: pvarg use mycomty ! Взамен use dfwinty type(variant), intent(out) :: pvarg end function VariantClear end interface ! Интерфейс функций MBConvertMBToUnicode и MBConvertMBToUnicode взят ! из модуля DFNLS (файл dfnls.f90). Они нужны для работы модульных ! функций ConvertStringToBSTR и ConvertBSTRToString interface integer(4) function MBConvertMBToUnicode(mbstr, unicodestr, flags) !dec$ attributes default :: MBConvertMBToUnicode character(*), intent(in) :: mbstr |