You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Microsoft Access与Runtime2013调用GetMonitorInfo获取rcMonitor结果差异问题

Access Runtime 2013调用Windows API获取屏幕参数与完整版差异问题

问题描述

我需要实现Access表单通过Windows API获取第二屏幕的Left、Right、Top、Bottom值,用于缩放调整时的appbar计算。但使用Microsoft Access Runtime 2013调用GetMonitorInfo获取当前屏幕数值时,结果与完整版Microsoft Access完全不同。想明确:

  • 这种差异是否正常?
  • 是否受Access Runtime的架构影响?
  • 为何直接调用Windows API仍会受两者差异影响?

核心代码

' 1.) 从当前窗体位置获取监视器句柄
lngCurrentMonitorHWnd = MonitorFromWindow(frmAccessForm.hwnd, MONITOR_DEFAULTTONULL)

' 2) 获取当前监视器信息及逻辑尺寸
objCurrentMonitorInfo.cbSize = Len(objCurrentMonitorInfo)
Call GetMonitorInfo(lngCurrentMonitorHWnd, objCurrentMonitorInfo)

' 3) 赋值当前监视器信息变量
mlngCurrentScreenLeft = objCurrentMonitorInfo.rcMonitor.Left
mlngCurrentScreenRight = objCurrentMonitorInfo.rcMonitor.Right
mlngCurrentScreenTop = objCurrentMonitorInfo.rcMonitor.Top
mlngCurrentScreenBottom = objCurrentMonitorInfo.rcMonitor.Bottom

测试结果

完整版Microsoft Access(365/2019/2016/2013)

  • 缩放100%:获取的屏幕参数与实际物理分辨率匹配
  • 缩放125%:获取的参数适配系统缩放比例,数值符合缩放后的逻辑坐标

Microsoft Access Runtime 2013

  • 缩放100%:获取的屏幕参数与完整版一致
  • 缩放125%:获取的参数未适配系统缩放,数值与实际逻辑坐标偏差明显

已尝试方案

  1. 绕过Access窗体句柄,改用资源管理器窗口句柄获取监视器句柄,结果仍有差异:
' 1.) 通过资源管理器句柄获取监视器句柄
lngCurrentMonitorHWnd = MonitorFromWindow(69911, MONITOR_DEFAULTTONULL)

' 2) 获取当前监视器信息及逻辑尺寸
objCurrentMonitorInfo.cbSize = Len(objCurrentMonitorInfo)
Call GetMonitorInfo(lngCurrentMonitorHWnd, objCurrentMonitorInfo)
  1. 更换监视器句柄获取方式,使用MonitorFromPoint基于鼠标位置获取,结果仍有差异:
' 1.) 通过鼠标位置获取监视器句柄
GetCursorPos objMousePoint   
lngCurrentMonitorHWnd = MonitorFromPoint(objMousePoint.x, objMousePoint.y, MONITOR_DEFAULTTOPRIMARY)

' 2) 获取当前监视器信息及逻辑尺寸
objCurrentMonitorInfo.cbSize = Len(objCurrentMonitorInfo)
Call GetMonitorInfo(lngCurrentMonitorHWnd, objCurrentMonitorInfo)

解答

1. 差异是否正常?

这种差异不正常,属于Access Runtime 2013的兼容性问题,并非Windows API调用的预期行为。

2. 是否受Access Runtime架构影响?

是的,核心原因在于DPI感知模式的差异:

  • 完整版Access 2013及后续版本默认启用DPI感知,会自动适配系统缩放比例,调用API时返回经过缩放的逻辑坐标。
  • Access Runtime 2013默认未启用DPI感知,系统会对其进行DPI虚拟化(系统级缩放),此时调用GetMonitorInfo会返回未经缩放的物理坐标,而非适配后的逻辑坐标,导致数值偏差。

3. 为何直接调用Windows API仍受影响?

Windows API的坐标返回值会受调用进程的DPI感知模式影响:

  • 进程启用DPI感知时,API返回适配系统缩放的逻辑坐标。
  • 进程未启用DPI感知时,系统开启DPI虚拟化,API返回物理坐标,系统会自动缩放进程界面,但进程自身获取到的坐标未经过适配,因此出现差异。

解决建议

  1. 修改Access Runtime 2013的DPI感知设置:

    • 找到Access Runtime 2013主程序MSACCESS.EXE(通常路径为C:\Program Files (x86)\Microsoft Office\Office15)
    • 右键属性→兼容性→勾选“高DPI缩放替代”,下拉选择“应用程序”
    • 保存设置后重启Runtime,再测试API调用结果
  2. 代码中手动处理DPI缩放:

    • 通过GetDpiForMonitor或GetDeviceCaps获取当前监视器的DPI值,计算缩放比例后对GetMonitorInfo返回的坐标进行手动转换:
      Dim dpiX As Long, dpiY As Long
      GetDpiForMonitor lngCurrentMonitorHWnd, MDT_EFFECTIVE_DPI, dpiX, dpiY
      Dim scaleX As Double, scaleY As Double
      scaleX = dpiX / 96 ' 96为标准DPI值
      scaleY = dpiY / 96
      ' 转换坐标至适配缩放后的逻辑值
      mlngCurrentScreenLeft = objCurrentMonitorInfo.rcMonitor.Left * scaleX
      mlngCurrentScreenRight = objCurrentMonitorInfo.rcMonitor.Right * scaleX
      mlngCurrentScreenTop = objCurrentMonitorInfo.rcMonitor.Top * scaleY
      mlngCurrentScreenBottom = objCurrentMonitorInfo.rcMonitor.Bottom * scaleY
      

内容的提问来源于stack exchange,提问作者Chau Chun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:50:46