Теллес М. - Borland C++ Builder. Библиотека программиста - 1998
.pdfBorland C++ Builder (+CD). Библиотека программиста 321
шаблонов и другими важными добавлениями.
Это программное средство обеспечивает максимальное увеличение производительности по сравнению с более старыми средствами типа Visual C++ или Borland C++. Кроме того, для наследственности приложений CBuilder может использовать уже имеющиеся коды MFC или OWL. И наконец, так как CBuilder может использовать компоненты Delphi, он согласуется с существующей базой кодов тысяч модулей, для которой не требуется перекодирования или переделки.
Может ли CBuilder работать с MFC?
Да, но вы должны иметь версию MFC, поставляемую с Borland C++ версии 5.02 или выше. Кроме того, вы должны компилировать библиотеки MFC, используя файл сборки (makefile), поставляемый Borland. Формы CBuilder могут прямо быть использованы в приложениях MFC (подробнее об этом — в следующих далее вопросах).
Я бы, на самом деле, задал вопрос вам — так ли вы уверены в том, что хотите использовать MFC с CBuilder? MFC — устаревшая система, которая слишком велика, плохо написана, короче говоря, работа с ней обеспечит вам только боль в шее, и ничего больше. Не торопитесь упрекать меня в фанатичности — я профессионально работал с MFC с самого момента появления этой системы (тогда еще с Microsoft C 7.0). Так что я знаю, что говорю, а верить мне или нет — ваше дело.
Может ли CBuilder работать с OWL?
Да, библиотека OWL может быть скомпилирована с CBuilder. Вам придется заново собрать библиотеки, используя компилятор CBuilder, поскольку в CBuilder изменен формат объектных файлов для поддержки обработки исключительных ситуаций, встроенной в новую систему.
Собирается ли фирма Borland избавиться от OWL?
В отношении OWL фирма Borland занимает нейтральную позицию — она не избавляется от этой нее, но перспективы может определить только рынок. Учитывая все обстоятельства, скорее всего в обозримом будущем OWL будет продолжать свою существование, в основном благодаря большому количеству коммерческих приложений, использующих ее.
Что такое VCL?
VCL – это сокращение от Visual Component Library, то есть библиотека визуальных компонентов. VCL — это библиотека компонентов (уже скомпилированных), которая охватывает большинство стандартных объектов Windows. Объекты VCL могут быть как визуальными, так и не визуальными. Самое важное состоит в том, что VCL это полноценная библиотека (то есть сборник, а не жесткая иерархическая структура), и ее отдельные компоненты могут использоваться независимо от системы. Благодаря этому формы VCL могут быть использованы в динамически подключаемых библиотеках (DLL), а также поддерживаются некоторыми другими компиляторами — например, формы CBuilder можно использовать в приложениях на Visual C++.
Где я могу получить дополнительную информацию?
Существует множество различных источников информации о CBuilder. Лучший из них — Web- узел фирмы Borland (http://www.borland.com), который содержит самую свежую информацию по CBuilder, в частности, последние исправления ошибок. Там же вы найдете полную информацию обо всех уже известных ошибках и множество другой технической информации.
Borland C++ Builder (+CD). Библиотека программиста 322
Кроме того, на любом Web-узле, посвященном Delphi вы почти наверняка найдете что-то и о
CBuilder.
Как мне скомпилировать программу, если я работаю в режиме редактора Brief Emulation?
В этом режиме для компиляции вы можете воспользоваться комбинацией клавиш Ctrl+F9.
Как мне изменить тип проекта, выбираемый по умолчанию?
Контролирует тип приложения, устанавливаемый по умолчанию при выборе команды File ä New Application окно Object Repository. Для того, чтобы выбрать тип текущего приложения в качестве типа по умолчанию для нового проекта, откройте окно Object Repository, выбрав команду меню File ä New. В открывшемся страничном диалоге перейдите на страницу Projects и выберите тип приложения, который вы хотите поставить для создания по умолчанию. Приложение этого типа будет теперь генерироваться при выборе команды File ä New Application.
У меня пропадает окно сообщений об ошибках. Как его вернуть?
Попробуйте увеличить размер окна редактора — иногда это помогает. Еще вы можете щелкнуть правой кнопкой в окне редактора и во всплывшем меню выбрать пункт Message View (просмотр сообщений).
Мое консольное приложение не использует VCL. Как мне убрать ее из компоновки?
Выберите команду главного меню View ä Project Makefile. Найдите строку, начинающуюся с
«ALLLIB». Удалите VCL.LIB из make-файла. Измените CP32MT.LIB на CW32MT.LIB. После этих манипуляций строка «ALLLIB» должна выглядеть следующим образом:
ALLLIB = $(LIBFILES) import32.lib cw32mt.lib
Как мне использовать внешние DLL с CBuilder?
Используйте программу IMPLIB.EXE, которая поставляется с CBuilder для создания библиотеки импорта. После этого обычным образом скомпонуйте полученную библиотеку с вашим приложением.
Как мне создать статическую библиотеку в CBuilder?
Вы не можете этого сделать. CBuilder может создавать только исполняемые файлы и DLL. Для создания статической библиотеки вам придется использовать версии компилятора, работающие из командной строки и специальную программу LIB.
Где находится Мастер диалогов (Dialog Wizard)?
Мастер диалогов поставляется только с версиями CBuilder Professional и выше; он находится в директории Examples. Для того, чтобы использовать его, вам придется сначала скомпилировать и сынсталлировать его.
Почему при исключении информации отладчика размер EXE-файла не уменьшается?
Информация отладчика хранится в файле, имеющем то же имя, что и ваш проект и расширение TDS. Поскольку эта информация хранится вне исполняемого файла, ее исключение не уменьшит
Borland C++ Builder (+CD). Библиотека программиста 323
его размера.
Что за файлы создает CBuilder? Которые из них я могу удалить?
Кроме исходных файлов вашего приложения (*.CPP, *.H, *.DFM), CBuilder создает еще несколько файлов в директории с исходным кодом. Некоторые из них — такие как *.MAK и *.RES, нужны для того, чтобы собрать ваше приложение. Другие же могут быть удалены после создания исполняемого файла. Можно смело удалять файлы *.OBJ, *.TDS, *.IL?. Файлы *.OBJ — это объектные файлы, включенные в исполняемый файл. Файлы *.TDS — это файлы символов отладчика. Файлы *.IL? — это файлы прогрессирующей компоновки (incremental link). Кроме того, все файлы вида *.~?? — это резервные копии, и при желании вы можете удалить и их. Резервные копии создаются, когда вы производите какие-нибудь изменения в редакторе.
Где находятся компоненты для страницы Samples палитры компонентов?
Вы найдете их в директории \CBuilder\examples\controls. Для того, чтобы использовать их, вам придется сначала их скомпилировать и сынсталлировать (в отличие от бета-версии).
Где находятся управляющие элементы для Internet?
Управляющие элементы для Internet поставляются только с версией CBuilder Professional и выше. Они находятся на странице Internet палитры компонентов.
Замечание
Недавно фирма Borland представила и сделала доступными управляющие элементы для Internet на своем Web-сайте. Так что теперь их можно найти и там (www.borland.com).
Как мне сделать так, чтобы у нескольких компонентов на форме было одинаковое значение свойства?
Проще всего — выбрать все необходимые компоненты, удерживая нажатой клавишу Shift и щелкая них мышью. Потом надо просто перейти в Object Inspector и изменить в нем значение требуемого свойства. Это изменение отразится во всех выделенных компонентах.
Общие вопросы программирования
Что такое «Compiler Error #1» и как мне от нее избавиться?
Ошибка компилятора №1 (Compiler Error #1) может быть вызвана различными причинами. Как правило, вы сможете избавиться от нее, закрыв CBuilder, а затем запустив вновь и загрузив свой проект при помощи команды File ä Reopen. Если это не поможет, вам придется разобраться в том, что же происходит на самом деле. Перейдите в окно DOS, запустите программу make, задав ей в качестве параметра make-файл вашего проекта; изучите выдаваемые ошибки и исправьте их.
Что такое AnsiString и как его преобразовать в Char *?
AnsiString — это Delphi-совместимые строки, используемые в CBuilder. Если у вас есть возможность выбора, используйте лучше AnsiString, а не строки STL и массивы символов.
Благодаря наличию большого количества весьма достойно оформленных методов использовать их проще, чем просто строки или char *.
Например, вместо того, чтобы использовать чреватые ошибками методы типа strcat и strcpy, вы
Borland C++ Builder (+CD). Библиотека программиста 324
можете использовать методы AnsiString, соответственно += и =, как это показано в следующем фрагменте кода:
// Если вам не сделать по другому char szBuffer[20];
strcpy ( szBuffer, "This is a good test"); strcat ( szBuffer, " and so is this!");
// А лучше сделать так
AnsiString strBuffer;
strBuffer = "This is a good test"; strBuffer += " and so is this!";
В этом примере текст, скопированный в szBuffer, на самом деле переполнит буфер и вызовет появление ошибки, которую будет очень трудно найти. Во втором случае, использовав AnsiString вы будете гарантированы от подобных проблем.
Что же касается второй части вопроса, то для преобразования AnsiString в char * вам надо использовать метод AnsiString c_str. Например:
void func(char *strBuffer); // Прототип некоей функции AnsiString s = "This is a good test";
func(s.c_str());
Как добавляют элементы в множество?
Для добавления элемента в множество, например, в свойство FontStyle используется оператор <<. Для добавления элемента «полужирный» (bold) в объект-стиль шрифта надо написать следующую строку:
pMyFont->Style << fsBold;
Что означает ошибка «Member function must be called ...»?
Ошибка «Member function must be called ...» («Должна вызываться функция класса ...») случается достаточно часто у программистов, которые привыкли программировать на языке Pascal, и, переключаясь на C++, забывают о скобках. Как правило, эта ошибка означает, что если, например, у вас есть класс Foo, у которого есть метод Bar, то вы пишите:
Foo f; f.Bar;
На самом деле вы должны написать: Foo f;
f.Bar();
В языке Pascal вы можете вызывать функцию или метод, не имеющие аргументов, не используя скобки, а в C++ наличие скобок в вызовах функций строго обязательно. По наличию скобок компилятор определяет, что вы пытаетесь вызвать функцию, а не передать чему-нибудь адрес функции класса. Например:
void func(int x); func(f.Bar);
кардинально отличается от:
Borland C++ Builder (+CD). Библиотека программиста 325
func(f.Bar);
В первом примере результат вызова метода Bar передается в функцию. Во втором же — адрес функции класса Bar передается в функцию func в качестве аргумента. Это и вызывает ошибку компилятора.
Что означает ошибка «Structure required»?
Ошибка «Structure required» («Требуется структура») означает, что вы пытаетесь вызвать что-то используя точку (.) вместо стрелки (->). Когда вы используете указатель на структуру или объект, используйте стрелку. Если вы имеете дело с реальным объектом или ссылкой на объект, используйте точку. Например:
Foo *pFoo;
pFoo->Bar(); // ОК
pFoo.Bar(); // Ошибка: нужна стрелка. В этом случае и //генерируется ошибка, о которой мы говорим.
Foo foo;
foo->Bar(); // Ошибка: нужна точка foo.Bar(); // ОК
Как исправить ошибку «Linker Error: Failed to create map file»?
Опять же, к возникновению этой ошибки может привести множество причин. Например недостаток места на диске или нарушение набора файлов пошагового линкера (incremental linker). Для того, чтобы перебороть эту проблему, закройте CBuilder и удалите из директории с вашим проектом все файлы с расширением IL?. Кроме того, в некоторых случаях может помочь выполнение команды Build All (собрать все).
Как добавить ресурсы в проект?
Выберите пункт Add To Project (добавление в проект) и добавьте RC или RES файл, содержащий ресурс, с которым вы хотите работать в вашем проекте. CBuilder автоматически распознает эти файлы и запускает компилятор ресурсов для файла RC, а также встраивает RES файл в ресурсы проекта. Вы также можете использовать макросы USERC и USERES в вашем файле проекта:
USERES("myresources.res");
USERC("myresources.rc");
Можно ли динамически подгрузить библиотеку VCL?
Нет. На данный момент VCL может быть только статически подгружена в программу, фирма Borland клятвенно обещала, что в следующих версиях CBuilder VCL можно будет подгружать динамически.
Как пошагово выполнить исходный код VCL при отладке?
Вы должны собирать программу, используя отладочную версию VCL. В использовании исходного кода VCL есть три стадии. Во-первых, вам надо включить информацию отладчика, с тем чтобы вы могли использовать его. В главном меню выберите пункт Options ä Environment и щелкните на
Borland C++ Builder (+CD). Библиотека программиста 326
закладке Library. Щелкните на кнопке Build with debug info (собирать с информацией отладчика). Далее вам надо присоединить версию VCL, предназначенную для отладки. На той же самой странице страничного диалога установите флажок Link with debug VCL (линковать с отладочной версией VCL). И, наконец, вам надо сообщить отладчику, где находится исходный код VCL. Все в том же страничном диалоге щелкните на закладке Preferences и введите путь к исходному коду в поле Path for Source (путь к исходному коду). Разделяйте каждый путь точкой с запятой (;).
Почему отладка столь медленна? Как ее ускорить?
Есть несколько способов для ускорения отладки. Самый действенный, конечно, это добавить оперативной памяти в ваш компьютер. У вас не получится сколько-нибудь серьезной работы с ОЗУ менее 32 Мбайт. Есть и другие способы. Уберите все неиспользуемые или ненужные переменные из окна просмотра. Чем меньше вещей система должна отслеживать, тем быстрее она работает. На время отладки закройте окно Object Inspector. Оно обновляется при каждом шаге, так что это позволит вам чуть-чуть убыстрить процесс.
Компилятор нагло врет! Мои переменные имеют неправильное значение!
Скорее всего, с компилятором все в порядке. Попробуйте выполнить в CBuilder следующий код:
int func()
{
int x = 2; int y = 3;
MessageBox(NULL, "Добрались до функции!", "Info", MB_OK);
}
В свое приложение вставьте вызов функции func и пройдитесь по ней по шагам при помощи отладчика. Взгляните на значения переменных x и y в окне просмотра. Скорее всего, они будут равны 0. Ошибка компилятора? Нет. Компилятор увидел, что вы их никогда не используете, и поэтому не рассматривает их. Отладчик знает об их существовании (поскольку они все-таки есть в коде), но также знает и то, что у них нет значений. В результате вы видите 0. Если вы не используете переменные, они не будут иметь значений при отладке. Если вы действительно хотите знать их значения, попробуйте следующее:
int func(void)
{
int x = 2; int y = 3;
AnsiString strTemp = " X = " + AnsiString(x) + " Y = " + AnsiString(y); MessageBox(NULL, strTemp.c_str(), "Info", MB_OK);
}
В окне сообщения вы увидите правильные значения переменных.
Как получить доступ к принтеру или буферу обмена?
В CBuilder уже определены объекты для принтера и буфера обмена. Лучше использовать их, а не пытаться создавать свои собственные объекты. Для принтера определен объект, называющийся Printer, который вызывается как функция. Например:
// Начать новую страницу в принтере
Borland C++ Builder (+CD). Библиотека программиста 327
Printer()->BeginPage();
Точно также и буфер обмена используется как функция Cliboard().
Как поставить выравнивание байтов в CBuilder?
К сожалению, CBuilder игнорирует опции компилятора по выравниванию, заменяя их своими собственными. Следовательно, вы не можете использовать флаги компилятора -a1/2/3. Вместо этого, используйте директиву pragma pack, как показано ниже:
// Выровнять на один байт
#pragma pack(push,1)
struct StructureNeedingAligment
{
// Данные структуры
}
// Отключить выравнивание
#pragma pack(pop)
Как принимать перетаскиваемый (drag-and-drop) файл в моей форме?
Как всегда, с улыбкой. На самом деле вам надо обработать метод WM_DROPFILES. Пример:
void TMainForm::WMDropFiles(TWMDropFiles& Msg)
{
char szTemp[256];
int nNumberOfFiles = DragQueryFile(Msg.Drop, 0xFFFFFFFF, szTemp, 256 );
for ( int nFile = 0; nFile < nNumberOfFiles; ++nFile)
{
//Получаем имя перетаскиваемого файла
DragQueryFile( Msg.Drop, nFile, szTemp, 256 );
//Делаем что-то с файлом
ProcessFileName(szTemp);
}
// Заканчиваем процесс
DragFinish(Msg.Drop);
}
Как изменить размер компонента до размера формы?
Самый простой способ — установить свойство компонента Aligment в значение alClient. Это будет автоматически изменять размер компонента в размер формы каждый раз, когда ее размер будет изменяться (включая и первое ее появление).
Если у вас есть какая то особая причина изменять размер компонента во время исполнения (например, вам может понадобиться оставить вокруг него 1 пиксель), вы можете сделать это при помощи свойств компонента Top, Left, Height и Width. Например:
// Увеличиваем поле редактирования до размера формы,
Borland C++ Builder (+CD). Библиотека программиста 328
// оставляя вокруг него границу в 2 пикселя
Edit1->Top = 2;
Edit1->Left = 2; Edit1->Width = Width - 4; Edit1->Height = Height - 4;
Как использовать макрос TRACE в CBuilder?
Для использования макроса TRACE вам надо сделать две вещи. Во-первых, определить символ __TRACE. Во-вторых, подключить заголовочный файл checks.h. Пример:
#define __TRACE
#include <checks.h>
TRACE("Я здесь!\n");
Замечание
Вывод из макроса TRACE осуществляется в файл с названием OutDbg1.TXT, который загружается в редактор файлов. Он не сохраняется автоматически, вам надо сохранить его из редактора. Кроме того, CBuilder не предложит вам сохранить его при закрытии проекта, так что если вы его открыли, то не забудьте сохранить.
Как отобразить кусочек растрового рисунка?
Используйте класс TImageList. У компонентов TImageList есть метод Draw, в который можно задать границы; он очень похож на функцию Windows API BitBlt.
Как динамически создать компонент во время исполнения?
Очень просто. Используйте оператор new:
*pEdit = new TEdit(this) pEdit->Parent = this; pEdit->Left = 10; pEdit->Top = 10; pEdit->Height = 20; pEdit->Width = 200; pEdit->Visible = TRUE;
Не забудьте установить свойство parent компонента, а то он не будет отображаться. В примере подразумевается, что «this» — это форма, но это может быть любой компонент, имеющий окно.
Как эмулировать sprintf при работе со строками?
Используйте класс String. Например, для того, чтобы отформатировать десятичное число, вы должны написать что-то вроде:
// Вместо sprintf(szBuffer, "%d", nNumber); String s = String(nNumber);
Borland C++ Builder (+CD). Библиотека программиста 329
// Можно создавать форматированные строки внутри текста
String s = " Hello, world! Мне " + String(nNumber) +
"лет от роду";
Библиотека стандартных шаблонов (STL)
Почему при использовании класса vector выдается целый ворох ошибок?
Наверное, вы делаете что-нибудь типа:
#include <vector.h> int func(void)
{
vector<int> array;
}
и на строке vector<int> как раз и получаете свой ворох ошибок. Для исправления ситуации используйте именованную область видимости для STL, которая называется std. Вот код, который разрешит ваши проблемы:
#include <vector.h>
use namespace std; // Просто добавьте эту строку int func(void)
{
vector<int> array;
}
Можно ли использовать STL в компонентах?
Естественно. Не забудьте только добавить соответствующий заголовочный файл (vector, list и т. п.) и полностью определить имя компонента STL, используя выражение std::. Что касается всего остального, можно смело сказать, что компоненты STL работают в компонентах точно также, как и в простых приложениях.
Библиотека визуальных компонентов (VCL)
Как программно добавить элементы в список или комбинированный список?
Это можно сделать при помощи метода Add свойство Items. Другими словами, когда вы работаете с элементами списка или комбинированного списка, вы работаете напрямую со свойством Items. CBuilder разделил всю работу со списками (комбинированными списками) на отдельные части — для обработки данных и модификации самих списков.
Например для того, чтобы добавить элемент в конец списка, вам наде написать следующую строку кода:
ListBox1->Items->Add( "MyItem1" );
Для модификации заданного элемента списка вы обращаетесь к свойству items как к массиву и пишите следующее:
Borland C++ Builder (+CD). Библиотека программиста 330
ListBox1->Items[nInd] = "MyItem2";
И, наконец, для удаления элемента из списка, используя метод Remove:
ListBox1->Remove(0); // Удаление первого элемента списка
Как в своем компоненте или форме обработать сообщение Windows (WM_USER)?
Любое сообщение Windows из числа тех, что не обрабатываются компонентом CBuilder, может быть добавлено в него при помощи карты сообщения (message map). Для этого определите сообщение как константу:
#define WM_MY_Message (WM_USER+1)
После этого в описание класса формы или компонента (находящееся, как известно, в заголовочном файле) добавьте следующие строки:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_MY_MESSAGE,TMessage, OnMyMessage)
END_MESSAGE_MAP
Наконец, определите в своем классе метод OnMyMessage как метод класса, имеющий один аргумент типа TMessage:
void __fastcall OnMyMessage( TMessage& msg );
Далее, уже в коде функции вы можете определить любые действия, которые должны выполняться при получении заданного пользователем сообщения. Если вы используете сообщение, определенное Windows, но не имеющее воплощения в CBuilder, опустите последний шаг. Все остальные шаги останутся точно такими же.
Когда следует использовать модификатор __fastcall?
Не обязательно использовать модификатор __fastcall в ваших собственных методах. Только методы, добавляемые в компоненты, должны использовать его в обязательном порядке. Методы, замещающие в ваших компонентах методы VCL так же должны применять __fastcall.
Все это вызвано тем, что VCL была написана на языке Pascal. В языках C++ и Pascal используются разные соглашения о вызовах, в связи с чем и был введен модификатор __fastcall — для корректного истолкования аргументов.
Почему при инсталляции собственных компонентов появляются сообщения о странных ошибках?
Мне кажется, вопрос должен звучать так: «При инсталляции все вроде бы работает нормально, но компонент ведет себя странно — выдает сообщение о нарушении прав доступа (access violation). Как с этим бороться?»
Скорее всего, при компиляции компонента не производилось выравнивание по границе слова. Если вы изменили выравнивание директивой компилятора С++ или Pascal, компонент может выдавать непредсказуемые результаты.
