本文说明:如何在 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*、string、callback 等 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* 等)
- 在
.yt定义 POD 字段(整数/小数等) .yp形参写&矩形.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. 对照清单(写代码前勾选)
- DLL 是 x86 还是 x64?工程架构是否一致?
- 导出是 C 名还是修饰名?用工具确认
取导出函数能取到非 0。 - 字符串是宽字符还是窄字符?窄字符是 UTF-8 还是 ACP?
- 「长整数指针」是 4 字节
long*还是 8 字节long long*? - 回调约定是 stdcall 还是 cdecl?
- 谁分配、谁释放返回的字符串/缓冲?
- 是否在退出路径上调用了
关闭/释放DLL?
按上述选型后,再在 .yp、动态 Call 或 .ypp 封装中选一种主路径即可。更细的指针边界与命令列表见 dll-pointers.md。