YStudio Y++

第三方 DLL 插件对接指南

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

本文说明:如何在 Y++ 中加载并调用任意第三方 DLL(图像、自动化、硬件、加密等插件),以及 C / 厂商文档里常见的参数类型在 Y++ 中有没有对应类型、没有时用哪些支持库命令转换。

相关文档:

文档 内容
dllapi.md .yp 静态声明语法(库名、别名、结构引用)
dll-pointers.md 指针边界全表、按地址 Call 命令清单
userclass.md .ypp 自定义类封装插件 API
usertype.md .yt 结构体(对接 RECT* 等)

1. 先选对接方式

方式 适用 DLL 从哪来 要点
B. 动态加载(推荐第三方插件) 路径可配置、导出名多、或厂商文档是「先取地址再 Call」 .yc / .ypp加载DLL(路径) 不需要 .yp,不需要 @"...",不需要 @模块取导出函数调用函数Ex
A. .yp 声明 WinAPI / 导出名长期固定的自有库 系统 API 可省略库名;插件写 @"xxx.dll"@模块 全局变量 IDE「新建 API 文件」;.yc 用别名调用
C. .ypp 类封装 希望写成 插件.打开() / 插件.某方法(...) 内部通常走 B 类字段保存模块句柄;业务只调方法

推荐顺序(第三方插件):B → 需要时再包一层 C。
.yp(方式 A)适合系统 API 或极少变动的固定导出名;不要以为「已经 加载DLL 了,还要再在 .yp@模块」——那是把 B 和 A 混用。两条路径可以并存(例如 .yp 调 user32,业务插件走 B),但模块句柄不会自动合并到 .yp

