Bubble's blog
Home
About
CWebBrowser实现 JavaScript 调用 C++
Category:
技术
Date:
2025-01-07T09:17:04Z
在 MFC 的 **CWebBrowser** 控件中,通过使用 COM 接口,可以实现 JavaScript 调用 C++ 的功能。以下是详细步骤: --- ### **实现原理** 1. **注册 ActiveX 接口:** 将 C++ 的方法通过 COM 的方式暴露给 JavaScript 使用。 2. **网页调用 COM 方法:** JavaScript 可以通过 `window.external` 对象调用暴露的接口方法。 3. **通信逻辑:** - C++ 定义接口并实现方法。 - JavaScript 调用这些方法并接收返回值。 --- ### **实现步骤** #### **1. 定义 C++ COM 接口** 创建一个继承自 `IDispatch` 的 COM 类,用于定义 C++ 的方法。通过 `IDispatch`,可以暴露方法给 JavaScript。 ```cpp // MyBrowserInterface.h #pragma once #include <afxdisp.h> // 包含 IDispatch class CMyBrowserInterface : public IDispatch { public: CMyBrowserInterface(); virtual ~CMyBrowserInterface(); // IUnknown 接口方法 STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IDispatch 接口方法 STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo); STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId); STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr); // 自定义方法 HRESULT ShowMessage(BSTR message); HRESULT AddNumbers(int a, int b, int* result); private: ULONG m_refCount; }; ``` 实现 `CMyBrowserInterface.cpp`: ```cpp #include "MyBrowserInterface.h" #include <afxwin.h> CMyBrowserInterface::CMyBrowserInterface() : m_refCount(1) {} CMyBrowserInterface::~CMyBrowserInterface() {} // IUnknown 方法 STDMETHODIMP CMyBrowserInterface::QueryInterface(REFIID riid, void** ppvObject) { if (riid == IID_IUnknown || riid == IID_IDispatch) { *ppvObject = static_cast<IDispatch*>(this); AddRef(); return S_OK; } *ppvObject = nullptr; return E_NOINTERFACE; } STDMETHODIMP_(ULONG) CMyBrowserInterface::AddRef() { return InterlockedIncrement(&m_refCount); } STDMETHODIMP_(ULONG) CMyBrowserInterface::Release() { ULONG count = InterlockedDecrement(&m_refCount); if (count == 0) delete this; return count; } // IDispatch 方法 STDMETHODIMP CMyBrowserInterface::GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } STDMETHODIMP CMyBrowserInterface::GetTypeInfo(UINT, LCID, ITypeInfo**) { return E_NOTIMPL; } STDMETHODIMP CMyBrowserInterface::GetIDsOfNames(REFIID, LPOLESTR* rgszNames, UINT cNames, LCID, DISPID* rgDispId) { if (wcscmp(rgszNames[0], L"ShowMessage") == 0) { *rgDispId = 1; return S_OK; } else if (wcscmp(rgszNames[0], L"AddNumbers") == 0) { *rgDispId = 2; return S_OK; } return DISP_E_UNKNOWNNAME; } STDMETHODIMP CMyBrowserInterface::Invoke(DISPID dispIdMember, REFIID, LCID, WORD, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO*, UINT*) { if (dispIdMember == 1) // ShowMessage { if (pDispParams->cArgs == 1 && pDispParams->rgvarg[0].vt == VT_BSTR) { CString message(pDispParams->rgvarg[0].bstrVal); AfxMessageBox(message); return S_OK; } return DISP_E_BADPARAMCOUNT; } else if (dispIdMember == 2) // AddNumbers { if (pDispParams->cArgs == 2 && pDispParams->rgvarg[0].vt == VT_I4 && pDispParams->rgvarg[1].vt == VT_I4) { int a = pDispParams->rgvarg[1].intVal; int b = pDispParams->rgvarg[0].intVal; int result = a + b; if (pVarResult) { pVarResult->vt = VT_I4; pVarResult->intVal = result; } return S_OK; } return DISP_E_BADPARAMCOUNT; } return DISP_E_MEMBERNOTFOUND; } ``` --- #### **2. 将接口绑定到 WebBrowser** 将 `CMyBrowserInterface` 绑定到 `CWebBrowser` 控件,使其暴露给 JavaScript。 ```cpp CComPtr<CMyBrowserInterface> m_spBrowserInterface; // 初始化接口并绑定 m_spBrowserInterface = new CMyBrowserInterface(); CComQIPtr<IAxWinAmbientDispatch> spAmbient(m_browser.GetControlUnknown()); if (spAmbient) { spAmbient->PutExternalDispatch(m_spBrowserInterface); } ``` --- #### **3. JavaScript 调用 C++ 方法** 在 HTML 文件中,通过 `window.external` 访问 `CMyBrowserInterface` 的方法: ```html <!DOCTYPE html> <html> <head> <title>JavaScript to C++</title> </head> <body> <button onclick="callCpp()">Call C++</button> <script> function callCpp() { if (window.external) { // 调用 C++ 的 ShowMessage 方法 window.external.ShowMessage("Hello from JavaScript!"); // 调用 AddNumbers 方法 let result = window.external.AddNumbers(10, 20); alert("Result of AddNumbers: " + result); } } </script> </body> </html> ``` --- ### **注意事项** 1. **安全性:** 确保暴露的接口不会被恶意 JavaScript 滥用。 2. **调试:** 使用浏览器调试工具检查 JavaScript 调用的返回值和错误信息。 3. **兼容性:** CWebBrowser 控件使用 IE 引擎,确保脚本支持的功能与目标 IE 版本一致。
Share
Permalink
×
0 Comments
latest
No comments.
Name
Email
Site
Comment
Human check: 1 + 7 = ?
Links
CSDN
GitHub
WHOIS
吾爱破解
看雪论坛
Categories
Default
0
技术
24
时事
0
Change Theme
Perfect Blue
Black Swan
0 Comments latest
No comments.