YStudio Y++

Y++ 指针 / DLL 边界对照手册

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

本文整理 整数指针、文本指针、字节集指针 以及相关 DLL / WinAPI 边界在 Y++ 中的全部处理方式:已支持、半支持、不支持,以及推荐写法。

相关入口:

硬约束

  1. 没有「整数指针 / 文本指针」类型关键字;地址用 长整数 / 整数 传递。
  2. WinAPI 的 int*(32 位出参) 必须用 DLL_整数指针32 + DLL_读整数指针32,不要用 DLL_整数指针(那是 64 位变量址)。
  3. 取文本指针地址(文本变量) 不是 LPCWSTR;日常宽串用 .yp 的 文本,或 DLL_文本指针W。
  4. 调用函数Ex / DLL_调用* 参数 ≤16;失败立刻看 DLL_取错误()。
  5. 工程位数必须与 DLL 一致(x86 进程不能加载 x64 插件)。
  6. 回调形参写 子程序指针(不加 &);传入时写 &函数名。

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 没有 整数* / 字节* 关键字。统一策略:

  1. 形参声明为 整数(语义 = 地址)
  2. 调用时用 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++ 声明」已做的自动化

转换器会:

  1. 猜测导出名所属 DLL(表驱动 + 启发式,如 MessageBox*→user32,CreateFile*→kernel32)
  2. 输出里自动插入 @\"xxx.dll\" 并分组
  3. 合并进已有 .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)