Welcome

首页 / 软件开发 / VFP / vfp中应用com技术

vfp中应用com技术2007-05-09说在前面

COM这个单词大家听得不少了,它到底是什么,它到底有没有实用价值。如果它对我们有用,那么在Visual FoxPro怎样编写COM组件。笔者将站在Visual FoxPro开发人员的立场上,与大家一起探讨以上问题,希望对您有所帮助。可能这是一篇国内很难看到的有关Visual FoxPro与COM的文章,所以肤浅、不当之处难以避免,我就尽力而为了!

两年多前,我为了一个极其复杂的报表而头疼时,偶然想到了Word这一伟大的书写工具——用 Word还有什么写不出的!于是我就使用DDE控制Word,这实在是一场噩梦,无法实现复杂的功能,因为我不知道与Word通讯的语法。正当我犯愁之时,天赐良机,我参加了美国的一个工业ERP的培训,那套ERP实际上就是一组用VC++写的控制逻辑,当时范例中使用VB调用它们。老外告诉我,用Delphi、PB都可以调用……它们能行,那么Visual FoxPro应该也行,尝试之下,果然不出所料。我是学VBA出身的(水平很差),所以我知道Word其实一套组件,那么Visual FoxPro与Word的通讯就不成问题了……很快的我写出了一套很棒的专用报表程序,我也深深的被COM技术所吸引,我知道一个新时代来到了!

我的第一次COM经历就是这样:Visual FoxPro充当COM客户端程序,由Word提供相关服务。这种由Visual FoxPro充当COM的客户机,控制其他的COM组件,在这两年间我做过不少应用,如Excel、Power Point、WHS(Windows 系统提供的脚本组件)、ADO……有时候我甚至会用VB写一个组件供Visual FoxPro调用,这种应用常用于API的调用,Visual FoxPro不支持结构类型的变量,这样调用很多API函数时就发生了极大的困难,用VB把相关的API函数重新封装,就可以解决问题了。现在我遇到Visual FoxPro不能解决的问题时,总是考虑一下操作系统是不是提供相应的COM组件或是有没有第三方的组件可以被调用……

COM为Visual FoxPro 带来了什么

Visual FoxPro还可以编写COM服务器,这种组件可以在其他支持COM的语言里调用,实现他们难以实现的功能,当然多数是数据库方面的问题。我使用Visual FoxPro的编写COM组件也是因为一个工业控制项目,当时工业数据被采集到PC机的客户端时,客户希望保存数据到数据库,并提供相应的查询、报表功能。这种要求不过分,但对于工业控制软件来讲却是有难度的(软件分工不同、开发人员各有专长)。

我知道在过去,对于同类的问题基本上有两种方法:一种就是用C访问底层的Fox函数库,另一种就是外部执行Fox程序。前一种对开发人员的要求很高,并且很难实现丰富多彩的功能,例如要同时访问SQL Server数据库与DBC怎么办,问题多多!后一种效果更是不好,稳定性太差,我看到过不少这样的应用,给我的感觉就是老是出错!

说到这里,大家也许明白了COM实际上解决了应用程序的整合,您可以在客户不知不觉中,使用了好多其他语言的优势,很简单的完成任务。从界面效果来说,别人看到的还是程序的主界面,不会有其他窗口跳出来影响画面;从程序的控制来说更有好处,有过外部调用exe文件的人都知道,很难控制它的运行进程、知道它的运行结果,就像“断了线的风筝”——只能由它去了!现在有了COM组件,您可以完全摆脱这个局面了,调用它的方法、设定它的属性、响应它的事件,于是它就很听话了,就像客户程序自身的一部分。COM的又一个好处就是扩展了Visual FoxPro的应用范围,现在我们可以简单的把Fox程序分布到各种场合(商业、工业、互联网,只要有数据库处理事务的地方),与其它系统无缝的集成在一起,我做的那个工业应用就是这样。

COM技术的还可以为软件开发带来新的思路,不同语言的程序员可以在一起工作,不同模块可以被做成独立的组件,这样更容易维护,升级软件时就只要替换部分的组件。这里我想到了国内现在比较流行的软件开发业务——为财务软件做接口,很多客户希望自己的MIS系统与财务软件连在一起,数据共享。现在的做法是“硬连接数据库,直接操作数据”,这样很不好——财务数据得不到保全、系统的二次开发变得只有财务软件公司能做,因为数据库的结构、业务的记录只有他们清楚。如果财务软件包是一套组件,财务软件只是这一组件的实现,那么这种二次开发就变得安全、容易了。(关于财务软件的评论只是从COM技术的角度出发,不考虑其他因素)

