本文记录如何从Win32桌面程序中使用WebView2。

创建Win32桌面项目

参考Get started with WebView2 in Win32 apps

假定你使用的是Visual Studio 2022,并安装好了相应的WorkLoad。 以及安装好了WebView Runtime或者合适的Edge浏览器版本。

首先创建一个基于C++的Windows Desktop Application。 安装相应的NuGet包:

  • Microsoft.Windows.ImplementationLibrary,提供WIL和WRL的源代码文件
  • Microsoft.Web.WebView2,提供对WebView2的支持

根据https://github.com/MicrosoftEdge/WebView2Samples/tree/master/GettingStartedGuides/Win32_GettingStarted来调整代码, 主要有下面几点:

  • 在InitInstance中,把WebView2相关的代码加载到UpdateWindow(hWnd);之后
  • 在WndProc中,去掉用不到的消息,比如WM_COMMAND、WM_PAINT等;然后增加WM_SIZE的处理,让WebView的大小随着窗口大小的变化而变化

完成以上的工作,就能得到一个只由WebView2构成的窗口了。

小结:

注入HostObject

参考Call native-side code from web-side code

目的是通过AddHostObjectToScript将一个COM例现注入到WebView2中,供JS调用。这个COM例现必须实现有IDispatch接口,以实现接口方法的动态查询和调用。

示例代码在https://github.com/MicrosoftEdge/WebView2Samples/tree/master/SampleApps/WebView2APISample

注意点:

  • 需要修改HostObjectSample.idl的编译选项,把生成的TLB文件的路径改为$(OutDir)$(ProjectName).tlb,主要是为了跟生成的exe文件在一起
    • 如果名字没有搞对,在JS中使用此HostObject的时候会出现Error loading type library/DLL错误。
  • 对于方法HostObjectSample::GetTypeInfo中的LoadTypeLib(L"WebView2APISample.tlb", &m_typeLib),要把WebView2APISample改为上一条生成的tlb的文件名字

技巧:

改造成C++/WinRT项目

首先参考Modify a Windows Desktop application project to add C++/WinRT support, 对Windows Desktop Application项目进行改造。

注意点:

  • 在pch.h中加入#pragma comment(lib, "windowsapp")

构建的时候会遇到如下错误:

Error	MIDL2003	[msg]redefinition [context]: _FLAGGED_WORD_BLOB	
Error	MIDL2003	[msg]redefinition [context]: IUnknown

wrong command injection when compiling legacy midl file #1033 的解释是使用了CppWinRT之后, 就没办法兼容在同一个项目中兼容旧的COM的IDL。看构建过程,在CppWinRT中,MIDL调用的时候使用到了@"x64\Debug\ProjectName.vcxproj.midlrt.rsp",导致出错。 一个解决的办法是将COM的IDL移到一个单独的静态库的项目中。

注意点:

  • 主项目需要添加一个到静态库项目的引用
  • 确保LoadTypeLib使用的是正确的tlb文件

根据 Can’t build any xaml islands app with 2.7.0-prerelease.210827001 #5793 直接编辑工程文件,在一个PropertyGroup里面开启<WebView2UseWinRT>true</WebView2UseWinRT>。 可以观察到:

  • 拷贝到目标目录中的Microsoft.Web.WebView2.Core.dll体积变大了
  • CppWinRT生成了x64\Debug\Generated Files\winrt\Microsoft.Web.WebView2.Core.h

本来想用ICoreWebView2DispatchAdapter Interface将WinRT对象转为带IDispatch的COM对象,不过感觉这货可能还没有实现。

小结:

(完)