费解的问题(高分求解)(100分)

D

dcba

Unregistered / Unconfirmed
GUEST, unregistred user!
谁都知道C++Builder的底层使用pas文件写的,所以很多VCL只是有一个头文件,实现部分在对应的pascal文件里
我们使用时只要include相应的头文件就可以使用了
我们也因此知道,c++buildershi可以直接编译pas文件的,所以有了pas文件,我问直接加入到工程里(project)
在运行,c++builder就能自动产生对应的hpp文件,我们只要inculde这个hpp文件,在任何地方就都可以使用pasli定义的类或函数了
我是这样做的,完全没问题
但是,如果使用这个pas文件,就必须先将pas文件加入到工程里,再include相应的hpp文件,才能使用
如果仅仅liclude相应的hpp文件,而我们在程序理由用到了某个pascal函数,就会产生link错误,说
[Linker Error] Unresolved external '......'
即:某函数未实现。(当然相对pas文件的hpp文件,dcu文件,obj文件一个也不少)
问题似乎是多此一举,只要我们把pas文件使用project菜单的add to project项,加入到工程里,就一点问题也没有了
但是我有一点搞不明白了,我们直接用vcl的控件时,c++builder不也是只include相应的hpp文件,并没有把什么对应的pas文件加入到工程里
为什么这样编译就不会出错呢?
请大家帮帮我,能不能只要includehpp文不用把pas文件也加入到工程里
 
hpp文件,系统已经将程序加到运行库中,所以不必自己再加入,就像安装第三方控件那样
,装好后就可以使用了!!
而你刚才说的是代码程序,首先得引用:(delphi中用uses/C++Builder中用#include)
然后将代码程序加到你的工程文件中来引用
这样编辑的时候就会找到相应的代码,否则就会出错!!!
建议将你所说的代码生成dll文件,随便在哪个程序环境中都能调用!!
 
但是我说的那段代码里含有类的定义,好像delphi的不能通过dll来输出累吧
如果可以我该怎样写?在c++builder该怎样调用呢?
 
把pas或dcu的路径加入工程文件的路径中如何?
 
已经试过了,没用
 
确实没用。
我看了project.dpr文件有以下内容:
<SPARELIBS value="vcl.lib rtl.lib vcldb.lib adortl.lib bdertl.lib vcldbx.lib ibxpress.lib
cds.lib bdecds.lib qrpt.lib teeui.lib teedb.lib tee.lib dss.lib teeqr.lib
visualdbclx.lib dsnapcrba.lib dsnapcon.lib bcbsmp.lib inetdbbde.lib
inetdbxpress.lib dbexpress.lib nmfast.lib bcbie.lib soaprtl.lib dclocx.lib
dbxcds.lib indy.lib bcb2kaxserver.lib"/>
<PACKAGES value="vcl.bpi rtl.bpi dbrtl.bpi adortl.bpi vcldb.bpi vclx.bpi bdertl.bpi
vcldbx.bpi ibxpress.bpi dsnap.bpi cds.bpi bdecds.bpi qrpt.bpi teeui.bpi
teedb.bpi tee.bpi dss.bpi teeqr.bpi visualclx.bpi visualdbclx.bpi
dsnapcrba.bpi dsnapcon.bpi bcbsmp.bpi vclie.bpi xmlrtl.bpi inet.bpi
inetdbbde.bpi inetdbxpress.bpi inetdb.bpi nmfast.bpi webdsnap.bpi
bcbie.bpi websnap.bpi soaprtl.bpi dclocx.bpi dbexpress.bpi dbxcds.bpi
indy.bpi bcb2kaxserver.bpi"/>
是不是有这段内容的原因?
 
比较了一下delphi和C++builder的
lib目录下的内容:
delphi下是dcu多多
c++builder是lib,bpi多多
 
dcba:
>>好像delphi的不能通过dll来输出累吧
怎么不可以呢?可以啊!
 
jianl:
你说的是什么意思?我不太明白?
小笨苯:
你说可以那我该怎样写pas的dll,在里面声明类?在c++builder该怎样调用这个dll的类呢?
 
dcba:
你这个问题涉及很多方面啊!:)
好,我就耐心地说说自己的看法。
C++Builder共享Delphi的VCL(VCL是用Object Pascal写的),这是由于这一点,很多人都瞧不起
它,认为它不是纯粹意义上的C++,是个大杂烩。其实,Delphi也不是完全用Object Pascal写
的。Delphi编译的程序执行效率(听好,我说的是执行效率,不是开发效率)这么高,说白了就是
运行速度这么快,是有原因的。原因就是Delphi和C++Builder都共享了Borland C++的编译器
的后端,所以,它们三个编译出的目标文件的格式是一致的,所以,运行效率也理所当然地很
相近。我说这话是有根据的,以前在某本书上看到过,现在一时想不起来了 :-( 好在,还可以
找到另一个证据,在http://www.delphibbs.com/delphibbs/dispq.asp?lid=62610这个帖子中,
aimingoo大侠的分析是最好的佐证。所以,我一直以来对C++Builder的看法还是很不错的!
言归正传,
其实,如果你细心一点的话,应该能发现,在你的工程中,将xxx.pas文件删除掉,将编译好的
xxx.obj加入进工程,一样能够编译通过。其实拓展开去,C++Builder使用的库文件是.lib,
(.lib可以看作是许多个.obj文件链接成的),这就是为什么在C++Builder中只写上#include <vcl.h>
或#include "xxx.hpp"就可以了,而没有加入.pas或.obj,就是因为都已经在.lib文件中了,
直接链接就可以了。
如果不信,你可以试一试,你将../Borland/CBuilder5/Source/Vcl下的*.pas全部删除或移到
搜索路径找不到的地方,你建立一个功程,编译运行一下,没有丝毫影响。进一步,你再将
../Borland/CBuilder5/Lib/Obj下的*.obj都删除,也没事。但*.hpp和*.lib文件删除可就
不行咯。
那么,怎样才能是改动的VCL代码生效呢?这一点BCB确实要比Delphi麻烦一些,拿修改标准
对话框显示信息的consts.pas为例:
1. 新建一工程,将汉化后的consts.pas拷贝到这个工程所在的目录下,加入工程中,也就是View-->
Project Manager-->选中该工程-->在右键弹出菜单中选择Add,将consts.pas加入进去,保存。
2. Project-->Options,在Compiler页中单击Release按钮,这是为了去掉编译后的目标代码中的调试
信息,然后,编译此工程。
3. 将../CBuilder5/Lib/Release/Vcl50.lib复制到工程所在的目录中,在命令行下执行
tlib Vcl50.lib -+consts.obj,然后将新的Vcl50.lib再复制回去,至此大功告成。
4. 你可以另新建一工程来试一下,不过,由于我们刚才修改的是../CBuilder5/Lib/Release/Vcl50.lib,
所以要静态编译才行,其实,还有一个Vcl50.lib,那就是../CBuilder5/Lib/Debug/Vcl50.lib,它们
之间的区别我就不多说了。
以上的修改过程进一步证明了C++Builder使用的库文件是.lib文件。
至此,问题解释清楚了。
>>小笨苯:
>>你说可以那我该怎样写pas的dll,在里面声明类?在c++builder该怎样调用这个dll的类呢?
哎呀!是哪个家伙节外生枝,说什么在dll中声明类,和这个题目有什么关系? :)
好,为什么说明“可以”,我就从书上抄一段代码吧。5~~~~我以后再也不多嘴了 :) 嘿嘿
==================================================================================
为了能使用DLL中的类及其成员,必须在DLL中专门输出一些例程作为类及其成员的外壳,外部
程序调用的仍然是这些输出的例程,而这些例程专门操作于类及其成员,从而达到在外部访问
DLL中类和其成员的目的。
{ DLL工程文件 }
Library MyDLL;
uses
Unit1 in 'Unit1.pas';
Unit2 in 'Unit2.pas';
end.

