2014-09-29 93 views
2

所以,Delphi程序不是DPI的意识。直到最近,当我需要具有高DPI的计算机中的真实屏幕分辨率(Wrong resolution reported by Screen.Width when "Make it easier to read what's on screen" is 150%)时,这并没有让我感到困扰。一些建议是让应用程序高DPI知道(XML清单),但其他人警告我们,这涉及到很多工作!所以,懒惰(或缺乏时间),我想知道是否有一个技巧来计算真实的分辨率。如何在高DPI系统中获得真实的屏幕分辨率?

一个非常肮脏的技巧,我想到的将是创建一个DPI知道的伴侣工具(小控制台应用程序)。我所要做的就是调用这个工具并从中获得真正的分辨率。 漂亮斯巴达,但它应该工作。无论如何,必须有更好的方式来做到这一点!

回答

4

Win32_DesktopMonitor WMI类将产生信息。

例如,使用从这里取代码: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. 

如果出于任何原因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

+0

这听起来像一个美妙的解决方案。不幸的是,我对WMI的一些不好的经验在某些电脑上不可用。我的程序在一些WMI函数之前使用。最后我不得不删除它们。如果您在Google中搜索“WMI不可用”,则会看到很多报告。 – Ampere 2015-10-28 17:33:53

+0

@ davidhefferman-我知道为什么我有这么多与WMI相关的错误:WMI是一种服务,在某些系统上默认情况下不会启用! https://www.youtube.com/watch?v=JgsHfc-4TUE – Ampere 2015-10-28 18:03:29

+0

这不符合我的WMI体验 – 2015-10-28 18:10:06