检索辅助监视器DPI的正确方法是什么?

时间:2015-10-31 01:07:38

标签: c# c++ wpf winapi

问题
在Windows 8.1(及更新版本)上,DPI设置是每个监视器。我可以在系统设置中清楚地看到我的主显示器(笔记本电脑)设置为125%dpi,而我的备用显示器设置为100%dpi。我的应用程序完全用C#编写,我尝试的每个API调用都会导致辅助监视器的DPI不正确。请记住,我在我的进程初始化中调用此方法,并在清单中指定了DPI:

(shcore.dll)
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS::PROCESS_PER_MONITOR_DPI_AWARE);

尝试

(shcore.dll) 
GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE::MDT_EFFECTIVE_DPI, &dpiX, &dpiY)

(无论hMonitor句柄如何,结果为120)

(user32.dll)
IntPtr dC = CreateDC(...);
double logX = (double)GetDeviceCaps(dC, LOGPIXELSX);
double logY = (double)GetDeviceCaps(dC, LOGPIXELSY);

(无论CreateDC的设备名称如何,结果为120)

监控布局
另一件让我感到困惑的事情是,第一台显示器位于{0,0,1920,1080},但第二台显示器位于{2400,0,2400,1350},实际桌面大小为{4800x1350},虚拟桌面大小{3840x1080},但显示器之间缺少我无法解释的像素,我不明白。

                 Screen 1    Screen 2
Actual Pixels:   1920x1080   2400x1350
Virtual Pixels:  1536x864    1920x1080
Top-Left Coord:  0x0         2400x0
Actual DPI:      120 (125%)   96 (100%)
Returned DPI:    120 (125%)  120 (125%)

另一种我可以确认显示器是不同DPI的方法是,将任何DPI识别应用程序的中心点拖过监视器之间的边界将导致窗口改变它的大小以在显示器之间保持一致(WPF通过以下方式实现默认值)。

1 个答案:

答案 0 :(得分:3)

我已经和它斗争了一天,在发布问题后不到一个小时我找到了答案。如果有人在将来遇到这个问题,我会在这里留下这个问题。

正如我上面尝试的那样,获取备用监视器DPI的正确方法是shcore.dll GetDpiForMonitor方法。问题是SetProcessDpiAwareness没有及早调用以在windows / wpf应用程序中产生影响。我通过创建一个新的控制台应用程序和一个新的wpf应用程序并用最少的代码重现它来测试它。控制台应用程序返回正确的值,而wpf应用程序返回不正确的值。

解决方案是将以下内容添加到清单文件中:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
  </windowsSettings>
</application>

这里的关键是dpiAware标记的值,它是True/PM而不仅仅是True,这才是最重要的。