文档库 最新最全的文档下载
当前位置:文档库 › VFP使用技巧

VFP使用技巧

VFP编程技巧
在VFP中如何历遍所有文件夹和文件

在VFP中,能象一些杀毒软件那样,找遍磁盘的所有文件夹和文件吗?
答案是肯定的,而且很简单:
*利用VFP的Create Cursor -SQL命令建立有5个字段的临时库
*结合前面提到的ADIR()函数便可完成。
下面是具体代码:

dqml='C:' &&需扫描的盘符
use
Create Cursor mylsdbf (wjmc c(120),wjcd n(10),wjrq d,wjshj c(10),wjsx c(6))
xGS=1
xCD=0
append BLANK
REPL wjmc WITH dqml
do while !eof()
nRecn=Recn()
dqml=allt(wjmc)+'\'
x=adir(Mysz,(dqml+'*.*'),'rashd')
if x<>0
for I=3 to x
Mysz(I,1)=dqml+Mysz(I,1)
xGS=xGS+1
xCD=xCD+Mysz(I,2)
endf
append from array Mysz for allt(wjmc)<>'.' AND allt(wjmc)<>'..' and 'D'$wjsx
endi
go nRecn
skip
endd
use

这里有以上例子的源代码实例下载



在VFP如何利用低级文件操作函数读取*.INI文件

VFP为我们提供了16个低级文件操作函数,充分利用这些函数,几乎可对所有文件进行本来只有汇编、C等语言才能进行的操作。
*.INI文件其实也是ASCII码文本文件,只不过有其特定的规律而已。
下面以读取system.INI中[boot.description]关键字里的mouse.drv标识符中的值为例来说明:

nPath_ls=fullpath('https://www.wendangku.net/doc/772019459.html,',2)
nPath=strtran(nPath_ls,'https://www.wendangku.net/doc/772019459.html,','system\') &&取得Windows\system\的目录名
dkwjm=nPath+'system.ini' &&需打开文件的路径和文件名
Fp=Foren(dkwjm,0) &&以只读(默认方式0可以不用)打开文件
if Fp<0
 wait wind '打不开您指定的文件'
 retu
endi
do while !Feof(Fp)
wjnr=Fgets(Fp) &&从打开的文件中读取一行
if atc('mouse.drv',wjnr)=1
exit
endi
endd
=Fclose(Fp) &&关闭打开的文件
x=atc('=',wjnr)
nQdz=iif(x>1,suns(wjnr,x+1),'') &&nQdz='标准鼠标'字符串
retu

我只不过是说明如何运用VFP提供的这些函数,至于如何建立和改写文件,为何用Fgets()来读取数据而不用Fread()来读取数据等,可以查阅VFP帮助。VFP3.0的帮助是一本很好的中文教科书。


如何改变文件的最后修改日期和时间

在WINDOW 9X下我们没办法来改变一个文件的日期和时间,那在VFP能办到吗?
在WINDOW 9X下文件的日期和时间有创建、修改和访问三种,在通常情况下我们所说的文件日期和时间指的是修改这一项。
那在VFP下如何改文件日期和时间呢:
Fp=Foren('需打开的文件',2) &&以读写方式打开文件
if Fp<0
wait wind '打不开您指定的文件'
retu
endi
wjnr=Fr

ead(fp,1) &&从打开的文件头中读一个字节到wjnr
=Fseek(Fp,0,0) &&将文件指针移到文件头(回到原来的位置)
=Fwrite(Fp,wjnr,1) &&向打开的文件头中写入一个字节
=Fclose(Fp) &&关闭打开的文件

即把读取的那个字节原封不动的再写入文件,从而达到了将当前系统
的日期和时间来改写文件的日期和时间目的。
如何在程序的开始检测权限和根据权限操作

 在一个程序的开始部分,如何根据不同的口令字来区分不同的登权限,各自的
口令字和权限设置又如何加以保密,以防止非法查看和修改?
我们辛辛苦苦编制的程序又如何根据每台机器的硬件来加以判断用户的合法
与非法,以防止非法拷贝?
针对以上问题,我编制了一个简单的程序实例供有兴趣的朋友参考。

该实例并非十分完美,也很简单,意在提供一种思路,大家可根据自己的情
况,加以完善。
实例共有一个数据表和四个模块组成,分别是:
一、KLK.DAT 
这是经过vfpjmdbf.vcx加密后的数据表,解密后的表结构如下:
========================================================
表文件名: KLK.DBF
数据记录数: 3
最近更新的时间: 10/17/1999
代码页: 936
字段 字段名 中文含义 类型 宽度 小数位 索引 排序
 1 BH 编号 字符型 2
 2 XM 姓名 字符型 8
 3 PASSKL 口令字 字符型 12
 4 QX 权限 数值型 1
 5 VARJB 硬盘卷标 数值型 12
** 总计 ** 36
=========================================================

二、Main.prg
系统初始化主程序,大家在调试时务必首先运行它,否则后面的模块无法运行。
它很简单:
set stat off
set scor off
set date ansi
set century on
set hours to 24
set escape off
set dele on
set safe off
SET STATUS BAR OFF
SET SYSMENU TO
SET SYSMENU AUTOMATIC on
shutdown quit
debug0=.t. &&为后面的模块提供检测菜单是否运行的条件
Dqml=sys(5)+sys(2003)+'\' &&取当前目录,调试时请您改为本程序所在目录
do (Dqml+'菜单1.mpr') &&打开菜单文件
do form (Dqml+'pass') &&打开效验口令字表单
read even
on shutdown
rele debug0
set sysmenu on
set sysmenu to defa
on error

三、pass.scx 表单。
功能:口令字效验、取出KLK中保存的硬盘卷标、判断当前硬盘卷标是否
合法、 取出KLK中的权限。
在表单及对象的方法或事件中,各自的代码是:
1.this.ini
if type('debug0')='U' &&如果未通过Main.prg而调式,则:
wait wind '请您从执行Main.PRG开始,进行调式......'
this.relea

se
retu
endi
******以下为解密klk.dat文件**************************************
thisform.Vfpjmdbf1.pass_kl='12345678' &&设置加解密口令
thisform.Vfpjmdbf1.path_ml=dqml &&设定klk.dat文件所在目录
thisform.Vfpjmdbf1.jiEmi_file='klk.dat' &&存放密码的资料库文件名
thisform.Vfpjmdbf1.jiEmi &&解密klk.dat文件,并打开以'klk'为别名的工作区
thisform.Vfpjmdbf1.Visible=.f. &&隐藏 Vfpjmdbf1
Go top
******************以下为取磁盘卷标的WIN32API调用*******************
Stor 0 to C_var,C_cd,C_qf
C_disk='c:\' &&指定磁盘
DECLARE INTEGER GetVolumeInformation IN Win32API STRING @, STRING @,;
INTEGER,; INTEGER @, INTEGER @, INTEGER @, STRING @, INTEGER
xx=GetVolumeInformation(C_disk,"",20,@C_var,@C_cd,@C_qf,0,0)
CLEAR DLLS
* C_var=指定磁盘的卷标,是个十进制的数值。
if varjb=0 &&klk.varjb=0 表明是第一次运行本软件
repl varjb with C_var &&将磁盘卷标写入klk.varjb字段
thisform.Vfpjmdbf1.jiAmi_file=''
thisform.Vfpjmdbf1.jiAmi &&先关闭,以保存修改
*要保存修改必须经Vfpjmdbf1.jiAmi来关闭库才行,
thisform.Vfpjmdbf1.jiEmi_file='klk.dat' &&存放密码的资料库
thisform.Vfpjmdbf1.jiEmi &&再打开
else &&否则是已运行过本软件
if varjb<>C_var &&判断klk.varjb是否等于当前磁盘卷标(C_var)
=Messagebox("对不起!您现在运行的软件未经过作者确认,不能运行... ",;
0+48+0,"警告")
quit
endi
endi

2.this.unload
if type('debug0')='U'
do Case &&根据klk.qx字段决定菜单的屏蔽操作
case qx=1
set skip of bar 1 of 权限F .t.
set skip of bar 2 of 权限F .t.
case qx=2
set skip of bar 1 of 权限F .t.
set skip of bar 2 of 权限F .t.
set skip of bar 3 of 权限F .t.
endc
use &&关闭klk
endi

3.thisform.text1.keypress
if nKeyCode#13
retu
endi
loca for allt(this.value)==allt(Passkl) &&查找相符的口令字
if !foun()
=Messagebox("对不起!您的口令有误,不能运行...... ",; 0+48+0,"警告")
thisform.release
quit &&退出系统,为了简单,口令效验我只设了一次。
endi
thisform.release

四、查看和修改KLK的表单,这里就不具体写代码了。

五、菜单1.MPR 主菜单,这里就不具体写代码了。

实例中的权限密码是:0=全权 口令=aaaaaa
1=可修改自己的密码 口令=666666 
2=不能作任何修改 口令=888888


需要以上程序源代码实例的,这里下载

从以上代码中可以看出,里面没有什么新的东西,所用的工具

或资料,在我网上都
可找到,我只不过是把它们拼凑一下而已。您可把这个实例编译成EXE文件(VFP5.0的
朋友可能无法把共享版的Vfpjmdbf.vcx编进去),先在您的机器上运行一下,然后再
把它们直接拷贝到另外一台机器上一试,您看看还能运行否?
当然,别人只要用REFOX7.06把里面的Main.prg反编译出来,去掉:
“ do form (Dqml+'pass')”这一句,还是可以非法拷贝的,那怎么办?
最好的办法是加密您的EXE文件,这样您的软件就比较保险了,最起码Refox等现成
的反编译工具是不可能反编译的。
在我网上有加密VFP&EXE的工具下载,您可下载一试。
需要说明的是:在我网上下载的vfpjmdbf.vcx和Vfp&Exe.exe都是共享版,功能和
使用次数都有一定的限制,如果您觉得还可以,请您花很少一点钱来注册这两个工具,
注册后,我将提供正式版和今后的免费升级。(最新Vfp&Exe.exe可以设置您自己的图表了)


如何把数字转换为汉字大写金额代码分析

[编程心得]又和您见面了,这次所写的是:怎样才能合理利
用 VFP本身所提供的命令和函数来组织代码、编制程序,以提高
运行效率。为了能说明问题,我以数字转换为大写为例,通过对
三组代码的对比来谈谈我个人对此问题的认识。
每种语言提供给我们的命令或函数,可以说最能体现这种语
言的本质,而每个程序员如何运用和组织这些命令或函数,则可
以直接反映这个程序员对这种语言的理解和掌握程度。现在虽然
更多的是强调如何学习和掌握面向对象的编程方法,以及如何灵
活运用这些对象中的事件和方法来组织代码,但我们切不可忽视
对这些最基本的语言命令或函数的学习、理解和灵活掌握。
下面我们以数字转换为大写为例来加以说明:
对于如何把数字转换为汉字大写金额的编程,我在网上看到
了许多种写法,代码最多的一种写法,其代码竟多达 100多行,
让人看了眼花缭乱,很难理解,而代码最少的却连10行都不到,
而其运行结果却是完全相同,可见理解和合理组织编程语言所提
供的命令和函数是何等的重要。
考虑到版面的原因,那近百行的代码我就不具体举例了,下
面的这些代码是我自行组织编写的,如有雷同,则纯属巧合:
 代码一、
FUNCTION Rmbzh
1. PARA nDhsj
2. rmbxx=allt(str(nDhsj,12,2))
3. lszs=allt(str(int(nDhsj)))
4. cd0=len(lszs)
5. dws0='元拾佰千万拾佰千亿'
6. sh0='壹贰叁肆伍陆柒捌玖零'
7. rmbdx=''
8. cd1=cd0
9. for I=1 to cd0
10. lspd=right(lszs,cd1)
11. if val(lspd)=0
12. rmbdx=rmbdx+iif(cd1>4,'万元','元')
13. exit
14.

endi
15. ss=int(val(subs(lszs,I,1)))
16. if ss#0
17. rem0=SUBSTRC(sh0,ss,1)+SUBSTRC(dws0,cd1,1)
18. else
19. rem0=iif(I#cd0,'零','元')
20. endi
21. rmbdx=rmbdx+rem0
22. cd1=cd1-1
23. endf
24. do while atc('零零',rmbdx)>0
25. cc=10-atc('零零',rmbdx)
26. rmbdx=strtr(rmbdx,'零零',SUBSTRC(dws0,cc,1),1,1)
27. rmbdx=strtr(rmbdx,'零零','零',1,1)
28. rmbdx=strtr(rmbdx,'零零','',1,1)
29. endd
30. lsxs=allt(str(nDhsj,12,2))
31. lsxs=right(lsxs,2)
32. if val(lsxs)#0
33. ss=int(val(subs(lsxs,1,1)))
34. rem0=SUBSTRC(sh0,ss,1)+'角'
35. rmbdx=rmbdx+rem0
36. ss=int(val(subs(lsxs,2,1)))
37. rem0=iif(ss=0,'整',SUBSTRC(sh0,ss,1)+'分')
38. rmbdx=rmbdx+rem0
39. else
40. rmbdx=rmbdx+'整'
41. endi
42. Retu rmbdx
这组代码是从纯数字的角度去考虑如何转换的,所以显得不
够简洁, 比如第3行和第31行,分别把整数部分和小数部分加以
分开,各自进行转换,就显的没有这个必要,但它也有可取之处,
比如:
 1.充分利用了系统提供的函数,尤其是SUBSTRC()这个双字节
函数。
 2.它运行的结果可以达到完全口语化的汉语金额,如:
12300.00元,其运行的结果是:壹万贰千叁佰元整,完全符合支
票类填写方式。但却不符合填充类方式。

 代码二、
FUNCTION Rmbzh
1. PARA nDhsj, nDW &&nDW如果等于1,表示要金额单位
2. nDzs=strt(allt(str(nDhsj,15,2)),".","") &&把小数点去掉
3. hzdx="零壹贰叁肆伍陆柒捌玖"
4. cDW="分角元拾佰仟万拾佰仟亿拾佰仟"
5. rmbdx=""
6. nCd=len(nDzs)
7. for i=1 to len(nDzs)
8. NumS=substrc(hzdx,int(val(subs(nDzs,i,1))+1),1)
9. nDWs=iif(nDW=1,substrc(cDW,nCd,1),spac(2))
10. rmbdx=rmbdx+NumS+nDwS
11. nCd=nCd-1
12. endfor
13. Retu rmbdx
 这个代码就是在我网上提供下载的那个实例,可以看出它非常简洁,
编程线路清醒,第7行和第8行分别是数字转换和单位转换,不仅简单
明了,而且还可根据需要选择是否需要金额单位,但也有缺点,就是
不能象上例那样做到完全口语化,我之所以把它作为实例供下载,原
因就在于其清晰的思路和简洁的代码组织形式。
那么这组代码还可以“精简”(其实应该叫合并)吗?答案是:
当然可以。

 代码三、
FUNCTION Rmbzh
1. PARA nDhsj, nDW &&nDW如果等于1,表示要金额单位
2. nDzs=strt(allt(str(nDhsj,15,2)),".","")
3. hzdx="零壹贰叁肆伍陆柒捌玖分角元拾佰仟万拾佰仟亿拾佰仟"
4. rmbdx=""
5. for i=len(nDzs) to 1 step -1
6. NumS=substrc(hzdx,2*val(subs(nDzs,len(nDzs)-i+1,1))+1,1)
7. nDws=iif(nDW=1,substrc(hzdx,i+10,1),space(2))
8. rmbdx=rmbdx+NumS+nDwS
9. endfor
10. Retu rmbdx
 可以看出这组代码

又比上一组少了三行代码,而其最终运行的结果
是一样的,但它所带来的副作用是:代码不直观明了,不细细查看,
一时难以明白,尤其是第6行和第7行中substrc()中的参数需经过多
次运算方可得知,这对今后的维护带来了不便,我一般不采用这种写
法。如果硬是要再合并的话,那这组代码还可以继续合并,比如可以
把6-8行的代码合并为1行。

从上面的这几这几组代码我们不难看出,同一种运行目的,可以
有各种不同的代码组成和表现形式,也可以体现每个程序员各自不同
的编程风格,但不管如何,提高程序的运行效率是每个程序员所共同
追求的。
如果您有一定的汇编知识,可以把第二组代码和第三组代码编译
成可执行程序后,进行反汇编,这时您就会发现它们的汇编结果几乎
是完全相同的,也就是说它们在运行时仍然把您浓缩在一行中的源代
码分开,一条指令再一条指令地执行的,并不是按您源代码中的意愿,
一行代码就一条指令,因而这种“合并”,对提高运行速度和效率没
任何作用。既然如此,一味追求VFP源代码的“精简” 就显的毫无意
义了,反而给自己带来维护的不便。所以不管如何写代码,直观清晰
的编程思路和尽可能地提高运行效率才是我们所提倡的编程风格。
我谈了这么多所谓的体会,并不是说我写的代码就是高效率和完
全合理的,我只是想从另一个角度来谈谈如何在学习和掌握面向对象
编程的过程中,认识和重视这些最基本的知识,只有这样才不会浪费
VFP为我们提供的这些非常丰富的命令和函数。
自办了这个[编程心得],我收到了许多编程爱好者的来信,希望
我继续写下去,可能是由于我的水平有限,还真有些感到骑虎难下,
所以每期的主题显得很凌乱,还望各位理解。如果大家觉得这个栏目
对您的编程有所帮助的话,那我会继续努力的。
我期待着您的批评和建议。


如何注册ActiveX控件

我曾在“编程心得(三)”中提到:“经常在网上看到因“XXX.OCX
没有注册,不能运行,怎么办?”这个问题,最近我也陆续开发了一些以
.OCX为后缀的ActiveX控件,这次我就简要地介绍一下什么是ActiveX控
件、如何注册ActiveX控件的问题。
如果我们直接讲OLE控件(Object Link and Enbed 译: 对象链接
与嵌入)恐怕大家就比较熟悉了,因为在VFP的帮助里常常会看到“OLE”
这三个字母,而OLE是指在Windows环境下应用程序间信息共享和传送的一
种技术,其包含的内容非常广泛,OLE控件(.OCX)只不过是OLE庞大技术
体系中的一种。在VFP中,我们可以简单和笼统地说:Ac

tiveX控件(.OCX)
就是目前最高版本的OLE控件。
在这里我并不想详细介绍OLE或ActiveX,而是介绍如何注册ActiveX
控件和当系统出现“XXX.OCX没有注册”后怎么办的问题。
1.ActiveX控件一般存放在什么文件夹里:
要注册ActiveX控件,你首先必须知道ActiveX控件具体的文件名和它
所在的文件夹。ActiveX控件是以 .OCX为后缀的文件,Windows 95/98操
作系统一般都把ActiveX控件存放在:系统\System\文件夹中(这也是每个
应用程序查找ActiveX控件时默认的文件夹),当然根据需要您也可放在其
他文件夹中,如果是这样,一旦存放ActiveX控件的文件夹名重命名,那您
就必须重新对该ActiveX控件进行注册,否则就会出现“XXX.OCX没有注册”
或“找不到XXX.OCX文件”的提示。(这点您将会在下面的介绍中知道原因)
2.如何注册ActiveX控件:
所谓注册,就是在系统注册表文件System.dat中建立一个主键,在
Windows 9X 中,是建立在“HKEY_CLASSES_ROOT\CLSID\”键下的。
在VFP中注册ActiveX控件一般有以下三种简单的方法:
A、通过VFP菜单的选择项进行注册: 进入VFP编辑状态,在VFP系统主
菜单的[工具]-[选项]-[控件]-[ActiveX 控件]-[按添加按钮],选择您要
注册ActiveX控件的文件夹和文件名,VFP就会自动向系统注册表进行注册,
注册完后您只需在控件列表框“ActiveX控件名”前的复选择框里打钩,就
可在表单设计器的[表单控件]-[ActiveX控件]中进行选择使用了。

B.直接运行Regsvr32.EXE系统文件进行注册,
可在VFP的程序中执行:Ren Regsvr32 [PATH]\xxx.ocx
进行注册。

C.利用Regedit.exe注册表编辑器,在编辑器的查找里直接输入 .OCX
文件名进行查找,找到:
“HKEY_CLASSES_ROOT\CLSID\{xxxxxxxxxxxxxxxxxxxxxxxxxxx}”主键
后,再利用注册表编辑器菜单上-[注册表]-[导出注册表文件]-然后在文件
选择窗里输入导出的注册表文件名,并在下面的[导出范围]单选框中选[选
择的分支],最后按[保存],这样您就把该控件在注册表中的主键保存在一
个 .REG的注册表文件里了。在需要注册该控件的机器上,您只要直接在这
个 .REG的注册表文件上双击鼠标,系统就会询问您是否要将该.REG文件写
入本机的System.dat文件中,也就是进行注册。 如果选择“是”,那就进
行注册了。
那么我们保存的这个.REG注册表文件里有些什么呢?
下面是MP3PLAY.OCX在导出的.REG注册表文件中的内容:
REGEDIT4
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}]
@="Dialog-Medien Mp3Play Control"
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}\ProgID]
@="Mp3Play.Mp3PlayCtrl.1"
[HKEY_CLASSES_ROOT\CLSID\{3B0

0B10D-6EF0-11D1-A6AA-0020AFE4DE54}\InprocServer32]
@="C:\\MP3\\MP3PLAY.OCX"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}\ToolboxBitmap32]
@="C:\\MP3\\MP3PLAY.OCX, 1"
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}\MiscStatus]
@="0"
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}\MiscStatus\1]
@="131473"
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}\Control]
@=""
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}\TypeLib]
@="{3B00B10A-6EF0-11D1-A6AA-0020AFE4DE54}"
[HKEY_CLASSES_ROOT\CLSID\{3B00B10D-6EF0-11D1-A6AA-0020AFE4DE54}\Version]
@="1.0"