做法 对不对
只在 创建完毕加载DLL,再用 取导出函数 / 调用函数Ex ✅ 完整路径 B,无需 .yp
.yp 顶写 @"D:\\插件\\x.dll",首次调别名自动 LoadLibrary ✅ 纯路径 A
.yp 顶写 @模块 g_模块,且 .yc 里先 g_模块 = 加载DLL(...) ✅ A+B 绑定句柄(要写 .yp
已经 加载DLL 了,却仍被迫为每个导出写 @模块 / @"..." ❌ 改用路径 B(见 §2)即可去掉 .yp

工程位数必须与 DLL 一致(常见插件为 x64)。路径可用绝对路径或相对运行目录。


2. 最小可运行骨架(动态加载,无需 .yp)

文本 dll路径 = "D:\\插件\\MyPlug.dll"
长整数 模块 = 0

函数 取址(文本 导出名) 长整数 {
    如果 (模块 == 0) {
        返回(0)
    }
    返回(取导出函数(模块, 导出名))
}

函数 dll无参(文本 导出名) 整数 {
    长整数 p = 取址(导出名)
    如果 (p == 0) {
        返回(0)
    }
    返回(到整数(调用函数Ex(p)))
}

函数 dll一参(文本 导出名, 整数 参数) 整数 {
    长整数 p = 取址(导出名)
    如果 (p == 0) {
        返回(0)
    }
    返回(到整数(调用函数Ex(p, 参数)))
}

函数 主窗口.创建完毕() {
    模块 = 加载DLL(dll路径)
    如果 (模块 == 0) {
        信息框("加载失败: " + DLL_取错误())
        返回()
    }
    ' 之后直接 dll无参("StartXxx") / dll一参("SetYyy", 123)
}

函数 主窗口.即将关闭() {
    如果 (模块 != 0) {
        释放DLL(模块)
        模块 = 0
    }
}

可选:用字典缓存导出名 → 地址(注意 字典_置 必须赋回变量):

通用 函数表 = 创建字典()

函数 取址(文本 导出名) 长整数 {
    如果 (字典_含键(函数表, 导出名) == 假) {
        函数表 = 字典_置(函数表, 导出名, 取导出函数(模块, 导出名))
    }
    返回(字典_取长整数(函数表, 导出名))
}

注意:

  • 窗口关闭前 释放DLL,避免析构阶段再碰 DLL。
  • 类方法名若与支持库同名(如无参 加载DLL()),类内调用带参的 加载DLL(路径) 时按实参个数区分。 用自定义类封装时,把 模块 / dll路径 做成字段,把「取址 / 打开 / 关闭」做成方法即可(见 userclass.md)。

2.1 同时加载多个 DLL

可以多次调用 加载DLL每次返回各自的模块句柄;之后用对应句柄 取导出函数 / 调用函数Ex,互不覆盖:

长整数 插件A = 加载DLL("D:\\插件\\A.dll")
长整数 插件B = 加载DLL("D:\\插件\\B.dll")
如果 (插件A == 0 || 插件B == 0) {
    信息框(DLL_取错误())
    返回()
}
长整数 pFoo = 取导出函数(插件A, "Foo")
长整数 pBar = 取导出函数(插件B, "Bar")
调用函数Ex(pFoo)
调用函数Ex(pBar)
' 关闭前分别释放
释放DLL(插件A)
释放DLL(插件B)

注意:不要把两个 DLL 的句柄写进同一个变量里覆盖掉;每个插件保留自己的 长整数 字段/全局变量。


3. Y++ 类型与 C 类型总表

Y++ 没有 int*char*stringcallback 等 C 关键字。
地址一律用 整数 / 长整数 传递;字符串用 文本;二进制用 字节集

3.1 按值传递(入参 / 返回值)

C / 厂商文档常见写法 Y++ 有无直接对应 写法 说明
void 省略返回类型或
int / INT / UINT / DWORD / HWND / HANDLE 整数 句柄也常用 整数/长整数
short / WORD 短整数
unsigned char / BYTE 字节
BOOL 逻辑
float 单浮点
double 小数(亦称双精度)
long long / __int64 / INT64 / SIZE_T(按 64 位整) 长整数整数(运行时多为 64 位整型)
long(MSVC Windows 上固定 32 位) 无单独类型 按值:用 整数 传值通常可;出参 long* 见 §4.2 勿当成 long long
string / std::string / CString string 关键字 入参用 文本 / 文本A,或 DLL_参数("文本W"/"文本A", …) 见 §4.3
wchar_t* / LPCWSTR 有(编组) .yp文本;动态调用用 DLL_参数("文本W", …)
char* / LPCSTR(当字符串用) 有(编组) .yp文本A;动态调用用 DLL_参数("文本A"/"utf8"/"文本", …) 文本A/utf8 为 UTF-8;裸「文本」在 DLL_参数 里默认系统 ACP
char*(当字节缓冲用) 无专用类型 字节集 + 取字节集指针地址,或 DLL_申请内存 见 §4.5
函数返回指针再转字符串 半支持 指针到文本A / 指针到文本W,再按厂商要求释放

3.2 指针 / 出参 / 回调(概览)

C / 厂商写法 Y++ 有无「指针类型」关键字 推荐做法
int* / INT* / LPDWORD(出参) DLL_整数指针(整数变量)DLL_参数("整数指针", 地址)
long*(32 位出参) 4 字节缓冲:DLL_创建整数缓冲区(0, 4)DLL_申请内存(4) + 读写
long long* / INT64* 取长整数指针地址(长整数变量);或缓冲字节数 8
float* / double* 取小数指针地址 / 自建缓冲 + 指针到小数/指针到单浮点
BOOL* 取逻辑指针地址 或单字段 .yt + &
BYTE* / 缓冲首址 取字节集指针地址 / 取字节指针地址 / DLL_申请内存
RECT* 等 POD 结构 .yt 定义 + .yp&类型名
回调 / FARPROC / xxxCallback .yp子程序指针;动态:&函数名DLL_回调(&函数名, "stdcall")

原则: 能自动编组(.yp文本/文本A/&结构/子程序指针)就不要手搓地址;只有文档写「传指针 / 出参」时才用 DLL支持 / 指针操作。


4. 参数类型详解与示例

以下示例默认用 动态调用调用函数Ex)。若已在 .yp 声明,把「地址形参」改成 整数,调用时同样传这些辅助命令的返回值即可。

4.1 整数指针 / int*(最常见出参)

Y++ 侧:用 整数 变量 + DLL_整数指针

整数 结果 = 0
调用函数Ex(取址("SomeApi"), 对象, DLL_整数指针(结果))
输出(到文本(结果))   // 调用后直接读变量

等价:

调用函数Ex(取址("SomeApi"), 对象, DLL_参数("整数指针", 取整数指针地址(结果)))
命令 分类 作用
DLL_整数指针(变量) DLL支持 专供 DLL 出参的 int* 友好封装
取整数指针地址(变量) 指针操作 通用取址

