PBIDEA:用 uo_file 做文件读写全解(文本与 blob 直读直写、句柄式读写、文件加密与占用查询,PB10 基准 · PB12.5 实测)
PBIDEA:用 uo_file 做文件读写全解(文本与 blob 直读直写、句柄式读写、文件加密与占用查询,PB10 基准 · PB12.5 实测)阅读说明
1. 适用版本:一律以文末【版本快照】为准;本文写作与实测基准为 PB10,PB 12.5 双轨读数逐字一致(快照与两版对照见第十二节)
2. 支持数据库:本文全程不连数据库 —— 纯本地文件操作,所有示例在你机器上就能直接跑
3. 操作系统与环境要求:Windows 7 及以上;需安装 PBIDEA 运行库(uo_file 位于 websuite 库,依赖 PbIdea.dll),PB10 与 PB12.5 各需配套版本
4. 难度系数:★★☆☆☆(二星。方法都是「一个函数一件事」的直路子,难点集中在字节定位、编码与句柄语义这几处坑)
5. 其它阅读说明:目录版块里已写过 uo_dir(目录枚举)、uo_stream(内存二进制流)、uo_blob(二进制数据处理)三篇,本文不重复它们的活儿,分工见第一节;示例代码可放进任意 NVO 方法或窗口按钮事件里直接运行
一、uo_file 是什么,跟近邻们怎么分工
PB 原生的文件三件套 FileOpen/FileRead/FileWrite 有个老毛病:文本和二进制是两条路(LineMode!/TextMode!/Binary! 模式选错全盘错),blob 读写还得自己管长度。uo_file 把「文件」这件事拆成了两层:
[*]直读直写层:一个函数搞定整个文件 —— BlobFromFile/BlobToFile(二进制)、StringFromTextFile/StringToTextFile(文本,自动转码)。不用管打开关闭,读完即走。
[*]句柄层:OpenFile → ReadFile/WriteFile/Seek/ReadLine → CloseFile,适合大文件分段处理、定点改写、加锁独占。
uo_file 一共 49 条有效声明(对照随版导出源码),按用途分五类:
类别代表方法本文是否实测
文本直读直写StringToTextFile / StringFromTextFile是(全边界)
blob 直读直写BlobFromFile / BlobToFile是(全边界)
句柄式读写OpenFile / ReadFile / WriteFile / Seek / ReadLine / CloseFile是(全边界)
加密与拆分EncryptoFile / DecryptoFile / EncryptoFileRead / SplitTextFile是
查找与占用FindFile / QueryFileLocker / fileGetFullPath是(FindFile 限 3 参形态)
对话框与杂项GetFileOpenName / GetFileSaveName / SetUserOption / Printf / 剪贴板文件列表否(对话框需人交互;剪贴板文件列表已由 uo_clipboard 那篇覆盖,Printf 属控制台输出,测试 harness 里取不到)
跟近邻的分工边界,一句话说清:
[*]uo_dir 管「目录」:列文件、建删目录、文件时间与大小,它不开文件内容;
[*]uo_stream 管「内存」:那是把一块内存当流来读写,不落盘;
[*]uo_blob 管「字节本身」:hex/base64、按类型读写、校验值,输入输出都是内存里的 blob;
[*]uo_file 管「磁盘上的文件」:从文件到字符串/blob 的搬运、句柄、锁、加密落盘。
四者经常串着用:uo_file 读进来,uo_blob 处理,uo_file 写回去。
二、文本直读直写:一个函数管编码
StringToTextFile(字符串, 文件名, utf8)、StringFromTextFile(文件名) 是我最推荐的两个入门方法,因为编码这件事它们替你做了一大半。先看能直接跑的例子:
// 目的:把一段含中文的文本写进文件再读回来(ANSI/GBK 编码)
uo_file lf
boolean lb_w
string ls_cn, ls_back
lf = create uo_file
// 待写入内容:前段定义,直接赋值
ls_cn = '总量=你好 明细 123'
// 写文件:第三参 utf8=false 走 ANSI(中文 Windows 上就是 GBK)
lb_w = lf.StringToTextFile(ls_cn, 'ex1.txt', false)
// 读回来:StringFromTextFile 自动识别编码并转换
ls_back = lf.StringFromTextFile('ex1.txt')
destroy lf
MessageBox('文本往返', '写入=' + String(lb_w) + ' 读回=[' + ls_back + ']')
实测读数:写入=true 读回=[总量=你好 明细 123],两版一致。
第三参 utf8 是本文第一个值得背下来的开关,实测字节账目如下(内容固定为「你好」两个汉字):
utf8 参数落盘字节数字节内容读回
false4GBK 双字节编码2 字符,原样
true93 字节 BOM(EF BB BF)+ 6 字节 UTF-82 字符,原样
三条实测结论:
[*]utf8=true 会写 BOM。不想要 BOM 的场合(比如给某些只认纯 UTF-8 的老系统供数),得意识到文件头多了 3 个字节。
[*]StringFromTextFile 的「自动编码转换」是真的:BOM 头、GBK、UTF-8 三种形态我各写了一版,读回全是原字符串,没让我碰一个转码函数。没有 BOM 的 UTF-8 文件读回也正常。
[*]空字符串写不进去:StringToTextFile('', 文件, false) 返回 false,文件根本不创建。想造一个 0 字节占位文件,用 BlobToFile 配空 blob?也不行,照样 false。这一点跟「PB 原生 FileOpen 直接创建空文件」的习惯不同,注意。
三、blob 直读直写:二进制落盘两条函数
// 目的:任意二进制内容落盘与回读(不要求是文本)
uo_file lf
blob lb_src, lb_back
boolean lb_w
long ll_len
lf = create uo_file
// 待写入的二进制:由字符串转 blob。PB10 起每字符 2 字节(UTF-16LE)
lb_src = Blob('PK-HEADER-91-BINARY')
// 写文件:目标已存在则整文件截断重写
lb_w = lf.BlobToFile(lb_src, 'ex2.bin')
// 读回
lb_back = lf.BlobFromFile('ex2.bin')
ll_len = Len(lb_back)
destroy lf
MessageBox('blob 往返', '写入=' + String(lb_w) + ' 字节数=' + String(ll_len) + ' 内容=[' + String(lb_back) + ']')
实测读数:写入=true 字节数=38 内容=(19 个字符 × 2 字节 = 38,两版一致)。
这一节的坑比文本层多:
[*]Blob(字符串) 是 UTF-16LE,每字符 2 字节。Blob('ABC') 的 Len 是 6 不是 3。想让字节数等于字符数,走 StringToTextFile(它会转 ANSI/GBK)或者用 uo_blob 的编码转换。
[*]覆盖即截断:对已有文件 BlobToFile 写入更短内容,文件长度就是新内容的长度,不会残留旧尾巴。实测先写 12 字节再写 4 字节,文件从 12 变 4。StringToTextFile 同样截断(长内容 17 字节改写短内容 5 字节,落盘 5 字节)。
[*]读不存在的文件不报错也不返回 NULL:BlobFromFile('不存在.bin') 返回一个 Len=0、IsNull=false 的空 blob。判断「文件在不在」要靠 uo_dir.exist 或 PB 原生 FileExists,别拿空 blob 当信号。
[*]空 blob / 空串写文件一律 false(见第二节第 3 条),这是防误清空的好设计,但也意味着「用这组函数造 0 字节文件」这条路不存在。
四、句柄式读写:OpenFile 一家的真实语义
直读直写够用就别碰句柄;要分段读、定点改、加锁,才用这一层。先给一个按行读文本的完整例子:
// 目的:句柄式按行读文本 —— 先造 GBK 文本文件,再打开逐行读
uo_file lf
boolean lb_o, lb_r1, lb_r2, lb_r3, lb_r4, lb_c
string ls_l1, ls_l2, ls_l3, ls_l4, ls_out
lf = create uo_file
// 先造一个 GBK 编码的三行文本文件(CRLF 分行)
lf.StringToTextFile('L1' + Char(13) + Char(10) + 'L2' + Char(13) + Char(10) + 'L3', 'ex3.txt', false)
// 打开已存在的文件(1 参形态:可读可写,但文件必须已存在)
lb_o = lf.OpenFile('ex3.txt')
// 逐行读;到文件尾(EOF)返回 false
lb_r1 = lf.ReadLine(ls_l1)
lb_r2 = lf.ReadLine(ls_l2)
lb_r3 = lf.ReadLine(ls_l3)
lb_r4 = lf.ReadLine(ls_l4)
lb_c = lf.CloseFile()
destroy lf
ls_out = '打开=' + String(lb_o) + ' 行1=[' + ls_l1 + '] 行2=[' + ls_l2 + '] 行3=[' + ls_l3 + '] EOF=' + String(lb_r4)
MessageBox('按行读', ls_out)
实测读数:打开=true 行1= 行2= 行3= EOF=false,两版一致。注意第 4 次 ReadLine 到了 EOF 返回 false,且 ref 参数被清空。
OpenFile 有四个重载,实测语义如下:
形态文件已存在文件不存在实测结论
OpenFile(文件名)能开,可读也可写失败(false)1 参不创建文件,别拿它当「新建」用
OpenFile(文件名, read!)能开失败(false)编译通过;read! 是合法枚举值
OpenFile(文件名, write!)能开(整写截断,见下)自动创建新建文件靠它
OpenFile(文件名, read!/write!, lockFile)lockFile=true 独占同上锁语义见第五节
OpenFile(文件名, …, lockFile, isTempFile)同上同上isTempFile=true 关闭即删,实测 FileExists=false
三个最容易翻车的语义,全部实测过:
[*]Seek 的单位是字节,不是字符。对 UTF-16 内容(WriteFile 写出来的东西)做定位时最容易懵。实测:12 字节文件('ABCDEF' 的 UTF-16LE),Seek(2) 返回 2(字节位置),紧接 WriteFile(Blob('XY')) 覆盖第 2~5 字节,结果内容是 AXYDEF —— 第二个字符'B'起被换掉。再确认一次三种 method:
// 目的:演示 Seek 三种定位方式(0=从文件头,1=从当前位置,2=从文件尾)
uo_file lf
blob lb
long ll1, ll2, ll3
lf = create uo_file
// write! 打开(文件不存在会自动创建),写入 12 字节
lf.OpenFile('ex5.bin', write!)
lf.WriteFile(Blob('ABCDEF'))
// 从头偏移 2 字节
ll1 = lf.Seek(2, 0)
// 从当前位置再前进 2 字节
ll2 = lf.Seek(2, 1)
// 从文件尾回退 4 字节
ll3 = lf.Seek(-4, 2)
lf.CloseFile()
lf.OpenFile('ex5.bin', write!)
lf.Seek(8)
lf.WriteFile(Blob('XY'))
lf.CloseFile()
lb = lf.BlobFromFile('ex5.bin')
destroy lf
MessageBox('Seek 语义', '三种返回=' + String(ll1) + '/' + String(ll2) + '/' + String(ll3) + ' 覆写后=[' + String(lb) + ']')
实测读数:三种返回=2/4/8 覆写后=。返回值是移动后的字节位置;第 8 字节处覆写 4 字节,正好换掉第 5、6 个字符('EF'→'XY'),文件保持 12 字节。
[*]WriteFile 是「从指针处覆盖」,不截断尾部。只有「write! 打开后直接从头整写」才等效截断(实测 12 字节文件整写 4 字节 → 4 字节);一旦 Seek 过再写,尾部原样保留。想要「定点改一个字段、后面不动」,这正是你要的;想要「截断重写」,就别 Seek,从头整写。
[*]ReadFile 带 readSize 参数时按字节读、指针跟着走;不带参数读整个文件。实测连续两次 ReadFile(lb, 3) 拿到的是相邻的 3 字节(第二次的 String 显示出半个 UTF-16 字符的乱码,这正是按字节走的铁证);Seek(0) 归位后重读正常。全量读之后指针仍在文件头(Seek(0,1) 查询为 0),可以接着部分读。
句柄层还有三条边界,实测结论直接给:
[*]未打开句柄调 ReadFile/WriteFile/Seek 不崩:返回 0 / 0 / -1,温和失败。CloseFile 未开过句柄返回 false,关两次也是 false。
[*]read! 打开的句柄 WriteFile 照样写进去!这是全篇最意外的一条:read! 只是「打不开不存在的文件」的语义声明,运行时不拦写。我拿 read! 句柄对 8 字节 GBK 文件 WriteFile 了 10 字节 UTF-16,返回 wn=10,文件被写坏。别指望 read! 保护文件,要保护用 lockFile 或权限。
[*]append! 编译不过:OpenFile(文件, append!) 报 C0052。fileaccess 这个枚举实测只认 read! 和 write!。追加写入的替代方案:write! 打开 → Seek(0, 2) 到尾部 → WriteFile。
还有一条配套发现:WriteFile(Blob(字符串)) 写的是 UTF-16LE,而 ReadLine 按字节扫 CRLF。两者混用必错位:我用 WriteFile 写了 12 字节的 'L1\r\nL2',ReadLine 只读出半个字符。文本按行走,就用 StringToTextFile 造文件(GBK 单字节)再 ReadLine;二进制按块走,就 WriteFile + ReadFile,别交叉。
五、锁与占用:lockFile 与 QueryFileLocker
文件被别的进程占用是运维排障的常客,uo_file 给了两件工具。
// 目的:独占锁 + 查询文件被哪个进程占用
uo_file lf1, lf2
boolean lb1, lb2, lb3, lb4
long ll_pid
string ls_exe, ls_out
lf1 = create uo_file
lf2 = create uo_file
// 造文件
lf1.StringToTextFile('LOCK91', 'lock.txt', false)
// 独占打开(第三参 lockFile=true)
lb1 = lf1.OpenFile('lock.txt', write!, true)
// 第二个对象再开:读、写都进不去
lb2 = lf2.OpenFile('lock.txt', read!)
lb3 = lf2.OpenFile('lock.txt', write!)
// 释放后第二家立刻能开
lf1.CloseFile()
lb4 = lf2.OpenFile('lock.txt', write!)
// 顺手演示占用查询:pid + 进程完整路径(ref 参数带回)
lf2.CloseFile()
lf2.OpenFile('lock.txt', write!)
ll_pid = lf2.QueryFileLocker('lock.txt', ls_exe)
lf2.CloseFile()
destroy lf1
destroy lf2
ls_out = '独占=' + String(lb1) + ' 别家读=' + String(lb2) + ' 别家写=' + String(lb3) + ' 释放后=' + String(lb4)
MessageBox('锁与占用', ls_out + ' 占用进程=' + String(ll_pid) + ' ' + ls_exe)
实测读数(本机):独占=true 别家读=false 别家写=false 释放后=true;QueryFileLocker 拿到 pid=7644,exe 带回调用者自己的完整进程路径——因为测试进程自己握着句柄。文件一关,pid 回 0、exe 回空串。
这条在排障时的用法很直接:客户说「文件删不掉/写不进」,把文件名丢给 QueryFileLocker,谁占用一目了然。
六、文件加密落盘:EncryptoFile 三件套
// 目的:敏感文件加密落盘、解密还原(密钥字符串自定义)
uo_file lf
boolean lb_e, lb_d
string ls_back
lf = create uo_file
// 明文先落一份
lf.StringToTextFile('PAY-2026-91', 'pay.txt', false)
// 加密:源文件 → 密文文件
lb_e = lf.EncryptoFile('pay.txt', 'pay.enc', 'k91')
// 解密:密文 → 明文;密钥错则返回 false 且不生成目标文件
lb_d = lf.DecryptoFile('pay.enc', 'pay2.txt', 'k91')
ls_back = lf.StringFromTextFile('pay2.txt')
destroy lf
MessageBox('文件加密', '加密=' + String(lb_e) + ' 解密=' + String(lb_d) + ' 还原=[' + ls_back + ']')
实测读数:加密=true 解密=true 还原=,两版一致。四个实测结论:
[*]密钥错了不给你解出一堆乱码:DecryptoFile 返回 false,目标文件根本不生成。防御干净,别拿解密失败猜密钥。
[*]EncryptoFile 第四参 compress=true 是「先压后密」:往返解密正常(实测还原原样)。但注意小文件压缩反而更大——14 字节明文,不压密文 48 字节、压缩后密文 56 字节。压缩只在重复度高的较大文件上有收益,别无脑开。
[*]EncryptoFileRead(密文文件, 密钥) 直接返回明文 blob,少落一次盘。但它返回的是原始字节的 blob:直接 String(lb) 显示乱码(blob 默认按 UTF-16 解释),要 String(lb, EncodingANSI!) 才是明文。这一步没做的话,你会以为解密坏了——我第一眼就是这么误判的。
[*]密文文件大小与明文无固定比例(14 字节明文 → 48 字节密文),别用文件长度当校验,解密后比对内容或走 uo_blob 的摘要。
七、FindFile:4 参是幌子,3 参才是真身
这是本篇最重要的「防坑」发现。随版导出源码里 FindFile 有两个重载:
形态源码里有吗实测编译实测运行
FindFile(目录, 扩展名, 是否含子目录)有通过返回命中个数
FindFile(目录, 扩展名, 是否含子目录, ref string files[])有C0084: Bad number of arguments不可用
4 参那个 ref 数组形态编译不过——类型库里没有注册它,签名探测当场砍掉。所以拿文件列表只有一条路:3 参形态 + 事件回调(子类继承 uo_file、覆写 ue_filefind 事件)。实测返回值本身可信(递归查 *.txt 返回 43 个命中),但要注意两点:
[*]ue_filefind 事件实测一次都没触发:我造了覆写事件的子类,把命中计数和文件名都记进实例变量,跑完事件计数仍是 0、文件名仍是空。返回个数是对的,事件回调链路在这个运行形态下没接通。要把「遍历过程」拿到手,现阶段更稳的是 uo_dir 的 files/dirs 枚举;ue_filefind 的行为我标注为未实测通过,等后续版本再验。
[*]扩展名参数要带通配:'*.txt' 有命中,裸写 'txt' 返回 0。别按「扩展名不带点」的直觉写。
八、SplitTextFile:大文本拆分
SplitTextFile(文件名, 每份大小M) 返回拆出的份数。实测 26 字节小文件按 1M 拆,返回 1(不足一份也算一份)。参数单位是 M,所以它的用武之地是日志、导出文本这类大文件按块切割;文件名会自动带序号后缀。小文件拆它纯属浪费,1M 以下的直接整读。
九、实测坑清单(照着避,一条是一条)
[*]Blob(字符串) 是 UTF-16LE,每字符 2 字节;要 ANSI 字节数走 StringToTextFile。
[*]StringToTextFile utf8=true 带 3 字节 BOM;对端不认 BOM 时要注意。
[*]空字符串/空 blob 一律写不进(返回 false),0 字节文件造不出来。
[*]BlobFromFile 读不存在的文件返回空 blob(非 NULL、不报错),文件存在性判断交给 FileExists/uo_dir.exist。
[*]1 参 OpenFile 不创建文件;新建文件必须 write!。
[*]1 参与 read! 形态对已存在文件都能写——read! 不拦 WriteFile,别拿它当只读保护。
[*]append! 编译不过(C0052);追加 = write! + Seek(0, 2)。
[*]Seek 单位是字节;UTF-16 内容下「字节 × 2 = 字符」。
[*]WriteFile 从指针处覆盖、不截尾;整写(不 Seek)才等效截断。
[*]ReadFile(n) 按字节读、指针跟走;ReadLine 按 ANSI 字节扫行,与 UTF-16 内容混用必错位。
[*]QueryFileLocker 的 ref 参数带回进程完整路径,返回值是 PID;文件未被占用时 PID=0。
[*]EncryptoFileRead 返回原始字节 blob,显示要 String(lb, EncodingANSI!)。
[*]FindFile 4 参形态编译不过(C0084),3 参 + 事件回调是唯一路;扩展名要带 *.。
[*]CloseFile/析构都会释放句柄(uo_file 的 destructor 里就调了 CloseFile),但长循环里仍建议显式关,Windows 句柄配额不是无限的。
十、PB12.5 差异与版本快照
10.1 版本快照(2026-11-08 核验)
项目实测值
版本源目录维护方 PBIDEA 最新构建(10 = PB10 轨,125 = PB12.5 轨)
运行库字节数与 md518,291,200 字节 / 740f9f474d841e3fa4d06d532ecd8994
PE 导出函数数2608(解析 PE 导出表得出,不看目录名、不看体积)
源码导出目录export_20261010(GBK、无 BOM、575 文件)
核验日期2026-11-08
PBIDEA 的版本会持续更新,运行库字节数与 md5 每次补丁都可能变,而接口行为以当时的构建为准。本文全部签名均与该快照导出的 uo_file 源码逐条对照;如果你手上的 PbIdea.dll 不是这个字节数,建议先按本文第二节的最小示例跑一遍再上生产。
10.2 两版行为对照
本轮全部用例(含负探针)PB10 与 PB12.5 两版编译读数与运行读数逐条一致,未发现版本差异。唯一提醒:Blob() 的 UTF-16LE 行为是 PB10 起的 Unicode 内码所致,PB9 及更早版本(ANSI 内码)下 Blob('ABC') 是 3 字节——跨老版本移植时这一处要重验。
十一、与相近方案对比
需求推荐理由
整文件读进内存改一改写回去uo_file 直读直写两行搞定,自动转码
大文件分段处理 / 定点改写uo_file 句柄层Seek 按字节定位,WriteFile 覆盖不截尾
列目录、建删目录、文件时间uo_diruo_file 的 FindFile 事件链路未实测通过
内存流式组装数据(不落盘)uo_streamuo_file 一切操作都过磁盘
字节级加工(hex/base64/摘要)uo_blob拿到 blob 之后的事归它
独占写文件 / 查占用进程uo_file lockFile + QueryFileLocker原生 FileOpen 的 LockReadWrite! 跨进程行为不稳
十二、实机验证情况
[*]探针规模:38 个探测 NVO、4 个文章示例方法,全部走真实编译与运行。PB10 基线(--pb-version 100 全量编译 0 错误、对象齐全)与 PB12.5 实跑(PBVM 运行 .pbtest 逐例 PASS)双轨完成,两版读数逐字比对一致。
[*]负向探测:append! 形态(C0052)、FindFile 4 参形态(C0084)两条「源码有但用不了」的路已实测排除;GetFileOpenName/GetFileSaveName 对话框族、SetUserOption/GetUserOption、Printf、AddAppPathToEnv 未实测(需人工交互或改变进程环境变量),文中未将其作为示例。
[*]未实测标注:ue_filefind 事件回调(返回个数可信、事件未触发)已如实标注;SplitTextFile 仅验证小文件行为,大文件切分边界(多 M 文件、序号命名)未展开。
[*]文中全部示例代码均来自实跑通过的用例,读数如实引用,无一行推演代码。
本帖最后由 pbai 于 2026-11-8 06:42 编辑
【PB10 兼容版示例包】uo_file91_pb10.zip(9.6 KB)
把文章里 4 个示例做成了 PB10 兼容版 PBL,读者可以直接下载跑通,不用自己拼代码。
■ 包内清单
- uo_file91.pbl:示例库(nvo_art91,4 个示例方法 of_art_t1..of_art_t4)
- src/nvo_art91.sru:GBK / CRLF / 无 BOM 源码
- tests/t_ex1..t_ex4.pbtest:自验证脚本(第七节有期望读数表,可自行复验)
- readme.txt:说明文档(GBK / CRLF)
■ 环境要求
1. 适用版本:PB10 基准(PBL 按 PB10 编译 0 错);PB12.5 同源码实测通过,两版读数逐字一致。
2. Windows 7 及以上;需安装 PBIDEA 运行库(PbIdea.dll + Pbidea_cs.dll,uo_file 在 websuite 库),位数 32 位。
3. 数据库:本包全部示例不依赖数据库,无需建表 SQL。
■ 部署步骤
1. 把 uo_file91.pbl 加进工程库列表(Library Painter 或 pbt 的 liblist)。
2. 确认 PbIdea.dll 在系统搜索路径或与 exe 同目录。
3. 调用 nvo_art91 的四个方法,或照 src 源码抄进自己的对象。
■ 使用方法
四个示例的完整调用片段在 readme.txt 第四节(文本往返 / blob 往返 / 句柄按行读 / 文件加密往返),可直接贴进窗口按钮事件运行。
■ 自验证
tests 下四个 pbtest 逐个跑,诊断文件 uof91_exN.txt 的内容应与下列期望逐字一致:
- ex1:w=true back=[总量=你好 明细 123]PASS
- ex2:w=true rlen=38 back=PASS
- ex3:o=true l1= l2= l3= r4=false c=truePASS
- ex4:e=true d=true back=PASS
四项全中即环境正常;不一致先查 PBIDEA 运行库版本(对照原帖版本快照)与写入目录权限。
■ 实机验证情况
1. PB10 轨:导入 0 错、全量编译 0 错、4 用例运行全 PASS。
2. PB12.5 轨:同源码导入 0 错、全量编译 0 错、4 用例运行全 PASS,读数与 PB10 逐字一致。
3. 对话框族(GetFileOpenName/GetFileSaveName)与 FindFile 的 ue_filefind 事件回调未实测通过,文中已如实标注,本包不含相应代码。
常见坑与排错 12 条见 readme.txt 第五节;文章正文有 14 条坑清单与 Seek 字节语义详解。
页:
[1]