我之所以写这些,是为了让您理解ActiveX控件放在“系统\System\”文件
夹和放在其他文件夹中的区别,我的这个MP3PLAY.OCX是放在C:\MP3\文件夹里的,
所以上面的红色部分就明确标明了ActiveX控件所在的文件夹,也就是:如果这个
文件夹被重新命名后,您必须重新进行注册的原因所在。而如果是放在:
“系统\System\”里,那这些红色的部分就是这样写的了:
@="MP3PLAY.OCX"
@="MP3PLAY.OCX, 1"
可以看出,这里已没有C:\MP3\文件夹名了。

上面的兰色部分就是一个ActiveX控件是不是在注册表文件里进行注册的标志,
也就是该控件在注册表文件里的主键名。

必须注意的是,上面B和C方法的注册,只是在注册表中进行了注册,如果您想
在VFP编辑时象其他控件那样在表单设计器的[表单控件]-[ActiveX控件]中看见它,
则您还必须进行方法A中的绿色部分。

希望通过上面这些简单的介绍,当您再遇到“XXX.OCX没有注册,...”时,您
可以找出原因,自行处理了。

利用DOS下的内部或外部命令来完成VFP无法达到的功能

 这次“心得”继续谈谈编程中的一些小技巧,这些小技巧您可能已经知道,
