标题:VFP封装结构类型示例
取消只看楼主
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用sych在2022-3-17 08:21:08的发言:

取不了目录

这个是取文件名对话框,取文件夹对话框是另一个API,有空可以写个示例。
2022-03-17 08:38
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用cssnet在2022-3-16 10:53:44的发言:
其实当时我说的指针,指的是回调函数指针。
一般若遇太过复杂的Windows API调用,在VFP中我会选择直接放弃。
倘若有可能,则会在VC写的DLL中新增一个函数,用C处理好,然后返回结果让VFP程序直接使用。
如此一来,就不必非要勉强VFP去处理它本就不擅长的、或处理起来相当困难、相当笨拙的、涉及到Windows系统核心部分的API调用。
当然,这就要求VFPer应当具备最起码的VC编程基础。
不过,既然已经要用到比较复杂的Api了,那么掌握C应当也算是最起码的程序员基本功罢?

1、回调函数问题。是函数类型指针(函数指针)的问题,VFP是没有这概念,原因是解释语言,通常函数指针是静态编译的产物。
有兴趣可以试试用其他语言写个相对通用的接口来处理部分VFP需要的“回调函数”问题。

2、VFP调用API的必要性问题。试回想一下好多年前(或VFP的前身年代),VFP基本上都很少讨论API,因为那时VFP已经感觉到自己很强大。
随着时代的发展进步,VFP却遭遇不幸得不到相应的发展,在不少方面已经不适应时代要求,尤其是进入互联网时代,VFP自己也感觉有些力不从心了。这时候VFPer也很无奈。年轻有精力的可以另谋高就转行,但相信这时不少VFPer都奔5奔6,甚至有奔7,要这把年纪的去休掉VFP另娶谈何容易,也不现实。要吃饭,程序还是要做下去,只能深挖VFP的潜能,将《深入Windows核心编程》在VFP得到应用。


2022-03-17 09:35
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用sych在2022-3-17 08:47:23的发言:

为根目录的时候多一个“\”

你截图来看看
我这未见异常

2022-03-17 09:42
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
调用 WinApi 回避不了指针,有必要讨论一下指针的问题。

不少初接触指针的人,也感觉指针不好学、难把握好。可能是因为一开始接触的编程语言太高级,对指针感觉太抽象。想当年DOS时代也有用debug命令来写汇编生成com,没有什么变量名、数据类型等等高级货,全是与寄存器、地址打交道。建议学编程的一定要了解一下汇编,最起码能看得明白基本常用的代码。不论什么编程语言写出来的程序,机器码(汇编)是他的最终归宿。

指针,不管对新手还是老手来说,都有犯错的可能,这不奇怪,很正常的事。有个“C0000005”的异常代号应该不陌生,还有以前的Wndows蓝屏也是常事,这大都是指针的开放性不受约束带来的问题,编程的一不小心指针就会犯傻。所以,现在的高级编程语言也有不引入指针的概念,希望少犯傻。VFP也有涉及到指针的命令,如SYS(2600,,),这命令会有可能犯傻的,之前就有贴讨论过这问题。

凡事要一分为二看,不要因指针会犯傻就不用。指针是个好东东,有时没他整不出好东东来。之前不久有贴讨论过从网页获取量大的JSON数据问题,用VFP字符串命令解释出全部数据要80多秒,放入JS对象解释要几秒,调用API用指针解释不到1秒,就是传说中的“秒杀”。所以,必要时该出手就要出手。


2022-03-17 11:15
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用sych在2022-3-17 11:17:53的发言:

单独选择一个文件时,正常
一次选择多个文件时,且是根目录下的文件时,会多一个“\”

