启用 TWebBrowser 高 DPI 支持

Enabling TWebBrowser High DPI support

我正在使用支持高 DPI 的 RAD Studio Rio。

但它似乎在 TWebBrowser 上不起作用,至少在默认情况下不像在其他 VCL 组件上那样起作用。

因此,当我将应用程序从低 DPI 显示器拖到高 DPI 显示器时,用户界面和所有组件都会调整大小(包括网络浏览器容器),但网络浏览器内的内容不会保持不变。

我确信它可以启用,因为在显示器之间移动 Internet Explorer 确实会自动更改内容大小。

所以问题是如何也为 TWebBrowser 启用它?

我注意到当拖动 IE window 时,“缩放”设置会自动更改(从 100% 到 200% - 200% 是高 DPI 显示器的 DPI 缩放值),因此可以通过使用缩放,或以其他方式。但是还有一个滚动条大小的问题。

我还注意到 DOCHOSTUIFLAG_DPI_AWARE 标志的存在,它可能有用,但我还不知道如何使用它。

编辑:我创建了一个 IDocHostUIHandler 后代 class,其中包含 GetHostInfo 函数,我可以在其中控制标志,其中添加 DOCHOSTUIFLAG_DPI_AWARE 自动将 TWebBrowser 缩放到系统 DPI(如果系统 DPI 设置为 150%,Web 浏览器也会自动缩放到 150%)。不需要为此使用 FEATURE_BROWSER_EMULATION 注册表项。

更多信息请访问 https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa753260(v=vs.85)

TWebBrowser 包装了 InternetExplorer,因此控件的呈现不是由任何 VCL 代码完成的,而是由嵌入式 Internet Explorer 代码完成的。我们已经在各种项目中使用了它,设置兼容模式是获得所需显示的关键。

由于 IE 可以 正确缩放,您需要确保您在正确的模式下运行。 @Ondrej Kelle 的评论是 a useful article,应该向您展示如何执行此操作,因此我不会在这里重复。

我找到了两种方法:

解决方案 1
通过注册表项和值为您的应用程序启用 IE FEATURE_96DPI_PIXEL

uses
  System.SysUtils,
  System.Win.Registry,
  Vcl.Forms,
  Winapi.Windows;

procedure EnableDpiAwareness;
var
  Reg: TRegistry;
  App: string;
begin
  Reg := TRegistry.Create;
  try
    App := ExtractFileName(Application.ExeName);
    Reg.RootKey := HKEY_CURRENT_USER;

    if Reg.OpenKey('Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_96DPI_PIXEL', True) then
    begin
      Reg.WriteInteger(App, 1);
      Reg.CloseKey;
    end;
  finally;
    Reg.Free;
  end;
end;

解决方案 2
实现 TWebBrowser 的后代 class,重新实现 IDocHostUIHandler 接口(如 OP 编辑​​中所述):

unit DpiAwareWebBrowser;

interface

uses
  Winapi.Mshtmhst,
  SHDocVw;

type
  TDpiAwareWebBrowser = class(TWebBrowser, IDocHostUIHandler)
    strict private
      // IDocHostUIHandler "override"
      function GetHostInfo(var pInfo: TDocHostUIInfo): HRESULT; stdcall;
  end;

implementation

const
  DOCHOSTUIFLAG_DPI_AWARE = 000000;

function TDpiAwareWebBrowser.GetHostInfo(var pInfo: TDocHostUIInfo): HRESULT;
begin
  // original code from TWebBrowser.GetHostInfo
  pInfo.cbSize := SizeOf(pInfo);
  pInfo.dwFlags := 0;
  pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_NO3DBORDER;
  pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_THEME;
  pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_DPI_AWARE; // NEW added flag
  Result := S_OK;
//  ResizeScrollBars; // will be called by subsequent routines anyway.
end;

end.

两种方式做同样的事情。

DOCHOSTUIFLAG_DPI_AWARE
Internet Explorer 8. Causes layout engine to calculate document pixels as 96 dpi. Normally, a document pixel is the same size as a screen pixel. This flag is equivalent to setting the FEATURE_96DPI_PIXEL feature control key on a per-host basis.

来源:Microsoft Docs - DOCHOSTUIFLAG enumeration