但我还是希望这些技巧能对您有所帮助:

1.利用DOS下的内部或外部命令来完成VFP无法完成的功能:

A.利用DOS下的ATTRIB.EXE程序来改变文件的属性。我曾介绍过用VFP
的RENAME命令来更改文件属性的方法,其实用DOS下的ATTRIB.EXE更加方便。
ATTRIB.EXE程序是DOS操作系统的外部命令之一,在C:\WINDOWS\COMMAND\
文件夹里,
用法: RUN /N ATTRIB [+或-] [R S H] 文件名
比如: RUN /N ATTRIB -R -S -H XXX.DAT
把XXX.DAT文件的只读、隐含和系统属性去掉,如果把“-”改为“+”,则作
用相反。

B.利用DOS的内部命令DIR来取得指定磁盘上所有的文件夹和文件名、 磁
盘格式化时建立的磁盘卷标序号、文件夹及文件的长文件名和短文件名、文件
夹和文件的个数等。
用法: RUN DIR [*或?] [/s /...] > 文件名
比如想取得C:盘下的所有文件夹和文件,则:
RU

N DIR C:\*.* /S > DISK_C.TXT
这样就会在当前目录下建立一个名为DISK_C.TXT的文本文件,文件里包含了上
面提到的所有数据,下面是其中的一部分:

