标题:VFP封装结构类型示例
取消只看楼主
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
结帖率:100%
已结贴  问题点数:20 回复次数:37 
VFP封装结构类型示例
近日,有贴谈到“调用Windows API时,如何正确地传递struct(结构体)参数”的问题。
连接:https://bbs.bccn.net/thread-508544-1-1.html

VFP调用API涉及到结构类型,通常是用字符串来表达结构类型成员数据,这方法看似简单,
但易读性差,很不好理解,尤其对初接触调用API的容易搞错。

封装结构类型的类,可提高VFP语言的表达能力,提高学习编程效率。

示例以 PARAFORMAT2 结构简单描述,对于复杂的结构体有待探讨


程序代码:
**    VFP封装结构类型示例
**    思路:
**    定义一个二维数组(aSTRUCT)用来描述结构体成员属性
**    每一行表达一个成员属性:名称(Name),类型(Type), 大小(Size),地址偏移量(Offset)
**    定义 STRUCT_ARRAY 类,提供初始化结构成员属性函数 stInit()
**    定义 STRUCT_CALSS 类,提供读写结构成员数据函数 getValue()、setValue()

DECLARE long malloc IN msvcrt as apiMalloc long
DECLARE long free IN msvcrt as apiFree long
DECLARE long SendMessage IN user32 as apiSendMessage long,long,long,long

of = CREATEOBJECT("form1")
of.show(1)
CLEAR ALL
RETURN

DEFINE CLASS form1 as Form 
    ADD OBJECT rich AS Olecontrol WITH top=10,left=10,width=200,height=200,OleClass="RICHTEXT.RichtextCtrl.1",visible=1
    PROCEDURE rich.init
        this.text = ""
        pf = CREATEOBJECT("PARAFORMAT2")
        st = CREATEOBJECT("STRUCT_CALSS", pf)
        st.setValue("cbSize", st.nSize)
        st.setValue("dwMask", 256)
        st.setValue("dyLineSpacing", 300)
        st.setValue("bLineSpacingRule", 4)
        #define WM_USER 0x0400
        #define EM_SETPARAFORMAT (WM_USER + 71)
        apiSendMessage(this.hWnd, EM_SETPARAFORMAT, 0, st.pBuffer)
        RELEASE st,pf
        this.text = "123456789"+0h0D0A+"abcdefghijk"+0h0D0A+"ABCDEFGHIJK"++0h0D0A
    ENDPROC
ENDDEFINE

DEFINE CLASS PARAFORMAT2 AS STRUCT_ARRAY
    PROCEDURE init
        DIMENSION this.aSTRUCT[24,4]
        this.stInit(1,  "cbSize",           "N",4)    && DWORD
        this.stInit(2,  "dwMask",           "N",4)
        this.stInit(3,  "wNumbering",       "N",2)    && WORD
        this.stInit(4,  "wEffects",         "N",2)
        this.stInit(5,  "dxStartIndent",    "N",4)
        this.stInit(6,  "dxRightIndent",    "N",4)
        this.stInit(7,  "dxOffset",         "N",4)
        this.stInit(8,  "wAlignment",       "N",2)
        this.stInit(9,  "cTabCount",        "N",2)
        this.stInit(10, "rgxTabs",          "C",128)  && DWORD[MAX_TAB_STOPS], MAX_TAB_STOPS=32
        this.stInit(11, "dySpaceBefore",    "N",4)
        this.stInit(12, "dySpaceAfter",     "N",4)
        this.stInit(13, "dyLineSpacing",    "N",4)
        this.stInit(14, "sStyle",           "N",2)
        this.stInit(15, "bLineSpacingRule", "N",1)    && BYTE
        this.stInit(16, "bOutlineLevel",    "N",1)
        this.stInit(17, "wShadingWeight",   "N",2)
        this.stInit(18, "wShadingStyle",    "N",2)
        this.stInit(19, "wNumberingStart",  "N",2)
        this.stInit(20, "wNumberingStyle",  "N",2)
        this.stInit(21, "wNumberingTab",    "N",2)
        this.stInit(22, "wBorderSpace",     "N",2)
        this.stInit(23, "wBorderWidth",     "N",2)
        this.stInit(24, "wBorders",         "N",2)
    ENDPROC
ENDDEFINE