COM的缺陷

COM这么好,但并非没有缺陷。我认为最主要的是版本问题,就是人们常说的“Dll Hell”,常用ActiveX控件的人对这种问题一定是有体验的,COM也一样。比如,控制Word的代码就要很小心Word的版本,甚至是语言种类,不然的话保不准程序就会出错……COM的另外一个缺点就是COM组件的运行效率,主要是在被建立实体对象的时候显得有点慢,这个问题我们可以通过“早期绑定”、连接池来解决,即使不能很好的改善,我认为这个问题也是无关痛痒的,毕竟COM的好处太大了……

Visual FoxPro 与三层构架

按正常的逻辑,写COM必定要写三层应用,实际上要把Visual FoxPro配置在三层结构的中间层编写COM是唯一的方法,但是各位务必明白COM组件并非只能用于三层构架,上文我提到的各种应用基本上不属于三层应用的范畴。

三层构架把整个软件系统分为用户界面、商业逻辑、数据存储这三个层次。三层构架的特色在于用户界面不直接与数据库打交道,所有客户请求都必须通过中间层组件更新到数据库中。这样就有两大好处:头一个好处就是商业逻辑代码的统一维护,再一条好处就是解决大量用户同时访问数据库的问题。

把所有的商业逻辑都写在中间层里,这样当商业逻辑变化时就可以之更新中间层的程序,对客户界面不产生影响。这是一种理想,笔者认为用户界面设计与数据关联性很大,大家在设计单层结构、双层结构时应该是有这个体会的:怎样的数据源就必须有怎样的界面与之相配;三层应用中用户界面与中间层打交道,同样界面就必须跟着中间层走,如果中间层的商业逻辑明显变化用户界面是不可能不变的。于是代码的统一维护并没有带来各类用户界面相对稳定,这样代码的统一维护只是一个诱人的果子,吃了也不见得甜。

三层结构最诱人的地方在于解决大量用户同时访问数据库的问题。我们知道当前最好的Oracle 数据库可同时支持500个连接,不幸的是实践证明当活动连接达到这个数目时,数据库服务器往往是承担不起的。500个请求同时访问数据库,这在Web领域、在大型企业都是很细松平常的事情。解决之道,无非是减轻某一时刻数据库服务器的压力,在进一步说就是分配工作到不同的数据库服务器、让客户请求排队等候,别一窝蜂的挤到数据库那里,这就是动态负载平衡和排队机制,那么谁来完成这项工作呢?用户界面是理所当然不可能的,数据库已经很吃力了当然也不能再麻烦它了,只有中间层可以胜任。现在的MTS、COM+就是这样的工具,Visual FoxPro的组件支持MTS、COM+,于是将我们的编写的组件放在MTS、COM+中运行,我们就享用到了MTS、COM+的特性,一切不需要我们操心。

微软为什么强调Visual FoxPro 在Web服务器的应用

Web服务组件是最典型的中间层应用,它的特色是用户界面通过组件与服务器的交互的次数较少,例如在客户端我们查询一批数据,中间层得到请求检索数据库返回光标并即时产生HTML文档返回给客户,完成后就可以释放组件。同样这个行为,在单层、两层应用中可能就很复杂,可能我们需要对查询结果进行维护,再更新到服务器,再刷新光标……Web应用下的数据库强调是的查询——根据复杂的逻辑产生查询结果,而对数据的维护不太看中。(这就是为什么Web专用数据库MySQL不支持事务处理、存储过程的原因吧……)

对于这种应用,作为专业的数据库开发程序,Visual FoxPro可以说是手到擒来、不在话下的,开发起来也没有什么难度,所以微软强调Visual FoxPro在Web上的应用是很有道理的。

还有一种三层应用就是企业级应用,它的特点就是利用三层结构实现两层或单层结构下的应用程序,同时利用三层构架解决商业代码的维护和大量数据访问的问题。可以想象这种企业级的应用对开发组件的要求是很高,在国外往往有专业的公司开发这类组件,用户只需根据实际应用做二次开发。据我所知,Delphi的第三方产品中就有这样的东西,价格异常昂贵,比Delphi还贵很多……Visual FoxPro同样也能开发这样的组件,只是难度问题……处于商业角度,微软不提Visual FoxPro在这方面的应用是有道理的,毕竟与其它工具相比我们没有什么优势……