4.2 长整数型指针:long*long long*

这是对接第三方插件时最容易出错的一点。

文档写法 MSVC Win32/x64 实际宽度 错误做法 正确做法
long* / 「长整数型指针」(部分文档常指 32 位) 4 字节 DLL_整数指针(整数变量)(Y++ 整数 常为 8 字节) 申请 4 字节缓冲,读写时指定字节数 4
long long* / __int64* / INT64* 8 字节 用 4 字节缓冲 取长整数指针地址(长整数变量) 或缓冲字节数 8

对接 long* 出参(推荐安全缓冲):

通用 出参 = DLL_创建整数缓冲区(0, 4)   // 第二个参数 = 字节数
调用函数Ex(取址("GetRect"), 对象, DLL_取缓冲区指针(出参), …)
整数 v = DLL_读缓冲区整数(出参, 4)
DLL_释放缓冲区(出参)

或手动堆内存:

长整数 buf = DLL_申请内存(4)
调用函数Ex(取址("GetXxx"), 对象, buf)
整数 v = DLL_读整数(buf, 4)
DLL_释放内存(buf)

对接 long long* / 64 位指针:

长整数 x = 0
调用函数Ex(取址("GetInt64"), 对象, 取长整数指针地址(x))

多个 32 位出参时,可一次申请更大缓冲,用 指针偏移(buf, 4) / 指针偏移(buf, 8) 传多个地址(厂商示例里常见「四个 int 出参」)。

4.3 文本 / string / char* / wchar_t*

需求 Y++ 命令 / 声明
宽字符入参 文本 .yp 直接 文本;或 DLL_参数("文本W", "内容") / DLL_文本指针W
UTF-8 窄串入参 文本 + 转换 DLL_参数("文本A", s)DLL_参数("utf8", s) / DLL_文本指针A
系统 ACP 窄串(兼容常见插件窄字符串约定) 文本 DLL_参数("文本", s)(默认 ACP)
返回的窄串指针 → Y++ 文本 指针到文本A(指针);若插件要求释放再调释放导出
返回的宽串指针 指针到文本W(指针)
// 宽字符 MessageBox 风格
调用函数Ex(pMsg, 0, DLL_参数("文本W", "内容"), DLL_参数("文本W", "标题"), 0)

// 插件返回 UTF-8 指针,再释放
长整数 p = 调用函数Ex(取址("GetVersion"))
文本 ver = 指针到文本A(p)
调用函数Ex(取址("FreeString"), p)

易错: 取文本指针地址(文本变量) 取的是 Y++ 文本对象地址,不是 LPCWSTR 缓冲区。DLL 边界请用 文本 / DLL_文本指针W / DLL_参数("文本W", …)

4.4 回调 / callback / 函数指针

场景 写法
.yp 声明 形参写 子程序指针 名不要& / 引用
.yc 传入 &我的回调
调用函数Ex 调用函数Ex(p, …, &我的回调)DLL_回调(&我的回调, "stdcall") / "cdecl"
函数 热键回调(整数 keycode, 整数 modifiers) 整数 {
    输出("热键 " + 到文本(keycode))
    返回(0)
}

// 注册(约定以厂商文档为准,Windows 回调多为 stdcall)
调用函数Ex(取址("RegisterHotkey"), 对象, 120, 10, &热键回调)

回调形参类型尽量与文档一致(整数/长整数),返回值同理。约定不对会导致栈破坏或关闭时崩溃。

4.5 字节指针 / 字节集指针 / 二进制缓冲

C 写法 Y++ 命令
BYTE* / unsigned char* 缓冲 字节集 取字节集指针地址(数据)
单个 BYTE* 出参 字节 变量 取字节指针地址(b)
插件要你分配的缓冲 DLL_申请内存(字节数),用完 DLL_释放内存
从地址读回 指针到字节集(地址, 长度) / 指针到字节
字节集 data
' ... 准备内容 ...
长整数 p = 取字节集指针地址(data)
如果 (p == 0) {
    输出("空字节集无缓冲")
    返回()
}
调用函数Ex(取址("LoadBuffer"), 对象, p, 字节集长度(data))

4.6 双精度 / 单浮点(按值与指针)

写法 Y++
double 按值 小数;动态调用:DLL_参数("小数", matchVal)
float 按值 单浮点DLL_参数("单浮点", v)
double* / float* 出参 取小数指针地址 等,或申请缓冲后 指针到小数 / 指针到单浮点
小数 sim = 0.85
调用函数Ex(取址("Match"), 对象, 路径, DLL_参数("小数", sim), …)

浮点按值若直接裸传整数位模式可能不安全,优先 DLL_参数("小数"/"单浮点", …)

4.7 结构体指针(RECT* 等)

  1. .yt 定义 POD 字段(整数/小数等)
  2. .yp 形参写 &矩形
  3. .yc 传入结构变量(出入参)

结构内 文本 字段已按 LPCWSTR 编组;字节集/嵌套类型/数组及窄串细节见 dll-pointers.md §3.5。第三方插件若要求「自己填一块内存」,改用 DLL_申请内存 + 按偏移 DLL_写整数 / DLL_写文本A

4.8 「地址」形参 / 句柄 / 模块

含义 Y++
模块句柄(LoadLibrary) 长整数加载DLL 返回值
插件对象指针 / 接口指针 长整数,创建接口导出的返回值
任意指针当整数传 长整数/整数DLL_参数("地址", p)
调用函数Ex(取址("DoWork"), 对象, 某指针, …)

5. DLL_参数 类型字符串速查

用于 调用函数Ex / DLL_调用 标明真实编组意图:

DLL_参数 第一参(类型名) 含义
"文本W" / "textw" / "lpcwstr" 宽字符指针
"文本A" / "utf8" / "lpcstr" UTF-8 窄串指针
"文本" / "text" 窄串,默认系统 ACP
"整数指针" / "int*" 传地址(出参)
"长整数指针" / "int64*" 传地址(语义标签;实际仍传你给出的地址值)
"小数" / "单浮点" 浮点按值包装
"整数" / "长整数" / "逻辑" 整型/逻辑按值
"地址" / "指针" / "pointer" 原样传地址整数
"小数指针" / "单浮点指针" / "字节指针" / "逻辑指针" 传地址(需你先取到正确宽度的地址)

输出型整数优先:

DLL_参数("整数指针", 取整数指针地址(x))
' 或更短:
DLL_整数指针(x)

不要对已是地址的值再套一层错误取址。


6. 支持库命令分类索引

6.1 DLL支持(边界友好)

命令 用途
加载DLL / 释放DLL 加载/卸载
取导出函数 GetProcAddress
调用函数Ex 按地址(或 Y++ 函数名)调用,≤16 参
DLL_调用 / DLL_调用整数 / DLL_调用文本 按 DLL 名 + 导出名调用
DLL_参数 / DLL_回调 参数与回调包装
DLL_文本指针W / DLL_文本指针A 文本 → 地址
DLL_整数指针 整数变量 → int*
DLL_字节集指针 字节集变量 → 缓冲首址(空字节集为 0)
DLL_申请内存 / DLL_释放内存 / DLL_填充内存 堆缓冲
DLL_写整数 / DLL_读整数(可指定 1/2/4/8 字节) 对接 long* 等宽度
DLL_写文本A/W / DLL_读文本A/W 向缓冲写/读串
DLL_创建整数缓冲区 / DLL_创建文本缓冲区A/W / DLL_取缓冲区指针 / DLL_读缓冲区* / DLL_释放缓冲区 安全出参缓冲
DLL_取错误 最近一次错误信息
置DLL约定 / DLL_内存加载 / DLL_写出 约定、内存映射、落盘

6.2 指针操作(通用内存)

命令 用途
取整数/长整数/小数/逻辑/字节/字节集/数组/通用指针地址 取变量地址
指针偏移 / 取指针地址 地址加减
指针到整数/长整数/小数/单浮点/字节/字节集/文本A/文本W/逻辑… 从地址读
指针写整数 / 指针写长整数 / 指针写小数 / 指针写单浮点 / 指针写字节 / 指针写逻辑 / 指针写字节集 向地址写(按类型分命令,无统称 指针写*
指针是否可读 安全检查

设计原则:DLL_ = 对接 DLL 优先;指针操作* = 底层读写。


7. .yp加载DLL:两条路径,不要混为一谈

7.1 先答几个问题

问题 答案
@"MyPlug.dll" 必须写吗? Windows 系统 API(如 GetWindowRect)可不写库名,运行时按导出名在常见系统 DLL 中自动查找。第三方插件须写 @"..." / 库短名,或用 @模块 全局变量(见下)。
只靠初始化 加载DLL("路径") 可以吗? 可以,且第三方插件推荐这样做(路径 B)不要 .yp不要 @模块;用 取导出函数调用函数Ex。完整骨架见 §2。
全局 模块 = 加载DLL(...) 后,.yp 能直接调吗? 仅当你仍想用 .yp 别名时:在 .yp 顶写 @模块 模块。若不想维护 .yp,直接路径 B,无需 @模块
写了 .yp 还要 加载DLL 吗? 写了 @模块 时要先赋值;只写了 @"dll" 时首次调别名会自动 LoadLibrary

7.2 路径对照

路径 A:.yp 路径 B:动态加载
是否需要 .yp 文件
库名 / 句柄从哪来 ① 系统 API 自动探测@"dll" / 库短名 ③ @模块 全局变量 加载DLL 返回的句柄
.yc 里怎么调 取窗口矩形(...)别名 调用函数Ex(取导出函数(模块, "名"), …)
典型场景 WinAPI、稳定导出 插件路径可配置、导出很多

7.3 路径 B 示例(无 .yp

长整数 模块 = 加载DLL("D:\\插件\\MyPlug.dll")
长整数 p = 取导出函数(模块, "CreateInterface")
长整数 对象 = 调用函数Ex(p)
' … 业务 …
释放DLL(模块)

完整骨架见 §2。第三方插件、类封装推荐以此为主。

7.4 路径 A:.yp 里库名 / 模块句柄怎么写

语法模板:

[库短名] [返回类型] API导出名(参数...) 别名 [@"库.dll"]

五种绑定方式(任选其一;系统 API 可不写库名):

写法 示例 说明
系统 API 自动探测 逻辑 GetWindowRect(整数 窗口句柄, &矩形 框) 取窗口矩形 在 kernel32 / user32 / gdi32 等常见系统 DLL 中按导出名查找;无需 @"user32.dll"
② 文件顶 @"库.dll",后面继承 见下方 切库后后续行可省略短名
③ 每行前加库短名 user32 逻辑 GetWindowRect(...) 取窗口矩形 显式指定 DLL
@模块 全局变量 @模块 g_插件模块 global.yc加载DLL 赋给的全局句柄取导出;类内可直接调别名
⑤ 别名后写库 整数 GetTickCount() 取启动毫秒 @"kernel32.dll" 混用多 DLL

系统 API 无库名声明(①):

逻辑 GetWindowRect(整数 窗口句柄, &矩形 框) 取窗口矩形
整数 GetTickCount() 取启动毫秒

全局模块句柄 + 类内直接调用(④):

global.yc

长整数 g_插件模块 = 0
文本 dll路径 = "D:\\插件\\MyPlug.dll"

主窗口.创建完毕 或初始化函数:

g_插件模块 = 加载DLL(dll路径)

apis.yp

@模块 g_插件模块
长整数 CreateInterface() 创建接口
无 DestroyInterface(长整数 对象) 销毁接口

某插件.ypp 类方法里可直接:创建接口()销毁接口(对象)(须保证调用前已 加载DLL)。

继承当前库(②):

@"user32.dll"

' 以下两行合法:未写 user32,仍归属 user32.dll
逻辑 GetWindowRect(整数 窗口句柄, &矩形 框) 取窗口矩形
逻辑 GetClientRect(整数 窗口句柄, 矩形 &框) 取客户区矩形
DestroyWindow(整数 窗口句柄) 销毁窗口

每条都写短名(②)——与系统 API 常用写法相同,等价:

user32 逻辑 GetWindowRect(整数 窗口句柄, &矩形 框) 取窗口矩形
kernel32 整数 GetTickCount() 取启动毫秒

第三方插件 .yp 示例:

@"MyPlug.dll"
长整数 CreateInterface() 创建接口
无 DestroyInterface(长整数 对象) 销毁接口
整数 DoWork(长整数 对象, 文本A 路径, 整数 出参指针) 做工作
逻辑 EnumItems(子程序指针 回调, 长整数 用户数据) 枚举项

也可用短名(文件名去掉 .dll):MyPlug 长整数 CreateInterface() 创建接口

7.5 易错、易混淆

误解 实际
「第三方 DLL 也能不写库名」 仅常见 Windows 系统 API 可自动探测;插件须 @"..." / 库短名 / @模块 变量
@模块 不用先 加载DLL 句柄为 0 时取不到导出;须在 .yc 事件里先 变量 = 加载DLL(...)
@"MyPlug.dll" 必须每一行都写」 文件顶 @"..."@模块 一次即可;或每条用短名
.yp整数 形参 = 任意指针」 &矩形 才是结构指针;裸地址形参仍写 整数,调用处用 DLL_整数指针
「回调形参要写 & .yp 里写 子程序指针不要&

7.6 仍会报错的情况

写法 结果
第三方导出名无库绑定(无 @模块、无 @"...")且不在系统 DLL 中 运行时为 null,调用无效或返回 0
旧版 函数 … 单行声明 已废弃,解析报错

字典下标 配置["键"] 读写字典、命令 DLL_字节集指针 已支持(见 §4.5、§6.1)。

更细的 .yp 语法见 dllapi.md

7.7 形参对照

.yp 形参 对应
文本 / 文本A 宽/窄字符串入参
整数 / 长整数 / 小数 / 单浮点 / 逻辑 / 字节 / 短整数 按值
整数(语义为地址) 调用处传 DLL_整数指针 / DLL_字节集指针 / 取字节集指针地址
&某结构 / 某结构 &名 / 引用 某结构 名 .yt 结构指针
子程序指针 回调(声明处不加 &

从 C 头文件转换:打开 .yp → 右键 API 转 Y++ 声明…;自动猜的库名不对时,手改 @"插件.dll" 或库短名。


8. 推荐工程组织

源代码/
  global.yc          # 全局:插件实例、路径、缓存字典
  main.yc            # 窗口事件:创建完毕里 打开(),即将关闭里 关闭()
  某插件.ypp         # 类:字段 + 取址 + 各 API 方法
  可选 apis.yp       # 稳定导出的 .yp 声明
  可选 models.yt     # 结构体

类封装示例结构:

类 某插件 {
    长整数 对象 = 0
    长整数 模块 = 0
    文本 dll路径 = "插件.dll"

    方法 取址(文本 名) 长整数 { … }
    方法 打开() { … 加载DLL … 创建接口 … }
    方法 关闭() { … 销毁 … 释放DLL … }
    方法 析构() { 关闭() }
    方法 某业务(文本 路径) 文本 { … 调用函数Ex … }
}

global.yc

某插件 插件

主窗口.创建完毕插件.打开()
主窗口.即将关闭插件.关闭()


9. 常见错误对照

现象 可能原因 处理
创建接口返回 0 导出名错、位数不符、字典_置 未赋回、路径错 打日志:取导出函数 地址与 DLL_取错误()
出参永远是 0 / 乱值 long* 当成 8 字节 整数 出参 改用 4 字节缓冲(§4.2)
中文乱码 宽/窄、ACP/UTF-8 选错 确认厂商是 wchar_t* 还是 char*;改用 文本W / utf8 / 文本(ACP)
一调用就崩 调用约定、参数个数、回调约定错误 对照文档改 stdcall/cdecl;先用少参数试调
关闭程序闪退 析构时仍调 DLL,或未卸回调 窗口关闭时显式 关闭();先卸钩子再 释放DLL
组件 [xxx] 不存在 把类实例方法误判成控件 确认是 类实例.方法(;方法名是否写错
类内 加载DLL(路径) 编译失败 与无参类方法同名冲突 升级 IDE 后按实参个数分流;或给类方法改别名如 初始化()

10. 对照清单(写代码前勾选)

  1. DLL 是 x86 还是 x64?工程架构是否一致?
  2. 导出是 C 名还是修饰名?用工具确认 取导出函数 能取到非 0。
  3. 字符串是宽字符还是窄字符?窄字符是 UTF-8 还是 ACP?
  4. 「长整数指针」是 4 字节 long* 还是 8 字节 long long*
  5. 回调约定是 stdcall 还是 cdecl?
  6. 谁分配、谁释放返回的字符串/缓冲?
  7. 是否在退出路径上调用了 关闭 / 释放DLL

按上述选型后,再在 .yp、动态 Call 或 .ypp 封装中选一种主路径即可。更细的指针边界与命令列表见 dll-pointers.md