DEFINE CLASS STRUCT_ARRAY AS Session
    DIMENSION aSTRUCT[1,4]
    
    PROCEDURE stInit(n, cName, cType, nSize)
        this.aSTRUCT[n,1] = cName
        this.aSTRUCT[n,2] = cType
        this.aSTRUCT[n,3] = nSize
        this.aSTRUCT[n,4] = IIF(n>1, this.aSTRUCT[n-1,3]+this.aSTRUCT[n-1,4], 0)
    ENDFUNC 
ENDDEFINE

DEFINE CLASS STRUCT_CALSS AS Session
    stObj = NULL
    pBuffer = 0
    nSize = 0
    
    PROCEDURE init(stObj)
        this.stObj = stObj
        LOCAL nRowCount
        nRowCount = ALEN(this.stObj.aSTRUCT, 1)
        this.nSize = this.stObj.aSTRUCT[nRowCount,3] + this.stObj.aSTRUCT[nRowCount,4]
        this.pBuffer = apiMalloc(this.nSize)
        SYS(2600, this.pBuffer, this.nSize, REPLICATE(0h00,this.nSize))
    ENDPROC
    
    PROCEDURE Destroy
        apiFree(this.pBuffer)
    ENDPROC
    
    HIDDEN FUNCTION getRow(cName)
        LOCAL nRow
        nRow = ASCAN(this.stObj.aSTRUCT, cName)
        RETURN IIF(nRow>0, ASUBSCRIPT(this.stObj.aSTRUCT,nRow,1), 0)
    ENDFUNC 
    
    FUNCTION getValue(cName)
        LOCAL n, nSize, nOffset, ret
        n = this.getRow(cName)
        IF n == 0
            RETURN NULL
        ENDIF 
        nSize   = this.stObj.aSTRUCT[n,3]
        nOffset = this.stObj.aSTRUCT[n,4]
        RETURN ICASE(this.stObj.aSTRUCT[n,2]=="N", CTOBIN(SYS(2600, this.pBuffer+nOffset, nSize), TRANSFORM(nSize)+"RS"),;
                     this.stObj.aSTRUCT[n,2]=="C", SYS(2600, this.pBuffer+nOffset, nSize),;
                     NULL)
    ENDFUNC 
    
    FUNCTION setValue(cName, vValue)
        LOCAL n, nSize, nOffset, ret
        n = this.getRow(cName)
        IF n == 0
            RETURN ""
        ENDIF 
        nSize   = this.stObj.aSTRUCT[n,3]
        nOffset = this.stObj.aSTRUCT[n,4]
        IF this.stObj.aSTRUCT[n,2]=="N" AND VARTYPE(vValue)=="N"
            RETURN SYS(2600, this.pBuffer+nOffset, nSize, BINTOC(vValue, TRANSFORM(nSize)+"RS"))
        ELSE
            IF this.stObj.aSTRUCT[n,2]=="C" AND VARTYPE(vValue)=="C"
                vValue = LEFT(vValue, nSize)
                nSize = LEN(vValue)
                RETURN SYS(2600, this.pBuffer+nOffset, nSize, vValue)
            ENDIF
        ENDIF    
        RETURN ""
    ENDFUNC 
ENDDEFINE
搜索更多相关主题的帖子: 结构 this RETURN 类型 long 
2022-03-14 21:53
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
将 STRUCT_ARRAY 整合到 STRUCT_CALSSS,这样简洁些
程序代码:
**    VFP封装结构类型示例
**    思路:
**    定义一个二维数组(aSTRUCT)用来描述结构体成员属性
**    每一行表达一个成员属性:名称(Name),类型(Type), 大小(Size),地址偏移量(Offset)
**    定义 STRUCT_CALSS 类,提供初始化结构成员属性、读写结构成员数据函数 stInit()、getValue()、setValue()

DECLARE long malloc IN msvcrt as apiMalloc long
DECLARE long free IN msvcrt as apiFree long
DECLARE long SendMessage IN user32 as apiSendMessage long,long,long,long

of = CREATEOBJECT("form1")
of.show(1)
CLEAR ALL
RETURN

DEFINE CLASS form1 as Form 
    ADD OBJECT rich AS Olecontrol WITH top=10,left=10,width=200,height=200,OleClass="RICHTEXT.RichtextCtrl.1",visible=1
    PROCEDURE rich.init
        this.text = ""
        pf = CREATEOBJECT("PARAFORMAT2")
        pf.setValue("cbSize", pf.nSize)
        pf.setValue("dwMask", 256)
        pf.setValue("dyLineSpacing", 300)
        pf.setValue("bLineSpacingRule", 4)
        #define WM_USER 0x0400
        #define EM_SETPARAFORMAT (WM_USER + 71)
        apiSendMessage(this.hWnd, EM_SETPARAFORMAT, 0, pf.pBuffer)
        RELEASE pf
        this.text = "123456789"+0h0D0A+"abcdefghijk"+0h0D0A+"ABCDEFGHIJK"++0h0D0A
    ENDPROC
ENDDEFINE

DEFINE CLASS PARAFORMAT2 AS STRUCT_CALSS
    PROCEDURE init
        DIMENSION this.aSTRUCT[24,4]
        this.stInit(1,  "cbSize",           "N",4)    && DWORD
        this.stInit(2,  "dwMask",           "N",4)
        this.stInit(3,  "wNumbering",       "N",2)    && WORD
        this.stInit(4,  "wEffects",         "N",2)
        this.stInit(5,  "dxStartIndent",    "N",4)
        this.stInit(6,  "dxRightIndent",    "N",4)
        this.stInit(7,  "dxOffset",         "N",4)
        this.stInit(8,  "wAlignment",       "N",2)
        this.stInit(9,  "cTabCount",        "N",2)
        this.stInit(10, "rgxTabs",          "C",128)  && DWORD[MAX_TAB_STOPS], MAX_TAB_STOPS=32
        this.stInit(11, "dySpaceBefore",    "N",4)
        this.stInit(12, "dySpaceAfter",     "N",4)
        this.stInit(13, "dyLineSpacing",    "N",4)
        this.stInit(14, "sStyle",           "N",2)
        this.stInit(15, "bLineSpacingRule", "N",1)    && BYTE
        this.stInit(16, "bOutlineLevel",    "N",1)
        this.stInit(17, "wShadingWeight",   "N",2)
        this.stInit(18, "wShadingStyle",    "N",2)
        this.stInit(19, "wNumberingStart",  "N",2)
        this.stInit(20, "wNumberingStyle",  "N",2)
        this.stInit(21, "wNumberingTab",    "N",2)
        this.stInit(22, "wBorderSpace",     "N",2)
        this.stInit(23, "wBorderWidth",     "N",2)
        this.stInit(24, "wBorders",         "N",2)
        STRUCT_CALSS::init
    ENDPROC
ENDDEFINE

DEFINE CLASS STRUCT_CALSS AS Session
    DIMENSION aSTRUCT[1,4]
    pBuffer = 0
    nSize = 0
    
    PROCEDURE init
        LOCAL nRowCount
        nRowCount = ALEN(this.aSTRUCT, 1)
        this.nSize = this.aSTRUCT[nRowCount,3] + this.aSTRUCT[nRowCount,4]
        this.pBuffer = apiMalloc(this.nSize)
        SYS(2600, this.pBuffer, this.nSize, REPLICATE(0h00,this.nSize))
    ENDPROC
    
    PROCEDURE Destroy
        apiFree(this.pBuffer)
    ENDPROC
    
    PROCEDURE stInit(n, cName, cType, nSize)
        this.aSTRUCT[n,1] = cName
        this.aSTRUCT[n,2] = cType
        this.aSTRUCT[n,3] = nSize
        this.aSTRUCT[n,4] = IIF(n>1, this.aSTRUCT[n-1,3]+this.aSTRUCT[n-1,4], 0)
    ENDFUNC  
    
    HIDDEN FUNCTION getRow(cName)
        LOCAL nRow
        nRow = ASCAN(this.aSTRUCT, cName)
        RETURN IIF(nRow>0, ASUBSCRIPT(this.aSTRUCT,nRow,1), 0)
    ENDFUNC 
    
    FUNCTION getValue(cName)
        LOCAL n, nSize, nOffset
        n = this.getRow(cName)
        IF n == 0
            RETURN NULL
        ENDIF 
        nSize   = this.aSTRUCT[n,3]
        nOffset = this.aSTRUCT[n,4]
        RETURN ICASE(this.aSTRUCT[n,2]=="N", CTOBIN(SYS(2600, this.pBuffer+nOffset, nSize), TRANSFORM(nSize)+"RS"),;
                     this.aSTRUCT[n,2]=="C", SYS(2600, this.pBuffer+nOffset, nSize),;
                     NULL)
    ENDFUNC 
    
    FUNCTION setValue(cName, vValue)
        LOCAL n, nSize, nOffset
        n = this.getRow(cName)
        IF n == 0
            RETURN ""
        ENDIF 
        nSize   = this.aSTRUCT[n,3]
        nOffset = this.aSTRUCT[n,4]
        IF this.aSTRUCT[n,2]=="N" AND VARTYPE(vValue)=="N"
            RETURN SYS(2600, this.pBuffer+nOffset, nSize, BINTOC(vValue, TRANSFORM(nSize)+"RS"))
        ELSE
            IF this.aSTRUCT[n,2]=="C" AND VARTYPE(vValue)=="C"
                vValue = LEFT(vValue, nSize)
                nSize = LEN(vValue)
                RETURN SYS(2600, this.pBuffer+nOffset, nSize, vValue)
            ENDIF
        ENDIF    
        RETURN ""
    ENDFUNC 
ENDDEFINE

2022-03-15 08:12
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
回复 3楼 cssnet
从某方面说确实如此,尤其是不太熟悉调用 API 函数的人,甚至不清楚“结构类型”是什么也不足为奇,因VFP没有这方面是概念。

  
2022-03-15 11:51
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
回复 3楼 cssnet
“用字符串来伪装struct,只要5行代码,而用类来封装模拟struct,则需要100+行代码,而且类代码比较艰深晦涩”
编程不是代码越少越好是吧? 易读好理解的代码对程序的更新维护和交流好处多多,一个软件的发展过程更新维护占不少耗费的。

“还用到比较危险的malloc和free,我自己写C代码,都竭力避开手动内存分配”
malloc和free没那么恐怖吧,这对家伙是C语言最基本的东东,好多高级指令都是基于他的。只要能用好编程语言,不管是那门语言,提供是指令都可用。
当然,作为示例只能点到即止,简单调用malloc和free,没有考虑异常情况。

“比较要命的一点是:STRUCT_CALSS.init()需要VFPer手动填充,一个疏忽,也会跟构造“伪字符串”一样,因对不准结构成员数据宽度而出错。”
这点确实有点难为VFPer,看看C的头文件一大堆、里面声明的结构类型就明白,这不是三两日就写得出来、写得好的,所以说用C编程高大尚是有原因的。
平时用到的类封装起来,以后再用就简单了,如示例PARAFORMAT2类,再次引用直接CREATEOBJECT就OK了,不用每次都去构造“伪字符串”。

综上,个人初步结论是:
要扩展VFP这个老古董,就要下苦功。封装类,就是先苦后甜,不管学什么编程语言,道理一样。
2022-03-15 12:23
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用cssnet在2022-3-15 11:18:48的发言:
倘若是相对复杂的struct,比如指针成员,即使是用类封装,也十分困难,几近徒劳。

虽然VFP没有指针的概念,但指针也好理解,当他是一个long变量也可以。
指针主要理解其两大特性:地址属性和大小属性。
不同类型的指针差别主要是大小属性,如字符类型指针大小属性为1byte、32位整数型指针大小属性为4byte
2022-03-15 13:07
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用cssnet在2022-3-15 15:48:19的发言:

你比方说,结构体pf的16进制值如下:

bc 00 00 00 00 01 00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc
cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc
cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc 2c 01 00 00 cc cc 04 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc

将空格移除,头上再加个0h就能直接用了,试问——还花时间精力搞“类封装”作甚?!


只针对个别的事情可以这样做.
成员复杂数据变动性大时,这样静态不断去截糊修改怕耗费也不小。
要对各成员非常了解才不容易搞错,因为可读性差(可以说是无可读性),搞错了也不容易发现和调试,以后更新维护就更不用说了,怕到时连自己也看不明。

封装成类,不是针对某一具体事情来做,是一个系统工程,一经封装就可以代代相传。
其实写个结构类也不是什么难的事,如:
程序代码:
MASM代码
PARAFORMAT2 STRUCT
  cbSize            DWORD    ?
  dwMask            DWORD    ?
  wNumbering        WORD     ?
  wEffects          WORD     ?

