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%:获取的参数未适配系统缩放,数值与实际逻辑坐标偏差明显
已尝试方案
- 绕过Access窗体句柄,改用资源管理器窗口句柄获取监视器句柄,结果仍有差异:
' 1.) 通过资源管理器句柄获取监视器句柄 lngCurrentMonitorHWnd = MonitorFromWindow(69911, MONITOR_DEFAULTTONULL) ' 2) 获取当前监视器信息及逻辑尺寸 objCurrentMonitorInfo.cbSize = Len(objCurrentMonitorInfo) Call GetMonitorInfo(lngCurrentMonitorHWnd, objCurrentMonitorInfo)
- 更换监视器句柄获取方式,使用
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返回物理坐标,系统会自动缩放进程界面,但进程自身获取到的坐标未经过适配,因此出现差异。
解决建议
修改Access Runtime 2013的DPI感知设置:
- 找到Access Runtime 2013主程序
MSACCESS.EXE(通常路径为C:\Program Files (x86)\Microsoft Office\Office15) - 右键属性→兼容性→勾选“高DPI缩放替代”,下拉选择“应用程序”
- 保存设置后重启Runtime,再测试API调用结果
- 找到Access Runtime 2013主程序
代码中手动处理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
相关产品推荐
相关产品推荐