Volume in drive C has no label
Volume Serial Number is 3846-11DF
Directory of C:\

COMMAND COM 94,282 06-19-98 20:01 https://www.wendangku.net/doc/772019459.html,
WZT1 25 10-11-99 23:44 WZT1
WZT2 25 10-11-99 23:44 WZT2
WINDOWS < DIR > 05-04-99 20:56 WINDOWS
......

22 file(s) 234,496 bytes
40 dir(s) 1530,612,224 bytes free

具体的数据格式这里就不介绍了。

C.利用DOS的内部命令DATE来改变系统日期
VFP本身没有办法改变系统的日期或时间,用WIN32 API虽说可以改变,
但十分复杂(在我的[专题文章]栏目里有介绍),如果用 DOS的内部命令:
DATE来改变系统日期就比较方便了,方法是:
RUN DATE [MM/DD/YY]

比如把系统日期改为2000年10月1日,则
RUN DATE 10/01/2000

如果您需用变量来改日期,则:
mDATE='10/01/2000'
RUN DATE &mDATE

同理,如果想改变时间则用DOS的内部
命令TIME来达到。
类似的命令还有一些,您可自己一试,需要说明的是,利用DOS下的命令,
会出现DOS窗口,您可以建立个快捷方式,将其设为最小化,使用时调用这个快
捷方式,可以以最小化窗口来执行DOS的命令。 也许您发现了,利用DOS的内部
命令时RUN命令后不能带“/N” 。

