本文整理 整数指针、文本指针、字节集指针 以及相关 DLL / WinAPI 边界在 Y++ 中的全部处理方式:已支持、半支持、不支持,以及推荐写法。
相关入口:
- 命令签名表(面板式):
basic-dll.md(DLL支持)、basic-pointer.md(指针操作) - 声明语法:
dllapi.md(.yp) - 自定义结构:
usertype.md(.yt) - 第三方插件对接(加载、出参、
long*、回调、类封装):third-party-dll.md
硬约束
- 没有「整数指针 / 文本指针」类型关键字;地址用
长整数/整数传递。 - WinAPI 的
int*(32 位出参) 必须用DLL_整数指针32+DLL_读整数指针32,不要用DLL_整数指针(那是 64 位变量址)。 取文本指针地址(文本变量)不是LPCWSTR;日常宽串用.yp的文本,或DLL_文本指针W。调用函数Ex/DLL_调用*参数 ≤16;失败立刻看DLL_取错误()。- 工程位数必须与 DLL 一致(x86 进程不能加载 x64 插件)。
- 回调形参写
子程序指针(不加&);传入时写&函数名。
1. 三层机制(先选对层)
| 层 | 用途 | 典型命令 / 语法 |
|---|---|---|
A. .yp 自动编组 |
日常 WinAPI / 导出函数:文本、结构引用、回调 | 文本 / 文本A / &矩形 / 子程序指针 |
| B. DLL支持 | 把 Y++ 值变成「地址整数」再塞进 .yp 的 整数 形参 |
DLL_文本指针W/A、DLL_整数指针32、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 的 文本 字段) |
&类型名 |
已支持:打包为可写宽缓冲(≥1024 wchar),调用后回写 |
结构内嵌嵌套 .yt / 定长数组(≤256) |
&类型名 |
已支持(标量与嵌套回写;文本同上;字节集见下行) |
| 结构内嵌 字节集 | &类型名 |
已支持:非空→BYTE* 指向 Y++ data(原地改写);空→scratch≥4096,调用后按尾零裁剪回写;改指针无法接管 |
const MSGBOXPARAMSA* 等窄串结构 |
&类型 + 文本A 字段 |
.yt 写 文本A(UTF-8 LPCSTR,可写缓冲≥1024 字节并回写);旧绕路 整数 + DLL_文本指针A 仍可用 |
const 修饰 |
忽略 | 调用约定上按指针传入即可,不新增类型 |
防闪退:宽窄串不要混用
| 错误写法 | 后果 | 正确写法 |
|---|---|---|
.yt 用 文本 对接 DLL 的 LPCSTR / char* |
宽指针当窄指针读 → 乱码或 访问冲突 | 字段改 文本A;或 整数 + DLL_文本指针A;顶层形参用 .yp 文本A |
.yp 写 文本 对接窄串 API(如 lstrlenA) |
同上 | 改 文本A,或 整数 + DLL_文本指针A |
.yp 写 文本A 对接 LPCWSTR |
窄缓冲当宽串读 → 闪退 | 改 文本,或 DLL_文本指针W |
用 取文本指针地址(文本变量) 当 LPCWSTR |
取的是变量对象址,不是宽串缓冲 | .yp 文本,或 DLL_文本指针W |
2.4 标量指针 / 缓冲区指针(无专用 .yp 类型)
.yp 没有 整数* / 字节* 关键字。统一策略:
- 形参声明为
整数(语义 = 地址) - 调用时用 DLL支持 或 指针操作 得到地址
| C / Win | 推荐拿地址方式 | .yp 形参 |
|---|---|---|
int* / LPDWORD(32 位出参) |
DLL_整数指针32 + DLL_读整数指针32(或 DLL_创建整数缓冲区) |
整数 |
Y++ 整数 变量址(64 位) |
DLL_整数指针 / 取整数指针地址 |
整数(非标准 Win int*) |
long long* |
取长整数指针地址(变量) |
整数 / 长整数 |
BYTE* / char* 二进制缓冲 |
DLL_字节集指针(字节集) / .yp 写 字节 名[] |
整数 或数组形参 |
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 内嵌数组字段 |
定长 ≤256 经 &结构 编组;不定长 [] 仍跳过 |
| 旧写法(仍可用) | .yp 用 整数 地址 + DLL_字节集指针 / 取字节集指针地址 |
| Y++ 数组对象地址(慎用) | 取数组指针地址 |
3. 按「指针种类」拆开说明
3.1 整数指针(int* / 出参)
Y++ 的 整数 是 64 位。给 WinAPI 传真正的 int*(32 位) 请用:
长整数 p = DLL_整数指针32(0)
取进程退出码指针(取当前进程(), p)
整数 code = DLL_读整数指针32(p)
或 DLL_创建整数缓冲区(0, 4) + DLL_取缓冲指针 + DLL_读缓冲区整数。
DLL_整数指针(变量) / 取整数指针地址 取的是 64 位整数变量 的地址;小端下部分 int* 出参碰巧能改到低 32 位,但布局不保证,优先用上面的 32 位助手。
备选: 单字段结构体 + &整数盒子(走 .yp UserRef 编组)。
3.2 文本指针(宽 / 窄)
.yp 直接写 文本`
- 签名:
首选,勿绕路
.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)
嵌套 / 定长数组 / 字节集(已支持)
//.yt
坐标点 {
整数 x = 0
整数 y = 0
}
线段 {
坐标点 起点 ' 嵌套结构 → 内嵌 POD
坐标点 终点
整数 标记[4] ' 定长数组 ≤256 → 连续 LONG[4]
文本 备注 ' → 可写宽缓冲(≥1024),调用后回写
字节集 附加 ' → BYTE*(原地改写即回写;勿改指针)
}
//.yp
某库 逻辑 ProcessLine(&线段 线) 处理线段
//.yc
线段 L
L.起点.x = 1
L.终点.y = 2
L.备注 = "hello"
处理线段(L) ' 调用后起点/终点/标记/备注会回写;附加以原地改写为准
编组规则摘要:
| 字段形态 | Win 侧 | 回写 |
|---|---|---|
| 标量(整数/短整数/字节/逻辑/浮点…) | 对应 Win 标量 | 是 |
嵌套 .yt(深度 ≤4) |
内嵌匿名结构 | 是(递归) |
定长数组 T 名[N](1≤N≤256) |
T[N] / 嵌套结构数组 |
是(字节集除外) |
| 文本 | 可写宽缓冲 → LPCWSTR |
是(缓冲 ≥1024 wchar,以 \0 结尾回写) |
| 文本A | 可写 UTF-8 缓冲 → LPCSTR |
是(缓冲 ≥1024 字节,以 \0 结尾回写;语言层仍按文本读写) |
| 字节集 | BYTE* |
非空原地改写;空字段提供 ≥4096 scratch 并尾零裁剪回写;DLL 改指针无法接管 |
不定长 [] / 定长 >256 |
跳过 | — |
深度上限 4 层;直接自引用仍由 .yt 侧禁止。
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_整数指针32(+ DLL_读整数指针32) |
指针写整数 等(需自备缓冲) |
| 二进制缓冲首址 | 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支持。下列签名以 IDE 元数据为准。
6.1 加载 / 导出 / 约定
加载DLL / LoadLibrary
- 签名:
长整数 加载DLL(文本 路径) - 说明:模块句柄;失败多为
0
释放DLL / FreeLibrary
- 签名:
逻辑 释放DLL(长整数 模块)
取导出函数
- 签名:
长整数 取导出函数(长整数 模块, 文本 导出名) - 说明:入口地址;失败
0
置DLL约定
- 签名:
逻辑 置DLL约定(文本 注册名称, 文本 约定) - 说明:
winapi/stdcall/cdecl
DLL_内存加载
- 签名:
逻辑 DLL_内存加载(文本 DLL资源路径, [文本 注册名称=""]) - 说明:
:/dll/…嵌入映射;空注册名=文件名
DLL_写出
- 签名:
逻辑 DLL_写出(文本 源, 文本 写出路径, [逻辑 覆盖=真], [逻辑 自动创建目录=真], [逻辑 校验内容=真])
DLL_取错误
- 签名:
文本 DLL_取错误()
6.2 地址助手(边界优先)
DLL_文本指针W
- 签名:
长整数 DLL_文本指针W(文本 文本) - 说明:→
LPCWSTR;同次调用内使用
DLL_文本指针A
- 签名:
长整数 DLL_文本指针A(文本 文本) - 说明:UTF-8 窄串址(TLS)
DLL_整数指针
- 签名:
长整数 DLL_整数指针(整数 变量) - 说明:64 位变量址;非 Win
int*
DLL_整数指针32
- 签名:
长整数 DLL_整数指针32([整数 初值=0]) - 说明:WinAPI
int*;同句最多 16 个
DLL_读整数指针32
- 签名:
整数 DLL_读整数指针32(长整数 指针) - 说明:读回上式缓冲
DLL_字节集指针
- 签名:
长整数 DLL_字节集指针(字节集 变量) - 说明:空字节集→
0
6.3 动态调用
调用函数Ex
- 签名:
通用 调用函数Ex(通用 函数名或地址,...) - 说明:≤16 参;地址或 Y++ 函数名
DLL_调用
- 签名:
通用 DLL_调用(文本 DLL文件, 文本 函数名, [文本 调用约定="winapi"], [文本 返回类型="通用"],...)
DLL_调用整数
- 签名:
整数 DLL_调用整数(文本 DLL文件, 文本 函数名, [文本 调用约定="winapi"],...)
DLL_调用文本
- 签名:
文本 DLL_调用文本(文本 DLL文件, 文本 函数名, [文本 调用约定="winapi"],...)
DLL_调用数组
- 签名:
通用 DLL_调用数组(文本 DLL文件, 文本 函数名, [文本 约定="winapi"], [文本 返回类型="通用"], 数组 参数)
DLL_调用整数数组 / DLL_调用文本数组
- 签名:
整数/文本 同上简化返回
DLL_参数
- 签名:
通用 DLL_参数(文本 类型, 通用 值, [整数 代码页=0]) - 说明:类型:
文本W/文本A/utf8/整数指针/地址等
DLL_回调
- 签名:
长整数 DLL_回调(子程序指针 回调, [文本 约定="stdcall"]) - 说明:包装回调地址
裸文本默认按 系统 ACP;宽/UTF-8 用 DLL_参数("文本W"/"文本A"/"utf8", …)。
6.4 内存 / 缓冲区
DLL_申请内存
- 签名:
整数 DLL_申请内存(整数 字节数)
DLL_释放内存
- 签名:
无 DLL_释放内存(整数 指针)
DLL_填充内存
- 签名:
逻辑 DLL_填充内存(整数 指针, 整数 字节值, 整数 字节数)
DLL_写整数 / DLL_读整数
- 签名:
逻辑 DLL_写整数(整数 指针, 整数 值, [整数 字节数=4])/整数 DLL_读整数(整数 指针, [整数 字节数=4])
DLL_写文本A
- 签名:
逻辑 DLL_写文本A(整数 指针, 文本 内容, [整数 最大字节数=0], [整数 代码页=0])
DLL_写文本W
- 签名:
逻辑 DLL_写文本W(整数 指针, 文本 内容, [整数 最大字符数=0])
DLL_读文本A
- 签名:
文本 DLL_读文本A(整数 指针, [整数 最大字节数=0], [整数 代码页=0])
DLL_读文本W
- 签名:
文本 DLL_读文本W(整数 指针, [整数 最大字符数=0])
DLL_创建整数缓冲区
- 签名:
通用 DLL_创建整数缓冲区([整数 初始值=0], [整数 字节数=4])
DLL_创建文本缓冲区A
- 签名:
通用 DLL_创建文本缓冲区A([文本 初始文本=""], [整数 最大字节数=260], [整数 代码页=0])
DLL_创建文本缓冲区W
- 签名:
通用 DLL_创建文本缓冲区W([文本 初始文本=""], [整数 最大字符数=260])
DLL_取缓冲区指针
- 签名:
整数 DLL_取缓冲区指针(通用 缓冲)
DLL_读缓冲区整数
- 签名:
整数 DLL_读缓冲区整数(通用 缓冲, [整数 字节数=4])
DLL_读缓冲区文本A / W
- 签名:
文本 DLL_读缓冲区文本A(通用 缓冲, [整数 最大字节数=0], [整数 代码页=0])等`
DLL_释放缓冲区
- 签名:
逻辑 DLL_释放缓冲区(通用 缓冲)
6.5 示例
长整数 u = LoadLibrary("user32.dll")
长整数 p = 取导出函数(u, "MessageBoxW")
调用函数Ex(p, 0, DLL_参数("文本W", "你好"), DLL_参数("文本W", "标题"), 0)
FreeLibrary(u)
整数 tick = DLL_调用整数("kernel32", "GetTickCount", "winapi")
回调:传 &函数名;cdecl 可用 DLL_回调(&函数名, "cdecl")。
DLL_内存加载(":/dll/x.dll", "x.dll") 后可用注册名走 DLL_调用。
7. 场景速查
| 你想做的事 | 做法 |
|---|---|
| MessageBoxW | .yp:文本;直接传字符串 |
| lstrlenA / 窄串哈希 | .yp:文本A;或 整数 + DLL_文本指针A |
| GetWindowRect | .yt 矩形 + &矩形 |
| GetExitCodeProcess 出参 | 整数 形参 + DLL_整数指针32 + DLL_读整数指针32 |
| 读文件到缓冲再交给 DLL | 字节集 + DLL_字节集指针 |
| EnumWindows 回调 | 子程序指针 + &回调函数 |
MessageBoxIndirectW 类(结构内 LPCWSTR) |
.yt 文本字段 + &结构(已编组) |
MessageBoxIndirectA 类(结构内 LPCSTR) |
窄指针用 整数 + DLL_文本指针A |
| 插件返回的函数指针再 Call | 调用函数Ex(地址, …)(§6 已实现) |
| const 指针参数 | 当普通指针;转换器去 const |
8. 能力与边界
本节说明当前可用能力与已知边界(写代码时按此选用写法,勿依赖未列出的行为)。
可用
.yp:文本/文本A/ 标量 /&结构(含结构内 文本→LPCWSTR、文本A→LPCSTR、嵌套类型、定长数组≤256、字节集→BYTE* 入参)/子程序指针/ 动态加载- DLL支持:
DLL_文本指针W/A、DLL_整数指针、DLL_整数指针32/DLL_读整数指针32 - DLL支持:
加载DLL/取导出函数/调用函数Ex/DLL_调用*/DLL_调用数组(按元素类型打包)/DLL_参数/缓冲/内存映射等 - 指针操作:取址、读写、偏移、字节集缓冲址
- API 转 Y++:剥 const、猜 DLL、自动
@\"dll\"
边界(请按下列方式处理)
| 场景 | 正确做法 |
|---|---|
结构体内嵌 LPCSTR / 窄串字段 |
.yt 写 文本A(UTF-8);或旧绕路 整数 + DLL_文本指针A |
结构体内嵌不定长 [] 或定长 >256 |
&结构 不编组这些字段;定长请用 1≤N≤256 |
| 结构内文本/字节集作为 DLL 出参回写 | 文本:可写缓冲 ≥1024 wchar,调用后回写;字节集:非空原地改写,空字段 scratch≥4096+尾零裁剪回写(勿改指针) |
| 第三方 DLL 位数 | 工程架构须与 DLL 一致(x86 进程无法加载 x64 插件,反之亦然) |
9. 最小示例汇总
' --- 文本自动 ---
消息框(0, "你好", "标题", 0)
' --- 文本指针命令 ---
整数 nw = 宽串长度指针(DLL_文本指针W("Wide"))
整数 na = 窄串长度指针(DLL_文本指针A("narrow"))
' --- 整数出参 ---
长整数 pCode = DLL_整数指针32(0)
取进程退出码指针(取当前进程(), pCode)
整数 code = DLL_读整数指针32(pCode)
' --- 字节集缓冲 ---
字节集 buf
长整数 p = DLL_字节集指针(buf)
' --- 结构引用 ---
矩形 r
取窗口矩形(主窗口.句柄, r)