Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Теллес М. - Borland C++ Builder. Библиотека программиста - 1998

.pdf
Скачиваний:
764
Добавлен:
13.08.2013
Размер:
4.35 Mб
Скачать

Borland C++ Builder (+CD). Библиотека программиста 231

ресурс (user resource). Этот тип ресурса предназначен для хранения данных любого вида, которые вам нужны, если вам не подходят никакие другие типы ресурсов. Трудно представить пример такого ресурса, так как нет четкого определения пользовательского ресурса. Важно отметить, что все данные для форм CBuilder хранятся в исполняемом файле в виде пользовательских ресурсов. Эта информация содержит такие вещи, как значения свойств, определения меню, обработчики событий в форме. Вы можете посмотреть на информацию, содержащуюся в ресурсе формы, просмотрев форму в текстовом виде. Это можно сделать, нажав на форме правую кнопку мыши и выбрав из появившегося локального меню команду View as Text (посмотреть в текстовом виде).

Работа с компилятором ресурсов

Если вы хотите добавить ресурсы, например информацию о версии, в исполняемый файл вне среды CBuilder, то вам нужно немного поработать с одной из двух версий компилятора ресурсов. Первая версия просто компилирует файл ресурса, а вторая компилирует и встраивает его в исполняемый файл. Обычно вы будете сначала запускать первый компилятор для проверки вашего файла ресурсов, а затем использовать второй компилятор.

Для добавления ресурса версии в вашу программу вам сначала нужно создать новый файл ресурса, содержащий информации о версии. Создайте в CBuilder новый файл и добавьте в него следующие строки:

VS_VERSION_INFO VERSIONINFO

FILEVERSION 1,0,0,1

PRODUCTVERSION 1,0,0,1

FILEFLAGSMASK 0x3fL

FILEFLAGS 0x0L

FILEOS 0x4L

FILETYPE 0x1L

FILESUBTYPE 0x0L

BEGIN

BLOCK "StringFileInfo"

BEGIN

BLOCK "040904B0"

BEGIN

VALUE "CompanyName", "\0"

VALUE "FileDescription", "Test Application\0"

VALUE "FileVersion", "1, 0, 0, 1\0"

VALUE "InternalName", "Test\0"

VALUE "LegalCopyright", "Copyright (C) 1997\0"

VALUE "LegalTrademarks", "\0"

VALUE "OriginalFilename", "Test.EXE\0"

VALUE "ProductName", "Test Application\0"

VALUE "ProductVersion", "1, 0, 0, 1\0"

END

END

END

Блок информации о версии содержит информацию, которую могут прочитать такие программы, как редактор ресурсов; она дает пользователю возможность выяснить, какова версия программы, кто ее написал и т. д.

Чтобы скомпилировать предыдущий блок, поместите его в файл project1.rc и наберите следующую

Borland C++ Builder (+CD). Библиотека программиста 232

команду в командной строке:

brcc32 project1.rc

Вы увидите следующий вывод программы (если не будет найдено ошибок):

C:\book\LoadMenu>brcc32 project1.rc

Borland Resource Compiler Version 5.02

Copyright (C) 1990, 1997 Borland International.

All rights reserved.

Эта программа скомпилирует файл ресурса, проверив его на синтаксические ошибки. Для

компиляции и встраивания ресурса в исполняемый файл наберите команду

brc32 project1.rc

В результате файл ресурса скомпилируется, а затем полученный файл RES будет добавлен к исполняемому файлу. Когда вы это сделаете, пользователь сможет получать информацию о программе, если вы включите информацию о версии, например, в команду Help д About.

Работа с динамически связываемыми библиотеками (DLL)

Выше в главе мы рассматривали хранение ресурсов в динамической библиотеке. Однако кроме ресурсов вы можете хранить в DLL многие другие вещи, самой важной из которых является код функций. DLL — одна из самых полезных и мощных возможностей, когда-либо добавленных в операционную систему Windows. Используя DLL, вы решаете две главные задачи в разработке приложений: ограничения по памяти и проблемы с версиями.