谈谈VFP中变量的问题

最近一直在忙于开发ActiveX控件,加上没有合适的心得可谈,许多
网友希望我能继续把它写下去,看来我还得继续努力。
这次我们谈谈有关内存变量和方法程序作用域的问题。我在网上发现
许多初学编程的网友对此概念比较模糊,或许这个问题对您来说太简单了,
但对初学者来说,不但难理解,而且又找不到能详细这方面知识的资料。
下面就谈谈我对此的理解,供大家参考:
一、变量
我们在有关VFP的书上常常看到的是局部(私有)和全局(共公)变量
的介绍,而对于学过VB的朋友来说除了这两种变量外,可能知道还有个叫窗
口级的变量,那在VFP中是否也有这种变量呢?“有”。在这里我们不妨就叫
“表单级变量”吧(其实就是:容器或对象的属性)。
1.局部(私有)变量:
局部变量,也可以称动态变量,即可以随时定义,其作用域仅限于定义
它的某个过程、方法和事件,对其他过程、方法和事件来讲它并不存在。定
义它的过程、方法和事件执行完毕,该变量自行释放,不占用内存空间,如
果您再次进入还得重新定义和赋值。
2.全局(共公)变量:
全局变

量,也可以称静态变量,需用Public命令定义,往往在程序的开
始部分定义,系统会专门开辟一块空间用于全局变量,一旦定义,其作用域
是整个程序的全过程,即您可以在任何过程、方法和事件中对它读取和赋值,
且所赋的值在未被赋新值前一直有效。
它在整个程序未退出前一直占用着内存空间。要释放全局变量,必须用
RELEASE EXTENDED来一次性全部释放,在程序运行中执行了
RELEASE ALL、RELEASE ALL LIKE 或 RELEASE ALL EXCEPT 时并不释放全局
变量。如果用RELEASE XXX 指明具体要释放的全局变量名,可以在名义上释
放,但它所占用的内存空间并未被真正释放,只是您看不到罢了。
3.表单级变量(也就是:容器或对象的属性):
明白了局部和全局变量,再来了解表单级变量就不难理解了,表单级变
量的作用域为本表单本身及表单内所有对象的方法和事件,它随着表单的打
开而建立,表单的释放而释放。
那么什么样的变量是表单级变量呢?说白了就是:所有可以设置和取出
返回值的表单或对象的属性,都属于表单级变量,比如:
Caption、Height、Enabled等,也可以说凡是在表单编辑器的属性窗口中能
看到的可读写的容器或对象的属性,就是表单级变量。也许有人会问,这些
属性都是系统定义的,我们自己可以定义吗? 可以,但我们只能定义表单
(FORM1)属性,不能给对象定义属性。
那么如何定义呢? 进入表单编辑器,选择主菜单的[表单]-[新建属性]
-在[名称]里填写你要新建的属性名(表单级变量名),如果你用的是VFP3.0
或VFP6.0,你还可以在下面的说明里写上你新建属性 的说明,这样在 Form1
属性窗口中的下方,就可以看到你对该属性的说明。填写完了按添加按钮,
你就定义了一个表单级变量了。不信你到Form1 属性窗口的[其他]里去找,
看看有没有你刚定义的这个属性名,其初始值=.F.。
一旦定义了新的属性,就可以和其他表单属性一样读写了。如果按上面
的办法我们定义了一个名为Bdsx的属性,那你既可以在Form1属性窗口中直接
对它赋值,也可在本表单的任何方法和事件中对它赋值,只是在读写它时必
须加上THIS. 或 THISFORM. 如:

