如何解决高DPI问题?

时间:2015-10-28 17:20:53

标签: delphi delphi-xe7

我需要从Delphi程序中获取桌面分辨率 但是,如果该程序不是DPI意识到Windows会对真正的屏幕分辨率撒谎,那么所有类型的问题都会从这里出现。

由于让程序完全了解DPI(我尝试避免WMI solution)是太多的工作了,我正在考虑使用一个快速的肮脏技巧:我将创建一个微观的DPI感知控制台程序,阅读真正的分辨率。

主程序将在每次需要分辨率时使用启动这个小程序(隐藏)。看起来很简单。正确?

问题1:我还有其他(更好)的选择吗? 问题2:我试图创建那个小程序。虽然有10行代码,但其EXE大小为2.1MB,内存占用为5.4MB! 我能把它缩小吗?如果程序足够小(RAM低于1MB),我可以让它一直运行而不会惹恼用户。

2 个答案:

答案 0 :(得分:2)

  

问题1:我还有其他(更好)的选择吗?

您可以根据之前的问题使用WMI:How to obtain the real screen resolution in a High DPI system?

  

问题2:我试图创建那个小程序。虽然有10行代码,但其EXE大小为2.1MB,内存占用为5.4MB!我能把它缩小吗?

诀窍是避免使用任何VCL单元,并尽量减少您使用的RTL单元的数量。您的目标应该是仅使用Windows单位。或者甚至避免它,并为您需要的功能创建自己的Windows API导入。

另一种选择是使用不同的编程语言创建此程序,该语言能够更好地删除死代码。我可能会用一个简短的C程序来做这件事。

答案 1 :(得分:0)

这是30KB的普通图标,15KB(如果你使用UPX),用Delphi 10 Seattle编译,在我的系统中大约需要150-200ms。

program ScreenSupport;

{$APPTYPE CONSOLE}

{$WEAKLINKRTTI ON}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}

uses
  Windows,
  Messages;

{$R *.res}

{$SetPEFlags $0200} // IMAGE_FILE_DEBUG_STRIPPED}      // $0200
{$SetPEFlags $0004} // IMAGE_FILE_LINE_NUMS_STRIPPED}  // $0004
{$SetPEFlags $0008} // IMAGE_FILE_LOCAL_SYMS_STRIPPED} // $0008
{$SetPEFlags $0001} // IMAGE_FILE_RELOCS_STRIPPED}     // $0001

Const WM_APP = $8000;
      msgSendScreenres = WM_APP+1;
      SM_CXVIRTUALSCREEN = 78;
      SM_CYVIRTUALSCREEN = 79;

function GetDesktopHeight: Integer;
begin
  Result := GetSystemMetrics(SM_CYVIRTUALSCREEN);
end;

function GetDesktopWidth: Integer;
begin
  Result := GetSystemMetrics(SM_CXVIRTUALSCREEN);
end;

procedure SendScreenRes(t: THandle);
begin
  if t = 0 then Exit;
  PostMessage(t,msgSendScreenres,GetDesktopWidth,GetDesktopHeight);
end;

function IsAnyParam(s: string): Boolean;
Var a: Integer;
begin
  Result := False;
  if ParamCount = 0 then Exit;
  for a := 1 to ParamCount do
   if ParamStr(a) = s then Exit(True);
end;

function StrToInt(const S: string): Integer;
Var E: Integer;
begin
  Val(S, Result, E);
end;

begin
// screen res requested
  if IsAnyParam('-screenres') then begin
    try
      SendScreenRes(StrToInt(ParamStr(2)));
    except
      Exit;
    end;
  end;
end.

要使用它,请从主应用程序中调用它:

Const msgSendScreenres = WM_APP+1;

ShellExecute(0,'open','ScreenSupport.exe',PChar('-screenres '+IntToStr(Form1.Handle)),'',SW_HIDE);

然后在主机上的私人声明中添加它

procedure WMScreenRes(var Msg: TMessage); message msgSendScreenres;

然后抓住它

procedure TForm1.WMScreenRes(var Msg: TMessage);
begin
  ScreenWidth  := Msg.WParam;
  ScreenHeight := Msg.LParam;
end;