本文记录如何从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构成的窗口了。
小结:
- 参考Debug WebView2 apps with Microsoft Edge DevTools,有几种方式可以在WebView2中打开开发者工具。
- IDispatch interface (oaidl.h)是IDispatch接口的文档。
- 参考Walkthrough: Create a traditional Windows Desktop application (C++)
- 参考Windows Runtime C++ Template Library (WRL)
注入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
错误。
- 如果名字没有搞对,在JS中使用此HostObject的时候会出现
- 对于方法
HostObjectSample::GetTypeInfo
中的LoadTypeLib(L"WebView2APISample.tlb", &m_typeLib)
,要把WebView2APISample
改为上一条生成的tlb的文件名字
技巧:
- 可以使用OLE-COM Object Viewer来查看TLB的内容
- 此工具随Windows SDK安装,命令行是oleview。初次使用需要让它在具有Admin权限的环境中,以注册要用到的COM组件
- 其他工具Type Library Viewers and Conversion Tools
改造成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对象,不过感觉这货可能还没有实现。
小结:
- Walkthrough: Create and use a static library
- Modify a C++ desktop (Win32) project to use Windows Runtime APIs
- Troubleshooting Microsoft Interface Definition Language 3.0 issues
(完)