本文整理 整数指针、文本指针、字节集指针 以及相关 DLL / WinAPI 边界在 Y++ 中的全部处理方式:已支持、半支持、不支持,以及推荐写法。
相关入口:
- 声明语法:
dllapi.md(.yp) - 自定义结构:
usertype.md(.yt) - 第三方插件对接(加载、出参、
long*、回调、类封装):third-party-dll.md
1. 三层机制(先选对层)
| 层 | 用途 | 典型命令 / 语法 |
|---|---|---|
A. .yp 自动编组 |
日常 WinAPI / 导出函数:文本、结构引用、回调 | 文本 / 文本A / &矩形 / 子程序指针 |
| B. DLL支持 | 把 Y++ 值变成「地址整数」再塞进 .yp 的 整数 形参 |
DLL_文本指针W/A、DLL_整数指针 |
| C. 指针操作 | 底层取址、读写任意内存、偏移 | 取整数指针地址、取字节集指针地址、指针到整数… |
推荐顺序: 能用 A 就用 A → 需要裸 int* / 手动 LPCWSTR 地址时用 B → 拼缓冲区 / 读已有内存用 C。
不要为指针再造一等类型(无「整数指针类型」「文本指针类型」关键字);地址一律用 长整数 / 整数 传递。
2. C / Win 类型 → Y++ 全表
2.1 标量(按值)
| C / Win | .yp 参数 / 返回 |
.yc 侧 |
|---|---|---|
void |
省略返回类型或写 无 |
无返回值调用 |
int / UINT / DWORD / INT_PTR / HWND / HANDLE… |
整数 |
整数 |
SHORT / WORD(16 位) |
短整数 |
短整数 |
BYTE / unsigned char |
字节 |
字节 |
BOOL |
逻辑 |
逻辑 |
float |
单浮点 |
单浮点 |
double |
小数 |
小数 |
long long / SIZE_T(按整型传) |
长整数 或 整数 |
同左 |
2.2 文本(自动编组,优先)
| C / Win | .yp |
说明 |
|---|---|---|
LPCWSTR / const wchar_t* / LPWSTR(入参) |
文本 |
边界按宽字符传递 |
LPCSTR / const char* / LPSTR(入参) |
文本A |
边界按 UTF-8 窄串传递(与系统 ANSI 不完全等同) |
返回 LPCWSTR |
返回类型 文本 |
常见;注意生命周期由被调方保证 |
不要用 取文本指针地址 去对接普通 LPCWSTR:它取的是文本变量对象地址,不是宽串缓冲区。
2.3 结构体指针
| C / Win | Y++ | 说明 |
|---|---|---|
RECT* / POINT* / 自定义 POD 结构指针 |
&类型名 / 类型名 &名 / 引用 类型名 名 |
类型须在 .yt 定义;出入参编组 |
结构内嵌 LPCWSTR(.yt 的 文本 字段) |
&类型名 |
已支持:打包为 LPCWSTR(入参,不回写) |
const MSGBOXPARAMSA* 等窄串结构 |
&类型 + 窄指针字段 |
.yt 暂无 文本A 字段;窄串指针可用 整数 + DLL_文本指针A 填入,或后续再开 文本A 字段 |
const 修饰 |
忽略 | 调用约定上按指针传入即可,不新增类型 |
2.4 标量指针 / 缓冲区指针(无专用 .yp 类型)
.yp 没有 整数* / 字节* 关键字。统一策略:
- 形参声明为
整数(语义 = 地址) - 调用时用 DLL支持 或 指针操作 得到地址
| C / Win | 推荐拿地址方式 | .yp 形参 |
|---|---|---|
int* / LPDWORD / INT_PTR*(出参) |
DLL_整数指针(变量)(或 取整数指针地址) |
整数 |
long long* |
取长整数指针地址(变量) |
整数 / 长整数 |
BYTE* / char* 二进制缓冲 |
取字节集指针地址(字节集) |
整数 |
LPCWSTR 但想手动传地址 |
DLL_文本指针W(文本) |
整数 |
LPCSTR 手动传地址 |
DLL_文本指针A(文本) |
整数 |
float* / double* |
取小数指针地址 等 + 自行约定 |
整数 |
BOOL* |
取逻辑指针地址 或单字段 .yt |
整数 或 &结构 |
2.5 函数指针 / 回调
| C / Win | Y++ | 注意 |
|---|---|---|
WNDENUMPROC / FARPROC / 回调 |
子程序指针 名 |
不要加 & / 引用 |
| 传入用户函数 | .yc 写 &函数名 |
与「子程序指针」形参配对 |
| 按任意地址 Call(插件返回的函数指针) | 调用函数Ex(地址, …) / DLL_调用* |
见 §6;先 取导出函数 或插件返回地址 |
2.6 数组
| 情况 | 做法 |
|---|---|
.yp 字节数组(字节数组缓冲) |
形参写 字节 名[],.yc 声明 字节 名[] 直接传入 |
.yp 字节集 |
形参写 字节集 名(勿加 []),亦可 |
.yp 其它元素数组 |
凡可作元素的标量均写 类型 名[]:整数/长整数/短整数/逻辑/小数/双浮点/单浮点 |
.yt 内嵌数组字段 |
见 usertype;经 &结构 时数组字段当前也可能受限 |
| 旧写法(仍可用) | .yp 用 整数 地址 + DLL_字节集指针 / 取字节集指针地址 |
| Y++ 数组对象地址(慎用) | 取数组指针地址 |
3. 按「指针种类」拆开说明
3.1 整数指针(int* / 出参)
专用命令: DLL_整数指针(整数变量)(支持库 → DLL支持)
// .yp
kernel32 逻辑 GetExitCodeProcess(整数 进程句柄, 整数 退出码指针) 取进程退出码指针
// .yc
整数 code = 0
取进程退出码指针(取当前进程(), DLL_整数指针(code))
输出(到文本(code)) // 调用后直接读变量
等价底层:取整数指针地址(code)(在 指针操作 分类下,语义偏通用取址)。
备选: 单字段结构体 + &整数盒子(适合想走 .yp UserRef 编组时)。
3.2 文本指针(宽 / 窄)
| 需求 | 命令 | 备注 |
|---|---|---|
日常 MessageBoxW(..., LPCWSTR, ...) |
.yp 直接写 文本 |
首选,勿绕路 |
| 日常窄串 API | .yp 写 文本A |
UTF-8 |
| 形参已写成「整数=地址」 | DLL_文本指针W / DLL_文本指针A |
A 用 TLS 环形缓冲,同句可多次 |
| 读内存里的宽/窄串 | 指针到文本W / 指针到文本A |
指针操作 |
整数 n = 宽串长度指针(DLL_文本指针W("hello"))
整数 m = 窄串长度指针(DLL_文本指针A("abc"))
易错: 取文本指针地址(文本变量) ≠ LPCWSTR。DLL 边界请用 文本 / DLL_文本指针W。
3.3 字节集指针(缓冲区)
DLL_字节集指针(字节集变量) 与 取字节集指针地址 等价,DLL 边界推荐前者:
字节集 buf
' ... 写入内容 ...
长整数 p = DLL_字节集指针(buf) // 空字节集返回 0
某DLL读缓冲(p, 字节集长度(buf))
读回:指针到字节集(地址, 长度);写入:指针写字节集。
3.4 其它标量取址(指针操作)
| 命令 | 对象 |
|---|---|
取字节指针地址 |
字节 变量(对象地址) |
取短整数(无单独命令时) |
用结构体或字节集布局 |
取长整数指针地址 |
长整数 |
取小数指针地址 |
小数 |
取逻辑指针地址 |
逻辑 |
取通用指针地址 |
通用 |
取数组指针地址 |
数组对象地址 |
读写:指针写整数 / 指针到整数 / 指针写长整数 / 指针偏移 / 指针是否可读 等。
3.5 结构体指针(.yt + &)
// .yt
矩形 {
整数 left = 0
整数 top = 0
整数 right = 0
整数 bottom = 0
}
// .yp
user32 逻辑 GetWindowRect(整数 窗口句柄, &矩形 框) 取窗口矩形
// .yc
矩形 r
取窗口矩形(主窗口.句柄, r)
限制: 结构内的 字节集 / 嵌套用户类型 / 数组 字段,当前 & 编组仍会跳过。
文本 字段已编组为入参 LPCWSTR(指向 Y++ 侧宽串,调用期间有效;不回写)。窄串 LPCSTR 字段请用 整数 + DLL_文本指针A,或等后续 文本A 字段类型。
3.6 const
| 写法 | 处理 |
|---|---|
const MSGBOXPARAMSA * |
与非 const 指针相同:按指针传入 |
const char* |
→ 文本A 或 DLL_文本指针A |
| API 转 Y++ | 转换器会剥掉 const / CONST |
不单独增加 const 类型关键字。
4. DLL支持 vs 指针操作(对照)
| 场景 | 用 DLL支持 | 用 指针操作 |
|---|---|---|
给 DLL 的 LPCWSTR 地址 |
DLL_文本指针W |
(不推荐 取文本指针地址) |
给 DLL 的 UTF-8 LPCSTR |
DLL_文本指针A |
自行转字节集再取址 |
给 DLL 的 int* 出参 |
DLL_整数指针 |
取整数指针地址 |
| 二进制缓冲首址 | DLL_字节集指针 / 取字节集指针地址 |
二者等价;DLL 边界优先 DLL_字节集指针 |
| 读/写任意地址 | — | 指针到* / 指针写* |
| 地址加减 | — | 指针偏移 / 取指针地址 |
设计原则:DLL_ = 边界友好、命名即用途;指针操作* = 通用内存工具。
5. 库名(user32 / @"user32.dll")能不能省略?
5.1 运行时真相
每个 .yp 函数最终必须知道 从哪个 DLL LoadLibrary。
不能「完全不写库、运行时魔法猜对所有 API」——系统无法从导出名 100% 唯一映射到 DLL(第三方插件更不可能)。
5.2 现在允许的省略方式
| 写法 | 是否要写库 | 说明 |
|---|---|---|
@"user32.dll" 后跟无短名的声明 |
文件内切一次即可 | 后续声明跟「当前库」 |
user32 MessageBoxW(...) 消息框 |
短名即可,等价 user32.dll |
不必写 @"..." |
MessageBoxW(...) 消息框 @"user32.dll" |
别名后写库 | 单条自带库 |
| 完全不写、也不靠当前库 | 不行 | 无法解析 |
5.3 「API 转 Y++ 声明」已做的自动化
转换器会:
- 猜测导出名所属 DLL(表驱动 + 启发式,如
MessageBox*→user32,CreateFile*→kernel32) - 输出里自动插入
@\"xxx.dll\"并分组 - 合并进已有
.yp时:已有库不再重复插入,已有别名跳过
因此:用户不必手打 @"user32.dll"——转换成功时会自动生成。
5.4 局限(需心里有数)
- 猜错时默认常落到
user32.dll(启发式兜底)→ 第三方 DLL / 冷门 API 必须人工改库名 - 无法从 C 声明 alone 推断「我的插件.dll」
- 运行时仍然依赖声明里的库字段;省略的是「手工输入」,不是「声明里彻底没有库」
6. 按地址 Call / 动态 DLL 调用(已实现)
支持库分类:基础支持库 → DLL支持。
6.1 核心命令
| 命令 | 作用 |
|---|---|
加载DLL / LoadLibrary |
加载模块 → 长整数句柄 |
释放DLL / FreeLibrary |
释放模块 |
取导出函数 |
GetProcAddress → 入口地址 |
调用函数Ex(地址, …) |
按地址动态调用(≤16 参);也可 调用函数Ex("Y++函数名", …) |
DLL_调用 / DLL_调用整数 / DLL_调用文本 |
按 DLL 名 + 导出名调用 |
DLL_参数(类型, 值) |
标明 文本W/A、整数指针、地址等 |
DLL_申请内存 / 读写 / 缓冲区系列 |
手动缓冲与安全缓冲区 |
DLL_内存加载 / DLL_写出 / 置DLL约定 / DLL_取错误 |
内存映射、落盘、约定、错误 |
6.2 示例
长整数 u = LoadLibrary("user32.dll")
长整数 p = 取导出函数(u, "MessageBoxW")
调用函数Ex(p, 0, DLL_参数("文本W", "你好"), DLL_参数("文本W", "标题"), 0)
FreeLibrary(u)
整数 tick = DLL_调用整数("kernel32", "GetTickCount", "winapi")
裸文本传给 DLL 时默认 系统 ACP(兼容常见插件窄字符串约定);宽字符 / UTF-8 请用 DLL_参数("文本W"/"文本A"/"utf8", …)。
6.3 注意
- 参数过多(>16)、导出名错误:立刻看
DLL_取错误() - 回调:传
&函数名;cdecl 可用DLL_回调(&函数名, "cdecl")(地址包装) DLL_内存加载(":/dll/x.dll", "x.dll")后可用注册名走DLL_调用;位数须与程序一致
7. 场景速查
| 你想做的事 | 做法 |
|---|---|
| MessageBoxW | .yp:文本;直接传字符串 |
| lstrlenA / 窄串哈希 | .yp:文本A;或 整数 + DLL_文本指针A |
| GetWindowRect | .yt 矩形 + &矩形 |
| GetExitCodeProcess 出参 | 整数 形参 + DLL_整数指针 |
| 读文件到缓冲再交给 DLL | 字节集 + 取字节集指针地址 |
| EnumWindows 回调 | 子程序指针 + &回调函数 |
MessageBoxIndirectW 类(结构内 LPCWSTR) |
.yt 文本字段 + &结构(已编组) |
MessageBoxIndirectA 类(结构内 LPCSTR) |
窄指针用 整数 + DLL_文本指针A;或待 文本A 字段 |
| 插件返回的函数指针再 Call | 调用函数Ex(地址, …)(§6 已实现) |
| const 指针参数 | 当普通指针;转换器去 const |
8. 已实现 / 缺口清单
已实现
.yp:文本/文本A/ 标量 /&结构(含结构内 文本→LPCWSTR)/子程序指针/ 动态加载- DLL支持:
DLL_文本指针W/A、DLL_整数指针 - DLL支持:
加载DLL/取导出函数/调用函数Ex/DLL_调用*/DLL_调用数组(按元素类型打包)/DLL_参数/缓冲/内存映射等 - 指针操作:取址、读写、偏移、字节集缓冲址
- API 转 Y++:剥 const、猜 DLL、自动
@\"dll\"
仍可增强
| 项 | 说明 |
|---|---|
结构体内嵌 LPCSTR / .yt 文本A 字段 |
当前文本字段按宽 LPCWSTR;窄串用 整数+DLL_文本指针A |
| 结构体内嵌字节集 / 嵌套类型 / 数组字段 | &结构 仍跳过 |
| 更准的 API→DLL 映射表 | 扩大转换器字典 |
| 第三方 DLL 位数 | 工程架构须与 DLL 一致(x86 进程无法 加载DLL 加载 x64 插件,反之亦然) |
9. 最小示例汇总
' --- 文本自动 ---
消息框(0, "你好", "标题", 0)
' --- 文本指针命令 ---
整数 nw = 宽串长度指针(DLL_文本指针W("Wide"))
整数 na = 窄串长度指针(DLL_文本指针A("narrow"))
' --- 整数出参 ---
整数 code = 0
取进程退出码指针(取当前进程(), DLL_整数指针(code))
' --- 字节集缓冲 ---
字节集 buf
长整数 p = 取字节集指针地址(buf)
' --- 结构引用 ---
矩形 r
取窗口矩形(主窗口.句柄, r)