In-Context挂钩函数注意事项

出于性能原因,客户端开发人员注册上下文内挂钩函数。 但是,由于这些挂钩函数映射到服务器的地址空间,客户端和服务器开发人员必须采取预防措施,以确保事件处理顺利进行。

面向客户端开发人员的预防措施

客户端开发人员应注意以下问题:

  • 上下文内挂钩函数不应使用大量处理器时间,因为挂钩函数必须在服务器应用程序继续之前返回。
  • 触发事件后,在调用挂钩函数时,与事件关联的窗口可能不再存在。 在执行与事件相关的任何其他操作之前,客户端必须验证与事件关联的窗口是否仍然存在。 为了确保窗口仍然存在,客户端使用 Microsoft Win32 IsWindow 函数。
  • 如果在其中定义挂钩函数的 DLL 链接到另一个 DLL,则客户端开发人员必须确保系统加载另一个 DLL。 如果使用 .def 文件隐式链接 (并导入) ,则附加 DLL 必须位于 Windows 目录或其中一个系统目录(例如 Windows\System、Windows\System32 或 Windows\SysWOW64)中。 如果使用 LoadLibrary) 显式链接 (,则必须在调用 LoadLibrary 时指定附加 DLL 所在的目录的完整路径。
  • 当包含挂钩函数的 DLL 加载到 16 位应用程序中时,上下文中挂钩函数可能会导致堆栈溢出。 出现此问题的原因是,16 位应用程序使用的固定堆栈大小不够大,无法容纳导致调用挂钩函数的系统函数调用链。

面向服务器开发人员的预防措施

服务器开发人员需要注意客户端应用程序可能会注册上下文中的挂钩函数。 当服务器调用 NotifyWinEvent 时,必须准备好处理 WM_GETOBJECT 和其他 IAccessible 方法。

接口指针无效

当客户端在上下文挂钩函数中调用 AccessibleObjectFromEvent 时,返回的 IAccessible 接口指针直接指向服务器地址空间中的代码。 如果客户端使用此指针调用接口属性,则组件对象模型 (COM) 库不涉及跨进程边界封送 (打包和发送接口参数) 或取消封送 (拆包参数,这些参数已跨进程边界发送) 且不会检测对象是否被销毁。

如果客户端调用已销毁对象的接口属性,则无效的接口指针会导致服务器的地址空间出现常规保护错误,除非服务器检测到这种情况。

为了防止接口指针无效,服务器 会创建用于包装可访问对象的代理对象 并监视可访问对象的生命周期。 例如,当客户端调用 IAccessible 属性以获取有关对象的信息时,代理会检查可访问对象是否仍然可用,如果是,则会将客户端的请求转发到可访问对象。 如果易访问对象被销毁,代理会向客户端返回错误。