确是,谢指正!
要改两句
程序代码:
        IF nDialogType==0 AND nLen > 0
            **cPaht = cFiles
            cPaht = ADDBS(cFiles)
            cFiles = ""
            DO WHILE nLen > 0        && 多选
                **cFiles = cFiles  + cPaht + "\" +  SYS(2600, pFile, nLen) + 0h0D0A
                cFiles = cFiles  + cPaht + SYS(2600, ptr, nLen) + 0h0D0A
                ptr = ptr + nLen + 1
                nLen   = apiStrlen(ptr)
            ENDDO
            cFiles = RTRIM(cFiles,0h0D0A)
        ENDIF   


[此贴子已经被作者于2022-3-18 04:36编辑过]

2022-03-17 11:34
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用吹水佬在2022-3-17 06:46:37的发言:

注意了!先截取上述示例部分相关代码,存在BUG。

继续指针的问题
示例存在一个使用指针时出现的 BUG --- 内存泄漏。
这种使用指针的错误有时还真不容易发现,因为他不是运行到相关语句时就一定会抛出异常,也许运行到一定时间后会突然抛出类似“内存不足”、“内存分配错误”等等的异常。所以,这个问题一定要重视,平时使用指针要养成良好的习惯。

  主要相关语句:

1、pFile = apiMalloc(nBuffSize)
2、pFile  = pFile + nLen + 1
3、apiFree(pFile)

先简单了解一下堆内存分配和释放过程:
调用 Malloc 时分配一块连续的内存单元,并记录这块内存的首址,同时将首址返回给调用 Malloc 的过程存放在 pFile。
调用 Free 时释放一块内存,传入的参数 pFile 是由 Malloc 分配的这块内存首址,系统先在管理分配内存块的链表里查找地址是 pFile 记录,找到时就删除这条记录,释放被管制的内存空间,给再次 Malloc 时分配使用。
问题来了,要正常 Free 就要确保 pFile 是由 Malloc 分配的这块内存首址。这里有两点是重点:一是 Malloc 与 Free 必须是成对出现的,也就是说有 Malloc 必有 Free ;二是 pFile 一定要是由 Malloc 返回的首地址的值。
好了,现在问题就清晰了,出现 BUG 的语句就是:

  pFile  = pFile + nLen + 1

执行这句后 pFile 发生改变了,已经不是这块内存首址,当执行 Free 时已经无法找到由 Malloc 分配的这块内存记录,导致释放内存资源出现异常或不能释放造成“内存泄漏”。

要避免这类错误,一定要记住:保管好由 Malloc 返回的指针。
可以这样操作:

  pTmp = pFile
  pTmp = pTmp + nLen + 1
  nLen = apiStrlen(pTmp)
  cFiles = SYS(2600, pTmp, nLen)

东指指,西指指
都医不好我的痴
今晚只有一再心思思
永远单思
2022-03-17 15:08
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用csyx在2022-3-17 14:58:47的发言:


期待早日看到同样风格的取文件夹功能,vfp的GetDir函数样式跟吹版的GetFile实在不协调


只贴出新增加的代码,看看之前的贴出的代码自己分别加入 StructCalss.h 和 StructCalss.prg
头文件新增
程序代码:
** Browsing for directory.
#define BIF_RETURNONLYFSDIRS   0x0001  && For finding a folder to start document searching
#define BIF_DONTGOBELOWDOMAIN  0x0002  && For starting the Find Computer
#define BIF_STATUSTEXT         0x0004  && Top of the dialog has 2 lines of text for BROWSEINFO.lpszTitle and one line if
                                       && this flag is set.  Passing the message BFFM_SETSTATUSTEXTA to the hwnd can set the
                                       && rest of the text.  This is not used with BIF_USENEWUI and BROWSEINFO.lpszTitle gets
                                       && all three lines of text.
#define BIF_RETURNFSANCESTORS  0x0008
#define BIF_EDITBOX            0x0010  && Add an editbox to the dialog
#define BIF_VALIDATE           0x0020  && insist on valid result (or CANCEL)

#define BIF_NEWDIALOGSTYLE     0x0040  && Use the new dialog layout with the ability to resize
                                       && Caller needs to call OleInitialize() before using this API