Ограничения по памяти в многозадачных операционных системах возникают из-за того, что одновременно загружено в память много программ. Многие из этих программ выполняют одни и те же задачи, однако каждая содержит свой собственный код для выполнения этой работы. Если бы весь этот код был извлечен из приложения и помещен в отдельный модуль, совместно используемый всеми запущенными программами, то было бы гораздо больше свободной памяти для программ. Это основная концепция DLL. Лучшим примером DLL может служить сама операционная система. Все компоненты Windows, которые вы вызываете из вашего приложения (код прорисовки, код файловой системы и т. д.), живут в наборе системных DLL, которые используются совместно всеми программами, работающими в Windows. Возможность совместно использовать этот код означает, что вашей программе не нужно держать этот код в себе.

Когда ваша программа загружает DLL, динамически или статически, происходит поиск в памяти на предмет того, загружена ли уже эта DLL. Если DLL найдена, то вместо того, чтобы загрузить вторую копию, операционная личит счетчик использования DLL. Вы это уже видели в нашем примере таблицы строк.

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

Borland C++ Builder (+CD). Библиотека программиста 233

отношения не имеют.

Создание DLL в CBuilder

Для того чтобы использовать код в DLL, нам сначала нужно создать DLL, содержащую код, верно? Верно. Давайте создадим такого зверя в CBuilder. Далее мы исследуем использование DLL, созданной в CBuilder, в другой системе, однако сейчас мы собираемся загружать эту DLL в CBuilder.

Одно небольшое замечание. На самом деле есть два разных способа использовать функции в DLL, созданной в CBuilder. Первый это создание библиотеки импорта утилитой implib, которая поставляется вместе с CBuilder. Затем библиотека импорта может быть напрямую встроена в приложение, и Windows автоматически загрузит вашу DLL во время выполнения. Запомните, что вам нужно использовать программу implib, поставляемую с CBuilder, а не более древнюю версию из другой системы, так как библиотеки CBuilder имеют другой формат, нежели старые библиотеки, и поэтому нужны свежие программы для генерации этих библиотек из DLL. Когда у вас есть библиотека импорта для вашей DLL, вы можете просто описать прототипы функций, которые вам нужны, и использовать их напрямую, как будто они были описаны в вашем приложении. В нашем примере мы более заинтересованы в механизме динамической загрузки, так что мы все сделаем сами.

Вэтом примере мы создадим DLL в другой среде разработки, в данном случае в Visual C++. Я выбрал эту среду отчасти оттого, что я хорошо знаю Visual C++, но в основном потому, что вы скорее будете использовать DLL из других источников (так называемые third-party), чем созданные в CBuilder. В любом случае нам нужно делать одно и то же, так почему бы не показать вам еще кое-что?

Вотличие от CBuilder среда Visual C++ (VC) не хочет сама создавать для вас DLL. Вместо этого она создаст файл сборки (makefile) и оставит его пустым, без исходных файлов. Как мне кажется, это еще одна веская причина для перехода на CBuilder. В любом случае создайте в Visual C++ новый файл и добавьте в него следующий код. Если у вас нет Visual C++ или вам лень загружать эту среду разработки и набирать весь этот код, вы можете найти данную DLL вместе с кодом примера на сопроводительном компакт-диске.

#include <windows.h> #include <stdlib.h> #include <string.h> #include <stdio.h>

