RichEdit控件调用EM_POSFROMCHAR触发访问违例异常咨询
问题诱因
该异常是Rich Edit控件版本兼容逻辑的文档误导、系统二进制实现偏差共同导致的,核心原因有三点:
- 类名不代表实际控件版本:
GetClassName()返回RichEdit20W仅能说明创建控件时使用了2.0版本对应的类名字符串,从Windows XP开始系统自带的riched20.dll已经全部是3.0及以上版本的实现,仅保留RichEdit20A/W类名注册做向下兼容,不存在独立的2.0版本二进制运行逻辑。 - 文档描述的自动兼容检测逻辑存在严重缺陷:所谓“检测到wParam不是有效POINTL指针就自动切换为2.0调用语法”的逻辑,在绝大多数系统版本的实现中仅做了
wParam != NULL的判断,不会校验指针指向的内存是否可写、是否为合法的用户态地址。你传入的wParam值为0x69,属于非零值,控件直接将其识别为POINTL结构指针,尝试向该地址写入坐标数据,直接触发访问违例。 - 64位环境下参数匹配偏差:如果你在x64架构下编译程序,将字符索引强转为WPARAM传入、lParam传0的写法,完全匹配3.0版本
EM_POSFROMCHAR的参数格式,控件根本不会进入兼容判断分支,直接按3.0规则解析参数。
修复方式
不要依赖不可靠的自动版本兼容逻辑,采用全版本兼容的写法调用即可:
POINTL pt = {0}; // 所有版本的Rich Edit都支持3.0格式的EM_POSFROMCHAR调用 SendMessage(hrichedit, EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)pos); // 坐标直接从pt结构中读取,无需依赖消息返回值
如果确实需要使用2.0版本的调用语法,必须先发送EM_GETRICHEDITVERSION消息获取控件真实版本号,确认版本为2.0及以下时再使用对应参数格式。
你观察到的反汇编向0x0000000000000069地址写入的行为,完全符合3.0版本的参数解析逻辑,也佐证了控件并没有进入你预期的2.0兼容分支。
内容的提问来源于stack exchange,提问作者user3161924
相关产品推荐
相关产品推荐

