YStudio Y++

DLL 工程(用 Y++ 编写并导出 `.dll`)

Y++ / YStudio 开发文档 · 一点滴

第一版为纯导出库:无窗口、默认代码视图。打开工程不会进设计画布。

相关:dllapi.md · dll-pointers.md · third-party-dll.md · 工程结构.md

硬约束

  1. 仅 .ysproj 中 "type": "dll" 可用 导出 / .yex(模块工程 "type": "module" 同样可用,见 ys-module.md)。
  2. 先写 函数,再在 .yex 用 导出 登记;导出名可与函数同名或用 ASCII 别名。
  3. 调用约定在项目设置选 stdcall(默认)或 cdecl;改后须重编 DLL 与宿主。
  4. 工程位数须与宿主一致;加载DLL 会做 PE 位数预检。
  5. 生成的 .yp 给宿主用别名调用;第三方也可 加载DLL→取导出函数→调用函数Ex。
  6. 「一键调用」测试仅覆盖无字节集/回调/数组的简单签名。
  7. 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 会弹窗 需用一键宿主 / 自建窗口工程