简体   繁体   English

在 Delphi / C++ Builder 中使用 WebView (EdgeHTML)

[英]Using WebView (EdgeHTML) in Delphi / C++ Builder

Am I understanding correctly that EdgeHTML is now available to desktop (Win32/Win64 applications) now in Windows 10?我是否正确理解 EdgeHTML 现在可用于 Windows 10 中的桌面(Win32/Win64 应用程序)? According to these blog posts:根据这些博客文章:

https://blogs.windows.com/msedgedev/2018/05/09/modern-webview-winforms-wpf-apps/ https://blogs.windows.com/msedgedev/2018/10/04/edgehtml-18-october-2018-update/ https://docs.microsoft.com/en-us/windows/communitytoolkit/controls/wpf-winforms/webview https://blogs.windows.com/msedgedev/2018/05/09/modern-webview-winforms-wpf-apps/ https://blogs.windows.com/msedgedev/2018/10/04/edgehtml-18- october-2018-update/ https://docs.microsoft.com/en-us/windows/communitytoolkit/controls/wpf-winforms/webview

It appears that Microsoft has added EdgeHTML WebViewControl for Windows desktop (Win32) apps which hasn't been available for desktop apps so far (only Trident based MSHTML control was available for desktop apps).看来微软已经为 Windows 桌面 (Win32) 应用程序添加了 EdgeHTML WebViewControl,到目前为止,该应用程序尚未可用于桌面应用程序(只有基于 Trident 的 MSHTML 控件可用于桌面应用程序)。

If this is true, is there a possibility to utilize this in Delphi/C++ Builder or do we have to wait for a new TWebView control in the new update of RAD Studio?如果这是真的,是否有可能在 Delphi/C++ Builder 中使用它,或者我们是否必须等待 RAD Studio 的新更新中的新TWebView控件? If possible - are there any code samples to look at (C++ Builder or Delphi that is)?如果可能 - 是否有任何代码示例可以查看(C++ Builder 或 Delphi)? And does the requirement of .NET means it can't be utilized in regular Win32/Win64 app as produced by RAD Studio? .NET 的要求是否意味着它不能在 RAD Studio 生成的常规 Win32/Win64 应用程序中使用?

This answer is outdated but may be interesting to learn about the technical background.这个答案已经过时,但了解技术背景可能很有趣。 RAD Studio 10.4 Sydney now supports using the Edge browser out of the box. RAD Studio 10.4 Sydney 现在支持使用开箱即用的 Edge 浏览器。 See my other answer .请参阅我的另一个答案


The WebView control is offered via WinRT and does not depend on .net. WebView 控件通过 WinRT 提供,不依赖于 .net。 You can use it from normal Win32 applications.您可以从普通的 Win32 应用程序中使用它。

WinRT (Windows Runtime), now in Windows 10 rebranded as UWP (Universal Windows Platform), is something like the successor of COM. WinRT(Windows 运行时),现在在 Windows 10 中更名为 UWP(通用 Windows 平台),类似于 COM 的继承者。

Like COM it is heavily based on interfaces and the available interfaces are defined in type libraries.与 COM 一样,它很大程度上基于接口,并且可用接口在类型库中定义。 For WinRT, the type libraries are stored in *.WinMD files in the Windows system directory.对于 WinRT,类型库存储在 Windows 系统目录中的 *.WinMD 文件中。 The type library which contains the functionality we need to embed the Edge browser is Windows.Web.winmd .包含我们需要嵌入 Edge 浏览器的功能的类型库是Windows.Web.winmd

Delphi does support using WinRT components and it comes with translations of some of the type libraries and some additional helper functions and classes to work with WinRT. Delphi 确实支持使用 WinRT 组件,并且附带了一些类型库的翻译以及一些附加的帮助函数和类以与 WinRT 一起使用。

However, there is currently no tool to automatically translate WinMD files or IDL files derived from WinMD files to Delphi code.但是,目前还没有工具可以将 WinMD 文件或从 WinMD 文件派生的 IDL 文件自动转换为 Delphi 代码。 If you want to use WinRT functionality that does not ship with Delphi, you have to manually translate the type definitions to Delphi code.如果要使用 Delphi 未附带的 WinRT 功能,则必须手动将类型定义转换为 Delphi 代码。

WinRT heavily uses generic interfaces (interfaces with type parameters) that are not compatible with the way generic interfaces work in Delphi. WinRT 大量使用通用接口(带有类型参数的接口),这些接口与 Delphi 中通用接口的工作方式不兼容。 This requires some manual adjustments when translating the type definitions.这需要在翻译类型定义时进行一些手动调整。

If you install the Windows Platform SDK, you find IDL and C++ translations of the WinRT type libraries in a directory like Drive:\\Windows Kits\\10\\Include\\10.0.17134.0\\winrt .如果安装 Windows 平台 SDK,您会在Drive:\\Windows Kits\\10\\Include\\10.0.17134.0\\winrt等目录中找到 WinRT 类型库的 IDL 和 C++ 翻译。

I have used these files as templates to create a very basic Proof of Concept Delphi project (for Delphi 10.2) which uses an embedded Edge browser.我使用这些文件作为模板来创建一个非常基本的概念证明 Delphi 项目(适用于 Delphi 10.2),它使用嵌入式 Edge 浏览器。 You can find the code below.您可以在下面找到代码。 In order to test this, just create a new VCL project, paste the code and connect the FormCreate , FormDestroy and FormResize events with the form.为了测试这一点,只需创建一个新的 VCL 项目,粘贴代码并将FormCreateFormDestroyFormResize事件与表单连接起来。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  System.Types,
  Winapi.Winrt,
  System.Win.WinRT,
  WinAPI.Foundation,
  WinAPI.Foundation.Types;

const
  SWebViewControlProcess = 'Windows.Web.UI.Interop.WebViewControlProcess';

type
  // Interface with functionality to interact with WebBrowser Control
  // https://docs.microsoft.com/en-us/uwp/api/windows.web.ui.iwebviewcontrol
  IWebViewControl = interface(IInspectable)
  ['{3F921316-BC70-4BDA-9136-C94370899FAB}']
    procedure Placeholder_SourceGet; safecall;
    procedure Placeholder_SourcePut; safecall;
    procedure Placeholder_DocumentTitle; safecall;
    procedure Placeholder_CanGoBack; safecall;
    procedure Placeholder_CanGoForward; safecall;
    procedure Placeholder_DefaultBackgroundColorPut; safecall;
    procedure Placeholder_DefaultBackgroundColorGet; safecall;
    procedure Placeholder_ContainsFullScreenElement; safecall;
    procedure Placeholder_Settings; safecall;
    procedure Placeholder_DeferredPermissionRequests; safecall;
    procedure Placeholder_GoForward; safecall;
    procedure Placeholder_GoBack; safecall;
    procedure Placeholder_Refresh; safecall;
    procedure Placeholder_Stop; safecall;
    procedure Navigate(source: IUriRuntimeClass); stdcall;
    procedure NavigateToString(text: HString); stdcall;
    // TODO: Declare further properties and functions of IWebViewControl
  end;

  IWebViewControlProcess = interface;

  // Declare  IWebViewControlSite
  IWebViewControlSite = interface(IInspectable)
  ['{133F47C6-12DC-4898-BD47-04967DE648BA}']
    function get_Process: IWebViewControlProcess; safecall;
    procedure put_Scale(value: Double); safecall;
    function get_Scale: Double; safecall;
    procedure put_Bounds(value: TRectF); safecall;
    function get_Bounds: TRectF; safecall;
    procedure put_IsVisible(value: Boolean); safecall;
    function get_IsVisible: Boolean; safecall;

    // TODO: Declare further properties and functions of IWebViewControlSite

    property Process: IWebViewControlProcess read get_Process;
    property Scale: Double read get_Scale write put_Scale;
    property Bounds: TRectF read get_Bounds write put_Bounds;
    property IsVisible: Boolean read get_IsVisible write put_IsVisible;
  end;

  // types for reacting to when the WebView has finished initialization
  IAsyncOperation_1__IWebViewControl = interface;

  IAsyncOperationCompletedHandler_1__IWebViewControl = interface(IUnknown)
  ['{d61963d6-806d-50a8-a81c-75d9356ad5d7}']
    procedure Invoke(asyncInfo: IAsyncOperation_1__IWebViewControl; asyncStatus: AsyncStatus); safecall;
  end;

  IAsyncOperation_1__IWebViewControl = interface(IInspectable)
  ['{ac3d28ac-8362-51c6-b2cc-16f3672758f1}']
    procedure put_Completed(handler: IAsyncOperationCompletedHandler_1__IWebViewControl); safecall;
    function get_Completed: IAsyncOperationCompletedHandler_1__IWebViewControl; safecall;
    function GetResults: IWebViewControl; safecall;
    property Completed: IAsyncOperationCompletedHandler_1__IWebViewControl read get_Completed write put_Completed;
  end;

  TWebViewControlCompleted = procedure(asyncInfo: IAsyncOperation_1__IWebViewControl; aasyncStatus: AsyncStatus) of object;

  TWebViewControlCompletedHandler = class(TInspectableObject,
      IAsyncOperationCompletedHandler_1__IWebViewControl
      )
  private
    FEvent: TWebViewControlCompleted;
  public
    procedure Invoke(asyncInfo: IAsyncOperation_1__IWebViewControl; aasyncStatus: AsyncStatus); safecall;
    constructor Create(AEvent: TWebViewControlCompleted);
  end;

   // The interface for interacting with the process hosting the web view control
   // https://docs.microsoft.com/en-us/uwp/api/windows.web.ui.interop.webviewcontrolprocess
  [WinRTClassNameAttribute(SWebViewControlProcess)]
  IWebViewControlProcess = interface(IInspectable)
  ['{02C723EC-98D6-424A-B63E-C6136C36A0F2}']
    function get_ProcessId: Cardinal; safecall;
    function get_EnterpriseId: HSTRING; safecall;
    function get_IsPrivateNetworkClientServerCapabilityEnabled: Boolean; safecall;
    function CreateWebViewControlAsync(hostWindowHandle: Int64; bounds: TRectF): IAsyncOperation_1__IWebViewControl; safecall;
    procedure Placeholder_GetWebViewControls; safecall;
    procedure Terminate; safecall;

    property ProcessId: Cardinal read get_ProcessId;
    property EnterpriseId: HSTRING read get_EnterpriseId;
    property IsPrivateNetworkClientServerCapabilityEnabled: Boolean read get_IsPrivateNetworkClientServerCapabilityEnabled;

    // TODO:
    //[eventadd] HRESULT ProcessExited([in] Windows.Foundation.TypedEventHandler<Windows.Web.UI.Interop.WebViewControlProcess*, IInspectable*>* handler, [out] [retval] EventRegistrationToken* token);
    //[eventremove] HRESULT ProcessExited([in] EventRegistrationToken token);
  end;

  // The CoClass to create an IWebViewControlProcess instance
  TWebViewControlProcess = class(TWinRTGenericImportI<IWebViewControlProcess>)
  end;

type

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
    FProcess: IWebViewControlProcess;
    FBrowser: IWebViewControl;
    FBrowserSite: IWebViewControlSite;
    procedure WebViewCompleted(asyncInfo: IAsyncOperation_1__IWebViewControl; aasyncStatus: AsyncStatus);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  Rect: TRectF;
  AsyncOperation: IAsyncOperation_1__IWebViewControl;
    CompletedHandler: IAsyncOperationCompletedHandler_1__IWebViewControl;
begin
  CompletedHandler:=TWebViewControlCompletedHandler.Create(WebViewCompleted);

  // Size for browser
  Rect:= TRectF.Create(0, 0, ClientWidth, ClientHeight);

  // Create hosting process
  FProcess:= TWebViewControlProcess.Create();

  // Create WebView Control
  AsyncOperation:= FProcess.CreateWebViewControlAsync(self.Handle, Rect);

  // We will get notified when the control creation is finished
  AsyncOperation.Completed:= CompletedHandler;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // If there is a hosting process, then terminate it
  if Assigned(FProcess) then
  begin
    FProcess.Terminate;
  end;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  if Assigned(FBrowserSite) then
  begin
    FBrowserSite.Bounds := TRectF.Create(0,0,ClientWidth, ClientHeight);
  end;
end;

procedure TForm1.WebViewCompleted(
  asyncInfo: IAsyncOperation_1__IWebViewControl;
  aasyncStatus: AsyncStatus);
var
  WinS: TWindowsString;
  Uri: IUriRuntimeClass;
begin
  // Initializing the WebView control was successful

  // Remember reference to control
  FBrowser:= asyncInfo.GetResults();
  FBrowserSite := FBrowser as IWebViewControlSite;

  // Load web page into control
  WinS:= TWindowsString.Create('http://www.whatismybrowser.com');
  Uri:= TUri.CreateUri(WinS);
  FBrowser.Navigate(Uri);
end;

{ TWebViewControlCompletedHandler }

constructor TWebViewControlCompletedHandler.Create(
  AEvent: TWebViewControlCompleted);
begin
  FEvent := AEvent;
end;

procedure TWebViewControlCompletedHandler.Invoke(
  asyncInfo: IAsyncOperation_1__IWebViewControl;
  aasyncStatus: AsyncStatus);
begin
  FEvent(asyncInfo, aasyncStatus);
end;

end.

在此处输入图片说明

RAD Studio 10.4 Sydney comes with enhanced support for the new Chromium-based Edge browser by Microsoft. RAD Studio 10.4 Sydney增强了对微软基于 Chromium 的新 Edge 浏览器的支持。

There is both a new Control TEdgeBrowser that can be used to use the Edge browser engine directly as well as the possibility to allow the classic TWebBrowser control to use the new Edge rendering engine automatically when it is available via the TWebBrowser.SelectedEngine property.有一个新的控件TEdgeBrowser可用于直接使用 Edge 浏览器引擎,以及允许经典TWebBrowser控件在通过TWebBrowser.SelectedEngine属性可用时自动使用新的 Edge 渲染引擎的TWebBrowser.SelectedEngine

Detailed explanation in this blog entry by Embarcadero: Embarcadero 在这篇博客文章中的详细解释:

As far as I know, we can't access the EdgeHtml from C++ now, Someone has submitted a suggestion on the uservoice site.据我所知,我们现在无法从 C++ 访问 EdgeHtml,有人在 uservoice 站点上提交了建议。 I suggest you could vote it.我建议你可以投票。 Expose EdgeHTML C++ API 公开 EdgeHTML C++ API

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM