Первый взгляд
Продукты фирмы Borland пользуются у нас в стране большой популярностью, и выход новой версии любого из ее инструментов разработки вызывает повышенный интерес у российских программистов. Появления очередной версии Delphi поклонники этого компилятора ожидали с двояким чувством. Ведь после ухода из Borland А. Хейлсберга, главного идейного вдохновителя проектов Delphi 1 и Delphi 2, многие (но не сам Хейлсберг) сомневались, сможет ли оставшаяся команда достойно продолжить так удачно начатое дело.
Сразу оговорюсь, что данная статья писалась на основе январской предварительной версии Delphi 3.0, полученной в результате участия в программе раннего ознакомления, поэтому конечный вариант продукта может несколько отличаться от описываемого.
Delphi 3 представляет собой универсальное средство создания приложений, и Borland прочит ему достойное место на рынке многоуровневых Internet/intranet-приложений и клиент-серверных систем.
Новая версия пакета поддерживает технологии COM (Component Object Model - модель составных объектов) и DCOM (Distributed COM), а также позволяет разработчикам создавать OLE-серверы, компоненты ActiveX и использовать COM-объекты в клиентских приложениях.
Инсталляция
Третья версия Delphi работает под Windows 95 или Windows NT 4.0. В комплект поставки клиент-серверной модификации пакета помимо самого компилятора входят:
- 16-разрядная версия Delphi 1.02;
- сервер Interbase 4.2 для Windows 95, поддерживающий до четырех пользователей и 12 соединений одновременно;
- онлайновая документация в формате Adobe Acrobat PDF;
- CASE Expert, служащий для импорта данных и создания структур БД из таких CASE-средств, как Sybase S-Designor, CSA SilverRun, Popkin’s System Architect, LogicWorks Erwin и Embarcadero ER/1;
- отдельный инсталлятор Local Interbase 4.2;
- OLEnterprise - средство для обеспечения взаимодействия по протоколу OLE/ DCOM с любым RPC- или COM-сервером.
В связи со значительным расширением возможностей QuickReport 2.0 по сравнению с его первыми версиями и из-за тесной интеграции с ним многих других библиотек генератор отчетов ReportSmith в составе Delphi больше не поставляется - при всем богатстве возможностей он оказался слишком "тяжелым" для распространяемых программ и требовал для работы значительного объема ОЗУ. Однако если у вас есть наработки, использующие этот генератор отчетов, его можно купить отдельно.
Компилятор
Сначала о грустном. Вопреки моим ожиданиям компилятор в Delphi 3, так же как и в Delphi 2, оказался написанным на Си++ (в Delphi 1 компилятор был написан на Borland Pascal и Assembler). Следовательно, опять не обойдется без грубых и просто непонятных ошибок и "шаманства" с оптимизатором кода.
Borland уверяет, что новый компилятор позволяет получать еще более оптимизированный и быстродействующий код, чем компилятор Delphi 2, который был далеко не самым плохим по этим параметрам.
Наиболее важное, на мой взгляд, языковое новшество - интерфейсы. Данный механизм, с одной стороны, служит для разработки объектов COM и ActiveX, а с другой являет собой разумную альтернативу нежно любимому поклонниками Си++ множественному наследованию. Интерфейс класса позволяет осуществлять доступ к нему без знания реализации, которая может быть вообще скрыта от разработчиков приложений. Интерфейсы в Delphi 3 совместимы со спецификациями COM. Это означает, что любой Delphi-объект, поддерживающий один или более интерфейсов, автоматически является COM-объектом и может взаимодействовать с COM-объектами, написанными на Си++, Java и других языках. Вот типичный пример такого интерфейса:
type
IMalloc = interface(IUnknown)
[‘{00000002-0000-0000-C000-000000000046}’]
function Alloc(Size: Integer): Pointer;
stdcall;
function Realloc(P: Pointer; Size: Integer): Pointer; stdcall;
procedure Free(P: Pointer); stdcall;
function GetSize(P: Pointer): Integer; stdcall;
function DidAlloc(P: Pointer): Integer; stdcall;
procedure HeapMinimize; stdcall;
end;
В отличие от классов, интерфейсы не могут содержать полей (переменных класса). Из-за этого и свойства интерфейса могут возвращать/устанавливать значения только через его методы. Интерфейс IUnknown является базовым предком всех интерфейсов (таким же, как TObject для классов). Описание интерфейса может содержать глобальный уникальный идентификатор интерфейса (GUID) - строковую константу вида ‘{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxx xxxxx}’, заключенную в квадратные скобки и следующую непосредственно за заголовком интерфейса. Каждый входящий в нее символ представляет собой шестнадцатиричное число. Модуль System содержит следующее описание GUID: type
PGUID = ^TGUID;
TGUID = record
D1: Integer;
D2: Word;
D3: Word;
D4: array[0..7] of Byte; end;
Если интерфейс содержит GUID, становится возможным ссылаться на реализацию этого интерфейса с помощью механизма опроса интерфейсов.
По умолчанию все методы интерфейса используют тип вызова register, то есть передача параметров происходит через регистры ЦП. Но если интерфейс предполагается использовать в модулях, написанных на разных языках программирования, то всем методам такого интерфейса должен быть явно присвоен тип вызова stdcall или safecall (о последнем будет рассказано ниже).
У интерфейсов есть одно значительное отличие от классов - их код не может наследоваться. Это обусловлено тем, что интерфейс сам по себе не содержит секции реализации (implementation), а код интерфейсных методов всегда содержится внутри класса, реализующего данный интерфейс. В этом контексте интерфейс подобен некоему классу, у которого все методы являются абстрактными и виртуальными.
Для реализации одного или нескольких интерфейсов внутри класса их следует перечислить через запятую в заголовке класса после класса-родителя, а все их методы должны быть реализованы совместимыми по вызовам методами класса.
Теперь о менее значительных изменениях в языке. Введено ключевое слово resourcestring - аналог const. Оно предназначено для описания строк, которые компилятор автоматически поместит в исполняемый файл или DLL-библиотеку как ресурс.
Из компиляторов Си++ перекочевала процедура Assert(Expr:Boolean; [Msg:String]), описанная в модуле System. Ее действие аналогично следующему коду:
if not Expr then raise AssertionFailed;
Эта процедура служит скорее для отладки, и в окончательном варианте программы ссылок на нее быть не должно. Для этого введена новая директива компилятора:
$ASSERTIONS ON/OFF или $C +/-
Изменилось представление логических типов данных ByteBool, WordBool и LongBool. Значение True в них теперь представляется 1, а не 1. Для типа Boolean все осталось по-прежнему: False = 0, True = 1.
Появился новый тип вызова safecall, применяемый в основном в так называемых двойных интерфейсах, которые используют два вида связывания: связывание во время компиляции на базе таблицы виртуальных методов и динамическое связывание с помощью механизма OLE Automation. Все методы такого интерфейса, за исключением унаследованных от IUnknown и IDispatch, должны использовать тип вызова safecall. По механизму передачи параметров и чистки стека этот метод аналогичен sdtcall.
Введен новый тип параметров - out, используемый тогда, когда вызываемая процедура или функция должна только возвращать, а не изменять передаваемые ей данные. Фактически это аналог множества переменных Result в функциях.
Механизм Packages
Packages (далее будем называть их пакетами) - это особый вид DLL-библиотек. Их применение оправдывает себя, если на одном компьютере работает несколько Delphi-приложений и нет смысла держать копию общего для них кода в каждом из exe-файлов.
В соответствии с этим переработана библиотека компонентов Delphi. Теперь все компоненты инсталлируются в нее, как пакеты. Это дает целый ряд преимуществ. Во-первых, для перекомпиляции каждого пакета нет необходимости перекомпилировать всю библиотеку компонентов. Во-вторых, для работы с проектом вам необходимо загрузить только используемые им пакеты. В-третьих, вам не надо самостоятельно заниматься созданием динамических библиотек, если несколько ваших программ используют одни и те же компоненты, так как пакеты с этими компонентами уже готовы к работе.
Package-файлы имеют расширение DPL (Delphi Package Library), для того чтобы их можно было отличить от обычных динамических библиотек.
Файл с исходным текстом пакета (*.DPK) не содержит объявлений типов, данных, процедур и функций. Он состоит из имени пакета, списка используемых пакетов и списка модулей, собственно составляющих пакет.
Сам пакет - только оболочка этих модулей, реализующая необходимую функциональность.
Среда Delphi IDE
Delphi IDE стала гораздо удобнее, несмотря на то, что в ней по-прежнему не хватает более достойного, чем Object Browser, аналога ClassView из Microsoft Developer Studio.
Ранее для отладки DLL-библиотек приходилось прибегать ко всевозможным ухищрениям типа выдачи отладочных сообщений или обрамления кода библиотеки, как обычного приложения. В Delphi 3 можно не заниматься этой малоприятной работой, указав в параметрах запуска имя приложения, использующего отлаживаемую DLL-библиотеку (поле Host application в меню Run Parameters).
Шаблоны кода (Code templates) представляют собой механизм замены часто используемых последовательностей типа ‘if-then-else’, ‘try-except’ и прочих более короткими обозначениями. При нажатии <Control-J> либо в редакторе кода строка над курсором развернется в текст шаблона (если она представляет собой его обозначение), либо появится выпадающий список шаблонов, из которого можно выбрать нужный.
Если вы набрали имя класса и поставили точку-разделитель, то всплывающее окошко покажет список методов, свойств и событий этого класса, из которого можно выбрать интересующий вас пункт. Время задержки перед появлением списка регулируется установками среды. Если вы набрали знак присваивания и нажали <Control-пробел>, вам будет предложен список корректных аргументов для присваивания, а если имя метода и открывающую скобку - появится список аргументов этого метода. Эти механизмы получили название Code completion (завершение кода).
При отладке приложения можно быстро узнать значение любой переменной или любого свойства, просто наведя на них курсор мыши. Появится всплывающее окошко с искомым значением. Этот механизм называется быстрым вычислением выражений (Tool-tip expression evaluation), и для его стабильной работы по понятным причинам надо отключать оптимизацию в параметрах проекта.
В новой версии Delphi введена очень полезная возможность, которой явно не хватало предыдущим версиям, - поиск текста по всему проекту. Для поиска текста по всем файлам проекта используйте пункт меню SearchFind in Files.
В Delphi 2.0 путь к репозиторию редактировался только программой regedit, что было несколько неудобно. Сейчас, выбрав пункт меню ToolsEnvironment options и страничку Preferences, можно проделать эту операцию с меньшими затратами.
Теперь в Delphi-проект можно включить информацию о версии (ресурс VersionInfo), пользуясь страничкой VersionInfo в настройках проекта, а компилятор заставить увеличивать номер версии при каждой перекомпиляции проекта.
Шаблоны компонентов (Component templates) представляют собой группу компонентов, которую можно добавить к форме за одну операцию. Они позволяют сконфигурировать расположенные на форме компоненты, а затем сохранить их порядок и свойства в палитре компонентов для повторного использования в других формах.
Для установки точек прерывания, отображения выполняемых строк программы и другой служебной информации в окне редактора слева введена специальная панель.
Служебная панель в окне редактора
Работа с базами данных
Новая версия Borland Database Engine (BDE) 4.0, полностью поддерживающая стандарт Unicode, включает в себя драйвер БД Microsoft Access. Правда, этот драйвер пока не поддерживает полей типа BCD.
Обновленный драйвер dBase включает поддержку сжатых индексов (*.CDX) и больших двоичных объектов (*.FPT) из FoxPro. Он также позволяет читать и создавать таблицы FoxPro версий 2.0, 2.5 и 2.6.
Для разработчиков клиент-серверных приложений полезно будет знать, что в новой версии 4.2 сервера Interbase основательно переработано ядро, а сам сервер выполнен в соответствии с архитектурой SuperServer. Это громкое название означает лишь то, что на каждое клиентское соединение запускается отдельная серверная нить (thread). В предыдущих версиях Interbase на каждое соединение запускался отдельный процесс (ibremote.exe). Следствием перехода к архитектуре SuperServer стало исправление одной грубой ошибки, заключавшейся в том, что при перезагрузке или любом сбое рабочей станции обслуживающий ее серверный процесс продолжал работать и занимать процессорное время сервера СУБД. Я полагаю, что это было связано с трудностью диспетчеризации друг друга равноправными процессами.
Как следствие расширения двухуровневой системы клиент-сервер до многоуровневой (multi-tiered) на страничке Data Access появились новые компоненты:
- TProvider обслуживает потоки запросов и данных между сервером БД и клиентом в многоуровневых системах;
- TClientDataSet реализует функции распределенного набора данных, находящегося в памяти клиентского приложения;
- TRemoteServer обслуживает соединение с удаленным сервером, если клиент является частью многоуровневой системы.
Претерпела значительные изменения и сама идеология построения иерархии классов для работы с БД. Передо мной однажды стояла задача: реализовать доступ к нестандартной СУБД, для которой отсутствовали IDAPI- и ODBC-драйверы. Думаю, я был далеко не единственным, кто столкнулся с проблемой такого рода. Логичным было бы написать класс, наследник TDataSet, так как в таком случае мой класс получился бы автоматически совместимым с большинством БД-ориентированных компонентов. Но реализация класса TDataSet содержала множество вызовов IDAPI (dbi-функций), хотя у TDataSet есть наследник TDBDataSet и по логике они должны быть именно в нем. Кроме того, инициализация IDAPI осуществлялась внутри модуля db.pas, содержащего TDataSet, следовательно, появлялась необходимость инсталлировать на клиентскую машину совершенно неиспользуемый BDE. Моей радости не было предела, когда, просмотрев исходные тексты VCL Delphi 3, я обнаружил, что в модуле db.pas нет ни одного dbi-вызова. Все они были перенесены в новый класс TBDEDataSet, который обладает дополнительной функциональностью в виде возможности проверки набора данных на отсутствие записей, сравнения закладок (Bookmarks) и проверки закладки на корректность. Это должно упростить написание классов для доступа к нестандартным источникам данных, а главное - дать возможность использовать стандартные компоненты и классы применительно к таким источникам.
Кроме этого, у класса TDataSet появилось свойство CacheBlobs:Boolean, отвечающее за кэширование больших двоичных объектов, например таблиц при их просмотре.
Новый компонент TDBRichEdit позволит хранить/редактировать текст формата RTF (Rich Text Format) в полях типа BLOB.
Так как такие поля можно кэшировать, то были расширены возможности компонента TDBCtrlGrid, служащего для представления данных в форме нестандартных таблиц. Теперь TDBCtrlGrid может содержать компоненты TDBImage и TDBMemo.
Библиотека компонентов VCL
В палитре компонентов появились две новые странички: Internet и Decision Cube. Некоторые компоненты переименованы или перенесены на другие странички. Страница Win95 теперь называется Win32, а OCX - ActiveX.
Палитра компонентов
Замечу, что несколько OCX-компонентов для построения приложений, работающих с Internet/intranet, появились уже в дополнении к пакету Delphi 2. В новой версии Delphi они прочно заняли свое место в палитре компонентов и к ним добавились новые:
- TClientSocket - реализация клиента TCP/IP;
- TServerSocket - реализация сервера TCP/IP;
- TWebDispatcher - для обработки HTTP-запросов;
- TPageProducer - для создания HTML-страниц "на лету" на основе шаблонов;
- TDataSetTableProducer - для создания HTML-таблиц "на лету" на основе записей любого потомка TDataSet;
- TQueryTableProducer - для создания HTML-таблиц "на лету" на основе записей TQuery (отличается от TDataSetTableProducer возможностью задавать входные параметры).
С помощью Delphi 3.0 можно создавать приложения для Web-серверов в стандартах CGI, WinCGI, ISAPI, NSAPI, что позволяет строить WWW-узлы и intranet-системы с доступом к базам данных на основе практически всех популярных Web-серверов.
В Delphi 3 заметно доработана библиотека QuickReport. Теперь в отчетах можно использовать вычисляемые, графические поля и memo-поля со шрифтовым выделением.
В VCL появилась хорошо себя зарекомендовавшая в Quick Report библиотека TeeChart, содержащая множество компонентов и функций для создания мощных аналитических приложений, немыслимых без развитых средств построения разнообразных графиков и диаграмм. Одной из сильных сторон TeeChart является простота построения графиков по любым источникам данных. Существуют два базовых компонента TeeChart: TChart и TDBChart, причем первый не использует классы доступа к данным, и, как следствие, программа, его использующая, не нуждается в установке BDE на клиентской машине, на необходимость чего часто жаловались пользователи QuickReport. Также очень удобно, что свойство DataSource (источник данных) у БД-ориенированных компонентов TeeChart описано, как TComponent, а не как TDataSet, что позволяет использовать для графика любые вновь придуманные источники данных. Один из компонентов библиотеки, TQRChart, служит для печати графиков в отчетах QuickReport.
Delphi 3 комплектуется стандартной версией TeeChart. Полная версия, включающая финансовые индикаторы и 100% исходного кода, поставляется отдельно за $99. Web-адрес для интересующихся: http://ourworld.compuserve. com/homepages/dberneda.
Другим заметным нововведением в Delphi 3 является нижеследующая группа компонентов поддержки принятия решений, располагающаяся на страничке Decision Cube в палитре компонентов:
- TDecisionCube - многомерная кросс-таблица;
- TDecisionQuery - запросы для построения кросс-таблиц и анализа данных;
- TDecisionDataSource - источник данных для построения многомерных кросс-таблиц;
- TDecisionPivot - компонент, позволяющий управлять размерностью и полями TDecisionCube;
- TDecisionGrid - компонент, отображающий многомерные данные в табличной форме;
- TDecisionGraph - компонент, отображающий поля TDecisionCube в виде графика, меняющегося по мере изменения размерности TDecisionCube.
Эти компоненты позволяют не только создавать и наглядно представлять многомерные кросс-таблицы и их сечения, но и в совокупности с компонентами TeeChart визуализировать данные с учетом современных требований к деловой графике и, что очень существенно, проводить многомерный анализ данных.
В Delphi 3 несколько расширена графическая подсистема. Создан новый компонент для просмотра AVI-файлов, во все графические классы встроена поддержка многопоточных (multithread) приложений, точнее, защита от некорректных обращений к классам нескольких одновременно работающих потоков. Напомню, что большинство классов в Delphi 2 такой поддержкой не обладало. Класс TCanvas содержит два новых метода: Lock и UnLock для установки/снятия монопольного доступа к области рисования. Введена поддержка битовых образов с количеством цветов 15,16 и 32 бита на пиксел, а также поддержка прозрачных изображений и палитр.
Появился в новой версии Delphi и пригодный для поточной работы аналог класса TList - TThreadList.
Кроме того, в Delphi 3 расширена поддержка кодировки Unicode, модифицированы функции AnsiLowerCase, AnsiUpperCase, ChangeFileText, ExtractFileDir, ExtractFileExt, ExtractFileName и ExtractFilePath и добавлен целый ряд новых функций работы со строками, в основном аналогичных уже имеющимся.
Из менее концептуальных нововведений можно отметить компонент для ввода даты или времени (TDateTimePicker), диалоги для открытия и сохранения картинок с возможностью предварительного просмотра (TOpenPictureDialog и TSavePictureDialog), панель кнопок в стиле Microsoft Office97 (TCoolBar).
Демонстрационные проекты
В связи со значительным расширением функциональности новой версии Delphi увеличено количество демонстрационных проектов. Это приложения для разговора (chat) через Internet, пример использования стандартных элементов управления Delphi внутри ActiveX-объекта, утилита для регистрации ActiveX-серверов, Web Browser и Web-сервер.
Телефон фирмы Borland International в Москве: (095) 366-4298,
Web-адрес: http://www.borland.com.
Олег Федоров