如何在高DPI系统中获得真正的屏幕分辨率? [英] How to obtain the real screen resolution in a High DPI system?

查看:275
本文介绍了如何在高DPI系统中获得真正的屏幕分辨率?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,Delphi程序不是DPI知道的。直到最近我才需要真正的屏幕分辨率(在更高的DPI计算机中,使其更容易阅读屏幕上的内容为150%时,Screen.Width报告的错误分辨率为)。一些建议是使应用程序高DPI感知(XML清单),但其他人警告我们这涉及很多工作!所以,懒惰(或缺乏时间),我想知道是否有一个技巧来计算真正的分辨率。



一个非常肮脏的伎俩跨越我的想法将是创建DPI知道的一个配套工具(微型控制台应用程序)。所有我需要做的就是调用这个工具,并从中获得真正的分辨率。
漂亮的斯巴达,但它应该工作。无论如何,一定要有更好的方法去做!

解决方案

Win32_DesktopMonitor WMI类将产生信息。



例如,使用从这里获取的代码: Delphi7:获取附加的监视器属性

  {$ APPTYPE CONSOLE} 

使用
SysUtils,
ActiveX,
ComObj,
变体;

函数VarStrNull(VarStr:OleVariant):string;
//虚函数处理空变量
begin
结果:='';
如果不是VarIsNull(VarStr)then
结果:= VarToStr(VarStr);
结束

procedure GetMonitorInfo;
var
objWMIService:OleVariant;
colItems:OleVariant;
colItem:OleVariant;
oEnum:IEnumvariant;
iValue:LongWord;

函数GetWMIObject(const objectName:String):IDispatch;
var
chEaten:Integer;
BindCtx:IBindCtx;
Moniker:IMoniker;
begin
OleCheck(CreateBindCtx(0,BindCtx));
OleCheck(MkParseDisplayName(BindCtx,StringToOleStr(objectName),chEaten,
Moniker));
OleCheck(Moniker.BindToObject(BindCtx,nil,IDispatch,Result));
结束

begin
objWMIService:= GetWMIObject('winmgmts:\\localhost\root\CIMV2');
colItems:= objWMIService.ExecQuery
('SELECT * FROM Win32_DesktopMonitor','WQL',0);
oEnum:= IUnknown(colItems._NewEnum)为IEnumvariant;
while oEnum.Next(1,colItem,iValue)= 0 do
begin
Writeln('Caption'+ VarStrNull(colItem.Caption));
Writeln('Device ID'+ VarStrNull(colItem.DeviceID));
Writeln('Width'+ VarStrNull(colItem.ScreenWidth));
Writeln('Height'+ VarStrNull(colItem.ScreenHeight));
Writeln;
结束
结束

begin
try
CoInitialize(nil);
try
GetMonitorInfo;
Readln;
finally
CoUninitialize;
结束
除了
在E上:异常do
begin
Writeln(E.Classname,':',E.Message);
Readln;
结束
结束
结束。

如果由于任何原因WMI不可用,则需要单独的DPI感知过程来完成工作。哪些也将涉及一些IPC。



另一个问题是Windows的最新版本已经改变了这些WMI类的行为。您可能需要使用不同的WMI查询。请参阅: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/138d387c-b222-4c9f-b3bb-c69ee890491c/problem-with-win32desktopmonitor-in- windows-8-platform?forum = windowsgeneraldevelopmentissues


So, Delphi programs are not DPI aware. This didn't bother me much until recently when I needed the real screen resolution (Wrong resolution reported by Screen.Width when "Make it easier to read what's on screen" is 150%) in a computer with High DPI. Some recommended was to make the application High DPI aware (XML manifest) but others are warning us that this involves a lot of work! So, being lazy (or lacking time), I wonder if there is a trick to compute the real resolution.

One very dirty trick that cross my mind would be to create a companion tool (tiny console app) that is DPI aware. All I have to do then is to call this tool and obtain the real resolution from it. Pretty spartan but it should work. Anyway, there must be a nicer way to do it!

解决方案

The Win32_DesktopMonitor WMI class will yield the information.

For instance, using code taken from here: Delphi7: Get attached monitor properties

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

function VarStrNull(VarStr: OleVariant): string;
// dummy function to handle null variants
begin
  Result := '';
  if not VarIsNull(VarStr) then
    Result := VarToStr(VarStr);
end;

procedure GetMonitorInfo;
var
  objWMIService: OleVariant;
  colItems: OleVariant;
  colItem: OleVariant;
  oEnum: IEnumvariant;
  iValue: LongWord;

  function GetWMIObject(const objectName: String): IDispatch;
  var
    chEaten: Integer;
    BindCtx: IBindCtx;
    Moniker: IMoniker;
  begin
    OleCheck(CreateBindCtx(0, BindCtx));
    OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten,
      Moniker));
    OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
  end;

begin
  objWMIService := GetWMIObject('winmgmts:\\localhost\root\CIMV2');
  colItems := objWMIService.ExecQuery
    ('SELECT * FROM Win32_DesktopMonitor', 'WQL', 0);
  oEnum := IUnknown(colItems._NewEnum) as IEnumvariant;
  while oEnum.Next(1, colItem, iValue) = 0 do
  begin
    Writeln('Caption      ' + VarStrNull(colItem.Caption));
    Writeln('Device ID    ' + VarStrNull(colItem.DeviceID));
    Writeln('Width        ' + VarStrNull(colItem.ScreenWidth));
    Writeln('Height       ' + VarStrNull(colItem.ScreenHeight));
    Writeln;
  end;
end;

begin
  try
    CoInitialize(nil);
    try
      GetMonitorInfo;
      Readln;
    finally
      CoUninitialize;
    end;
  except
    on E: Exception do
    begin
      Writeln(E.Classname, ': ', E.Message);
      Readln;
    end;
  end;
end.

If for any reason WMI is not available then you need a separate DPI aware process to do the work. Which will also entail some IPC.

Another problem is that recent versions of Windows have changed behaviour for these WMI classes. You may need to use different WMI queries. See here: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/138d387c-b222-4c9f-b3bb-c69ee890491c/problem-with-win32desktopmonitor-in-windows-8-platform?forum=windowsgeneraldevelopmentissues

这篇关于如何在高DPI系统中获得真正的屏幕分辨率?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