青春期1怎么看不了:VFP编程技巧

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 15:20:21
7月18日

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('command.com',2)
    nPath=strtran(nPath_ls,'COMMAND.COM','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=Fread(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.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.vcxVfp&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中,我们可以简单和笼统地说:ActiveX控件(.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\{3B00B10D-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:盘下的所有文件夹和文件,则:
      RUN 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  COMMAND.COM
      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.表单级变量(也就是:容器或对象的属性):
          明白了局部和全局变量,再来了解表单级变量就不难理解了,表单级变
        量的作用域为本表单本身及表单内所有对象的方法和事件,它随着表单的打
        开而建立,表单的释放而释放。
          那么什么样的变量是表单级变量呢?说白了就是:所有可以设置和取出
        返回值的表单或对象的属性,都属于表单级变量,比如:
        CaptionHeightEnabled等,也可以说凡是在表单编辑器的属性窗口中能
        看到的可读写的容器或对象的属性,就是表单级变量。也许有人会问,这些
        属性都是系统定义的,我们自己可以定义吗? 可以,但我们只能定义表单
        (FORM1)属性,不能给对象定义属性

          那么如何定义呢? 进入表单编辑器,选择主菜单的[表单]-[新建属性]
        -在[名称]里填写你要新建的属性名(表单级变量名),如果你用的是VFP3.0
        VFP6.0,你还可以在下面的说明里写上你新建属性 的说明,这样在 Form1
        属性窗口中的下方,就可以看到你对该属性的说明。填写完了按添加按钮,
        你就定义了一个表单级变量了。不信你到Form1 属性窗口的[其他]里去找,
        看看有没有你刚定义的这个属性名,其初始值=.F.。
          一旦定义了新的属性,就可以和其他表单属性一样读写了。如果按上面
        的办法我们定义了一个名为Bdsx的属性,那你既可以在Form1属性窗口中直接
        对它赋值,也可在本表单的任何方法和事件中对它赋值,只是在读写它时必
        须加上THIS. 或 THISFORM. 如:

          Thisform.Bdsx="hi 网友!您好"
          thisform.Label1.Caption=thisform.Bdsx

          上面讲了这么多有关变量的概念,那么在具体应用中,究竟用哪种变量好
        呢?这要看具体情况,但一般的原则是:
          带有全局性质的参数,最好用全局变量,比如用于确定登入者身份的参数、
        特定的操作目录等。在一个程序中全局变量越少,各过程、类、表单的独立性
        和可移植性就越强。
          凡是只在某个过程或事件中起中间过渡用的参数,就一律定义为局部变量,
        到需要用时再定义。
          凡是需在整个表单的各对象间进行读写的参数,就采用表单级变量,这样
        你的这个表单今后如果想移植到其他程序中使用,就只需改变一下数据环境了,
        无须再全部重新设计表单,也就是说这个表单相对于整个程序,它是个独立的
        整体。
          二、方法程序
          VFP允许我们自定义函数和过程程序,但如果以.PRG文件名定义的函数和过
        程程序,必须用 SET PROCEDURE TO ... 来打开和关闭,同时在这种过程程序
        中,无法使用诸如THISFORM.LABEL1....等具体的对象名,那在表单中有一段几
        个对象的CLICK的事件都需调用的代码,怎样在不重复写这些代码的情况下执行
        这段代码呢?我们可以在表单中建立和调用自定义的方法程序吗?又如何调用
        它们呢?
          1.直接带对象名加事件名调用,比如在COMMAND1.CLICK的事件中,有如下
        一段代码,这段代码在COMMAND2.CLICK和COMMAND3.CLICK中也需要执行,则在:
        COMMAND1.CLICK事件中的代码如果是:
          IF XXX=1
            WAIT WIND '你好!'
            .... ....
            .... ....

          ELSE
            WAIT WIND '嘿!大家好!'
            ... ...
            ... ...

          ENDI
          ... ...

        那在COMMAND2.CLICK和COMMAND3.CLICK的事件中只需写一句:
          THISFORM.COMMAND1.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
      相当于.FPT备注型文件,我们用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子句。

        很惭愧,我平时很少用VFP的报表设计器来编制打印程序(用其他语言代替的),
      所以能谈的体会很少,十分希望这方面的高手能介绍您的经验,谢谢!

14:53 | 添加评论 | 固定链接 | 写入日志 | VFP7月12日

VFP中如何调用其它程序(收藏)

豆三兄的??

VFP中我们可以用run来调用由VFP自身生成的.exe文件。命令格式:
run c:\..\*.exe

?????? 当调用非VFP自身生成的.exe文件时,需要加上绝对路径和参数。
一般来说,用VFP运行非VFP自身生成的可执行文件时,会有一个黑色的窗口显示一下。可以通过加上/n来隐藏这个窗口。例如运行Windows下的扫雷游戏,命令格式如下:
RUN/n C:\Windows\Winmine.exe
下面运行一个更复杂一点的程序。用word打开c:\下的一个名为mlx.doc的word文件,命令格式如下:
run /n3 C:\Program Files\Microsoft Office\Office\Winword.exe?? C:\mlx.doc
???? 参数:n 在运行时隐藏VFP的黑色窗口。
???????????????? 3 表示以最大化的方式运行程序。1正常方式、2最小化方式、3最大化方式

?????? 在这种情况下,虽然可以通过加上参数使程序程序能够流畅运行,但还是要指定绝对路径,而在实际开发时我们常常无法确定所需要启动的应用程序的文件名及其绝对路径。比如,在上例中,我们无法确定用户的word到底安装在什么地方,如果用户把word安装到了别的地方,上述命令便会出错。再如,一个.gif文件,有的用户喜欢用ACD See来打开,有的用户喜欢用IE来打开,有的用户喜欢用豪杰来打开,……
?????? 为了解这种情况我们可以调用Windows的文件关连来打开文件。即所有的文件都用系统默认的程序来打开。这就要调用Windows的Win32 API函数。调用方式如下:

DECLARE INTEGER ShellExecute IN shell32.DLL INTEGER HWND,STRING lpszOP,STRING lpszFile,STRING lpszParams,STRING lpszDir,INTEGER fsshowcmd
DECLARE INTEGER GetDesktopWindow IN win32api
HWND = GetDesktopWindow()
lpszOP = "open"
* 指定要打开的文件名
lpszFile ="c:\mlx.doc"
lpszParams = ""
lpszDir = "c:\temp"
fsshowcmd = 1
* 执行ShellExecute命令
LNRETURN = ShellExecute(HWND, lpszOP,lpszFile, lpszParams, lpszDir,fsshowcmd)

可以用任意的文件名来替换上文中的 c:\mlx.doc 。如果指定的文件名Windows无法找到相应的关连程序,这时程序将不会做出反应。有关的参数可以自行偿试进行修改,以达到最佳效果。

-------------------------------------------------------------
API函数ShellExecute的使用

ShellExecute
说明 Shellexecute 函数用于对文件执行一个动词(verb). 它通常用于启动一个与特定文件类相关联的应用程序. 例如, 要启动 Word 来读一个 .doc 文件, 或启动 记事本 来编辑一个 .txt 文件. 用于第二个参数中的最常用的动词是 "Open", 但其它可用的动词是 "edit","print","explore" 和 "properties". 有趣的是, 使用 "mailto:" 或 "http://" 前缀, ShellExecute 函数也可用于以一个给定的邮件地址启动默认的邮件阅读器或给定的 URL 启动默认的浏览器.


缩主文件 Shell32.dll

VFP 中的定义
DECLARE INTEGER ShellExecute IN "Shell32.dll" INTEGER hwnd,STRING lpVerb,STRING lpFile,STRING lpParameters,STRING lpDirectory,LONG nShowCmd

Visual FoxPro 应用示例
* 打开 Word 来编辑文件 "c:\mywordfile.doc"
=Shellexecute(0,"Open","c:\mywordfile.doc","","",1)

* 打开默认的浏览器并定位到天堂论坛
=Shellexecute(0,"Open","http://www.dbwin.net/bbs/index.asp?boardID=1&;page=1","","",1'>http://www.dbwin.net/bbs/index.asp?boardID=1&;page=1","","",1)

* 打开默认的邮件阅读器来发一封信给天堂版主
=Shellexecute(0,"Open","mailto:njjane@21cn.com","","",1)

* 打印文本文件 "c:\mytextfile.txt"
=Shellexecute(0,"Print","c:\mytextfile.txt","","",1)

用过《网络蚂蚁》的朋友都知道,在帮助菜单的对话框里作者留下了他的电子邮件地址,单击该邮件地址我们便能给作者发送电子邮件。这种功能看起来有些神秘,实际上只要利用Windows API的ShellExecute函数,便可轻松地实现该功能。

  ShellExecute是用来打开特定格式的文件(如WORD文件、EXCEL表格)的函数。该函数存放在Shell32.DLL动态链接库中,通过查阅MSDN,我们能够得到下述帮助:

  HINSTANCE ShellExecute(HWND hwnd,LPCTSTR lpOperation,LPCTSTR lpFile,LPCTSTR lpParameters,LPCTSTR lpDirectory,INT nShowCmd);

  其调用参数的含义如下:

  hwnd:指明打开文件的窗口句柄。

  lpOperation:指明操作类型,分别是"open"(打开)、"print"(打印)、"explore"(浏览)。

  lpFile:欲打开文件的文件名。这里应该将文件的含义向更深层次理解。文件可以是本地文件,也可以是远程文件;文件的类型可以是文本文件,也可以是多媒体文件。

  lpParameters:打开文件时所传递的参数。特别适合打开EXE文件。

  lpDirectory:文件所在路径。

  nShowCmd:打开文件时窗口的状态。0表示隐藏,1正常方式、2最小化方式、3最大化方式。

  如果该函数能够成功打开文件,则该函数的返回值大于32。该函数的返回值能够为你调试程序提供很多有用的信息,具体情况见MSDN内帮助文件。

  好,有了上述认识之后,我们便能在VFP的程序开发中利用ShellExecute函数来实现发送电子邮件的功能。新建一表单ABOUTME,在该表单上添加下列控件(见表1)。

  需要说明的是,在Label1中的MouseIcon设为一手型光标,其所对应的图标文件在系统内可以随处找到(利用查找文件功能),本文用的是Windows自带h_move.cur文件。针对Label11的各类设置都是为了将该标签打扮得更象"超文本"。

  添加完上述控件之后,接下来便是编写控件的CLICK事件代码了。对Label1和Label2的CLICK事件设定相同,其他代码为:

  *进行声明操作:

  DECLARE INTEGER ShellExecute IN shell32.DLL INTEGER HWND,STRING,STRING lpszFile,STRING,STRING,INTEGER

  *向kingdom@126.com邮箱内发送一封主题为"你好"的电子邮件。

  在Label1的CLICK事件里,添加以下代码:

  ShellExecute(0,"open","mailto:kingdom@126.com?subject=你好",0,0,1)

  在Label2的CLICK事件里,将上述语句改为:

  ShellExecute(0,"open","http://NationalTax.home.Chinaren.com",0,0,1)

  *以最大化窗口方式打开IE,进入作者主页。

  确认按钮的CLICK事件代码很简单:thisform.release

  运行上述表单,当鼠标移动到电子邮件或是作者主页区域时,鼠标便会变成一只手,点一下即可进行相应的操作:单击Label1,启动Outlook Express;单击Label2,启动IE,表单真有些像一个小型的IE!其实,在VFP的程序开发中,一些看似不可能的事件只要稍微用到一些Windows API,所有的事件一下子都变得简单多了。"山重水复疑无路,柳暗花明又一村",这可能就是编程的乐趣所在吧

  Windows API简介:

  Application Program Interface,即应用程序编程接口,它是Windows提供给程序员的一系列函数。这些API函数同一般的函数相似,同样具有输入输出参数,并编译到一个独立的文件中,该文件被称为动态链接库。运用API函数可以实现许多复杂和有趣的功能,如重新启动计算机、跟踪当前激活窗体、收发E-mail等。   


----------------------------------------
VFP中操作多种文件
??
     做为一种数据处理软件,VFP在使用上的简洁是人所共知的。在使用VFP进行应用程序开以时,有时会涉及到一些非数据处理方面的内容,比如在VFP中打开WORD文档、EXCEL图表、利用OE收发电子邮件,这些功能又恰恰是VFP的弱项。通常情况下,我们处理这些问题的方法是使用OLE(现称之为ActiveX)技术来完成。但是,在VFP中要熟练操作OLE对象,又是一件更麻烦的事情。拿用VFP接入互联网来说,你可以在VFP的表单中加入Microsoft Web浏览器控件,但是如果没有专业的技术文档,你要想顺利地使用浏览器控件,这基本上是不可能的。有没有一种更简单的办法来实现上述功能呢?有的。
  VFP提供了在应用程序中调用Windows API函数的功能。如果我们要在VFP程序中使用API函数,只需要在使用前先进行申明,告诉VFP你想调用的函数的基本情况。申明语句的语法如下:
  DECLARE 〔cFunctionType〕 FunctionName IN LibraryName 〔AS AliasName〕
   〔cParamType1 〔@〕 ParamName1, cParamType2 〔@〕 ParamName2,……〕
  其中各参数的具体含义如下:
  cFunctionType:被调用函数的返值。它可以是SHORT、INTEGER、SINGLE、DOUBLE、LONG、STRING六个类型之一。学过VC编程的朋友对这些数据类型肯定不会陌生。
  FunctionName :调用函数的名称。它是大小写敏感的。
  LibraryName:调用函数的所在地。它一般是一DLL文件名。
  cParameterType1 〔@〕 ParamName1, cParameterType2 〔@〕 ParamName2, :当对函数的调用属带参调用时,就应该申明参数的类型及名称。
  其实,使用VFP操作其他类型的文件,你不妨把这项工作交给系统替你来完成。在SHELL32.DLL动态链接库中,有一ShellExecute函数,它负责打开文件的操作,查阅MSDN,我们能够得到下述帮助: 
  HINSTANCE ShellExecute( HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile,LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd);
  其调用参数的含义如下:
   hwnd:指明打开文件的窗口句柄。
   lpOperation:指明操作类型,分别是"open"(打开)、"print(打印)"、"explore(浏览)"
   lpFile:欲打开文件的文件名。这里应该将文件的含义向更深层次理解。文件可以是本地文件,也可以是远程文件。文件的类型可以要文本文件,也可能是多媒体文件。
   LpParameters:打开文件时所传递的参数。特别适合对EXE文件的打开。
   LpDirectory:文件所在路径。
   NShowCmd:打开文件时窗口的状态。0表示隐藏,1表示最大化,2表示最小化。
  如果该函数打开文件的操作的成功,则该函数的返回值大于32。该函数的返回值能够为你调试程序提供很多有用的信息,详情请见MSDN内帮助文件。
  好,有了上面的认识,我们可以引入正题了。
  一、 在VFP中浏览网页。
  在VFP6.0提供了超级链接控件,使用该控件能够很简单地进入Internet。但是在VFP5中却没有此类控件,如果你想在VFP5中浏览互联网,只需在程序中添加如下代码:
  *进行申明操作:
  DECLARE INTEGER ShellExecute IN shell32.DLL INTEGER HWND,STRING, STRING lpszFile, STRING, STRING, INTEGER
  *以最大化窗口方式打开IE,并进入在线影院ShellExecute(0,"open","http://www.163film.com",0,0,1)
  二、 打开、打印WORD文档
  *若要打印文档,则将operate赋值为"print"
  operate="open"
  *打开hello.doc文档
  ShellExecute(0,operate,"c:\my documents\hello.doc",0,0,1)
  三、 带参调用EXE文件
  *下列语句将运行记事本程序,并打config.sys进行编辑
  ShellExecute(0,"open","notepad.exe","config.sys","c:\",1)
  四、 调用资源管理器
  *运行资源管理器查看C:盘内容
  ShellExecute(0,"explore",0,"c:\",0,1)
  五、在VFP中发送电子邮件
  *发送一封主题为新年"进步"的信到abcd@efg.com ShellExecute(0,"open","mailto:abcd@efg.com?subject=新年进步 ",0,0,1)
  以上便是ShellExecute常见的几种具体用途,怎么样,没想到在VFP中也能够这样容易地操作各种各样的文件吧!试试看,你肯定能够找到ShellExecute更加多的用途。

??

9:18 | 添加评论 | 固定链接 | 写入日志 | VFP

如何在一个类中用编程的形式中如一个方法程序(收藏)

表单运行时用BINDEVENT()来绑定事件,属性或方法从VFP自己的对象到其它VFP对象*--------------------------------列子1:在一个表单中有n个命令按钮,我想随便单击其中任何一个按钮,此表单关闭,进入另一个表单。
不想一个按钮一个按钮的添加代码,而想用动态方式将对象的CLICK事件与原有或新建的事件或方法绑定。----------------------------------------------------------------------------------可以为表单新建一个方法,比如MyMethod,然后写入诸如下面的代码:
THISForm.Release
DO FORM 表单名在表单的Init事件中加入以下代码:
FOR i = 1 TO THIS.ControlCount
??IF UPPER(THIS.Controls[i].BaseClass) == "COMMANDBUTTON"
????= BINDEVENT(THIS.Controls[i], "Click", THIS, "MyMethod")
??ENDIF
ENDFOR这样应该就可以了。但是,需要注意的是,只有VFP7以上版本才有BINDEVENT()函数。
也完全可以把按钮做成类,然后再向表单中添加若干基于该类的按钮。
不过如果如你所说,按钮是不可视的,那应该怎么都没用了。
列子2:
----------------------------------------------------------------------------------
动态加载一个控件,如按钮,并给按钮的Click事件绑定事件:1、建一个过程文件(如MyProc.PRG),内容如下
DEFINE CLASS myhandler AS Session
??PROCEDURE CmdClick
????MESSAGEBOX('ok',64,'') &&此处改为相应代码
????RETURN
??ENDPROC
ENDDEFINE??2、表单的INIT事件:SET PROCEDURE TO MyProc.prg
3、表单上动态加载控件按钮的CLICK事件:THISFORM.ADDOBJECT('Cmd_Test','CommandButton')
THISFORM.Cmd_Test.CAPTION='Cmd_Test'
THISFORM.Cmd_Test.TOP=100
THISFORM.Cmd_Test.LEFT=100
THISFORM.Cmd_Test.HEIGHT=25
PUBLIC oHandler
oHandler=NEWOBJECT("myhandler")
BINDEVENT(THISFORM.Cmd_Test,"Click",oHandler,"CmdClick")
THISFORM.Cmd_Test.VISIBLE=.T.??----------------------------------------------------------例子3:
*BINDEVENT() 函数。下面是一个简单示例。PUBLIC oform1oform1=NEWOBJECT("form1")
oform1.SHOW
RETURN
DEFINE CLASS form1 AS FORM
??TOP = 24
??LEFT = 158
??DOCREATE = .T.
??CAPTION = "Bindevent 示例"
??NAME = "Form1"??PROCEDURE _click
????THISFORM.text1.VALUE=THISFORM.ACTIVECONTROL.NAME &&此处可改为表单文件名
??ENDPROC??PROCEDURE INIT
????LOCAL i,j,cname
????THISFORM.LOCKSCREEN=.T.
????FOR i=1 TO 3
??????FOR j=1 TO 3
????????cname='cmd'+STR(i,1)+STR(j,1)
????????THISFORM.ADDOBJECT(cname,'commandbutton')
????????WITH THISFORM.&cname.
??????????.LEFT=j*100-60
??????????.TOP=i*40
??????????.CAPTION='按钮 &cname.'
??????????.HEIGHT=25
??????????.WIDTH=80
??????????.VISIBLE=.T.
????????ENDWITH
????????BINDEVENT(THISFORM.&cname.,'click',THISFORM,'_CLICK')
??????ENDFOR
????ENDFOR
????THISFORM.ADDOBJECT('text1','textbox')
????WITH THISFORM.text1
??????.LEFT=80
??????.TOP=160
??????.HEIGHT=25
??????.WIDTH=200
??????.VISIBLE=.T.
????ENDWITH
????THISFORM.LOCKSCREEN=.F.
??ENDPROCENDDEFINE*注意一点:Bindevent引用的代码中慎用“This”引用控件,它指向的还是原方法所在对象。如上例中,如果方法中出现“This”,则,它指的是表单,而不是按钮。??---------------------------------------------------------------
例子4:下列代码将Visual FoxPro主窗口的MouseMove事件绑定到自定义类MyHandler的MyMouseMove方法,绑定后,当在主窗口中移动鼠标时,将显示鼠标的坐标位置。PUBLIC oHandler???????????? &&注意,请将保存对象的变量设置为全局变量 oHandler=NEWOBJECT("MyHandler")??*!* 将_SCREEN.MouseMove绑定到oHandler.MyMouseMove=BINDEVENT(_SCREEN,"MouseMove",oHandler,"MyMouseMove")?? ??DEFINE CLASS MyHandler AS Custom???? ???? PROCEDURE MyMouseMove???????????? *!* 要保证该方法与_SCREEN.MouseMove有同样的参数设置???????????? LPARAMETERS nButton, nShift, nXCoord, nYCoord???? ???????????? WAIT WINDOW "鼠标坐标:"+STR(nXCoord)+"|"+STR(nYCoord) NOWAIT ???? ENDPROC ENDDEFINE9:12 | 添加评论 | 固定链接 | 写入日志 | VFP6月16日

VFP中实现可靠的随机密码和多用户权限控制 (收藏)

?????????? 在应用系统中,经常使用口令实现对系统操作权限的控制,常规的方法是在进入系统时提示操作者输入一个字符串口令。这种口令的设置方法多种多样,有的是将固定口令密码写在程序里,系统开始要求操作者输入该密码,正确方可进入,这种方法的缺点是密码不能改变,且全系统只有一个。还有一种方法是将操作者输入的密码通过加密,转换为加密伪码存储在数据库中,但这种方法的密码和伪码仍有显式的对应关系,容易被破解。本文介绍一种在VFP中用随机伪码存库的方法实现简单可靠的系统加密,并用此方法实现一个应用系统的多用户权限控制,这种方法的特点是实现简单,加密可靠,不易破解,可将一个1至7位的用户密码转换为20位的随机伪码,且每次重新设定密码时所产生的伪码都不相同,通过变换生成的20位伪码没有任何规律性,即使从数据库中擦除伪码也无法进入系统,从而实现了可靠的密码权限控制。 ---- 一、可靠的随机伪码存库 ---- 从用户密码到存库的随机伪码之间的变换由两个函数完成,一个是加密函数,一个是解密函数。加密函数的思想是对用户密码(真码)进行复杂化、隐蔽化处理,也就是将真码淹没在20位伪码中,加密函数如下: FUNCTION?? MAZH1
?????? PARAMETERS?? ZMZ
?????? ZMZ=VAL(ZMZ)
?????? N1=RAND()*10^9
?????? IF N1
?????????????? N1=N1+10^9
?????? ENDI
?????? N1=INT(N1)
?????? C1=STR(N1+ZMZ)+STR(N1)
?????? C2=SUBS(C1,5,20)+SUBS(C1,1,4)
?????? P1=''
?????? P2=''
?????? FOR II=1 TO 10
?????????????? P1=P1+SUBS(C2,2*II-1,1)
?????????????? P2=P2+SUBS(C2,2*II,1)
?????? ENDFOR
?????? WMZ=P1+P2
?????? RETURN?? WMZ
---- 若真码为:1234567,则伪码为:64915302152868193982,无论真码是一位还是相同多位,伪码总是具有同样的不确定性和复杂性,所以若想通过简化真码来分析伪码是不可能的。 ---- 解码函数是将数据库中存放的伪码转换成原用户密码,其代码如下:FUNCTION?? MAZH2
?????? PARAMETERS???? WMZ
?????? PP=''
?????? FOR II=1 TO 10
?????????????? PP=PP+SUBS(WMZ,II,1)+SUBS(WMZ,II+10,1)
?????? ENDFOR
?????? DD=SUBS(PP,17,4)+SUBS(PP,1,16)
?????? M1=SUBS(DD,1,10)
?????? M2=SUBS(DD,11,10)
?????? ZMZ=INT(VAL(M1)-VAL(M2))
?????? RETURN?? ZMZ
---- 由于提交的系统全是编辑的,非法者是无法得到密码转换函数中的信息的,所以解密方法是不易被发现的。 ---- 二、多用户权限控制的实现 ---- 对一个包含多种业务操作的应用系统,由于业务的要求,常需要限制不同操作者的业务操作范围,在VFP中,可以建立一个权限数据表,表中 有多个字段,分别用于存储了每个操作者的代号、姓名、口令以及是否可以操作业务模块的伪标识码,见下表: 工号 姓名 系 统 口 令 业务1操作标识码 业务2操作标识码 … 01 刘君红 71510714108669886598 75913 759130063600536 02817028179076390563 … 02 何晚平 17615822156435449957 8341 3834133074230642 56314563144262342423 …??03 刘棋东 16710714110199886591 044 18701188588160484 83413834133074230642 … 04 赵民 58613143131858393185 4611702 8171696390565 48710144103584210444 …??05 王雪菲 80614563147782342425 52412 171122488399485 53210299114872812320 … … … ??---- 系统的主表单上的多个业务模块由多个按钮来实现启动,那么在系统主表单的[确定]按钮的CLICK EVENT方法程序中添加一些判断代码,就可以实现系统的口令和操作权限控制。输入工号和口令后,按[确定],CLICK EVENT中的代码首先根据输入的工号,对权限数据表中对应记录的口令伪码进行解码,得出的真码与输入口令一致放可进入系统,口令测试通过后,再通过对每个业务所对应的伪标识码字段内容进行解码,确定该业务模块是否允许操作,进而将该模块的启动按钮的ENABLED属性设置为.T.或.F.。为了在系统一启动就打开权限数据表,要将权限表添加到主表单的数据环境中。主表单的一个按钮可以启动“权限维护”表单,该表单可以完成对每个工号的口令和操作权限设置。一般只有系统管理员被赋予“权限维护”的权限,不同工号的操作员在进入系统后可以自行修改自己的密码,而管理员无法知道操作员的密码,只能进行擦除,这一点更加提高了操作员密码的安全性。????---- 以上表单和程序在金长城PII/400机上用Visual Foxpro5.0调试通过 15:55 | 添加评论 | 固定链接 | 写入日志 | VFP

对DBF表进行加密或解密 (收藏)

*前提:被操作的表如果已经打开,一定要先关闭 *---------------------------------------
DBF_JM('temp.dbf',1) &&加密
DBF_JM('temp.dbf',0) &&解密
FUNCTION DBF_JM
??PARAMETERS filename,jm
??IF AT('.',filename)=0 filename=filename+'.dbf' &&处理文件名
??ENDIF
??IF jm=1 &&加密
????handle=FOPEN(filename,2) &&打开文件
????keybite=FREAD(handle,1) &&读表头第一个字节
????=FSEEK(handle,0) &&指针移回第一个字节
????=FWRITE(handle,CHR(ASC(keybite)+2)) &&用比原来高2的ASCII字符改写
????=FCLOSE(handle) &&关闭文件 ELSE &&解密
????handle=FOPEN(filename,2)
????keybite=FREAD(handle,1)
????=FSEEK(handle,0)
????=FWRITE(handle,CHR(ASC(keybite)-2)) &&用比原来低2的ASCII字符改写
????=FCLOSE(handle)
??ENDIF
ENDFUNC
*---------------------------------------
FUNCTION DBF_JieMi &&解密
??PARAMETERS lfile
??lfn=ALLTRIM(lfile)
??lh=FOPEN(lfn,12)
??=FSEEK(lh,0,0)
??=FSEEK(lh,8)
??lk1=FREAD(lh,1)
??lk2=FREAD(lh,1)
??=FSEEK(lh,0,0)
??=FSEEK(lh,8)
??=FWRITE(lh,CHR(ASC(lk1)-2),1)
??=FWRITE(lh,CHR(ASC(lk2)-2),1)
??=FCLOSE(lh)
??RETURN
ENDFUNC
FUNCTION DBF_JiaMi &&加密
??PARAMETERS lfile
??lfn=ALLTRIM(lfile)
??lh=FOPEN(lfn,12)
??=FSEEK(lh,0,0)
??=FSEEK(lh,8)
??lk1=FREAD(lh,1)
??lk2=FREAD(lh,1)
??=FSEEK(lh,0,0)
??=FSEEK(lh,8)
??=FWRITE(lh,CHR(ASC(lk1)+2),1)
??=FWRITE(lh,CHR(ASC(lk2)+2),1)
??=FCLOSE(lh)
??RETURN
ENDFUNC14:33 | 添加评论 | 固定链接 | 写入日志 | VFP

sql详解 (收藏)

Select 用途: 从指定表中取出指定的列的数据 语法: SELECT column_name(s) FROM table_name 解释: 从数据库中选取资料列,并允许从一或多个资料表中,选取一或多个资料列或资料行。SELECT 陈述式的完整语法相当复杂,但主要子句可摘要为:??SELECT select_list [ INTO new_table ] FROM table_source [ WHERE search_condition ] [ GROUP BY group_by_expression ] [ HAVING search_condition ] [ ORDER BY order_expression [ ASC | DESC ] ] 例: “Persons” 表中的数据有 LastName FirstName Address City Hansen Ola Timoteivn 10 Sandnes Svendson Tove Borgvn 23 Sandnes Pettersen Kari Storgt 20 Stavanger 选出字段名” LastName”、” FirstName” 的数据 SELECT LastName,FirstName FROM Persons 返回结果: LastName FirstName Hansen Ola Svendson Tove Pettersen Kari 选出所有字段的数据 SELECT * FROM Persons 返回结果: LastName FirstName Address City Hansen Ola Timoteivn 10 Sandnes Svendson Tove Borgvn 23 Sandnes Pettersen Kari Storgt 20 Stavanger Where 用途: 被用来规定一种选择查询的标准 语法: SELECT column FROM table WHERE column condition &#118;alue 下面的操作符能被使用在WHERE中: =,<>,>,<,>=,<=,BETWEEN,LIKE 注意: 在某些SQL的版本中不等号< >能被写作为!= 解释: SELECT语句返回WHERE子句中条件为true的数据 例: 从” Persons”表中选出生活在” Sandnes” 的人 SELECT * FROM Persons WHERE City='Sandnes' Persons 表中的数据有: LastName FirstName Address City Year Hansen Ola Timoteivn 10 Sandnes 1951 Svendson Tove Borgvn 23 Sandnes 1978 Svendson Stale Kaivn 18 Sandnes 1980 Pettersen Kari Storgt 20 Stavanger 1960 返回结果: LastName FirstName Address City Year Hansen Ola Timoteivn 10 Sandnes 1951 Svendson Tove Borgvn 23 Sandnes 1978 Svendson Stale Kaivn 18 Sandnes 1980 And & Or 用途: 在WHERE子句中AND和OR被用来连接两个或者更多的条件 解释: AND在结合两个布尔表达式时,只有在两个表达式都为 TRUE 时才传回 TRUE OR在结合两个布尔表达式时,只要其中一个条件为 TRUE 时,OR便传回 TRUE 例: Persons 表中的原始数据: LastName FirstName Address City Hansen Ola Timoteivn 10 Sandnes Svendson Tove Borgvn 23 Sandnes Svendson Stephen Kaivn 18 Sandnes 用AND运算子来查找Persons 表中FirstName为”Tove”而且LastName为” Svendson”的数据 SELECT * FROM Persons WHERE FirstName='Tove' AND LastName='Svendson' 返回结果: LastName FirstName Address City Svendson Tove Borgvn 23 Sandnes 用OR运算子来查找Persons 表中FirstName为”Tove”或者LastName为” Svendson”的数据 SELECT * FROM Persons WHERE firstname='Tove' OR lastname='Svendson' 返回结果: LastName FirstName Address City Svendson Tove Borgvn 23 Sandnes Svendson Stephen Kaivn 18 Sandnes 你也能结合AND和OR (使用括号形成复杂的表达式),如: SELECT * FROM Persons WHERE (FirstName='Tove' OR FirstName='Stephen') AND LastName='Svendson' 返回结果: LastName FirstName Address City Svendson Tove Borgvn 23 Sandnes Svendson Stephen Kaivn 18 Sandnes Between…And 用途: 指定需返回数据的范围 语法: SELECT column_name FROM table_name WHERE column_name BETWEEN &#118;alue1 AND &#118;alue2 例: “Persons”表中的原始数据 LastName FirstName Address City Hansen Ola Timoteivn 10 Sandnes Nordmann Anna Neset 18 Sandnes Pettersen Kari Storgt 20 Stavanger Svendson Tove Borgvn 23 Sandnes 用BETWEEN…AND返回LastName为从”Hansen”到”Pettersen”的数据: SELECT * FROM Persons WHERE LastName BETWEEN 'Hansen' AND 'Pettersen' 返回结果: LastName FirstName Address City Hansen Ola Timoteivn 10 Sandnes Nordmann Anna Neset 18 Sandnes Pettersen Kari Storgt 20 Stavanger 为了显示指定范围之外的数据,也可以用NOT操作符: SELECT * FROM Persons WHERE LastName NOT BETWEEN 'Hansen' AND 'Pettersen' 返回结果: LastName FirstName Address City Svendson Tove Borgvn 23 Sandnes Distinct 用途: DISTINCT关键字被用作返回唯一的值 语法: SELECT DISTINCT column-name(s) FROM table-name 解释: 当column-name(s)中存在重复的值时,返回结果仅留下一个 例: “Orders”表中的原始数据 Company OrderNumber Sega 3412 W3Schools 2312 Trio 4678 W3Schools 6798 用DISTINCT关键字返回Company字段中唯一的值: SELECT DISTINCT Company FROM Orders 返回结果: Company Sega W3Schools Trio Order by 用途: 指定结果集的排序 语法: SELECT column-name(s) FROM table-name ORDER BY { order_by_expression [ ASC | DESC ] } 解释: 指定结果集的排序,可以按照ASC(递增方式排序,从最低值到最高值)或者DESC(递减方式排序,从最高值到最低值)的方式进行排序,默认的方式是ASC 例: “Orders”表中的原始数据: Company OrderNumber Sega 3412 ABC Shop 5678 W3Schools 2312 W3Schools 6798 按照Company字段的升序方式返回结果集: SELECT Company, OrderNumber FROM Orders ORDER BY Company 返回结果: Company OrderNumber ABC Shop 5678 Sega 3412 W3Schools 6798 W3Schools 2312 按照Company字段的降序方式返回结果集: SELECT Company, OrderNumber FROM Orders ORDER BY Company DESC 返回结果: Company OrderNumber W3Schools 6798 W3Schools 2312 Sega 3412 ABC Shop 5678 Group by 用途: 对结果集进行分组,常与汇总函数一起使用。 语法: SELECT column,SUM(column) FROM table GROUP BY column 例: “Sales”表中的原始数据: Company Amount W3Schools 5500 IBM 4500 W3Schools 7100 按照Company字段进行分组,求出每个Company的Amout的合计: SELECT Company,SUM(Amount) FROM Sales GROUP BY Company 返回结果: Company SUM(Amount) W3Schools 12600 IBM 4500 Having 用途: 指定群组或汇总的搜寻条件。 语法: SELECT column,SUM(column) FROM table GROUP BY column HAVING SUM(column) condition &#118;alue 解释: HAVING 通常与 GROUP BY 子句同时使用。不使用 GROUP BY 时,HAVING 则与 WHERE 子句功能相似。 例: “Sales”表中的原始数据: Company Amount W3Schools 5500 IBM 4500 W3Schools 7100 按照Company字段进行分组,求出每个Company的Amout的合计在10000以上的数据: SELECT Company,SUM(Amount) FROM Sales GROUP BY Company HAVING SUM(Amount)>10000 返回结果: Company SUM(Amount) W3Schools 12600 Join 用途: 当你要从两个或者以上的表中选取结果集时,你就会用到JOIN。 例: “Employees”表中的数据如下,(其中ID为主键): ID Name 01 Hansen, Ola 02 Svendson, Tove 03 Svendson, Stephen 04 Pettersen, Kari “Orders”表中的数据如下: ID Product 01 Printer 03 Table 03 Chair 用Employees的ID和Orders的ID相关联选取数据: SELECT Employees.Name, Orders.Product FROM Employees, Orders WHERE Employees.ID = Orders.ID 返回结果: Name Product Hansen, Ola Printer Svendson, Stephen Table Svendson, Stephen Chair 或者你也可以用JOIN关键字来完成上面的操作: SELECT Employees.Name, Orders.Product FROM Employees INNER JOIN Orders ON Employees.ID = Orders.ID INNER JOIN的语法: SELECT field1, field2, field3 FROM first_table INNER JOIN second_table ON first_table.keyfield = second_table.foreign_keyfield 解释: INNER JOIN返回的结果集是两个表中所有相匹配的数据。 LEFT JOIN的语法: SELECT field1, field2, field3 FROM first_table LEFT JOIN second_table ON first_table.keyfield = second_table.foreign_keyfield 用”Employees”表去左外联结”Orders”表去找出相关数据: SELECT Employees.Name, Orders.Product FROM Employees LEFT JOIN Orders ON Employees.ID = Orders.ID 返回结果: Name Product Hansen, Ola Printer Svendson, Tove Svendson, Stephen Table Svendson, Stephen Chair Pettersen, Kari 解释: LEFT JOIN返回”first_table”中所有的行尽管在” second_table”中没有相匹配的数据。 RIGHT JOIN的语法: SELECT field1, field2, field3 FROM first_table RIGHT JOIN second_table ON first_table.keyfield = second_table.foreign_keyfield 用”Employees”表去右外联结”Orders”表去找出相关数据: SELECT Employees.Name, Orders.Product FROM Employees RIGHT JOIN Orders ON Employees.ID = Orders.ID 返回结果: Name Product Hansen, Ola Printer Svendson, Stephen Table Svendson, Stephen Chair 解释: RIGHT JOIN返回” second_table”中所有的行尽管在”first_table”中没有相匹配的数据。 Alias 用途: 可用在表、结果集或者列上,为它们取一个逻辑名称 语法: 给列取别名: SELECT column AS column_alias FROM table 给表取别名: SELECT column FROM table AS table_alias 例: “Persons”表中的原始数据: LastName FirstName Address City Hansen Ola Timoteivn 10 Sandnes Svendson Tove Borgvn 23 Sandnes Pettersen Kari Storgt 20 Stavanger 运行下面的SQL: SELECT LastName AS Family, FirstName AS Name FROM Persons 返回结果: Family Name Hansen Ola Svendson Tove Pettersen Kari 运行下面的SQL: SELECT LastName, FirstName FROM Persons AS Employees 返回结果: Employees中的数据有: LastName FirstName Hansen Ola Svendson Tove Pettersen Kari Insert Into 用途: 在表中插入新行 语法: 插入一行数据 INSERT INTO table_name &#118;alueS (&#118;alue1, &#118;alue2,....) 插入一行数据在指定的字段上 INSERT INTO table_name (column1, column2,...) &#118;alueS (&#118;alue1, &#118;alue2,....) 例: “Persons”表中的原始数据: LastName FirstName Address City Pettersen Kari Storgt 20 Stavanger 运行下面的SQL插入一行数据: INSERT INTO Persons &#118;alueS ('Hetland', 'Camilla', 'Hagabakka 24', 'Sandnes') 插入后”Persons”表中的数据为: LastName FirstName Address City Pettersen Kari Storgt 20 Stavanger Hetland Camilla Hagabakka 24 Sandnes 运行下面的SQL插入一行数据在指定的字段上: INSERT INTO Persons (LastName, Address) &#118;alueS ('Rasmussen', 'Storgt 67') 插入后”Persons”表中的数据为: LastName FirstName Address City Pettersen Kari Storgt 20 Stavanger Hetland Camilla Hagabakka 24 Sandnes Rasmussen Storgt 67 Update 用途: 更新表中原有数据 语法: UPDATE table_name SET column_name = new_&#118;alue WHERE column_name = some_&#118;alue 例: “Person”表中的原始数据: LastName FirstName Address City Nilsen Fred Kirkegt 56 Stavanger Rasmussen Storgt 67 运行下面的SQL将Person表中LastName字段为”Rasmussen”的FirstName更新为”Nina”: UPDATE Person SET FirstName = 'Nina' WHERE LastName = 'Rasmussen' 更新后”Person”表中的数据为: LastName FirstName Address City Nilsen Fred Kirkegt 56 Stavanger Rasmussen Nina Storgt 67 同样的,用UPDATE语句也可以同时更新多个字段: UPDATE Person SET Address = 'Stien 12', City = 'Stavanger' WHERE LastName = 'Rasmussen' 更新后”Person”表中的数据为: LastName FirstName Address City Nilsen Fred Kirkegt 56 Stavanger Rasmussen Nina Stien 12 Stavanger Delete 用途: 删除表中的数据 语法: DELETE FROM table_name WHERE column_name = some_&#118;alue 例: “Person”表中的原始数据: LastName FirstName Address City Nilsen Fred Kirkegt 56 Stavanger Rasmussen Nina Stien 12 Stavanger 删除Person表中LastName为”Rasmussen”的数据: DELETE FROM Person WHERE LastName = 'Rasmussen' 执行删除语句后”Person”表中的数据为: LastName FirstName Address City Nilsen Fred Kirkegt 56 Stavanger Create Table 用途: 建立新的资料表。 语法: CREATE TABLE table_name ( column_name1 data_type, column_name2 data_type, ....... ) 例: 创建一张叫“Person”的表,该表有4个字段LastName, FirstName, Address, Age: CREATE TABLE Person ( LastName varchar, FirstName varchar, Address varchar, Age int ) 如果想指定字段的最大存储长度,你可以这样: CREATE TABLE Person ( LastName varchar(30), FirstName varchar(30), Address varchar(120), Age int(3) ) 下表中列出了在SQL的一些数据类型: Data Type Description integer(size) int(size) smallint(size) tinyint(size) Hold integers only. The maximum number of digits are specified in parenthesis. decimal(size,d) numeric(size,d) Hold numbers with fractions. The maximum number of digits are specified in size. The maximum number of digits to the right of the decimal is specified in d. char(size) Holds a fixed length string (can contain letters, numbers, and special characters). The fixed size is specified in parenthesis. varchar(size) Holds a variable length string (can contain letters, numbers, and special characters). The maximum size is specified in parenthesis. date(yyyymmdd) Holds a date Alter Table 用途: 在已经存在的表中增加后者移除字段 语法: ALTER TABLE table_name ADD column_name datatype ALTER TABLE table_name DROP COLUMN column_name 注意:某些数据库管理系统不允许移除表中的字段 例: “Person”表中的原始数据: LastName FirstName Address Pettersen Kari Storgt 20 在Person表中增加一个名为City的字段: ALTER TABLE Person ADD City varchar(30) 增加后表中数据如下: LastName FirstName Address City Pettersen Kari Storgt 20 移除Person表中原有的Address字段: ALTER TABLE Person DROP COLUMN Address 移除后表中数据如下: LastName FirstName City Pettersen Kari Drop Table 用途: 在数据库中移除一个数据表定义及该数据表中的所有资料、索引、触发程序、条件约束及权限指定。 语法: DROP TABLE table_name Create Database 用途: 建立新的数据库. 语法: CREATE DATABASE database_name Drop Database 用途: 移除原有的数据库 语法: DROP DATABASE database_name 聚集函数 count 用途: 传回选取的结果集中行的数目。 语法: SELECT COUNT(column_name) FROM table_name 例: “Persons”表中原始数据如下: Name Age Hansen, Ola 34 Svendson, Tove 45 Pettersen, Kari 19 选取记录总数: SELECT COUNT(Name) FROM Persons 执行结果: 3 sum 用途: 以表达式传回所有值的总和,或仅 DISTINCT 值。SUM 仅可用于数值资料行。已忽略 Null 值。 语法: SELECT SUM(column_name) FROM table_name 例: “Persons”表中原始数据如下: Name Age Hansen, Ola 34 Svendson, Tove 45 Pettersen, Kari 19 选取”Persons”表中所有人的年龄总和: SELECT SUM(Age) FROM Persons 执行结果: 98 选取”Persons”表中年龄超过20岁的人的年龄总和: SELECT SUM(Age) FROM Persons WHERE Age>20 执行结果: 79 avg 用途: 传回选取的结果集中值的平均值。已忽略 Null 值。 语法: SELECT AVG(column_name) FROM table_name 例: “Persons”表中原始数据如下: Name Age Hansen, Ola 34 Svendson, Tove 45 Pettersen, Kari 19 选取”Persons”表中所有人的平均年龄: SELECT AVG(Age) FROM Persons 执行结果: 32.67 选取”Persons”表中年龄超过20岁的人的平均年龄: SELECT AVG(Age) FROM Persons WHERE Age>20 执行结果: 39.5 max 用途: 传回选取的结果集中值的最大值。已忽略 Null 值。 语法: SELECT MAX(column_name) FROM table_name 例: “Persons”表中原始数据如下: Name Age Hansen, Ola 34 Svendson, Tove 45 Pettersen, Kari 19 选取”Persons”表中的最大年龄: SELECT MAX(Age) FROM Persons 执行结果: 45 min 用途: 传回选取的结果集中值的最小值。已忽略 Null 值。 语法: SELECT MIN(column_name) FROM table_name 例: “Persons”表中原始数据如下: Name Age Hansen, Ola 34 Svendson, Tove 45 Pettersen, Kari 19 选取”Persons”表中的最小年龄: SELECT MIN(Age) FROM Persons 执行结果: 19 算术函数 abs 用途: 传回指定数值表达式 (Numeric Expression) 的绝对正值。 语法: ABS(numeric_expression) 例: ABS(-1.0) ABS(0.0) ABS(1.0) 执行结果: 1.0 0.0 1.0 ceil 用途: 传回大于等于给定数值表达式的最小整数。 语法: CEIL(numeric_expression) 例: CEIL(123.45) CEIL(-123.45) 执行结果: 124.00 -123.00 floor 用途: 传回小于或等于给定数值表达式的最大整数。 语法: FLOOR(numeric_expression) 例: FLOOR(123.45) FLOOR(-123.45) 执行结果: 123.00 -124.00 cos 用途: 在指定表达式中传回指定角度 (以弪度为单位) 的三角余弦值的数学函数。 语法: COS(numeric_expression) 例: COS(14.7 执行结果: -0.599465 cosh 用途: 传回以弧度为单位的角度值,其余弦为指定的 float 表达式,也称为反余弦。 语法: COSH(numeric_expression) 例: COSH(-1) 执行结果: 3.14159 sin 用途: 以近似的数值 (float) 表达式传回给定角度 (以弧度) 之三角正弦函数 (Trigonometric Sine)。 语法: SIN(numeric_expression) 例: SIN(45.175643) 执行结果: 0.929607 sinh 用途: 传回以弪度为单位的角度,其正弦为指定的 float 表达式 (也称为反正弦)。 语法: SINH(numeric_expression) 例: SINH(-1.00) 执行结果: -1.5708 tan 用途: 传回输入表达式的正切函数。 语法: TAN(numeric_expression) 例: TAN(3.14159265358979/2) 执行结果: 1.6331778728383844E+16 tanh 用途: 传回以弪度为单位的角度,其正切为指定的 float 表达式 (也称为反正切)。 语法: TANH(numeric_expression) 例: TANH(-45.01) 执行结果: -1.54858 exp 用途: 传回给定的 float 表达式的指数 (Exponential) 值。 语法: EXP(numeric_expression) 例: EXP(378.615345498) 执行结果: 2.69498e+164 log 用途: 传回给定的 float 表达式之自然对数。 语法: LOG(numeric_expression) 例: LOG(5.175643) 执行结果: 1.64396 power 用途: 传回给定表达式指定乘幂的值。 语法: POWER(numeric_expression,v) 例: POWER(2,6) 执行结果: 64 sign 用途: 传回给定的表达式之正 (+1)、零 (0) 或负 (-1) 号。 语法: SIGN(numeric_expression) 例: SIGN(123) SIGN(0) SIGN(-456) 执行结果: 1 0 -1 sqrt 用途: 传回给定表达式的平方。 语法: SQRT(numeric_expression) 例: SQRT(10) 执行结果: 10014:27 | 添加评论 | 固定链接 | 写入日志 | VFP

VFP 5.0远程视图使用面面观 (收藏)

武汉交通科技大学计算机系 吴业福 袁小玲??  摘要:远程视图是Visual Foxpro 5.0 中开发Client/Server 应用系统的基础,本文首先介绍了远程视图有关参数的放置技巧,然后介绍如何去设计、使用远程视图,最后讨论了使用远程视图的四个实际问题。??  关键词:远程视图;远程数据;连接;锁定;缓冲。??一、绪论??  VFP 是一种较好的客户/ 服务器应用系统开发工具,用VFP 开发C/S 系统的关键是如何访问远程数据( 远程服务器中的Table/View)。可以使用VFP 提供的SQL Pass-Through 函数访问远程数据,但最常用的方法是使用远程视图(Remote View) 去访问远程数据。本文结合本人的使用经验对远程视图的使用技巧加以介绍。??二、远程视图的环境设置   在设计远程视图时,需要对远程视图的有关环境信息进行设置。使用Tools 菜单中的Options.... 选项来设置Remote Data 选项。其选项设置说明如下:   *Share Connection: 指出今后设计的远程视图是否使用共享连接。使用共享连接可大大减少数据库服务器中客户访问许可数,但会影响客户机的访问速度。   *SQL Updates/Criteria: 指出对后台数据进行update 操作的条件。??  它有四种可能:??  ①Key Field only?????????? ②Key and Updatable Fields   ③Key and Modified Fields ?????????? ④Key and Time Stamp。   一般选择③较合适。??  *SQL Updates/Method: 指出对后台数据的更新方法。   它有两种选择:①SQL Delete then Insert ②SQL update。   一般选择②比较合适。   *Connection Defaults: 主要用于SQL Pass-Through 函数访问远程数据,对于远程视图则不需要放置。??三、远程视图的设计??  有两种方法设计远程视图,一是使用View Designer;二是使用SQL 语句。用View Designer 可设计较为简单的视图,而使用SQL 的Create Remote View 语句则可进行复杂视图的设计。如果试图去用View Designer 观察或修改( 用Create 创建的视图) 则极有可能被破坏它( 例如:若创建视图的Select 语句中含有exists 子句, 则一定会被破坏!)   1. 用Create 命令设计??  例如:假定连接名为WYFconnect,两个远程表为SealList 和ShipList. Create 命令可如下:??  CREATE SQL VIEW ViewTest REMOTE CONNECTION WYFconnect AS SELECT SealList.* FROM SealList, ShipList WHERE SealList IS NOT NULL AND SealList AND 箱号NOT IN (SELECT 箱号FROM ShipList WHERE ShipList. 箱号IS NOT NULL AND ShipList. 船名=SealList. 船名   使用该方法可以在程序中动态地构造满足不同条件的远程视图(View Designer 不能构造带参数的远程视图)。例如:设m.ShipName 为一可变内存变量,其创建语句为:   CREATE SQL VIEW ViewTest REMOTE CONNECTION WYFconnect AS SELECT * FROM SealList WHERE 船名=m.ShipName.   2. 用View Designer 设计   启动View Designer 选择连接名后出现设计图, 在其上部可以加入远程服务器中的表或视图,在其下部进行参数/ 条件设置:   *Select Criteria: 设置远程数据值上的记录必须满足的条件,类似于下SQL Select 语句中的Where 子句。在这里可以构造复杂条件,但条件中使用的函数和语法规则必须是后台数据库支持的,例如:不能使用DTOC( 日期)=‘90/01/01’,而必须使用Convert(char(10), 日期)=‘90/01/01’, 因为后台数据库不支持DTOC() 函数。   *Fields: 选择结果集中的字段,在这里要强调的是Function/Expression 的使用,使用它可构造出与源表字段不同的字段,如:T. 船名+‘’+T. 中文AS 船舶。实践证明Function/Expression 中不能使用双引号,而只能使用单引号。   *Order by 和Group by: 对结果分组、分类。要求符合后台数据库所支持的SQL 语法。   *Update Criteria: 设置视图的有关替换参数, 具体如下:??  ①要选中Send SQL Update??  ②SQL where 一般选择Key and Modify Fields??  ③Update Using 一般选择SQL Update ??  ④务请选择关键字段和可更改字段( 在钥匙符号下面和铅笔符号下面加“√”),否则将无法正确完成Insert/update 功能。??四、远程视图的使用??  1. 缓冲与锁定设置   对于远程视图,建议使用缓冲机制来提高远程视图的工作效率和使用的方便性。首先在Option 菜单中设置Data 组件,需设置下列参数:   ①选择Open Exclusive 以让库共享打开,库中的远程视图则可共享使用;   ②Locking And Buffering 设置:选中Automatic File locking 和Multiple Record Locks,并将Buffering 设置成Fields Buffering,加锁方式设置为“记录级乐观锁定”。在具体设计Form 时,对数据环境中的每一个远程视图光标可重新根据需要来设置锁定和缓冲机制。如果不重新设置,它取Form 的缺省设置。   2. 数据的写入与前台刷新   对于采用了Buffering 技术的远程视图,当修改/ 删除/ 增加了记录时,需用TableUpdate(.T.,.T.) 函数来确保数据写到后台数据库中;若要取消对缓冲区中视图数据的修改,需用TableRevert(.T.) 函数。例如:   Select View1 Append Blank Begin Transaction if TableUpdate(.T.,.T.) EndTranseaction else RollBack =TableRevert( ·T ·) endif   如果该远程视图与别的表/ 远程视图发生级联修改/ 删除/ 增加关系,则需使用事务机制,以确保数据的完整性。??  如果对应视图的后台表/ 视图数据发生变化时,使用下述方法让前台客户机中的数据与实际后台数据一致:??  ①Select 〈远程视图名〉   USE〈远程视图名〉&& 再次打开即可??  ②Select 〈远程视图名〉   =Requery() && 刷新缓冲区值 五、远程视图使用中碰到的若干问题????  1. 如何在一个远程视图中多次使用同一远程数据源? ??  依靠别名。例如:Select A. 船名,A. 航次,B. 姓名as 操作员,C. 姓名as 仓库员from Shipname A, worker B, worker C where A. 操作员代码=B.Code and A. 仓库员代码=C.Code   2. 设计远程视图时Select 语句的语法应符合VFP 或后台数据库? ??  后台数据库支持的SQL 语法。例如:Create SQL View AAA Remote Conection BB As Select A.* From Shipname A Where Convert(Char(10), 进港日期)=‘1998/05/30’   3. 远程视图能否使用Pack 和Recall 语句? ??  不能使用pack 语句,例如: use View1; delete for 〈条件〉 && 加删除标志 pack && 错误,必须使用TableUpdate () 函数   对于Recall 命令,如果已执行了TableUpdate(),则执行无效; 若未发Tableupdate(), 则可用Recall 来取消删除标记。??  4. 本地视图的数据源有远程视图,如何刷新本地视图? ??  例如:有两个远程视图Rview1 Rview2, 创建本地视图的命令为:Create SQL view As Select A.* B.* from Rview1 A,R view2 B where A. 箱号=B. 箱号??  刷新view 之前必须先刷新Rview1 和Rview2: =requery (“Rview1”) =Requery (“Rview2”) =Refresh (“view”) 六、小结   远程视图是VFP 访问远程数据服务器中数据的有利武器,有了前面的介绍,就可得心应手地设计C/S 应用系统了。??参考文献   〔1 〕E.sander 等著visual FoxPro3.0 实用指南机械工业出版社1996   The Skills of Using Remote View in Visual Foxpro 5.0   Wuyefu and Yuanxiaoling   Dept. Computer, Wuhan Transac