2023年12月16日发(作者:)

BCB6开发经验谈—

第三方控件的安装与卸载

写下此文章是为了那些还还没有接触过第三方控件的,而又为第三方控件的安装与卸载而烦恼的开发人员。就我所了解与使用过的有Raize、DevExpress、SuiPack、DBGridEh、FastReport等。

而如何正确的安装与卸载呢?并不像windows的安装程序与卸载那么傻瓜化。如果是傻瓜化的安装与卸载,那就没必要写下这遍文章指导初学者。

以前刚接触第三方控件时,也曾为安装某一控件使用,又过一段时间将其卸载后,重新新建一个工程就编译不过了而感到烦恼。

第三方控件的安装相对简单一点,像Raize控件,就一个文件就可以安装。DevExpress相对麻烦一点,现在都有一个Auto-Installor自动安装。在这里主要讲的是卸载第三方控件。

第三方控件的卸载,在BCB6中要经过三个步骤:

(1)Remove Packages. 移除相应的软件包。

[1] 打开BCB6,然后File->Close All。

[2] Component->Install Packages…,然后选择要移除的软件包,点击Remove按钮。

(2)Remove Include Path/Lib Path/Palette Pages 移除Include/Lib/Pages信息。

[1] Project->Option->Directories/Conditionals->Include Path,去除要移除第三方控件的Include路径。

[2] Project->Option->Directories/Conditionals->Lib Path,去除要移除第三方控件的Lib路径。

[3] Tools->Environment Options->Library,去除要移除第三方控件的Lib路径。

[4] Tools->Environment Options->Pallette->Pages,去除第三方控件的所有Page。

