如何在高DPI系统中获得真正的屏幕分辨率? [英] How to obtain the real screen resolution in a High DPI system?
问题描述
一个非常肮脏的伎俩跨越我的想法将是创建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屋!