BOOL WINAPI DllEntryPoint (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {

BOOL fSuccess = TRUE; switch (fdwReason) {

case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: break;

case DLL_PROCESS_DETACH: case DLL_THREAD_DETACH: break;

}

return (fSuccess);

}

extern "C"

{

Borland C++ Builder (+CD). Библиотека программиста 234

__declspec( dllexport ) int CalFunction1( void )

{

MessageBox(NULL, "You called function 1", "Info", MB_OK); return 0;

}

__declspec( dllexport ) int CallFunction2( const char *str )

{

MessageBox(NULL, "You called function 2", str, MB_OK); return 0;

}

__declspec( dllexport ) void CallFunction3( int nValue )

{

char szBuffer[20]; sprintf(szBuffer, "%d", nValue);

MessageBox(NULL, szBuffer, "Value", MB_OK);

}

}

Важным в этом коде являются три функции. Пока что вы можете игнорировать смешно выглядящие модификаторы declspec (dllexport). Это просто способ объяснить VC, что эти функции должны быть экспортируемыми в DLL, чтобы другие программы могли их использовать. Может быть, вы думали, что функции экспортируются по умолчанию; в таком случае многое в мире программирования под Windows является не таким, каким оно вам казалось.

В DLL определены три функции: CallFunction1, CallFunction2 и CallFunction3. Они отличаются типом возврата, а также количеством и типами аргументов. Мы будем использовать все три функции в нашем примере.

ЗАМЕЧАНИЕ

Как вы заметили, функции объявлены с модификатором extern «C» в предыдущем листинге. Visual C++ и CBuilder используют разные схемы изменения имени (mangling) при генерации имен для функций. Чтобы не смотреть в листинг экспорта и запоминать полученные имена функций в переделанном виде, мы разрешаем компилятору использовать соглашение о вызовах, а также схему внешних имен, принятые в C. Это означает, что в результате имена функций в экспортном виде будут просто CallFunction1 и т. д.

Когда мы определили DLL, следующим шагом является создание проекта в CBuilder, использующего функции, которые мы написали и экспортировали из DLL. Вы должны знать, что только экспортированные функции могут быть динамически загружены из DLL во время выполнения или встроены в ваше приложение через библиотеку импорта. Неэкспортированные

функции невидимы для окружающего мира и могут быть использованы только другими функциями в этой DLL. Мы используем эту возможность ниже в книге, когда будем рассматривать другую часть уравнения: использование DLL, созданных в CBuilder, в системе

Visual C++.

Создание формы для динамической загрузки DLL

Для того чтобы использовать нашу DLL в проекте CBuilder, нам нужна форма, с помощью которой пользователь вызывал бы эти функции, а также для просмотра результатов. На рис. 10.4 показана форма, которую мы будем использовать в нашем проекте динамической DLL. Как видите, мы построили эту форму, использовав три кнопки, метку и поле для ввода данных,

Borland C++ Builder (+CD). Библиотека программиста 235

посылаемых в функции в DLL.

Первый шаг при загрузке информации из DLL в точности такой же, как и при получении ресурсов из файла, то есть нам нужно получить ссылку на библиотеку с помощью функции API LoadLibrary. Для этого добавьте следующий код в конструктор формы:

__fastcall TForm1::TForm1(TComponent* Owner)

{

hLibHandle = LoadLibrary("vcdll.dll");

}

Аналогично, нам нужно убедиться, что ссылка на библиотеку освобождена, когда мы закончили с ней работать. Это делается в обработчике события OnClose формы, FormClose. Создайте обработчик и добавьте в него следующий код:

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

{

if ( hLibHandle ) FreeLibrary( hLibHandle );

}

Рис. 10.4. Форма для динамической загрузки DLL

По крайней мере, до этой точки процесс, которому мы следовали, полностью совпадает с тем, что мы делали при загрузке строк из DLL. Это место в процессе, где два примера расходятся. Давайте посмотрим на это, добавив обработчик для нажатия на первую кнопку (Вызвать функцию 1) в форму. Вот код, который нужно добавить в обработчик Button1Click:

void __fastcall TForm1::Button1Click(TObject *Sender)

{

if ( hLibHandle )

{

// Пытаемся загрузить функцию из библиотеки pfivFunc pFunc = (pfivFunc)GetProcAddress( hLibHandle,

"CallFunction1"); if ( pFunc ) (*pFunc)();

}

Borland C++ Builder (+CD). Библиотека программиста 236

}

Вам нужно добавить еще одну строку в файл, чтобы он скомпилировался. Добавьте следующую строку прямо над функцией, а потом мы поговорим о том, что же происходит в этом фрагменте кода:

typedef int (*pfivFunc)(void);

Пойдем по порядку. Эта строка (typedef) — способ описания нового типа в C или C++. Хотя она и выглядит совершенно по-другому, нежели обычные описания типов, которые вы когда-либо видели в своем коде, это на самом деле просто отдельный специальный случай оператора typedef.

Основная форма оператора typedef, которая просто описывает новый тип как более простую строку для компилятора, выглядит так: typedef описание-старого-типа описание-нового-типа. Вот простой пример, чтобы вы поняли, как это работает. Представьте, что вы хотите описать новый тип, IntBool, для представления логического (булевского) значения в виде целого. Этот тип не отличается от целого, но мы хотим, чтобы программист, читающий код, понимал, что данная переменная должна хранить только булевские значения (true, истина, или false, ложь) в целом представлении. Тогда мы напишем:

