Теперь не только в Delphi, но и в C++ Builder 3 есть библиотеки-пакеты.
Вместе с пакетом Borland Delphi 3 была анонсирована новая (ну не совсем, конечно) концепция динамических пакетов специализированных динамически загружаемых библиотек, куда программист может поместить код, который он желает вынести за пределы своего приложения, или сделать этот код разделяемым между несколькими приложениями, как, к примеру, это делает Microsoft Windows, разделяя вызовы ядра OC и упаковывая их в динамически загружаемые библиотеки. Сразу же оговоримся, что динамические пакеты, которые ниже мы будем называть просто пакетами, не имеют ничего общего с программными пакетами, пакетами из языка Java и пакетами для мусора. К сожалению, от термина "пакет" (package) никак не уйти, поэтому придется смириться с неизбежностью его повсеместного применения.
Но к делу. Предположим, вы разработали новый набор компонентов и приступили к его продаже или даже стали бесплатно его распространять через Internet. Популярность вашего детища растет не по дням, а по часам, и все кому не лень встраивают ваши компоненты в свои утилиты и программы. И вот однажды, любуясь парочкой свежих утилит неизвестных авторов, в которых применены ваши компоненты, вы осознаете, что размер этих программок несколько великоват - килобайт эдак по 400 каждая. Вас, естественно, одолевает интерес: и чего это там такого, что может так раздуть размер файла. Само собой, вы заглядываете внутрь компилированного кода и обнаруживаете, что и в той и в другой программке намертво встроен код библиотеки Borland VCL. И в этот момент вы понимаете, что статическая компоновка программы - это не очень-то хорошо. Славно бы было, если можно было вынести VCL в динамическую библиотеку. Предвидя такой оборот событий, компания Borland реализовала в Delphi 3, а теперь и в C++ Builder 3 всю библиотеку VCL как пакет. Это полезный шаг, благодаря которому несколько программ могут использовать один и тот же библиотечный код. Да и размер получаемых программ сократился во много раз. Так, если откомпилировать новый пустой проект, создаваемый по умолчанию средой C++ Builder 3, получится исполняемый файл размером 19,5 Кбайт. Более того, теперь программист может создавать собственные пакеты, пакуя в них все, что считает нужным вынести за рамки кода программы.
Типы пакетов
Пакеты C++ Builder 3 бывают двух видов: времени исполнения (runtime) и времени разработки (design time). Хотя случается, что один и тот же пакет работает и как пакет времени исполнения, и как пакет времени разработки. Пакет времени исполнения вмещает код, к которому программа обращается во время своей работы. В противоположность ему пакет времени разработки используется в процессе проектирования программы. В него обычно помещают код компонентов, специализированные редакторы свойств и прочие принадлежности, к которым программист обращается в процессе создания и настройки программы.
Пакеты, применяемые в Delphi, имеют расширение DPL. Что касается C++ Builder 3, то здесь пакетам присваивается расширение BPL. BPL-файл - далеко не единственный, получаемый в результате генерации пакетов. Одновременно с ним создается файл библиотеки импорта, имеющий то же самое имя, что и файл пакета, но с расширением BPI. Назначение библиотек импорта - создать интерфейс для использования динамически загружаемых библиотек из программы. После компиляции пакета на диске остается объектный файл OBJ, а если была включена опция "Generate .lib file", то вместе с библиотекой импорта будет создана статическая библиотека с расширением LIB.
Управление пакетами из среды разработчика
Управление пакетами в среде C++ Builder 3 производится с помощью меню Component, позволяющего добавить, удалить или же создать новый пакет с компонентами и одновременно подключить его к палитре компонентов.
Добавление и удаление пакетов
Чтобы добавить или удалить пакет времени исполнения или времени разработки, следует обратиться к команде меню Component Install Packages. Появившаяся диалоговая панель разделяется на две области: область установки и добавления пакетов времени разработки и область задания пакетов времени исполнения. Действительно, начав говорить о добавлении и удалении, мы поступили не совсем так, как нужно. Дело в том, что подключение пакетов к среде может произойти лишь в том случае, если это пакеты времени разработки или комбинированные пакеты. О пакетах времени исполнения так говорить нельзя, потому что они не добавляются в среду. Все, что с ними можно сделать, так это указать в качестве подгружаемых библиотек для создаваемого приложения.
Сначала рассмотрим область пакетов времени разработки. В списке, располагающемся в верхней части диалоговой панели Packages, перечислены все пакеты времени разработки. Чуть ниже этого списка C++ Builder 3 показывает имя файла, выделенного в списке пакета. Еще немного ниже расположены три кнопки: Add, Remove и Components. Нажатие на кнопку Add вызывает на экран диалоговую панель Add design package. Выберите в ней пакет времени разработки, который вы собираетесь подключить к среде C++ Builder 3. Убрать выделенный в списке пакет позволяет кнопка Remove. Третья кнопка - Components - отображает на экране окно, в котором демонстрируется список всех компонентов, упакованных в текущем (выделенном) пакете, что весьма удобно.
Поэтому прежде чем удалить тот или иной пакет, выделите его и посмотрите, что находится внутри него. Это снижает вероятность ошибочного удаления пакета.
Область пакетов времени исполнения - это то место, в котором задается, будет ли программа использовать пакеты (отмечаемая кнопка Build with runtime packages), и указывается, какие пакеты времени исполнения нужны для корректного функционирования программы. В строке редактирования через точку с запятой перечислены все пакеты, которые будут включены в ваш проект. Ненужный пакет можно удалить, стирая его имя в строке редактирования. И наоборот, если вписать имя пакета в список, он будет подгружен вашей программой. Удобнее добавить имя пакета, нажав на кнопку Add, расположенную рядом со строкой редактирования, и выбрав в диалоговой панели библиотеку импорта пакета. Пакеты времени исполнения, поставляемые с C++ Builder 3, приведены в таблице.
Таблица. Пакеты времени исполнения | |
Пакет | Содержащиеся в пакете модули |
VCL30.BPL | Ax, Buttons, Classes, Clipbrd, Comctrls, Commctrl, Commdlg, Comobj, Comstrs, Consts, Controls, Ddeml, Dialogs, Dlgs, Dsgnintf, Dsgnwnds, Editintf, Exptintf, Extctrls, Extdlgs, Fileintf, Forms, Graphics, Grids, Imm, IniFiles, Isapi, Isapi2, Istreams, Libhelp, Libintf, Lzexpand, Mapi, Mask, Math, Menu, Messages, Mmsystem, Nsapi, Ole2I, Oleconst, Olectnrs, Olectrls, Oledlg, Penwin, Printers, Proxies, Registry, Regstr, Richedit, Shellapi, Shlobj, Stdctrls, Stdvcl, Sysutils, Tlhelp32, Toolintf, Toolwin, Typinfo, Vclcom, Virtintf, Windows, Wininet, Winsock, Winspool, Winsvc |
VCLX30.BPL | Checklst, Colorgrd, Ddeman, Filectrl, Mplayer, Outline, Tabnotbk, Tabs |
VCLDB30.BPL | Bde, Bdeconst, Bdeprov, Db, Dbcgrids, Dbclient, Dbcommon, Dbconsts, Dbctrls, Dbgrids, Dbinpreq, Dblogdlg, Dbpwdlg, Dbtables, Dsintf, Provider, SMintf |
VCLDBX30.BPL | Dblookup, Report |
DSS30.BPL | Mxarrays, Mxbutton, Mxcommon, Mxconsts, Mxdb, Mxdcube, Mxdssqry, Mxgraph, Mxgrid, Mxpivsrc, Mxqedcom, Mxqparse, Mxqryedt, Mxstore, Mxtables, Mxqvb |
QRPT30.BPL | Qr2const, Qrabout, Qralias, Qrctrls, Qrdatasu, Qrexpbld, Qrextra, Qrprev, Qrprgres, Qrprntr, Qrqred32, Quickrpt |
TEE30.BPL | Arrowcha, Bubblech, Chart, Ganttch, Series, Teeconst, Teefunci, Teengine, Teeprocs, Teeshape |
TEEDB30.BPL | Dbchart, Qrtee |
TEEUI30.BPL | Areaedit, Arrowedi, Axisincr, Axmaxmin, Baredit, Brushdlg, Bubbledi, Custedit, Dbeditch, Editchar, Flineedi, Ganttedi, Ieditcha, Pendlg, Pieedit, Shapeedi, Teeabout, Teegally, Teelisb, Teeprevi, Teexport |
VCLSMP30.BPL | Sampreg, Smpconst |
Следует отметить, что добраться до пакетов можно и с помощью команды Project Options (комбинация клавиш
Создание новых пакетов
Создание новых пакетов в C++ Builder 3 - операция довольно простая и освоить ее можно за десять минут. Однако изначально нужно определить, с какой целью вы создаете свой пакет. Если это получение библиотеки компонентов и исходные тексты этих компонентов уже имеются, то наилучшим способом создать новый пакет будет вызов команды Component Install Component. Если же вы пытаетесь создать абсолютно новый пакет, да еще к тому же в нем будут не компоненты, а другого рода объекты, то нужно воспользоваться мастером File New Package.
Рассмотрим простейший случай, а именно создание нового пустого пакета. Как только вы отдали С++ Builder 3 команду File
New Package, возникает диалоговая панель, в которой нужно ввести имя создаваемого пакета и собственный комментарий к нему. Среда C++ Builder 3 создаст новый проект и сгенерирует начальный исходный текст:
//-------------------------------------- #include#pragma hdrstop USERES("mypack.res"); USEPACKAGE("vcl35.bpi"); //-------------------------------------- #pragma package(smart_init) //-------------------------------------- // Package source. //-------------------------------------- int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) { return 1; }
Как видите, пакет - это самая обычная динамически загружаемая библиотека DLL, о чем говорит наличие характерной точки входа DllEntryPoint. С точки зрения программиста интересны макроопределения USERES и USEPACKAGE. Для опытных пользователей C++ Builder 3 макрос USERES - не загадка, он всего лишь говорит о необходимости добавить в проект соответствующие ресурсы. А вот макрос USEPACKAGE - абсолютно новый. Им определяются пакеты, от которых зависит создаваемый пакет. Если вы планируете обращаться к коду, размещенному в другом пакете, то необходимо указать имя такого пакета с помощью макроопределения USEPACKAGE. Обратите внимание, что в новом проекте всегда присутствует ссылка на пакет, имя которого начинается с VCL. В этом пакете располагаются основные классы библиотеки VCL. Если же необходимо сослаться на другие пакеты, то самое удобное - обратиться за помощью к менеджеру проектов. В его окне вы найдете папку с именем Required. В этой папке показаны имена всех файлов, требуемых для корректной работы. Командой Add контекстного меню легко добавить и удалить ссылки на другие файлы.
А среда C++ Builder 3 сама вставит в исходный текст пакета макроопределение USEPACKAGE.
В новинку для программистов будет и директива #pragma package(smart_init). Она говорит о том, что модули, включенные в пакет, инициализируются в порядке их зависимости друг от друга. По умолчанию среда C++ Builder 3 сама задает эту директиву, и вам не потребуется включать ее вручную. Модифицированная версия этой директивы #pragma package(smart_init, weak) указывает компилятору, что объектный код данного модуля желательно не включать в пакет, а поместить его внутрь библиотеки импорта пакета (так называемая "слабая" упаковка). При компиляции программы, которая использует ваш пакет и модуль, объявленный "слабо" упакованным, объектный код этого модуля будет скомпонован вместе с файлом проекта, вместо того чтобы быть вынесенным в пакет. Это полезно в тех случаях, когда модуль используется редко или ссылается на библиотеки, которых может и не оказаться на вашем компьютере. Если ваше приложение использует такой модуль как "слабо" упакованный, то отсутствие библиотеки, на которую он ссылается, приведет к ошибке только вашей программы. Если же модуль находится внутри пакета, то пакет не может быть загружен из-за ошибки. В результате пострадает не только ваше приложение, но и все другие, ссылающиеся на ваш пакет, даже если отсутствующая библиотека им и не нужна. Опция "слабой" упаковки, как гласит документация C++ Builder 3, рассчитана на опытных разработчиков, поэтому старайтесь не использовать ее до тех пор, пока не поэкспериментируете и не разберетесь досконально, как она работает.
Более сложный случай - упаковка компонентов в новый пакет. Если воспользоваться командой Component Install Component, то вы получите диалоговую панель, предлагающую два варианта действия: либо редактировать уже существующий пакет, либо создать новый, добавляя в него код компонентов.
Задав имя нового пакета, вы должны указать и имя модуля, в котором находится исходный текст компонента, чей код должен быть помещен в пакет. В процессе компиляции будут обработаны как модуль нового компонента, так и модуль пакета. Впоследствии в пакет можно добавлять новые компоненты с помощью все того же меню Component Install Component.
В целом работа с пакетами - дело довольно простое и не требует длительных тренировок. Единственное, о чем следует позаботиться, так это о структуре создаваемых пакетов: старайтесь, чтобы добавляемые в них модули и классы были сгруппированы по общим функциям.