How to obtain the real screen resolution in a High DPI system?

前端 未结 1 951
我寻月下人不归
我寻月下人不归 2021-01-06 11:47

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 &q

1条回答
  •  时光说笑
    2021-01-06 12:36

    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

    0 讨论(0)
提交回复
热议问题