typedef int IntBool;

Теперь далее в коде мы можем использовать новый тип для описания переменных:

IntBool bMyInteger;

Для компилятора нет разницы в использовании типов int и IntBool. Он просто сопоставляет один другому. В нашем типе pfivFunc (см. выше) мы на самом деле написали, что тип pfivFunc представляет функцию, у которой нет параметров (ключевое слово void в скобках) и которая возвращает целое значение. Общая форма оператора typedef по отношению к функциям такова:

return-type (*function-name)(parameter types)

где return-type это тип возврата функции (int, void, bool и т. д.), а function-name имя определения typedef. Это имя, которое мы будем использовать как новый тип, точно так же, как мы использовали раньше IntBool. Parameter types список корректных типов C++ (включая новые типы). Если у вашей функции три параметра, скажем целое, вещественное и ссылка (reference) на объект класса Foo, то это будет выглядеть так: (int, float, Foo&).

Теперь, когда эта странность с оператором typedef в коде позади, весь оставшийся код ясен как божий день. Мы используем функцию API GetProcAddress для получения указателя на функцию, находящуюся в библиотек е DLL, на которую у нас есть ссылка. Этот указатель будет типа FARPROC, что есть просто указатель на функцию. Нам же нужно вызывать эту функцию с параметрами и проверять возвращаемое значение, так что нужно объяснить компилятору, что у функции есть такие параметры. Так как у нас есть замечательный оператор typedef, описывающий в точности прототип нашей функции, то мы преобразу ем возвращенный указатель типа

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

ЗАМЕЧАНИЕ

Очень важно, чтобы типы полностью соответствовали количеству и типу параметров, которые вы

Borland C++ Builder (+CD). Библиотека программиста 237

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

Как вы помните, первая функция (CallFunction1) в библиотеке просто отображала окно сообщения. Функция GetProcAddress извлекает адрес функции CallFunction1 из DLL, находя внешнее (экспортированное) имя в DLL, совпадающее с именем, которое мы передаем. Вот почему так важно использовать модификатор extern "C" в определении DLL. Иначе нам бы пришлось вызывать извращенное (mangled) (иногда его называют мягче, декорированное, decorated) имя в DLL, и в результате мы вызывали бы что-нибудь вида «CallFunction1@iv1». А в нашем случае мы обращаемся к функции просто по имени.

ЗАМЕЧАНИЕ

Вам, наверное, интересно, можете ли вы использовать функцию GetProcAddress для доступа к функциям в вашей программе и использования их, например, для реализации языка сценариев в вашей программе. Да, вы можете так делать. Если функции доступны по имени и вы знаете это имя, можете вызывать их из любой программы, на которую у вас есть ссылка. Теоретически, если вам удалось добыть ссылку на экземпляр запущенной программы, вы можете также запускать функции, содержащиеся в ней.

Для второй кнопки нам нужна функция, имеющая один аргумент строку (const char *) и возвращающая целое значение. Для определения типа, который представляет такие функции, нам нужно добавить следующую строку в исходный файл:

typedef int (*pficsFunc)(const char *);

Соответственно, мы теперь можем добавить обработчик для нажатия на вторую кнопку на форме, вызывающий вторую функцию в DLL (CallFunction2). Создайте обработчик для второй кнопки и поместите в него следующий код:

void __fastcall TForm1::Button2Click(TObject *Sender)

{

if ( hLibHandle )

{

// Пытаемся загрузить функцию из библиотеки pficsFunc pFunc = (pficsFunc)GetProcAddress( hLibHandle,

"CallFunction2"); if ( pFunc )

(*pFunc)(Edit1->Text.c_str());

}

}

Процесс загрузки отличается немногим. Мы просто извлекаем функцию CallFunction1 из DLL и затем косвенно ее вызываем через возвращенный указатель. В данном случае нам нужно послать функции строку для отображения, так что мы используем для этого текст, находящийся в поле ввода.

Стоит заметить, что данный код хорошо защищен. Есть несколько проблем, которые могут возникнуть в этом коде, так что он делает все, чтобы предотвратить (в случае каких-либо ошибок) появление катастрофических нарушений в системе. Во-первых, мы проверяем ссылку на DLL, не равна ли она NULL. Это может привести к серьезным проблемам у функции GetProcAddress. Когда мы проверили, что ссылка корректна (в силу нашего понимания), следующим мы проверяем

