import fsys.res;
主要用于枚举、加载和保存 aardio EXE 中的内嵌文件及库资源:enum/loadRes/saveRes。默认类型为字符串 "RES",枚举内嵌库可指定 "LIB"。
也支持其它 EXE/DLL 的 PE 资源;names/types/languages/list 提供普通数组查询。
import fsys.res;
// 枚举当前 EXE 的内嵌文件;回调不需要返回值。
var ok,err,code = fsys.res.enum(function(module,resType,resName){
var data = fsys.res.loadRes(resName,resType,module);
print(resName,#data);
});
if(!ok) return null,err,code;
// 枚举当前 EXE 的内嵌库。
fsys.res.enum(function(module,resType,resName){
print(resType,resName);
},"LIB");
通常读取工程内嵌文件可直接使用 string.load("/res/file.txt"),它能同时处理开发期硬盘文件和发布后的内嵌资源。enum 用于需要列出或批量处理资源的情况;默认模块在开发期是 aardio EXE,发布后是自己的 EXE。
| 函数 | 返回值 |
|---|---|
enum(proc, resType="RES", module) |
对每个名称调用 proc(module,resType,resName);成功返回 true |
types(module) |
全部类型的纯数组:数字 ID 或文本类型名 |
names(resType="RES", module) |
指定类型下的资源名称纯数组:数字 ID 或文本名称 |
languages(resName, resType="RES", module) |
真实存在的 LANGID 数值纯数组,可能包含 0 |
list(resType, module) |
{type;name;lang;size} 项目的纯数组,每个语言版本一项 |
loadRes(resName, resType="RES", module, lang) |
二进制字符串,保留所有字节,包括 NUL |
loadMenu(resName, module, lang) |
{version;helpId;items} 菜单数据表 |
decodeMenu(data) |
不访问文件,直接解码 MENU/MENUEX 字节串 |
module 可以是路径或 load 返回的有效指针;省略时使用当前 EXE 的 _HINSTANCE。LOAD_LIBRARY_AS_DATAFILE 加载并释放,不执行文件代码;借用的句柄不释放。list 再按语言升序排列,适合比较和序列化。[]。加载失败、参数错误等仍返回 null, err, code,不要用 : [] 隐藏错误。loadRes 的空资源返回 "",缺失资源返回 null, err, code。空字符串在 aardio 中为真值。for ... in 中时应加括号;更推荐先接收返回值并检查错误,再遍历。Windows 的数值资源 ID 是 16 位无符号整数,可取 0..65535。数值 7 与文本 "7" 保持区分。原生 API 的 "#7" 数值名称约定仍按 Windows 语义处理。
"MENU"、"ICON" 等字符串不是数字类型的隐式别名,可能是真实的自定义类型名。Windows API 常量不作运行时声明,代码使用 4/*_RT_MENU*/、3/*_RT_ICON*/ 或直接写数值。库中的常量条目仅供编辑器自动完成,将名称替换成数值,不依赖运行时变量。
import fsys.res;
var file = "C:\Windows\System32\notepad.exe";
var ids,err,code = fsys.res.names(4/*_RT_MENU*/,file);
if(!ids) return null,err,code;
for i,id in ids {
print(id); // number 或 string,没有原生资源指针
}
常用类型值:菜单 4、对话框 5、字符串表 6、快捷键表 9、原始数据 10、图标组 14、版本 16、HTML 23、清单 24。类型库直接使用字符串 "TYPELIB"。
调用原生 API 时,makeIntResource(value) 负责转成原生参数;getName(value) 反向转换。普通查询无需使用它们。getName 将空原生指针解释为资源 ID 0,将低位指针(包含 65535)转成整数,将有效的 UTF-16 名称指针转成 UTF-8。不要给 getName 传任意内存地址。
import fsys.res;
var file = "C:\path\resources.dll";
var langs,err,code = fsys.res.languages(100,10/*_RT_RCDATA*/,file);
if(!langs) return null,err,code;
for i,lang in langs {
var bytes,err,code = fsys.res.loadRes(100,10/*_RT_RCDATA*/,file,lang);
if(bytes===null) return null,err,code;
print(lang,#bytes);
}
lang:保留 Windows 默认资源语言选择/回退行为。lang,包括 0:必须存在这个 LANGID,绝不回退到其它语言。FindResourceExW 也可能发生语言回退;库会先核对实际语言列表,避免“请求日语却读到了中性/英语资源”。1815;资源类型或名称本身不存在时保留相应错误码。LANGID 是整数,不是 "zh-CN" 等字符串。常见值为 0(中性)、1033(英语/美国)、2052(中文/中国)。
调用方式为 enum(proc,resType="RES",module),回调参数顺序为 module,resType,resName。
import fsys.res;
fsys.res.enum(function(module,resType,resName){
var data = fsys.res.loadRes(resName,resType,module);
print(resName,#data);
// 不返回值即可继续;如果只要第一个资源,明确 return false。
},"RES","C:\path\app.exe");
"RES"、"LIB" 等自定义资源类型和名称为 UTF-8 string;数字资源类型/名称直接为 number。不用转换指针。false 才停止后续回调,null、0、true 都继续。names 共用一次名称收集和排序,再逐项调用普通 aardio 回调;停止不影响已经完成的名称收集。true;加载/参数/系统错误返回 null,err,code。loadRes,不要在回调中释放它。传路径的模块在 enum 返回或回调抛错后释放,不能保存该句柄留作以后使用;传入已有模块时仍由调用者负责释放。load(path, flags) 默认标志 2,只映射数据、不执行代码。若显式指定其它标志,则按 LoadLibraryExW 语义执行,特别是 0 可执行 DLL 入口。
只对自己从 load 获得的模块调用 free。free(null) 安全忽略,但它不能识别已释放的非空句柄,不要重复释放或释放 _HINSTANCE。
import fsys.res;
var updater,err,code = fsys.res.open("C:\path\copy.dll");
if(!updater) return null,err,code;
var ok,err,code = updater.update(10/*_RT_RCDATA*/,100,'abc\0def',2052);
if(!ok){
updater.close(true); // 丢弃暂存修改
return null,err,code;
}
return updater.close(); // 提交
open(path, true) 会在提交时移除全部旧资源,属于显式的破坏性操作;通常省略第二参数。update(type, name, data, lang=0) 暂存修改;data 可以是字符串或 buffer,数据会按确切字节长度写入。null:updater.update(10/*_RT_RCDATA*/,100,null,2052)。close(false)(默认)提交;close(true) 丢弃;重复关闭安全忽略,关闭后不能再更新。true,失败返回 null, err, code。aardio 内嵌目录使用文本类型 "RES" 和大写虚拟路径名称,因此 names/loadRes 的默认类型为 "RES"。
saveRes(srcDir="/", target="/") 和 saveAppData(resDir="/", target) 用于导出当前程序内嵌资源目录,发布期实现直接使用 names/loadRes。一般读取工程文件无需使用本库,直接 string.load("/res/file.txt") 就能兼容开发期硬盘文件与发布后的 EXE 内嵌资源。
| code | 含义 |
|---|---|
| 2 / 3 | 文件或路径不存在 |
| 6 | 更新器已关闭/无效句柄 |
| 13 | 损坏或不支持的菜单模板 |
| 87 | 参数类型、范围或 NUL 错误 |
| 1812 | PE 没有资源数据 |
| 1813 | 资源类型不存在 |
| 1814 | 资源名称不存在 |
| 1815 | 指定语言资源不存在 |
没有资源的 PE 可能完全没有资源目录,也可能保留空目录;Windows 会相应返回 1812 或 1813,库保留实际错误码。
检查第一个返回值或 ===null 即可,通常不需要 try/catch;不要在释放模块后才取 lasterr(),函数已经返回操作时的错误文本和错误码。