Thisform.Bdsx="hi 网友!您好"
https://www.wendangku.net/doc/772019459.html,bel1.Caption=thisform.Bdsx

上面讲了这么多有关变量的概念,那么在具体应用中,究竟用哪种变量好
呢?这要看具体情况,但一般的原则是:
带有全局性质的参数,最好用全局变量,比如用于确定登入者身份的参数、
特定的操作目录等。在一个程序中全局变量越少,各过程、类、表单的独立性
和可移植性就越强。

凡是只在某个过程或事件中起中间过渡用的参数,就一律定义为局部变量,
到需要用时再定义。
凡是需在整个表单的各对象间进行读写的参数,就采用表单级变量,这样
你的这个表单今后如果想移植到其他程序中使用,就只需改变一下数据环境了,
无须再全部重新设计表单,也就是说这个表单相对于整个程序,它是个独立的
整体。
二、方法程序
VFP允许我们自定义函数和过程程序,但如果以.PRG文件名定义的函数和过
程程序,必须用 SET PROCEDURE TO ... 来打开和关闭,同时在这种过程程序
中,无法使用诸如https://www.wendangku.net/doc/772019459.html,BEL1....等具体的对象名,那在表单中有一段几
个对象的CLICK的事件都需调用的代码,怎样在不重复写这些代码的情况下执行
这段代码呢?我们可以在表单中建立和调用自定义的方法程序吗?又如何调用
它们呢?
1.直接带对象名加事件名调用,比如在COMMAND1.CLICK的事件中,有如下
一段代码,这段代码在COMMAND2.CLICK和COMMAND3.CLICK中也需要执行,则在:
COMMAND1.CLICK事件中的代码如果是:
IF XXX=1
WAIT WIND '你好!'
.... ....
.... ....
ELSE
WAIT WIND '嘿!大家好!'
... ...
... ...
ENDI
... ...

那在COMMAND2.CLICK和COMMAND3.CLICK的事件中只需写一句:
https://www.wendangku.net/doc/772019459.html,MAND1.CLICK
就都可以调用这同一段代码了,无须重复写这段代码。

2.可以象表单级变量那样直接在表单上建立表单的方法程序:
进入表单编辑器,选择主菜单的[表单]-[新建方法程序]-在[名称]里填写你
要新建的方法程序名,如果你用的是VFP3.0或VFP6.0,你也可以在下面的说明里
写上你新建方法程序的说明,这样在Form1属性窗口中的下方,就可以看到你对
该方法程序的说明。填写完了按添加按钮,这样你就建立的一个新的方法程序,
你可以象FORM1.LOAD等方法那样在里面写入你的代码了,比如我们建立了一个名
为:BDFFCX的方法程序,在这个方法程序里我们把上面的这段代码写入BDFFCX:
IF XXX=1
WAIT WIND '你好!'
.... ....
.... ....
ELSE
WAIT WIND '嘿!大家好!'
... ...
... ...
ENDI
... ...

那你只要在COMMAND1.CLICK、COMMAND2.CLICK和COMMAND3.CLICK的事件
中写上如下一句就可执行这段代码了:

THISFORM.BDFFCX

如果您还想带参数调用,那首先必须在BDFFCX方法程序的第一句加上:
Rarameters XXX1,XXX2

把THISFORM.BDFFCX这句改为:

THISFORM.BDFFCX(xxx1,xxx2)

就可以带参数调用BDFFCX了。

 表单级方法程序和表

单级变量一样,随着表单的打开而建立,表单的释放而
释放。

----关于报表打印

VFP所提供的报表设计器虽说功能强大,并能提供所见所得的报表预览,
但我总觉得没有DOS下直接用代码编制的打印程序来得方便和自由,虽然DOS
没有预览功能。也正因为如此,我很少谈及VFP 的打印问题,为了和大家交
流,这次也谈谈VFP的报表打印问题,希望以此和大家共同探讨。
一、部分与打印有关的系统变量
VFP本身为我们提供了几个与打印有直接关系的系统变量,它们是:(部分)
_BOX 是否打印文字边框,.T.=打印
_GETNPD 指定或保存打印机接口驱动程序的文件名。
_PADVANCE 设定打印纸进纸方式,=FORMFEED(默认)整张进纸。
_PAGENO 设定或保存当前的打印页号。
_PBPAGE 设定或返回打印的起始页号。
_PEPAGE 设定或返回打印的终止页号。
_PCOLNO 设定或返回当前打印头的列。
_PLINENO 设定或返回当前打印头的行。
_PCOPIES 设定或返回打印份数。
_PLENGTH 设定或返回打印纸的页长,默认=66行长。
_PPITCH 设定打印机的打印密度。
_PQUALITY 设定打印机的打印质量。
... ...
这些变量在设计报表程序时,有些是很有用的,故在此列出。