{ Unit1单元文件 }
Unit Unit1;
Interface
type { 声明一个类 }
TMyClass = Class
private
Numbar: Integer;
protected
Procedure HowToAdd(I: Integer);
virtual;
{ 加法操作 }
public
constructor Create(InitalValue: Integer);
Property Add: Integer read Number write HowToAdd;
end;

var
MyClass: TMyClass;

Implementation
constructor TMyClass.Create(InitialValue: Integer);
begin
Number := InitialValue;
end;

procedure TMyClass.HowToAdd(I: Integer);
begin
Number := Number + I;
end;

{ Unit2单元文件 }
Unit Unit2;
Interface
uses
Unit1;
{外壳函数}
function CreateMyClass(InitialValue: Integer):TMyClass;
stdcall;
{ 构造 }
procedure FreeMyClass(MyInstance: TMyClass);
stdcall;
{ 析构 }
function MyAdd(MyInstance: TMyClass;
I: Integer):Integer;
stdcall;
exports
CreateMyClass, FreeMyClass, MyAdd;

Implementation
function CreateMyClass(InitialValue: Integer): TMyclass;
begin
Result := TMyClass.Create(InitialValue);
end;

procedure FreeMyClass(Myinstance: TMyClass);
begin
MyInstance.Free;
end;

function MyAdd(MyInstance: TMyClass;
I: Integer):Integer;
begin
MyInstance.Add := I;
Result := MyInstance.Add;
end;
==================================================================================
 
小笨苯:
你的第一点我完全同意
但是第二点你可能没理解我的意思
我的意思是dll输出类就像一个单元文件一样,不是输出类的实例,而是输出类的定义和声明
如果找你那样,在c++builder里引用这个dll,那我我们这样调用呢?
像这样么?
TMyclass *myclass;
myclass =CreateMyClass(5);
......
好,我们一编译,c++builder就会告诉我们:TMyclass未定义,这是显然的,因为我们这是从dll里得到了一个可以生成这个类的实例的函数
并没有得到有关这个类的定义的任何信息,到头来还是要在工程里加入这个类的定义的pas文件。
 
哦,是这样啊。我仅仅是从书上抄下来的,对此我理解不深。
我帮你查到了几个帖子,你看看吧。
http://www.delphibbs.com/delphibbs/dispq.asp?LID=109707
http://www.delphibbs.com/delphibbs/dispq.asp?LID=388174
http://www.delphibbs.com/delphibbs/dispq.asp?LID=508775
 
谢谢各位讨论
 
多人接受答案了。
 
顶部