VFP编程技巧
功能:口令字效验、取出KLK中保存的硬盘卷标、判断当前硬盘卷标是否
合法、 取出KLK中的权限。
在表单及对象的方法或事件中,各自的代码是:
1.this.ini
if type(''debug0'')=''U'' &&如果未通过Main.prg而调式,则:
wait wind ''请您从执行Main.PRG开始,进行调式......''
this.release
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为我们提供的这些非常丰富的命令和函数。
自办了这个[编程心得],我收到了许多编程爱好者的来信,希望
我继续写下去,可能是由于我的水平有限,还真有些感到骑虎难下,
所以每期的主题显得很凌乱,还望各位理解。如果大家觉得这个栏目
对您的编程有所帮助的话,那我会继续努力的。
我期待着您的批评和建议。