Visual FoxPro的COM基础

说句实话,目前用COM的人很多,写COM组件的人很少。我个人只经历过两次实际应用,一次上文已经提过了,再一次是我的一个朋友做的:Delphi做的界面,Visual FoxPro开发的数据处理程序(很棒的应用,以后有机会请他谈谈)。由于工作的关系,我不使用Fox做开发了,以后这种开发机会可能更少,撰写此文也是希望广大狐友发挥各自的聪明才智,发挥Visual FoxPro的至强威力。愿做抛砖引玉人!

Visual FoxPro能够编写的组件种类

COM是Component Object Model的简写,这种技术是建立在面向对象的程序设计思想上的,天然的满足多层分布是应用。在Visual FoxPro中我们可以编写两种类型的COM服务器(COM Server):进程外组件(out-of-process)和进程内组件(in-process)。进程外组件以Exe作为后缀名,进程内组件以Dll作为后缀名,其中进程内组件又分为单线程(single-threaded)组件和多线程(multi-threaded)组件。到底把我们编写的程序做成这样的组件,完全由Visual FoxPro来完成编译工作,如下图:

图1:连编选项对话框

进程内组件与客户程序运行在同一个内存空间中,这样数据交流的速度就比较快了,但是如果这个组件崩溃,就会影响客户程序。由于进程内组件与客户程序在同一个内存空间运行,这样如果要替换更新组件,就必须卸下整个运用程序,这对普通的应用是无所谓的,但是对于web应用却是很有影响,更换组件就必须荡下整个web服务器(大家是不是知道VFP黄页:http://www.universalthread.com就时常发布通告,用几个小时更新网站);进程外组件与客户程序运行在不同的内存空间,这样数据交换的速度就慢了,但两者互不干扰,这就有点像Visual FoxPro调用Word一样(Word是一个进程外COM组件),如果Word出错,Visual FoxPro作为客户程序并不会受什么影响,顶多是触发一个错误。

组件与组件用户界面

进程内组件不能带界面元素,进程外组件可以带有界面元素,这就是Word为什么看上去像一个普通的exe,但却是一个COM组件的原因了。这里我有一点想法与大家交流,既使是进程外组件,它可以带界面,但在开发时我们要尽力减少模式表单,因为COM组件往往处于无人职守状态,不时跳出模式表单让用户确认是不现实的,如果模式表单不被用户回应,COM程序进程将被堵塞,以后的客户机的请求就无法响应了。Visual FoxPro规定,开发的程序被编译成进程内组件后,将忽略界面元素,同时新的Vfp6t.dll运行时刻库(只有进程内组件可以使用这个运行库),许多用户界面命令和函数已被删除,其中包括旧的 FoxPro 2.x READ 和 @…Get/Say 支持。另外,存在于Vfp6r.dll 运行时刻中的某些设计器,例如表设计器和报表设计器已被删除。Vfp6t.dll 运行时刻仍支持表单等可视类。由此可见设计进程内调用组件时,“无人看守状态”的问题不是很突出的,问题出在进程外组件。如果我们能确定用户可以随时响应模式表单(就像Word那样)的话,这个问题也就不成其为问题了,但是组件确实时运行在“无人看守状态”这个问题就不得不被考虑,Visual FoxPro提供了sys(2335)的函数来处理进程外组件的“无人看守状态”问题,由于本文着重讨论进程内组件的开发,这里不再多说了。

我们的第一个COM组件

在98年,Visual FoxPro 6推出时,当时Visual FoxPro只能开发进程外组件与单线程的进程内组件,考虑到当时进程内组件运行效果、运行稳定性都不很好,国外的Fox专家提醒我们:不要使用Visual FoxPro开发进程内组件。随着Visual FoxPro 6的第一个服务包Visual Studio SP3 的推出,Visual FoxPro 具备了多线程组件的开发能力,前文提到的轻巧、专门支持进程内组件的运行时刻Vfp6t.dll也被推出,Visual FoxPro 在COM组件的编译上趋向于多线程的进程内组件,当然每一种类型的组件都有各自的特点,在不同的场合各有其存在的合理性。本文假设用户使用Visual FoxPro 6的SP3以上版本,把范例代码编译成为多线程的进程内组件,这样的话不打补丁的Visual FoxPro是不能适应本文的,当然如果你有Visual FoxPro 7,那么您会明显感到无论是开发效率还是运行效率,都比6.0版本要好得多,即使是Beta 版本。

现在就来看看我们的第一个COM组件吧,这是一个十分简单的程序,它的功能就是向表里面加入一条记录,如果添加失败就产生出提示。也许您不满意这个组建的微弱功能,那么您就发挥自己的聪明才智吧,这里我们只是表达一个意思……

数据库Demo.dbc中有两个表,分别是Item.dbf和Sys_id.dbf,Item.dbf的结构如下:

字段名称字段类型宽度默认值字段有效性规则
IdI4Getid(1)
First_nameC6 ! Empty(First_name)
Last_nameC6 ! Empty(Last_name)
SexC2 Inlist(sex,"男","女")
BirthdayD8 Year(Birthday)<1980
DescM4
其中字段ID的默认值数据库存储过程Getid()的返回值,Getid()可以从Sys_id表中返回唯一的整型数据,具体如下:

procedure getid
lpara lTableid
local lCurrid[1]
update sys_id set curr_id=curr_id+1 where tableid=lTableid
select curr_id from sys_id where tableid=lTableid into array lCurrid
if select("sys_id")>0
use in sys_id
endif
return lCurrid[1]
endproc

这段代码很简单,唯一值得一提的是:及时关闭数据表。笔者个人以为,这应该是COM编程的一个特点——减少数据库与组件的连接时间。虽然这里我们的应用不是三层构架,但我还是希望把这个精神传递给大家。也许有人有疑问:多次连接会不会很耗费时间或是系统资源?这个问题是很复杂的,总体来说三层应用中优化效率的关键是:数据库服务器最好不要保存每个连接的状态,要做到这个就必须保证连接是瞬时的。然而连接的瞬时往往会造成连接的频率增加,对于大型服务器型数据库(oracle、SQL Server等)连接到它们往往又是很慢的,甚至连接的速度要以分钟计算,这样看来“瞬时连接”好像是不足取,于是人们提出了种种优化方案(如连接池等)以解决连速度问题。不过,对于dbc这样的文件型数据库来说,每次连接数据库(打开表)的速度很快,特别是使用Fox本身的数据引擎,所以是否及时关闭连接(表)在这里显得不很重要,不过当我们编写连接到大型数据库组建的时候,特别是用于三层体系的组件,这个问题千万要好好考虑,因为这是优化系统效率的关键!

接着就是我们的组件代码了,COM的编写必须是基于OOP(面向对象)的,行为COM组件本身就是一个对象。在Visual FoxPro中我们建立COM组件的方法就是定义一个OLEPUBLIC类,我们可以通过类设计器建立它,也可以通过prg文件建立它,不过随着Visual FoxPro 7的推出,后一种可能更为流行,原因是:支持私有工作期的session类(表单类也支持私有工作期,但资源消耗较大)只能通过prg定义;通过prg定义的类可以在Visual Studio.NET中直接调试,而其他的不行;由于Visual FoxPro设计的COM组件基本不带界面,所以类设计器的“可视化”无优势可言,在加上Visual FoxPro 7的高效开发环境,prg的简洁更见优势。

废话就不多说了,下面就是我们COM组件的完整代码:

#define CL chr(13)+chr(10)

define class vfpcomtest as session olepublic

Datasession=2

PROCEDURE setpath
LPARAMETERS cNewVal
IF RIGHT(cNewVal,1)<>""
cNewVal=cNewVal+""
ENDIF
OPEN DATABASE cNewVal+"demo.dbc" SHARED
ENDPROC

procedure destroy
IF DBUSED("demo")
CLOSE DATABASES
ENDIF

endproc

function add_item
lpara cFirst_Name,cLast_Name,cSex,dBirthday,mDesc
local dBirthday
if pcount()<5
error "添加操作时缺少参数"
return
endif
insert into item(first_name,last_name,sex,birthday,desc) value(m.cFirst_Name,m.cLast_Name,m.cSex,m.dBirthday,mDesc)
if select("item")>0
use in item
endif
endfu


procedure error(lError,lMethod,lLine)
local cText

if select("item")>0
use in item
endif

cText=;
"出错时间:"+transform(datetime())+CL+;
"错误代码:"+str(lError,4)+CL+;
"错误提示:"+message()+CL+;
"错误方法:"+lMethod+CL+;
"错误行号:"+transform(lLine)+CL+CL

strtofile(cText,"c:com.txt",.t.)
comreturnerror("Visual FoxPro COM 服务器",cText)
endproc
enddefine

1.我们定义了一个OLEPUBLIC类,它的名称是:VFPCOMTEST,它的基类是:SESSION类。SESSION类是Visual FoxPro 6 SP3以后才提供的,它具有占用资源小、支持私有工作期的特色,于是成为定义COM组件(特别是进程内组件,如果希望开发带界面的进程外组件就不能用它了)的最佳选择;我们加入了OLEPUBLIC关键字,这是编译成为COM组件的关键,切不可省略。在代码中我们使用以下语句完成这些工作。

define class vfpcomtest as session olepublic
enddefine

2.接着我们设置类的DataSession属性的默认值为:2,表示使用私有工作期,如果设定它的值为1表示使用默认工作期,这与表单的DataSession属性是一样的。

3.由于我们使用DBC数据库演示,所以数据库所处的路径对系统来说就很重要。这里我们提供了一个SetPath方法来定位并打开数据库:

PROCEDURE setpath
LPARAMETERS cNewVal
IF RIGHT(cNewVal,1)<>""
cNewVal=cNewVal+""
ENDIF
OPEN DATABASE cNewVal+"demo.dbc" SHARED
ENDPROC

4.这个类的关键方法程序是ADD_ITEM,它的代码如下:

function add_item
lpara cFirst_Name,cLast_Name,cSex,dBirthday,mDesc
local dBirthday
if pcount()<5
error "添加操作时缺少参数"
return
endif
insert into item(first_name,last_name,sex,birthday,desc) value(m.cFirst_Name,m.cLast_Name,m.cSex,m.dBirthday,mDesc)
if select("item")>0
use in item
endif
endfu

很简单吧,有一点要说的就是当参数少于5个时,我们使用Error命令产生一个用户自定义错误,Error命令时Visual FoxPro 6中的新增加命令,更详细的使用大家可以参看有关资料。这里还有一点想说的是,在Visual FoxPro 的类定一种中过程(procedure)与函数(function)是一样的,选用谁可以根据您的喜好。

5.当COM组件被释放时我们必须做一些清理工作,这些代码可以写在Destroy事件中;如果想在COM组件被建立时作一些初始化工作,可以把代码写在Init事件中。

6.接着就是我们这个COM组件最关键的一段代码:出错陷阱。COM组件总是在后台运行的,甚至有时是在无人看守状态运行的,所以稳健的错误陷阱程序是十分重要的。COM组件可以很简单,就像我们的例子,但必须稳健,编写COM程序,要写的第一个方法程序就是Error方法。Error方法是Session类的自带的方法程序,当产生错误时被触发。我们的代码如下:

procedure error(lError,lMethod,lLine)
local cText

if select("item")>0
use in item
endif

cText=;
"出错时间:"+transform(datetime())+CL+;
"错误代码:"+str(lError,4)+CL+;
"错误提示:"+message()+CL+;
"错误方法:"+lMethod+CL+;
"错误行号:"+transform(lLine)+CL+CL

strtofile(cText,"c:com.txt",.t.)
comreturnerror("Visual FoxPro COM 服务器",cText)
endproc

在这段代码中,我们首先整理战场——关闭数据表;接着我们产生一个字符串,记录下有关本次出错的信息,并将它写入文本文件中,作为历史纪录登记在案;最后我们使用了COMRETURNERROR()函数告诉客户程序,COM组件出错了!

下面我们就讨论一下COM组件的错误处理。

情况一:如果我们在组件中不写任何错误陷阱程序(如类的ERROR方法或是ON ERROR例程),大家必须明白这是极其愚蠢的做法,除非您能保证程序不出错。在这种情况下如果COM组件发生错误,客户程序是可以得到组件出错的信息的。这里的问题在于COM组件出错后是不是可以接着正常运行,恐怕必须要处理一下残局才可以重新投入战斗,这个问题在普通编程中,大家应该已经明白了。

情况二:COM组件中拥有错误陷阱,但没有使用COMRETURNERROR()函数告诉客户程序COM组件发生了错误。这时一旦错误发生,就会触发有关错误处理程序,错误处理程序会调整COM的运行状态,使它恢复正常,这与普通程序的想法、做法是一致的。当错误被处理后,COM组件恢复到正常状态,于是COM组件的客户程序就不会知道COM组件曾经发生过错误。这不是一种理想的状况,它降低了COM组件与客户程序的互动性。就拿我们的例程来说如果添加记录时发生错误,记录明明没有被加入数据表格,但由于客户程序得不到COM组件出错消息,它很可能会提示用户记录添加成功,这样就有误会了。

情况三:当我们分析了前面两种情况,我们就会理解COMRETURNERROR()函数的意义:先用错误处理陷阱容错,再用COMRETURNERROR()告诉客户程序COM组件发生了错误,这是两全其美之举。以下是关于COMRETURNERROR()的用法:

COMRETURNERROR(cServerName,cErrorMessage)

1.cServerName:COM 服务程序的名称,可任意指定。

2.cErrorMesage:错误信息文本,一般可以用Message()函数返回值填入。如果要得到更详细的信息,可以向本例中那样,先组织文本。

COM组件是Windows系统下的一种规范,它的出错信息其实是一个结构类型的变量,要让客户程序知道COM组件出错了,只要把这个结构填写即可。Visual FoxPro为我们省了麻烦,我们可以使用COMRETURUERROR()轻易的完成这一工作……

对于客户程序得到的组件出错信息实际只是一个事后的通知,如果在COM中我们已经处理了错误(正常情况是这样),客户程序就不必担心COM的运行状态,仍然可以继续使用这个组件。所以总结一下整个错误处理过程:COM组件必须自己处理自己发生的错误,错误处理完毕再用COMRETURNERROR()函数向客户程序返回出错信息。

编译我们的COM组件

一般来说,在编译前我们应该设定项目的有关信息,不过这里Visual FoxPro好像有个小小的不足——通过prg文件建立的OLEPUBLIC类,在初次连遍前项目信息对话框的服务程序页是不可用的。所以在“正式”连编前,您可以任意编译以下,这样就可以设置COM组件的属性了。

项目信息对话框的服务程序页

这里有两个属性很重要:实例和项目名。

实例

实例有三种选项:不可创建、单独使用、多重使用。

1.如果我们选择“不可创建”,那么即使把代码编译成为COM组件(进程内或是进程外),这个组件都不能作为COM对象被使用,而只能作为普通的Visual FoxPro类在Visual FoxPro内部使用;

2.单独使用与多重使用的区别在于,在系统中组件建立多少个实例应付客户请求。这个选项只对进程外组件或单线程的进程内组件有效。这里我们用进程外组件来说明问题:我们把我们的代码它编译成单独使用的进程外组件,在Visual FoxPro中调用它:

ox1=ctreateobject("vfpcomtest.vfpcomtest")
ox2=ctreateobject("vfpcomtest.vfpcomtest")

这时打开Window 2000的任务管理器,您会看到:

单独使用时,COM组件对产生多个实例。

我们把我们的代码它编译成多重使用的进程外组件,在Visual FoxPro中调用它:

ox1=ctreateobject("vfpcomtest.vfpcomtest")
ox2=ctreateobject("vfpcomtest.vfpcomtest")

这时打开Window 2000的任务管理器,您会看到:

多重使用时,COM组件对产生一个实例。

3.对于进程内的多线程组件来说,总是创建“多重使用”的组件,“单独使用”总是被忽略的。

项目名

这个设定牵涉到怎样调用COM组件,默认情况下设这样的:项目名+.+OLEPUBLIC的类名,这里就是:Vfpcomtest.Vfpcomtest。调用它时就是:

ox1=ctreateobject("vfpcomtest.vfpcomtest")

正式联编

像图中这样设定(重新生成组件ID选中也可),按确定就行了。这里可能会出现的错误就是:不能更新文件。我们在开发组件时往往反复调试、反复联编,这样如果逐渐正处于调用状态的话,联编就会出错,这时只要释放组件即可,在Visual FoxPro中如下:

rele ox
*假设先前执行过:ox=createobject("vfpcomtest.vfpcomtest")

应用我们的COM组件

在Visual FoxPro中应用

ox=CREATEOBJECT("vfpcomtest.vfpcomtest")&&建立COM对象
ox.setpath ("D:First_com")&&设定数据库的位置
ox.add_item("f1","l1","1男",{^1975-12-26},"测试")&&添加一条记录
rele ox&&释放组件

在Delphi中应用

我已经写一个简单的测试程序,大家可以看看。