第一版为纯导出库:无窗口、默认代码视图。打开工程不会进设计画布。
相关:dllapi.md · dll-pointers.md · third-party-dll.md · 工程结构.md
硬约束
- 仅
.ysproj中"type": "dll"可用导出/.yex(模块工程"type": "module"同样可用,见 ys-module.md)。 - 先写
函数,再在.yex用导出登记;导出名可与函数同名或用 ASCII 别名。 - 调用约定在项目设置选
stdcall(默认)或cdecl;改后须重编 DLL 与宿主。 - 工程位数须与宿主一致;
加载DLL会做 PE 位数预检。 - 生成的
.yp给宿主用别名调用;第三方也可加载DLL→取导出函数→调用函数Ex。 - 「一键调用」测试仅覆盖无字节集/回调/数组的简单签名。
- YSS:与模块/窗口工程相同,使用
加载YSS/应用YSS(或有效.yss)须先开通 YSS 样式。
写法:先写函数,再导出
导出清单签名
| 写法 | 含义 |
|---|---|
导出 "相加" |
PE 导出名 = 函数名 相加 |
导出 "Add" = 相加 |
PE 名 Add,Y++ 函数仍是 相加 |
导出 ["相减"] |
批量同名导出 |
导出 相加 |
无引号亦可 |
' —— math.yc ——
函数 相加(整数 a, 整数 b) 整数 {
返回(a + b)
}
' —— exports.yex ——
导出 "相加"
导出 "Add" = 相加
导出 ["相减"]
调用约定
项目设置 → DLL 调用约定:stdcall(默认,Windows API 常用)或 cdecl(多数 C 库)。
生成的 .yp 会在别名后写上约定(stdcall / cdecl),宿主 thunk 按该约定生成。
DllMain 钩子
| 函数 | 时机 |
|---|---|
函数 DLL.加载 { … } |
LoadLibrary 成功(PROCESS_ATTACH) |
函数 DLL.卸载 { … } |
FreeLibrary / 进程退出(PROCESS_DETACH) |
新建 DLL 工程会自带 main.yc + exports.yex。菜单「添加新文件 → 导出清单 (.yex)」可再建。
右侧「导出」面板
| 操作 | 作用 |
|---|---|
| 刷新 | 按当前 .yc / .yex(含未保存编辑器)重扫导出表 |
| 勾选 | 多选后生成 .yp / 复制片段只含勾选项 |
| 双击行 | 跳转到函数定义源码 |
| Y++片段 | 复制 加载DLL / 取导出函数 / 调用函数Ex |
| C#片段 | 复制 [DllImport](含 CallingConvention) |
| 生成.yp | 写入本工程 源代码/{工程名}.yp(带约定),并复制全文 |
| 调用 | 填参后跑同级宿主,结果写回面板 |
| 一键宿主 | 创建/更新同级 {工程名}_host |
| 读PE | 解析发布目录 .dll 的导出表 |
| .yex 中 Ctrl+E | 插入尚未导出的函数 |
自动 .yp 示例
@"MyLib.dll"
整数 相加(整数 a, 整数 b) 相加 stdcall
整数 Add(整数 a, 整数 b) 相加 stdcall
生成规则:
| Y++ 形参/返回 | .yp / 导出侧 |
|---|---|
| 简单整数/文本 | 原样 |
| 字节集 | 长整数 xxx_ptr, 整数 xxx_len |
&结构 / 数组 / 子程序指针 |
按 .yp 语法写出 |
同级测试宿主
父目录/
MyLib/ ← DLL 工程
MyLib_host/ ← 一键测试创建的窗口工程
F5 编译 DLL 不会自动弹宿主。若尚无 .dll 会先编译本 DLL 再继续测试。
依赖清单 / 版本资源
- 项目设置 → DLL 依赖清单:每行一个同级工程名或
xxx.dll;宿主 F5 / 发布时只拉清单中的项及源码/.yp里出现的"xxx.dll"。 - VERSIONINFO:勾选「编译时写入」后,
.dll使用VFT_DLL。
导出 C-ABI(给 C# / C 用)
| Y++ | 导出 ABI | 说明 |
|---|---|---|
| 文本 入参 | LPCWSTR |
空指针按 L"" |
| 文本 返回 | LPCWSTR |
TLS 环形缓冲,调用方须立即拷贝 |
| 字节集 入参 | const unsigned char *ptr, int len |
两参数 |
| 字节集 返回 | const unsigned char * + 末尾 int *out_len |
TLS;out_len 写长度 |
| 整数/逻辑/小数 | long long / int / double 等 |
结构体 / 数组 / 字节集
| 场景 | 写法 | 说明 |
|---|---|---|
.yt 结构指针 |
.yp:&矩形 框 |
见 dll-pointers.md §3.5 |
| 字节缓冲 | 字节 缓冲[] 或 字节集 |
→ BYTE* |
| 整数数组 | 整数 表[] |
元素 64 位;32 位 int* 用 DLL_整数指针32 |
| 回调 | 子程序指针 cb |
不要加 & 类型前缀 |
宿主调用
长整数 模块 = 加载DLL(".\\你的库.dll")
长整数 p = 取导出函数(模块, "相加") ' 或 "Add"
整数 和 = 到整数(调用函数Ex(p, 2, 3))
释放DLL(模块)
把 dll 放在宿主工程根。路径须带 \\(如 .\\你的库.dll),否则 Windows 会先找真正的 exe 旁。
或使用生成的 .yp 别名直接调用。
产物与分发
| 动作 | 产物 |
|---|---|
| F5 / 编译 | 发布/{arch}/{cfg}/项目名.dll(及 .lib) |
| 发布打包 | 拷贝 .dll(及 .lib);不生成安装包 |
易错对照
| 错误 | 正确 |
|---|---|
窗口工程里写 导出 |
仅 DLL 工程 |
| 改 stdcall→cdecl 不重编宿主 | 双方都重编 |
| 宿主 x86 加载 x64 DLL | 架构一致 |
| 文本返回指针长期保存 | TLS 缓冲,立即拷贝到本地文本 |
| 以为 F5 DLL 会弹窗 | 需用一键宿主 / 自建窗口工程 |