(3)Remove File 修改文件,去除卸载了的*.lib/*.bpi(重要)

[1] 打开BCB 的安装目录->Bin,找到,然后用文本编辑器打开,显示一个xml文件的格式,工程库(),备用工程库(),软件包(),将相应的第三方控件*.lib与*.bpi去除。例如DevExpress就移除dx*.lib、cx*.lib、EQ*.lib与dx*.bpi、cx*.bpi、EQ*.bpi文件。

经过上面的修改,就把第三方控件完全卸载。重新新建一个工程就不会出现编译链接错误了。祝好运!

一段时间没用cbuilder了,再用的时候,发现总是磕磕绊绊,把遇到的一些“小问题”贴在这里,希望能给其他一些不熟悉cb6的人一些帮助:

1.先安装一些控件后,以后卸载,但编译后来的项目总提示找不到。。。,需要给一些lib,bpi指定路径?

解决方法:close掉工程,使用ultraedit打开.bpr文件,把你卸掉的一些*.bpi,*.lib从 ,中手工删除掉,保存。然后再打开编译就好了。

2.从旧版本cb项目中copy过来的文件,dfm格式以文本编辑器打开后是乱码?

cbuidler中打开,切换到设计视图,右键选中“Text DFM”,OK!

3.旧版本cb项目中的copy过来的Form,先执行FormCreate才执行构造函数?

使用ultraedit,执行批量替换: 选定你的代码目录录,对所有..dfm文件,执行

“OldCreateOrder = True” 替换为 “OldCreateOrder = False”

4. 加入到cc中的项目,打开时报错,提示“File Access Denied”或直接close你的cb6?

第一个问题是不应该把.res文件加入到cc,应该把该文件保存为私有; 第二种情况需要你把项目 .bpr,.bpf,.cpp三个文件先checkout,然后再打开,就没问题了!

5.使用TList时,使用delete 清除?

使用TList,一般我们都会 使用new ,添加指针类型到 TList中作为元素,因此在删除时,必须先delete每一个元素,再执行clear,然后在delte TList对象本身,如:

if (pSubExeList)

{

TSubExe* pSubExe=NULL;

for (int i = 0; i < pSubExeList->Count; i++)

{

pSubExe = (TSubExe*)pSubExeList->Items[i];

delete pSubExe;

}

pSubExeList->Clear();

delete pSubExeList;

pSubExeList = NULL;

}

虽然这是一个很简单的问题,但还是可以看到很多写的不正确的代码,:(

6.如果先生成了一个Form,后来需要把这个Form改为从另外一个基类Form继承?

方法是:1.修改类定义的方法,添加从基类继承;

2.修改构造函数,改为执行基类的构造函数;

3.点击Form,右键-》View As Text ,然后修改 第一个object为inherited

7.在cbuilder查找一个函数很麻烦?

建议使用gexperts工具,其中有一个功能 “Procedure List”,把这个菜单项拖到编辑区的右边,非常容易找函数,在代码量很多的情况下很方便。

另外这个工具还有个最常用的功能是:注释块和取消注释。写代码时没有这个东东真是累。

8.在实现自定义控件的时候或者动态构建界面的时候,需要写很多动态创建控件的代码。不知道怎么写或写起来太累?

有一个好方法,也是gexperts工具提供的,“Component to code”,先创建一个临时FOrm,把你想要动态创建的布局设计好,然后选中控件,点击“Component to code”,自动帮你生成了代码,你只需要copy过来,稍加整理就可以了。

9.特别多的头文件,到处都要添加include代码?

可以定义一个专门的.h 文件,把通常需要包含的所有include代码写在里面;以后用的时候就只用添加这一个.h 了。

10.几个常用的API函数:

找窗口:注意第一个是类名;第二个是窗口的Caption,返回窗口句柄

FindWindow(className,FormCaption)

动态启动另外一个可执行程序Exe,或者是打开文档:注意第四个参数,可用来传递程序的启动参数,参数之间以空格隔开,取参数。

ShellExecute (ParentFormHandle,"open",filename,startup arguments,default dir ,Show

Mode)

取应用程序启动参数:

ParamCount() :取参数个数;

ParamStr(argument index):取参数,因为ParamStr(0)标识的是执行程序文件的名称,因此实际上第一个参数是ParamStr(1);

发送消息:

PostMessage(Target WIndow Handle,Message Type ID,Message content Ptr,LParam):使用PostMessage时,当第二个参数,即自定义的消息标识

SendMessage(Target WIndow Handle,Message Type ID,Message content Ptr,LParam):用于发送消息,但等待结果返回。

PostMessage在进程内部使用的时候,消息内容含有指针类型,可以被成功接收;如跨进程,则只能使用copydata类型, SendMessage方法进行消发送:

COPYDATASTRUCT data;

= MsgFlag; //ת·¢ÏûÏ¢±êʶ

= ();

//memcpy(,cMsg,strlen(cMsg));

= Msg.c_str();

SendMessage(pExeWnd,WM_COPYDATA,(WPARAM)Application->Handle,(LPARAM)&data);

控件可以使用.gif格式的图片?

刚开始用的时候,发现TImage控件可以支持.gif格式的图片;后来发现又不行了,觉得很奇怪。原来是因为把TeeChart7控件卸载了! 装了TeeChart后,TeeChart自己包含了,经过编译安装后就可以让Timage在设计时加载Gif格式的图片了(不过还没试能不能显示动画)

控件需要内容纵向居中?

开始一直以为TLabel控件不能纵向居中,后来才发现lauout!很多控件都有layout属性,如果是内容布局的问题,就尝试设置一下layout!

13. 图标资源都是gif或者jpg格式的,不能在TImageList中使用?

这要借助于Acdsee工具,打开Acdsee,选中所有你的gif或是jpg格式的图片,右键“工具”……“转换文件格式”……选中你bmp或者ico,然后就可以加在imagelist中使用了!

或者使用Snagit工具,在snagit中有个“BatchConvertImages”更方便、好用。

14. delete Component的时候出现异常?

有的时候会犯一个简单的错误,如:

TFrame* pFrame;

void __fastcall TMainForm::CreateFrame()

{

pFrame = new TFrame(Application);

}

void __fastcall TMainForm::~TMainForm()

{

if(pFrame)

delete pFrame;

}

在执行析构的时候可能会导致异常。主要是因为构造的时候不应使用Application作为Owner,应该使用MainForm作为其Owner。所以在构造Component的时候一定要注意把哪个对象作为Owner,因为Owner负责对象流的保存及资源释放等。

第二部分

1、BCB 编辑快捷键

左/右移 块代码

选中 块代码

1 CTRL+ SHIFT+ I 是整片往右移,

2 CTRL+ SHIFT+ U 是整片文字往左移

2、得到执行程序的当前路径

ExtractFileDir(Application->ExeName);

3、循环中响应其它操作

在循环内加入Application->ProcessMessage()这一句。

4、向外部提供dll函数标准windows格式

extern "C" __declspec(dllexport) __stdcall __int32 Fun(__int32 n32_i);

5、从外部dll输入函数标准windows格式

extern "C" __declspec(dllimport) __stdcall __int32 Fun(__int32 n32_i);

6、对DLL的调试

RUN/PARAMETERS 中填上调用该DLL的 *.exe。

7、使用*.chm帮助文件

ShellExecute(NULL,NULL,帮助文件的路径,NULL,NULL,SW_SHOWNORMAL);

8、PB_C数据类型转换表

PB_C数据类型转换表 MICROSOFT PB(16Bit) PB(32Bit)

Bool Boolean Boolean

Byte, Char Char Char

Char* Ref string Ref String

Colorref Uint Ulong

Double Double Double

Dword Uint Ulong

Float N/A N/A

Handle Uint Ulong

Hdc Uint Ulong

Hfile Uint Ulong

Hinstance Uint Ulong

Hwnd Uint Ulong

Int Int Int

Long Long Long

Lparam Uint Ulong

Lpbyte Ref Int Ref Long

Lpcwstr Ref Blob Ref Blob (Unicode use ToUnicode())

Lpcvoid Ref String Ref String

Lpdword Ref Uint Ref Ulong

Lpfiletime Ref Time Ref Time

Lpint Ref Int Ref Long

Lpstr,Lpcstr Ref String Ref String

Lpvoid Ref Structstruct_inst Ref Struct struct_inst

Lpword Ref Int Ref Ulong

Mcierror Long Long

Pbyte Ref Int[#] Ref Long[#]

Short Int Int

Structure Ref Struct struct_inst Ref Struct Struct_inst

Uint Uint Uint

Void** SUBROUTINE SUBROUTINE

Word Int Long

Wparam Uint Ulong

9、使用CB内存漏洞工具

选中Progect/Option->CodeGuard

支持环境/

10、MFC基本运行库目录

11、数据库连接测试(ADO)

建一文件,*.udl,内容空。

双击,按照提示操作。

12、编译器设置

Project|Options

Compiler(编译)

"Full debug"(完全调试模式)

"Code optimization"(代码优化)

"debugging"(调试)

"Debug information"(调试信息)

"Line number information"(行数信息)

"Disable inline expansions"(禁用内联扩展)

"Pascal"标签

"Optimization"优化

"debugging"(调试)

"Linker"(链接)

"Create debug information"(生成调试信息)

"Don’t generate state files"(不要生成状态文件)

"Use dynamic RTL"(使用动态RTL)

"Directories/Conditionals"(路径/条件)

"Packages"(程序包)

"Build with runtime packages"(带运行时程序包编译)

Tools|Debugger Options

Integrated debugging"(集成调试器)

Project|Build All(彻底的编译)

13、设置RTL

C builder 有几种运行时库,多线程静态链接库,单线程静态链接库 以及动态的,含有

VCL的,下面介绍多线程静态链接库,单线程静态链接库 是没有VCL的,VCL中自动 包含多线程。

Use RTL multi-threaded static library 使用多线程静态链接库

到*.bpr 中,按下面的修改即可。

-vi- -c"/>

Use RTL single-threaded static library 使用单线程静态链接库

到*.bpr 中,按下面的修改即可。

14、CODEGUARD调试器

库文件/

一、编译 (Project/Option-> CodeGuard)

二、运行(Tools/CodeGuard Configuration)

文件为*.CGI

日志文件中,文件名为 *.CGI。用 View/Debug Window/CodeGuard Log察看或者记事本。

10.4 创建和编辑包

创建一个包需要指定:

· 包的一个名字。

· 新包要求使用或链接的其他包的列表。

· 包编译时包含或绑定的单元文件的列表。包实质上是这些包含已编译.BPL功能的源代码单元的封装,包含(Contains)列表是想编译进包的定制组件的源代码单元放置的地方。一个包由C++源文件(.CPP)和扩展名为.BPK的工程选项文件定义。这些文件由包编辑器生成。

10.4.1 创建包

创建包的过程如下。参见10.4.4节可获得关于这些步骤的更多信息。

1) 选择File|New,然后选择Package图标并单击“OK”。

2) 生成的包被显示在包编辑器中。

3) 包编辑器为新包显示出一个Requires节点和一个Contains节点。

4) 要把一个单元加入包含列表,点击Addtopackage快速按钮。在Addunit页的Unitfilename编辑框输入.CPP文件名,或点击Browse浏览文件,然后单击“OK”。选择的单元出现在Contains节点的包编辑器下。通过重复这个步骤增加其他单元。

5) 把一个包加入要求列表,点击Addtopackage快速按钮。在Requires页的Unitfilename编辑框输入一个.BPI文件名,或点击Browse浏览文件,然后单击OK(这将增加语句USEPACKAGE(“”)到步骤1生成的CPP文件)。选择的单元出现在Requires节点的包编辑器下。通过重复这个步骤增加其他包。

6) 点击Options快速按钮,并决定想创建的包的种类。

· 创建仅用于设计时的包(不能在运行时使用的包),选择Designtimeonly单选按钮。(或增加-Gpd链接器开关到BPK文件中:LFLAGS=...-)

· 创建仅用于运行时的包(不能被安装的包),选择Runtimeonly单选按钮。(或增加-Gpr链接器开关到BPK文件中:LFLAGS=...-)

· 创建设计时和运行时可用的包,选择Designtimeandruntime单选按钮。

7) 在包编辑器,点击Compilepackage快速按钮编译包。

10.4.2 编辑现有的包

下面是打开和编辑一个现有的包的方法。

· 选择File|Open(或File|Reopen)并选择一个CPP或BPK文件。

· 选择Component|InstallPackages,从DesignPackages列表中选择一个包,并点击Edit按钮。

· 当包编辑器打开时,在Requires节点选择包,右击鼠标,并选择Open。编辑一个包的说明或设置使用选项时,选择包编辑器中的Options快速按钮并选择Description标签页。ProjectOptions对话框的左下角有一个Default复选框。当它被选择时单击OK,所做的选择存为新的包工程的缺省设置。要恢复原来的设置,删除或重命名文件。

10.4.3 包源文件和工程选项文件

包源文件带有.CPP扩展名。包工程选项文件使用XML格式创建,并带有.BPK(Borland包)扩展名。通过在包编辑器的Contains或Requires子句上右击鼠标,并选择EditOptionSource显示包的工程选项文件。

注意 C++Builder维护.BPK文件。通常不需要自行编辑它。应该使用ProjectOptions对话框的Packages标签页来修改。

一个名为MyPack的包的工程选择文件的一部分如下所示:

在这种情况下,将包括下列代码:

MyPack的包含列表包括3个单元:MyPack本身、Unit2和Unit3。MyPack的要求列表包括VCL50和VCLDBX50。将组件打包如果使用NewComponent向导创建组件(通过选择Component|NewComponent),C++Builder在所需位置插入PACKAGE宏。但若在旧版本的C++Builder中定制组件,必须自行将PACKAGE加入两个地方。

C++Builder中一个组件的头文件声明必须包括以class引导的预定义的宏PACKAGE:

class PACKAGE Mycomponent :...

并且在组件被定义的CPP文件中,必须在Register函数的声明中包括PACKAGE宏:

PACKAGE宏扩展为语句以便允许类可输出到结果BPL文件或从文件中引入。

10.4.4 理解包的结构

“包”包括下列部分:

· 包名。

· 要求列表。

· 包含列表。

1.命名包

包名必须在工程中是唯一的。如果把一个包命名为STATS,包编辑器分别生成一个源文件和工程选项文件;编译器生成一个可执行文件,一个二进制映象和(可选)一个静态库。要在应用程序中使用包,把STATS加入RuntimePackages编辑框(选择Project|Options,并点击Packages标签页后)。

2.要求列表

要求列表指定当前包使用的其他外部的包。在编译时,要求列表中列出的外部包自动链接到使用当前包和

外部包的某一单元的任何应用程序。如果当前包中包含的单元文件引用其他包的单元,那个包应在当前包的要求列表中出现,或者应将它增加到要求列表中。如果它被从要求列表中省略,编译器将把它引入到包的“隐式包含单元”。

注意 你创建的大多数包将需要VCL50。任何依赖VCL单元的包(包括SysUtils)必须列出VCL50,或另外一个要求VCL50的包要在其要求列表中列出VCL50包。

(1) 避免循环的包引用

包的要求列表中包含循环的引用。这意味着:

· 包不能在它的要求列表中引用自身。

· 一个引用链终止前必须没有重引用链中的任何包。如果包A要求包B,那么之后包B就不能要求包A;如果包A要求包B,并且包B要求包C,之后包C不能要求包A。

(2) 处理重复的包引用

在包的要求列表中,或在RuntimePackages编辑框中,对包的重复引用将被编译器忽略。但为了编程清晰及可读性,应该找到并删除重复的包引用。

ns列表

Contains列表指出被绑定到包的单元文件。如果编写自己的包,就应先将自己的源代码存入.CPP文件,然后将该文件加入到Contains列表当中。避免使用重复的源代码包不能出现在另一个包的Contains列表中。直接包含在Contains列表中的单元,或通过这些单元而间接包含进Contains列表中的单元,在编译的时候都会被绑定到包。

一个单元不能(直接或间接)的被同一个应用程序(包括C++Builder的IDE)所使用的一个以上的包同时包含。这意味着,如果你创建的包中包含VCL50中的一个单元,就不能把这个包装入IDE中。要使用已包含在其他包中的单元,应将该包加入到Requires列表中。

10.4.5 编译包

编译包可以通过IDE,也可以使用命令行编译。

要使用IDE编译包,

1) 选择File|Open,选择包的源文件或工程选项文件,然后点击Open。

2) 打开编辑器后,选择Project|Make或Project|Build。

可以直接在包的源代码中插入编译器描述符。详细信息,参阅下面的“与包相关的编译器描述符”。如果使用命令行编译,可以使用与包相关的几个连接器开关。更多信息,参阅下文的“使用命令行编译器和链接器”。

1. 与包相关的编译器描述符

表10-2列出了可插入包的源代码中的一些包特定的编译器描述符。

2.虚包装

#pragmapackage(smart_init,weak)描述符影响.OBJ文件在包的.BPI和.BPL文件中的存储方式。如

果单元文件中出现#pragmapackage(smart_init,weak)描述符,编译器会在可能的情况下忽略该程序单元,而在其他应用程序或包要求使用该单元时,为其生成一个不包含在包中的本地化副本。使用这个描述符编译的单元称为“虚包装”。

例如,假设已经创建了只包含一个单元UNIT1的包PACK。同时假设UNIT1没有使用其他单元,但调用了。当编译包时,如果加入文件,UNIT1就不会被包含进中;同时也不必将与PACK一起分发。不过,UNIT1仍然包含在文件中,如果它被其他的包或应用程序引用,它会从文件中被复制并直接编译到工程中。

现在假设添加第二个单元UNIT2到包PACK中,并假设UNIT2使用了UNIT1。这时,即使在编译包时在中加入#pragmapackage(smart_init,weak)描述符,编译器仍然会将UNIT1包含进中。但其他的包或应用程序引用UNIT1时,仍使用从文件中复制的、不包含在包中的本地化副本。注意包含#pragmapackage(smart_init,weak)描述符的单元文件不能拥有全局变量。

#pragmapackage(smart_init,weak)描述符是为需要将BPL分发给其他C++Builder程序员的开发者提供的一个高级选项。它能帮助开发者避免分发不常用的DLL,并消除基于相同外部库的包之间产生的冲突。

例如,C++Builder的PenWin单元引用。大多数的工程不会使用PenWin,同时大多数的计算机中也没有安装。因此,PenWin单元在VCL50中是虚包装。当编译一个使用包VCL50和PenWin单元的工程时,PenWin从中被复制并直接绑定到工程中;生成的可执行文件静态链接到。

如果PenWin不是虚包装,会产生两个问题。首先,VCL50本身会静态链接到,因此在没有安装的计算机上将不能加载它。其次,如果试图创建一个包含PenWin的包,将会产生一个编译错误,因为PenWin单元同时包含在VCL50和你的包中。因此,若没有虚包装,PenWin就不能包含在标准的VCL50中分发。

3.使用命令行编译器和链接器

当从命令行编译时,使用-Tpp链接器选项以确保将工程作为一个包编译。其他特定的包选项在表10-3中列出。

kage和DesignPackage复选框;如果既不用-Gpr,也不用-Gpd,编译的结果包在设计时和运行时都可工作。-D选项对应于同一页的Description编辑框。-Gl选项对应于ProjectOptions对话框的Linker页中的e复选框。

4.成功编译创建的包文件

要创建包,需使用扩展名为.BPK的工程选项文件和源(.CPP)文件来编译。编译器生成的文件名匹配源文件名;也就是,如果源文件名为,工程选项文件应包括:

在这种情况下,编译工程创建的包名为。表10-4列出了成功编译一个包而生成的文件。

当编译时,BPI、BPL和LIB文件生成后缺省放置在由Tools|EnvironmentOptions对话框的Library页中指定的目录。可以点击包编辑器的Options快速按钮显示ProjectOptions对话框,然后在Directories/Conditionals页中修改缺省设置。