WebView2教程(基于C++)【五】JS与C++互访(下)

还有另外一种方式完成C++和JS交互的方式

WebView2允许把C++对象映射到JavaScript代码中。JavaScript代码拿到C++对象之后,就可以调用C++对象提供的方法了。

首先在工程中创建一个idl文件:

在Windows应用程序开发中,idl文件(Interface Definition Language 文件)主要用于定义跨进程或跨网络的组件间通信接口。

这些接口定义允许不同编程语言编写的组件相互通信,是实现组件对象模型(COM)、远程过程调用(RPC)和对象管理组(OMG)的CORBA等技术的关键元素。

接下来,我们编写这个文件的代码:

import "oaidl.idl";
import "ocidl.idl";

[uuid(BE3AE34D-5FCC-405E-BD52-1CDB06C28D5A), version(0.1)]
library HostLibrary
{
    //! [AddHostObjectInterface]
    [uuid(C7DEA087-CA5E-4CD7-A1BC-E62D741E3605), object, local]
    interface IHost : IUnknown
    {
        HRESULT CloseWindow();
    };
    //! [AddHostObjectInterface]
    [uuid(637abc45-11f7-4dde-84b4-317d62a638d6)]
    coclass Host
    {
        [default] interface IHost;
        interface IDispatch;
    };
}

接着编译以下这个文件

编译完成后,会生成两个代码文件

生成的代码文件我们不用管,我们要做的是实现这个接口的类:HostImpl

下面是HostImpl.h的代码

#pragma once
#include <windows.h>
#include <wil/com.h>
#include <wil/resource.h>
#include <wil/result.h>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <wrl.h>
#include <functional>
#include <map>
#include <string>
#include <wrl/client.h>
#include "Host_h.h"

class Win;
class Host : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, IHost, IDispatch>
{
public:
    Host(Win* win);
    STDMETHODIMP CloseWindow() override;
    STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) override;
    STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override;
    STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) override;
    STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override;
private:
    Win* win;
    wil::com_ptr<ITypeLib> m_typeLib;
};

下面是HostImpl.cpp的代码:

#include "HostImpl.h"

#include "Win.h"
Host::Host(Win* win):win{win}
{
}
STDMETHODIMP Host::CloseWindow()
{
    PostMessage(win->hwnd, WM_CLOSE, 0, 0);
    return S_OK;
}
STDMETHODIMP Host::GetTypeInfoCount(UINT* pctinfo)
{
    *pctinfo = 1;
    return S_OK;
}
STDMETHODIMP Host::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
{
    if (0 != iTInfo)
    {
        return TYPE_E_ELEMENTNOTFOUND;
    }
    if (!m_typeLib)
    {
        RETURN_IF_FAILED(LoadTypeLib(L"WebView2JS.tlb", &m_typeLib));
    }
    return m_typeLib->GetTypeInfoOfGuid(__uuidof(IHost), ppTInfo);
}
STDMETHODIMP Host::GetIDsOfNames(
    REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
{
    wil::com_ptr<ITypeInfo> typeInfo;
    RETURN_IF_FAILED(GetTypeInfo(0, lcid, &typeInfo));
    return typeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
}
STDMETHODIMP Host::Invoke(
    DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
    VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
    wil::com_ptr<ITypeInfo> typeInfo;
    RETURN_IF_FAILED(GetTypeInfo(0, lcid, &typeInfo));
    return typeInfo->Invoke(
        this, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}

我们这个对象公开了一个CloseWindow方法。

其他方法都是JS访问C++对象必须的,GetTypeInfo方法加载了一个tlb文件

编译运行程序,你会发现输出目录下就有这个tlb文件,这个文件的名字别搞错了。

现在需要把这个对象交给WebView2控件,代码如下:

// #include "HostImpl.h"
hostObj = Microsoft::WRL::Make<Host>(this);
VARIANT remoteObjectAsVariant = {};
hostObj.query_to<IDispatch>(&remoteObjectAsVariant.pdispVal);
remoteObjectAsVariant.vt = VT_DISPATCH;
webview->AddHostObjectToScript(L"host", &remoteObjectAsVariant);
remoteObjectAsVariant.pdispVal->Release();

这里的this就是我们前面介绍的Win对象。

现在我们写JavaScript代码,来调用HostImpl对象的这个CloseWindow

let closeBtn = document.getElementById("closeBtn");
closeBtn.addEventListener("mousedown", (e) => {
    e.preventDefault();
    e.stopPropagation();
    chrome.webview.hostObjects.sync.host.CloseWindow();
})

现在点击这个closeBtn就可以调用C++的CloseWindow方法了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值