Borland C++ Builder (+CD). Библиотека программиста 238

указатель, возвращенный функцией API GetProcAddress. Если функция не может найти запрошен

ную функцию в DLL или не может выполнить запрос по какой-то другой причине, то возврат от функции API будет равен NULL (большинство функций API, которые возвращают ссылки или указатели, вернут вам NULL в случае какой-либо ошибки). В таком случае нам не хотелось бы вызывать косвенно функцию, так как это приведет к нарушению защиты Windows или даже хуже.

Третья (последняя) кнопка вызывает функцию, которая имеет один параметрцелое и ничего не возвращает (void). Прототип функции в операторе typedef C++ выглядит так:

typedef void (*pfviFunc)(int);

После чего мы можем использовать этот тип для передачи данных в функцию, написав код для обработчика нажатия на третью кнопку. Добавьте этот обработчик и внесите в него такой код:

void __fastcall TForm1::Button3Click(TObject *Sender)

{

if ( hLibHandle )

{

// Пытаемся загрузить функцию из библиотеки pfviFunc pFunc = (pfviFunc)GetProcAddress( hLibHandle,

"CallFunction3"); if ( pFunc )

(*pFunc)(atoi(Edit1->Text.c_str()));

}

}

Опять же, мы извлекаем функцию из DLL, передавая ей на этот раз целый аргумент. Хотя я и предупреждал, что не надо передавать свойство Text в функцию, в данном случае это делать можно. Плохой идеей является передача свойства Text в виде строки функции, которая может изменить строку. В этом случае может получиться непредсказуемый результат. В случае же функции atoi, которая обещает не изменять переданный аргумент, это является относительно безопасным маневром.

Теперь, когда вы скомпилируете и соберете приложение, сможете увидеть результаты вашего упорного труда. Во-первых, убедитесь, что файл VCDLL.DLL находится в том же каталоге, что и программа (project1.exe). Тогда можно быть уверенным, что Windows найдет этот файл и загрузит его. Если вы не положите файл в тот же каталог, что и исполняемый файл, то Windows применит простой процесс для поиска этого файла. В первую очередь система будет искать этот файл в каталогах Windows и Windows\System (для Windows NT это, соответственно, WinNT, WinNT\System и WinNT\System32). Если файла там нет, то Windows будет искать в каждом каталоге, заданном в переменной окружения path (у Windows NT есть специальная переменная, которая задает путь для поиска DLL). И наконец, если файл не будет найден, функция LoadLibrary вернет NULL, что означает, что DLL не обнаружена.

Если вы на самом деле положили DLL в такое место, где Windows сможет его найти, форма загрузится и отобразит желанные кнопки. Введите какой-нибудь текст в поле ввода в нижней части формы и нажмите на вторую кнопку (Вызвать функцию2). Вы увидите окно сообщения с текстом, который вы ввели, показанное на рис. 10.5. Это означает, что функция была найдена и что текст был корректно передан функции в DLL.

Borland C++ Builder (+CD). Библиотека программиста 239

Рис. 10.5. Форма приложения «динамическая загрузка DLL» во время выполнения

На этом мы завершаем дискуссию о работе с динамическими библиотеками. Эта очень мощная технология позволяет вам вынести часть вашего кода, содержащего общие функции, во внешнюю разделяемую библиотеку, которую можно подгрузить при желании во время выполнения. У такого подхода есть два очевидных преимущества. Во-первых, код будет лежать в одном и том же месте, даже если его используют разные приложения. Это экономит дисковое пространство и память. Во- вторых, использование DLL для хранения общих функций программы позволит вам менять эти функции без необходимости изменять само приложение. Если в какой-то функции обнаружена ошибка, то вы просто распространяете среди пользователей DLL, содержащую эту функцию, вместо того чтобы рассылать всем все приложение целиком.

Что мы узнали в этой главе?

В этой главе мы исследовали обширную область ресурсов и их использование в приложениях CBuilder. Поскольку многое в Windows связано с ресурсами, это заставляет вас изучить как можно лучше ресурсы и возможности их использования в приложении. Вот основные моменты, которые вы должны были запомнить из этой главы:

·Все данные формы (свойства, обработчики событий, управляющие элементы и т. д.) хранятся в файле ресурса вашего приложения в системе CBuilder.

·В ресурсах можно хранить информацию, зависящую от региональных настроек, что важно для интернационализации вашего приложения.

·Используя присоединенный ресурс меню, вы можете настраивать меню по желанию пользователя. Используя функции Windows API, вы легко можете добавлять и удалять пункты меню в форме во время выполнения приложения.

·Динамически подключаемые библиотеки (DLL) являются одним из важнейших аспектов программирования в операционной системе Windows. DLL используются для хранения данных или кода, которые потом можно использовать во время выполнения вашего приложения для придания программе большей гибкости и расширяемости.

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

Borland C++ Builder (+CD). Библиотека программиста 240

Глава 11•Работа с Delphi

Использование форм Delphi в CBuilder

Использование модулей Delphi

Встроенный компилятор языка Pascal

Поворот текста с помощью Delphi

Как вам повторяют снова и снова, CBuilder — это просто Delphi, использующий для разработки приложений язык программирования C++ вместо Object Pascal. Если это действительно так (а это действительно так), то нельзя ли использовать объекты Delphi в CBuilder? И как было бы замечательно, если можно было бы взять уже созданные формы и программы Delphi и использовать их в CBuilder. И не является ли главной в использовании кода возможность использовать не только код из ранее разработанных приложений, но и код, написанный в другой среде разработки?

На самом деле вполне возможно использовать практически все элементы ваших приложений на Delphi в приложениях на CBuilder лишь с некоторыми ограничени ями, которые мы рассмотрим в этой главе. В CBuilder можно напрямую использовать формы Delphi и компоненты (обычно); даже код может использоваться в приложени ях на CBuilder без изменений. На самом деле, как вы увидите, можно даже смешивать в своих приложениях функции C++ и Pascal. Тонкая штука, этот

CBuilder.

Все новое это хорошо забытое старое

Много лет назад, когда я впервые начал писать программы под Windows, я был неприятно удивлен и расстроен тем, что все, что я разрабатывал под другие плат формы (MS-DOS и Unix), не компилировалось новыми компиляторами под Windows. Существовало множество ограничений на то, что можно и нельзя использовать (например, sprintf было использовать нельзя, а его уродливый клон wsprintf — можно). Ничего у меня не компилировалось, а то, что компилирова лось, работало не так, как должно было. Это было мое первое знакомство с концепцией совместимости (которую я бы скорее назвал концепцией несовместимости). Советы, получаемые от продавцов и производителей компиляторов, напоминали анекдот про пациента, который обращается к врачу с жалобой: «Доктор, когда я вот так поворачиваюсь, очень болит спинаи получает резонный совет: «Ну не поворачивайтесь так большеПрограммирование для Windows было очень похоже. Вся история повторилась заново, когда я начал работать с Visual Basic. Я не мог использовать написанный мной на C++ код, кроме как создавая DLL с экспортируемыми функциями, которые потом вызывались. Я находил это весьма досадным, поскольку есть вещи, которые Visual Basic просто не умеет делать хорошо, и я жаждал возможности использовать код на C/C++ вместе с теми вещами, которые VB делает действительно неплохо (например, работа со строками и размещение форм). А мои коллеги все время настаивали на том, что только сумасшедший (к каковым они меня почему-то причисляли) может мечтать о том, чтобы использовать сразу два языка. Они были в чем-то правы, и в какой-то момент я смирился с мыслью, что код можно писать только на одном языке.

Но вот появился CBuilder, и я внезапно осознал, что теперь я действительно могу писать приложения сразу на двух языках — Object Pascal и C++. И, что еще более обескураживающе, я могу использовать код, который я писал последние несколько лет на Pascal, не переписывая его на C++. Кажется, я попал в сказку.

В данной главе мы немного исследуем эту сказку. Вы узнаете, как можно использовать большую часть написанного в Delphi в CBuilder, что откроет вам дорогу для использования богатейшего набора компонентов, написанных для Delphi, которые вы сможете инсталлировать в CBuilder и использовать в своих приложениях. Кроме того, через множество книг, журналов, Web-сайтов,

Соседние файлы в предмете Программирование на C++