#define BIF_USENEWUI           (BIF_NEWDIALOGSTYLE + BIF_EDITBOX)

#define BIF_BROWSEINCLUDEURLS  0x0080  && Allow URLs to be displayed or entered. (Requires BIF_USENEWUI)

#define BIF_BROWSEFORCOMPUTER  0x1000  && Browsing for Computers.
#define BIF_BROWSEFORPRINTER   0x2000  && Browsing for Printers
#define BIF_BROWSEINCLUDEFILES 0x4000  && Browsing for Everything
#define BIF_SHAREABLE          0x8000  && sharable resources displayed (remote shares, requires BIF_USENEWUI)

新增结构类
程序代码:
DEFINE CLASS BROWSEINFOA AS STRUCT_CALSS
    PROCEDURE init
        DIMENSION this.aSTRUCT[8,4]
        this.stInit(1,  "hwndOwner",      "N",4)
        this.stInit(2,  "pidlRoot",       "N",4)
        this.stInit(3,  "pszDisplayName", "N",4)
        this.stInit(4,  "lpszTitle",      "N",4)
        this.stInit(5,  "ulFlags",        "N",4)
        this.stInit(6,  "lpfn",           "N",4)
        this.stInit(7,  "lParam",         "N",4)
        this.stInit(8,  "iImage",         "N",4)
        STRUCT_CALSS::init
    ENDPROC
ENDDEFINE

新增API
程序代码:
    DECLARE LONG CoTaskMemFree IN Ole32 LONG
     
    DECLARE long ILCreateFromPath    IN shell32 string@ 
    DECLARE long SHBrowseForFolder   IN shell32 long
    DECLARE long SHGetPathFromIDList IN shell32 long, long

demo
程序代码:
**     
**    StructCalss_DirDialog.prg 
**     
#INCLUDE StructCalss.h
SET PROCEDURE TO StructCalss.prg ADDITIVE
LoadApi() 

? myGetDir("C:\temp")

SET PROCEDURE TO
CLEAR ALL
RETURN

FUNCTION myGetDir(cDefDir)
    LOCAL bi, pDir, cDir, pci, pit
    pDir = apiMalloc(MAX_PATH)

    cDefDir = STRCONV(ADDBS(cDefDir)+0h00, 5)
    pci = ILCreateFromPath(@cDefDir)
    
    bi = CREATEOBJECT("BROWSEINFOA")
    bi.setValue("pidlRoot",       pci)
    bi.setValue("pszDisplayName", pDir)
    bi.setValue("ulFlags",        BIF_BROWSEINCLUDEFILES)
    
    pit = SHBrowseForFolder(bi.pBuffer)
  
    IF pit > 0
        SHGetPathFromIDList(pit, pDir)
        cDir = SYS(2600, pDir, apiStrlen(pDir))
        CoTaskMemFree(pit)
    ENDIF
    CoTaskMemFree(pci)
    apiFree(pDir)
    RETURN cDir
ENDFUNC

2022-03-17 21:28
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
回复 34楼 csyx
这个够强大的,VFP的表单应该就可以设计出来。
如果只是取文件夹或文件名,没必要搞得那么强大。

[此贴子已经被作者于2022-3-17 21:49编辑过]

2022-03-17 21:47
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用csyx在2022-3-17 21:36:26的发言:
照说api可以整出取文件的,取文件夹的应该也能吧

不用API,就用VFP自己的设计器就可以,拉几个控件到表单,显示文件夹和文件用操作系统提供的列表框控件,VFP的命令就可以遍历文件夹和文件。
2022-03-17 21:57
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
回复 36楼 csyx
有可能是调用 windows shell 的类
这贴主要是探讨封装调用API时用到的“结构类型”类,借调用API举例,不是设计什么完整的功能模块。
2022-03-17 22:03



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-508553-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.148165 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved