| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1203 人关注过本帖, 3 人收藏
标题:VFP封装结构类型示例(三)
只看楼主 加入收藏
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
结帖率:100%
收藏(3)
已结贴  问题点数:20 回复次数:5 
VFP封装结构类型示例(三)
相关贴:
https://bbs.bccn.net/thread-508553-1-1.html
https://bbs.bccn.net/thread-508669-1-1.html

前一贴探讨了VFP封装结构类型结构体的嵌套问题,示例中描述了如何操作结构体中的其他结构成员数据。
其中:
nm = CREATEOBJECT("NMHDR")
of = CREATEOBJECT("OFNOTIFYA")

nm.setValue("code", 123, of.getMemberAddr("hdr"))
这句是使用 NMHDR 结构类的 setValue 方法来设置 OFNOTIFYA 结构类 hdr 成员的 code 属性值。OFNOTIFYA 结构类的 hdr 成员是一个 NMHDR 结构类。

nm.getValue("code", of.getMemberAddr("hdr"))
这句是使用 NMHDR 结构类的 getValue 方法来获取 OFNOTIFYA 结构类 hdr 成的员 code 属性值。

STRUCT_CLASS 类的 getMemberAddr() 方法是用来获取结构成员的地址。

of.getMemberAddr("hdr") 就是获取 OFNOTIFYA 结构类 hdr 成的员的地址,这个地址也就是 OFNOTIFYA 结构体中 NMHDR 结构成员(hdr)的地址。

可见,只要能得到某结构类数据的首地址,就可以用这个结构类型的方法读写该类型的类成员数据。

下面用示例探讨一下结构类在VFP的应用:如何处理函数返回的不同的结构类数据。

这个问题在调用 Windows API 也是时常会遇到,就是函数返回的数据是因情况不同而返回不同的结构数据。调用该函数时就要考虑什么情况用什么结构的处理方法来获取该函数返回的数据。

采取的方法是分配一个足够大的临时缓存区,作为函数的(in/out)参数,函数通过他来存放不同结构类型的数据返回给调用者。调用者就可以根据函数返回的状态标志,采取相应的结构类方法获取函数返回的数据处理结果。

相关文件打包
StructClass_demo.rar (7.58 KB)

程序代码:
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)

#INCLUDE apiFuns.h
SET PROCEDURE TO apiFuns.prg, StructClass.prg ADDITIVE
LoadApi() 


st1 = CREATEOBJECT("STRUCT_1")
st2 = CREATEOBJECT("STRUCT_2")
mem = CREATEOBJECT("MEMORY")

nBufSize = MAX(st1.size, st2.size)  && 要足够大
pBuffer  = mem.malloc(nBufSize)     && 临时缓存

IF fun(pBuffer, nBufSize) == 1
    ? "aa = "+ TRANSFORM(st1.getValue("aa", pBuffer))
ELSE
    ? "bb = "+ TRANSFORM(st2.getValue("bb", pBuffer))
    ? "cc = "+ TRANSFORM(st2.getValue("cc", pBuffer))
ENDIF

SET PROCEDURE TO
CLEAR ALL
RETURN

FUNCTION fun(pBuffer, nBufSize)
    LOCAL st1,st2
    st1 = CREATEOBJECT("STRUCT_1")
    st2 = CREATEOBJECT("STRUCT_2")
    n = INT(2*RAND()+1)  && 随机 1 or 2
    IF n == 1
        st1.setValue("aa", 123)
        apiMemcpy_s(pBuffer, nBufSize, st1.addr, st1.size)
    ELSE
        st2.setValue("bb", 456)
        st2.setValue("cc", 789)
        apiMemcpy_s(pBuffer, nBufSize, st2.addr, st2.size)        
    ENDIF
    RETURN n
ENDFUNC

DEFINE CLASS STRUCT_1 as STRUCT_CLASS
    PROCEDURE init
        DIMENSION this.aSTRUCT[1,4]
        this.stInit(1, "aa", "I",4)
        STRUCT_CLASS::init
    ENDPROC
ENDDEFINE

DEFINE CLASS STRUCT_2 as STRUCT_CLASS
    PROCEDURE init
        DIMENSION this.aSTRUCT[2,4]
        this.stInit(1, "bb", "I",4)
        this.stInit(2, "cc", "I",4)
        STRUCT_CLASS::init
    ENDPROC
ENDDEFINE




搜索更多相关主题的帖子: 函数 数据 返回 类型 结构 
2022-03-27 20:26
独木星空
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:河北省曲阳县
等 级:版主
威 望:71
帖 子:935
专家分:683
注 册:2016-6-29
收藏
得分:0 
回复 楼主 吹水佬
学习了。谢谢吹水佬版主!

素数问题的解决是我学习编程永恒的动力。
2022-03-27 21:56
schtg
Rank: 12Rank: 12Rank: 12
来 自:Usa
等 级:贵宾
威 望:67
帖 子:1730
专家分:3324
注 册:2012-2-29
收藏
得分:10 
@吹版,继续学习,谢谢!
2022-03-28 06:02
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
VFP添加一个“结构类型”,为处理较复杂的数据集提供便捷。
其实VFP的表、数组也是一种特殊的结构数据类型,应该也是结构类型的产物,只是在VFP操作他们有各自的方法。表可按字段名操作,易读性好;数组只能按下标操作,易读性相对差点。
下面以查看DBF文件头信息为例,探讨一下“结构类型”在文件处理方面的应用,变通一下就可以方便地设计出其他格式的文件。

图片附件: 游客没有浏览图片的权限,请 登录注册

程序代码:
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)

#INCLUDE apiFuns.h
SET PROCEDURE TO apiFuns.prg, StructClass.prg ADDITIVE
LoadApi() 

CREATE TABLE tt (f1 I, f2 N(10,2), f3 C(20))
INSERT INTO tt VALUES (123, 456.78, "abcdeABCDE1234567890")
USE

hd = CREATEOBJECT("DBF头描述")
fd = CREATEOBJECT("DBF字段描述")
os = CREATEOBJECT("STRING")

pBuf = os.create(LEFT(FILETOSTR("tt.dbf"), hd.size))

FOR i=1 TO ALEN(hd.aSTRUCT,1)
    val = hd.getValue(hd.aSTRUCT[i,1], pBuf)
    IF hd.aSTRUCT[i,2]=="C"
        val = RTRIM(val,0h00)
    ENDIF 
    ? PADL(hd.aSTRUCT[i,1],14," "), TRANSFORM(val)
ENDFOR

* 文件头最后265字节包含一个头结束标志0x0D和DBC文件路径的相关信息
fds  = hd.getValue("首记录位置",pBuf) - hd.size - 264    && 所有字段描述占用字节数
pBuf = os.create(LEFT(FILETOSTR("tt.dbf"), hd.size+fds))
pBuf = pBuf + hd.size  && 字段描述开始地址
?
FOR k=1 TO fds/fd.size      && 字段数
    FOR i=1 TO ALEN(fd.aSTRUCT,1)
        val = fd.getValue(fd.aSTRUCT[i,1], pBuf)
        IF fd.aSTRUCT[i,2]=="C"
            val = RTRIM(val,0h00)
        ENDIF 
        ? PADL(fd.aSTRUCT[i,1],14," "), TRANSFORM(val)
    ENDFOR
    ?
    pBuf = pBuf + fd.size  && 下一个字段描述地址
ENDFOR
DELETE FILE tt.dbf
SET PROCEDURE TO
CLEAR ALL
RETURN

DEFINE CLASS DBF头描述 as STRUCT_CLASS
    PROCEDURE init
        DIMENSION this.aSTRUCT[10,4]
        this.stInit(1,  "文件标志",   "U",1)
        this.stInit(2,  "更新年",     "U",1)
        this.stInit(3,  "更新月",     "U",1)
        this.stInit(4,  "更新日",     "U",1)
        this.stInit(5,  "记录的数",   "U",4)
        this.stInit(6,  "首记录位置", "U",2)
        this.stInit(7,  "记录的长度", "U",2)
        this.stInit(8,  "保留",       "C",16)
        this.stInit(9,  "VFP页标志",  "U",2)
        this.stInit(10, "保留",       "U",2)
        STRUCT_CLASS::init
    ENDPROC
ENDDEFINE

DEFINE CLASS DBF字段描述 as STRUCT_CLASS
    PROCEDURE init
        DIMENSION this.aSTRUCT[7,4]
        this.stInit(1,  "字段名",     "C",11)  && 00 - 10
        this.stInit(2,  "字段类型",   "C",1)   && 11
        this.stInit(3,  "记录中位置", "U",4)   && 12 - 15
        this.stInit(4,  "字段长度",   "U",1)   && 16
        this.stInit(5,  "小数位数",   "U",1)   && 17
        this.stInit(6,  "字段标志",   "U",1)   && 18
        this.stInit(7,  "保留",       "C",13)  && 19 - 31
        STRUCT_CLASS::init
    ENDPROC
ENDDEFINE
2022-03-28 12:03
antony521
Rank: 3Rank: 3
等 级:论坛游侠
威 望:1
帖 子:170
专家分:175
注 册:2009-8-20
收藏
得分:10 
回复 4楼 吹水佬
2022-03-28 15:35
aqyejun
Rank: 4
等 级:贵宾
威 望:10
帖 子:147
专家分:113
注 册:2010-6-11
收藏
得分:0 
实在是高手!确实很难理解的结构类

【独叶为舟】工作室
2022-04-29 11:00
快速回复:VFP封装结构类型示例(三)
数据加载中...
 
   



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

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