VFP代码
DEFINE CLASS PARAFORMAT2 AS STRUCT_CALS
    PROCEDURE init
        DIMENSION this.aSTRUCT[24,4]
        this.stInit(1,  "cbSize",           "N",4)    && DWORD
        this.stInit(2,  "dwMask",           "N",4)
        this.stInit(3,  "wNumbering",       "N",2)    && WORD
        this.stInit(4,  "wEffects",         "N",2)

形式都差不多,再看看 OPENFILENAME 结构类
DEFINE CLASS OPENFILENAME AS STRUCT_CALSS
    PROCEDURE init
        DIMENSION this.aSTRUCT[20,4]
        this.stInit(1,  "lStructSize",       "N",4)
        this.stInit(2,  "hwndOwner",         "N",4)
        this.stInit(3,  "hInstance",         "N",4)
        this.stInit(4,  "lpstrFilter",       "N",4)

PARAFORMAT2 与 OPENFILENAME 是不是有好多相似的地方,编写时好多都可以复制粘贴或搜索替换,稍作修改就OK。
使用时直接按成员名称读写就可以,清晰明了,易学易用不容易搞错,构造“伪字符串”是没法比的。






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

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



吹版说得对!
确实先前光顾着一个人爽啦,未考虑日后维护与可读性。
其实或许可以折中一下,兼顾可读性。
试考虑,这样子处理如何:
*---------------------------------
* 参照API的struct PARAFORMAT2,命名所需变量:
cbSize = 0x000000BC  &&(4字节:其值为结构体总长度 = 十进制188)
dwMask = 0x00000100  &&(4字节:其值为修改行距所对应的Mask = 十进制256)
dyLineSpacing = 0x0000012C  &&(4字节:其值为自己设置的行距值 = 十进制300,单位为twips)
bLineSpacingRule = 0x04  &&(1字节:其值意思是确定改行距的单位为twips)
* 用命名参数填充所需的结构成员,至于与我无关者一概忽略:
pf = BINTOC(cbSize,"4RS") + BINTOC(dwMask,"4RS") + REPLICATE(0h00,156);
   + BINTOC(dyLineSpacing,"4RS") + 0h0000 + BINTOC(bLineSpacingRule,"1RS") + REPLICATE(0h00,17)
*---------------------------------

如此,简洁明了且变量有注释,变量命名直指结构成员,而"4RS"、"1RS"也明确标注了字节长度,估计十年后也看得分明,看得懂啦——不知君意如何?

如果经常会用到结构类型都这样子来写,功夫还真有点强劲,少点气力也不成。那个字符串中的每个用“+”间隔的内容都要想清楚、计准确,够费神的。

2022-03-15 21:26
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用cssnet在2022-3-15 11:18:48的发言:
倘若是相对复杂的struct,比如指针成员,即使是用类封装,也十分困难,几近徒劳。

就“指针成员”问题也写个示例,觉得没什么特别。

程序代码:
**     
**    StructCalss.h
**     
#define WM_USER             0x0400
#define MAX_PATH            260
#define EM_SETPARAFORMAT    (WM_USER + 71)

程序代码:
**     
**    StructCalss.prg
**     
DEFINE CLASS OPENFILENAME AS STRUCT_CALSS
    PROCEDURE init
        DIMENSION this.aSTRUCT[20,4]
        this.stInit(1,  "lStructSize",       "N",4)
        this.stInit(2,  "hwndOwner",         "N",4)
        this.stInit(3,  "hInstance",         "N",4)
        this.stInit(4,  "lpstrFilter",       "N",4)
        this.stInit(5,  "lpstrCustomFilter", "N",4)
        this.stInit(6,  "nMaxCustFilter",    "N",4)
        this.stInit(7,  "nFilterIndex",      "N",4)
        this.stInit(8,  "lpstrFile",         "N",4)
        this.stInit(9,  "nMaxFile",          "N",4)
        this.stInit(10, "lpstrFileTitle",    "N",4)
        this.stInit(11, "nMaxFileTitle",     "N",4)
        this.stInit(12, "lpstrInitialDir",   "N",4)
        this.stInit(13, "lpstrTitle",        "N",4)
        this.stInit(14, "Flags",             "N",4)
        this.stInit(15, "nFileOffset",       "N",2)
        this.stInit(16, "nFileExtension",    "N",2)
        this.stInit(17, "lpstrDefExt",       "N",4)
        this.stInit(18, "lCustData",         "N",4)
        this.stInit(19, "lpfnHook",          "N",4)
        this.stInit(20, "lpTemplateName",    "N",4)
        STRUCT_CALSS::init
    ENDPROC
ENDDEFINE

DEFINE CLASS PARAFORMAT2 AS STRUCT_CALSS
    PROCEDURE init
        DIMENSION this.aSTRUCT[24,4]
        this.stInit(1,  "cbSize",           "N",4)    && DWORD
        this.stInit(2,  "dwMask",           "N",4)
        this.stInit(3,  "wNumbering",       "N",2)    && WORD
        this.stInit(4,  "wEffects",         "N",2)
        this.stInit(5,  "dxStartIndent",    "N",4)
        this.stInit(6,  "dxRightIndent",    "N",4)
        this.stInit(7,  "dxOffset",         "N",4)
        this.stInit(8,  "wAlignment",       "N",2)
        this.stInit(9,  "cTabCount",        "N",2)
        this.stInit(10, "rgxTabs",          "C",128)  && DWORD[MAX_TAB_STOPS], MAX_TAB_STOPS=32
        this.stInit(11, "dySpaceBefore",    "N",4)
        this.stInit(12, "dySpaceAfter",     "N",4)
        this.stInit(13, "dyLineSpacing",    "N",4)
        this.stInit(14, "sStyle",           "N",2)
        this.stInit(15, "bLineSpacingRule", "N",1)    && BYTE
        this.stInit(16, "bOutlineLevel",    "N",1)
        this.stInit(17, "wShadingWeight",   "N",2)
        this.stInit(18, "wShadingStyle",    "N",2)
        this.stInit(19, "wNumberingStart",  "N",2)
        this.stInit(20, "wNumberingStyle",  "N",2)
        this.stInit(21, "wNumberingTab",    "N",2)
        this.stInit(22, "wBorderSpace",     "N",2)
        this.stInit(23, "wBorderWidth",     "N",2)
        this.stInit(24, "wBorders",         "N",2)
        STRUCT_CALSS::init
    ENDPROC
ENDDEFINE

DEFINE CLASS STRUCT_CALSS AS Session
    DIMENSION aSTRUCT[1,4]
    pBuffer = 0
    nSize = 0
    
    PROCEDURE init
        LOCAL nRowCount
        nRowCount = ALEN(this.aSTRUCT, 1)
        this.nSize = this.aSTRUCT[nRowCount,3] + this.aSTRUCT[nRowCount,4]
        this.pBuffer = apiMalloc(this.nSize)
        SYS(2600, this.pBuffer, this.nSize, REPLICATE(0h00,this.nSize))
    ENDPROC
    
    PROCEDURE Destroy
        apiFree(this.pBuffer)
    ENDPROC
    
    PROCEDURE stInit(n, cName, cType, nSize)
        this.aSTRUCT[n,1] = cName
        this.aSTRUCT[n,2] = cType
        this.aSTRUCT[n,3] = nSize
        this.aSTRUCT[n,4] = IIF(n>1, this.aSTRUCT[n-1,3]+this.aSTRUCT[n-1,4], 0)
    ENDFUNC  
    
    HIDDEN FUNCTION getRow(cName)
        LOCAL nRow
        nRow = ASCAN(this.aSTRUCT, cName)
        RETURN IIF(nRow>0, ASUBSCRIPT(this.aSTRUCT,nRow,1), 0)
    ENDFUNC 
    
    FUNCTION getValue(cName)
        LOCAL n, nSize, nOffset
        n = this.getRow(cName)
        IF n == 0
            RETURN NULL
        ENDIF 
        nSize   = this.aSTRUCT[n,3]
        nOffset = this.aSTRUCT[n,4]
        RETURN ICASE(this.aSTRUCT[n,2]=="N", CTOBIN(SYS(2600, this.pBuffer+nOffset, nSize), TRANSFORM(nSize)+"RS"),;
                     this.aSTRUCT[n,2]=="C", SYS(2600, this.pBuffer+nOffset, nSize),;
                     NULL)
    ENDFUNC 
    
    FUNCTION setValue(cName, vValue)
        LOCAL n, nSize, nOffset
        n = this.getRow(cName)
        IF n == 0
            RETURN ""
        ENDIF 
        nSize   = this.aSTRUCT[n,3]
        nOffset = this.aSTRUCT[n,4]
        IF this.aSTRUCT[n,2]=="N" AND VARTYPE(vValue)=="N"
            RETURN SYS(2600, this.pBuffer+nOffset, nSize, BINTOC(vValue, TRANSFORM(nSize)+"RS"))
        ELSE
            IF this.aSTRUCT[n,2]=="C" AND VARTYPE(vValue)=="C"
                vValue = LEFT(vValue, nSize)
                nSize = LEN(vValue)
                RETURN SYS(2600, this.pBuffer+nOffset, nSize, vValue)
            ENDIF
        ENDIF    
        RETURN ""
    ENDFUNC 
ENDDEFINE

FUNCTION LoadApi()
    DECLARE long malloc  IN msvcrt as apiMalloc long
    DECLARE long calloc  IN msvcrt as apiCalloc long,long
    DECLARE long free    IN msvcrt as apiFree   long
    DECLARE long _strdup IN msvcrt as apiStrdup string@
    DECLARE long strlen  IN msvcrt as apiStrlen long
    
    DECLARE long SendMessage IN user32 as apiSendMessage long,long,long,long
    
    DECLARE long GetOpenFileName IN comdlg32 long
    DECLARE long GetSaveFileName IN comdlg32 long
ENDFUNC

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

? myGetFileName(0, "C:\TEMP\__temp.txt", "Text Files (*.txt)|*.txt|All Files (*.*)|*.*", "打开文件", 0)
*? myGetFileName(0, "C:\TEMP\__temp.txt", "Text Files (*.txt)|*.txt|All Files (*.*)|*.*", "另存文件", 1, 0x80806)

SET PROCEDURE TO
CLEAR ALL
RETURN

*
* 打开对话框
* myGetFileName(hWnd, cDefFile, cType, cTitle, nDialogType, nFlags)
*
* 参数:hWnd .....。.... 指向所有者对话框窗口的句柄, 没有时为0。
*       cDefFile ....... 默认指定文件名
*       cType .......... 文件类型格式过滤字符串。
*                        如文件格式选择列表:
*
*                           [color=#0000FF]Text Files (*.txt)    [/color]
*                           [color=#808080]All Files (*.*)[/color]
*                   
*                           cType:"[color=#0000FF]Text Files (*.txt)|*.txt|All Files (*.*)|*.*"[/color]
*
*       cTitle ........ 对话框标题 
*                     
*       nDialogType ... 对话框类型,[color=#800000]0 选择打开文件, 1 选择另存文件[/color]
*
*       nFlags ........ 对话框的选项,参考 OPENFILENAME 结构成员 Flags 的描述。
*                       如不选择则按默认设置。
*
* 返回:返回选择的文件名,“取消”或选择无效的文件名时返回空串。
*
FUNCTION myGetFileName(hWnd, cDefFile, cType, cTitle, nDialogType, nFlags)
    LOCAL nBuffSize, of, pFile, pType, pTitle, ret, nLen, cPaht, cFiles

    nBuffSize = 80 * MAX_PATH             && 要有足够空间存放多个文件名。
    pFile = apiMalloc(nBuffSize)
    SYS(2600, pFile, LEN(cDefFile)+1, cDefFile+0h00)
    pType = apiMalloc(LEN(cType)+1)
    cType = STRTRAN(cType, "|", 0h00)     && 转为以0h00分隔
    SYS(2600, pType, LEN(cType)+1, cType+0h00)
    pTitle = apiStrdup(cTitle)
    
    IF EMPTY(nFlags)    && 设置默认值 
        * 打开,0x80000|0x1000|0x4|0x200 = OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_ALLOWMULTISELECT
        * 另存,0x80000|0x800 |0x4|0x2   = OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT
        nFlags = IIF(nDialogType==0, 0x81204, 0x80806)
    ENDIF

    of = CREATEOBJECT("OPENFILENAME")
    of.setValue("lStructSize", of.nSize)
    of.setValue("hwndOwner",   hWnd)
    of.setValue("lpstrFilter", pType)
    of.setValue("lpstrFile",   pFile)
    of.setValue("nMaxFile",    nBuffSize)
    of.setValue("lpstrTitle",  pTitle)
    of.setValue("Flags",       nFlags)

    IF nDialogType==0
        ret = GetOpenFileName(of.pBuffer)
    ELSE
        ret = GetSaveFileName(of.pBuffer)
    ENDIF

    cFiles = ""
    
    IF ret > 0
        LOCAL ptr
        ptr = pFile  
        nLen   = apiStrlen(ptr)    && pFile 以0h00分隔,以0h0000结束
        cFiles = SYS(2600, ptr, nLen)
        ptr = ptr + nLen + 1
        nLen   = apiStrlen(ptr)
        IF nDialogType==0 AND nLen > 0
            cPaht = ADDBS(cFiles)
            cFiles = ""
            DO WHILE nLen > 0        && 多选
                cFiles = cFiles  + cPaht + SYS(2600, ptr, nLen) + 0h0D0A
                ptr = ptr + nLen + 1
                nLen   = apiStrlen(ptr)
            ENDDO
            cFiles = RTRIM(cFiles,0h0D0A)
        ENDIF   
    ENDIF

    apiFree(pFile)
    apiFree(pType)
    apiFree(pTitle)
    RETURN cFiles
ENDFUNC





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

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

服——就一个字!
能将VFP玩到这样的程度,真心让人叹为观止!
讲真,今时今日,VFP对于我——相信对于论坛上很大一部分VFPer而言——也仅仅就是个仅供消遣的玩具,已不再能做到像十几、二十年前那样,费心费力去钻研、去挖掘VFP的艰深功能——事关,动力已没有,精力也不再允许了。
可,吹版展露出来的VFP功力,确是令人佩服啊!

VFP是面向对象编程,面向对象编程的核心是“类”,可以说无类不欢。

VFP原本只是一个桌面数据库集成系统,说是“集成系统”皆因其集数据库、人机交互(UI)于一身,麻雀虽小五脏俱全,基本运行库也只是几M,短小精干,运行效率高,易学易用,是一款开发高效的较为全面的入门学习编程语言。桌面数据库,他叫第二,就没叫第一。

只可惜,他英年早废,被时代抛弃。但只要windows支持32位应用,VFP还是会继续发光。

VFP编程语言与其他编程语言从语法结构上看本质上没什么区别,区别在于语言表达能力。如指针,VFP语言自身就没这说法,要VFP能使用指针就要提高VFP的表达能力。

幸运的是,VFP有表达 DLL 和 COM 的能力,windwos就有一大堆DLL和COM。可以说,理论上只要在windows能做到的,VFP也能做得到,能做多少就看对windows认识多少了。

也许看到这个时候,即时会问:VFP搞得那么深有必要吗?确实没必要,理性的就要选择更优秀开发平台。但,感性的对VFF爱不释手的通过在其他开发平台学到的返来帮助VFP提高表达能力,如写DLL扩展VFP功能,真是一家便宜两家着数,何乐而不为?

在BCCN发的处女贴,唠唠叨叨,啰啰嗦嗦,见谅!


2022-03-16 09:12
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用吹水佬在2022-3-15 21:36:41的发言:
程序代码:
    nBuffSize = 80 * MAX_PATH             && 要有足够空间存放多个文件名。
    pFile = apiMalloc(nBuffSize)
    SYS(2600, pFile, LEN(cDefFile)+1, cDefFile+0h00)
...............

    cFiles = ""
    
    IF ret > 0
        nLen   = apiStrlen(pFile)    && pFile 以0h00分隔,以0h0000结束
        cFiles = SYS(2600, pFile, nLen)
        pFile  = pFile + nLen + 1
        nLen   = apiStrlen(pFile)
        IF nDialogType==0 AND nLen > 0
            cPaht = cFiles
            cFiles = ""
            DO WHILE nLen > 0        && 多选
                cFiles = cFiles  + cPaht + "\" +  SYS(2600, pFile, nLen) + 0h0D0A
                pFile  = pFile + nLen + 1
                nLen   = apiStrlen(pFile)
            ENDDO
            cFiles = RTRIM(cFiles,0h0D0A)
        ENDIF     
    ENDIF

    apiFree(pFile)

ENDFUNC

注意了!先截取上述示例部分相关代码,存在BUG。
有兴趣的可以先看看BUG在哪里
2022-03-17 06:46



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




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

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