二、一些常用的打印技巧
1.怎样打印指定的页
REPORT FORM XXXX RANGE 2,5 TO PRINTER &&从第2起打至第5页止

2.如何计算总页数,以实现“第?页/总?页”
在打印前根据细节区所打印的记录条数,先进行计算,然后再打印,具体代码:
PUBL mPAGE
SELE XXX &&xxx=供打印的数据表
XX=10 &&XX=细节区所打印的记录条数
mPAGE=IIF(RECCOUNT()%XX=0,INT(RECCOUNT()/XX),INT(RECCOUNT()/XX)+1)

mPAGE就是总页数,这样在需要总页数的地方就可直接引用mPAGE变量了。

3.如何使报表打满一页
如果打印的记录不足一页,“页注脚”会自动上移,影响报表的美观,解决的
办法和上面的差不多,即补足一页中所缺少的记录(补足空白记录):

SELE XXX &&xxx=供打印的数据表
XX=10 &&XX=一页细节区所打印的记录条数
mI=RECCOUNT()%XX &&取得缺少的记录条数
FOR I=1 to mI
APPEND BLANK
ENDF

4.报表在设计时明明可以打印,可一安装到其他机器或重装系统后,就会出现
“XXX 带区太大不能放入页中”等提示,而且无法正常退出(尤其是对自定义纸张
大小的程序),这是为什么呢?
我们用报表设计器设计的打印程序,保存退出后,磁盘上就会出现 .frx和.FRT
文件,我们的所有设计均保存在这两个文件中。在VFP中 .frx相当于.DBF表,.FRT
相当于.F

PT备注型文件,我们用USE XXX.frx 可以象打开.DBF文件一样打开.frx文
件,在.frx文件中有个Expr备注型字段名,在这个字段名中有如下内容:其中()内是
我所加的译文
======================================================================
RIVER=winspool
DEVICE=Epson LQ-1600K
OUTPUT=LPT1:
ORIENTATION=0
PAPERSIZE=256 (纸张大小)
PAPERLENGTH=1000 (纸张长度)
PAPERWIDTH=1600 (纸张宽度)
DEFAULTSOURCE=8 (默认来源)
PRINTQUALITY=180 (打印质量)
COLOR=2
YRESOLUTION=180
TTOPTION=1
============================
==========================================
从这个Expr备注型字段里可以看出:PAPERSIZE=256 这里的256表示是自定义纸张,
如果:
PAPERSIZE=9 为A4、11为A5 具体数据见VFP帮助的Printfo()一节, 而:
PAPERLENGTH=1000 (纸张长度)
PAPERWIDTH=1600 (纸张宽度)
则分别代表自定义纸张的长度和宽度。 之所以会出现上面提到的问题,是因为系统重
新安装打印机后,WIN系统一般默认的是A4打印纸,与我们设计时保存在.frx文件里的
纸张不符,因而造成这种情况。 那么如何避免出现这个问题呢?
下面是一段检测纸张类型的代码,供您参考:
这段代码必须放在执行report form ... 命令前。

use xxx.frx in 0 ALIAS mPrint &&在空闲工作区以mPrint别名打开xxx.frx文件
x=atcline('PAPERSIZE',mPrint.Expr) &&取得PAPERSIZE在Expr字段中的行
sSIZE=subs(mline(mPrint.Expr,x),11) &&取得设计时保存的纸张类型
mSIZE=allt(str(Prtinfo(2))) &&取得当前打印机默认的纸张类型
x=atcline('PAPERLENGTH',mPrint.Expr) &&取得纸张长度在Expr字段中的行
sLEN=subs(mline(mPrint.Expr,x),13) &&取得纸张长度
x=atcline('PAPERWIDTH',mPrint.Expr) &&取得纸张宽度在Expr字段中的行
sWIDTH=subs(mline(mPrint.Expr,x),12) &&取得纸张宽度
use in 'mPrint' &&关闭xxx.frx文件
if sSIZE=mSIZE &&如果相符,则正常打印
 report form xxx.frx to printer
else
 Messagebox('请设定打印机纸张为自定义:长='+sLEN+',宽='+sWIDTH,0+48+0,'提示')
 report form xxx.frx to printer prompt &&打印前先打开打印机设置对话窗口
endi

5.不让打印的结果显示在屏幕上
report form xxx.frx to printer Noconsole

6.打印或打印预览时,如何使系统打印工具条不出现
系统提供的打印工具条,我们无法检测其各按钮的事件,不能掌握用户当时操
作的情况,那如何不让它出现呢?
首先您得做一个表单(最好是模式表单),用于代替系统的预览窗口(Preview),然后:
do form dybd &&打开这个表单
report form xxx.frx windows dybd
这样系统提供的打印

工具条就不会出现了。
当然如果自己再做个类似于打印工具条的类,既可掌握按钮事件又美观就更好了,
注:经查VFP3.0可能没有windows子句。


相关文档