给自己看的,方便以后查阅!对某些人,如果要加注释你才能看得懂,请绕行。
HTML中的测试代码
//测试JS调用C++,无参函数 function testCallFunc() { window.cat8637.TheFuncNoParam(); } //测试JS调用C++,带两个参数函数 function testCallFunc2() { var arg1 = document.getElementById("func2_input1").value; var arg2 = document.getElementById("func2_input2").value; alert(window.cat8637.TheFuncHave2Params(arg1,arg2)); //正确返回"head and tail"字符串。 }
第一部份:
CDialogEx继承类中加入下面属性
CComPtr<JSObject> m_jsObject;
并在构造class的时候加入下面的代码
m_jsObject = new JSObject();
第二部份:
void CTestWebBrowser_J2CDlg::NavigateComplete2Explorer1(LPDISPATCH pDisp, VARIANT* URL) { AddCustomObject(L"cat8637"); }
HRESULT CTestWebBrowser_J2CDlg::AddCustomObject(std::wstring objName) { HRESULT hRes; CComPtr<IDispatch> pDocDisp; CComQIPtr<IHTMLDocument2> pHtmlDoc2; CComQIPtr<IHTMLWindow2> pWindow; //Step1:Get pWindow IUnknown* pUnk = m_webBrowser.GetControlUnknown(); if (pUnk==NULL) return E_FAIL; CComQIPtr<IWebBrowser2> pWeb; hRes = pUnk->QueryInterface(IID_IWebBrowser2,(void**)&pWeb); if (FAILED(hRes) || pWeb==NULL) return hRes; hRes = pWeb->get_Document(&pDocDisp); if(FAILED(hRes) || pDocDisp==NULL) return hRes; hRes = pDocDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pHtmlDoc2); if(FAILED(hRes) || pHtmlDoc2==NULL) return hRes; hRes = pHtmlDoc2->get_parentWindow(&pWindow); if(FAILED(hRes) || pWindow==NULL) return hRes; //Step2: set JS object name DISPID dispid; IDispatchEx *pWndEx; hRes = pWindow->QueryInterface(&pWndEx); if (FAILED(hRes)||pWndEx==NULL) return hRes; hRes = pWndEx->GetDispID((BSTR)objName.c_str(), fdexNameEnsure, &dispid); if(FAILED(hRes)) return hRes; //Step3: method DISPID namedArgs[] = {DISPID_PROPERTYPUT}; static CComVariant avarParams[1];
//VARIANT avarParams[1];//IE11用这个 DISPPARAMS params; params.rgvarg = avarParams; params.rgvarg[0].pdispVal = m_jsObject; params.rgvarg[0].vt = VT_DISPATCH; params.rgdispidNamedArgs = namedArgs; params.cArgs = 1; params.cNamedArgs = 1; hRes = pWndEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL); if (FAILED(hRes)) return hRes; return S_OK; }
第三部份:
#ifndef _JS_LITESTEP_H__ #define _JS_LITESTEP_H__ #include <windows.h> #include <mshtmhst.h> #include <string> #include <map> /* Tester: Kagula@20141118 TestEnvironment: [1]vs2010SP3 + Win7 64bits From: Calling C++ function from JavaScript script running in a web browser control http://stackoverflow.com/questions/3747414/calling-c-function-from-javascript-script-running-in-a-web-browser-control */ class JSObject : public IDispatch { private: static const DISPID DISPID_USER_TheFuncNoParam = DISPID_VALUE + 1; static const DISPID DISPID_USER_TheFuncHave2Params = DISPID_VALUE + 2; std::map<std::wstring, DISPID> idMap; long ref; std::map<std::string, std::string> values; char *BSTRToLPSTR(BSTR bStr, LPSTR lpstr); public: JSObject(); // IUnknown virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); // IDispatch virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo); virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo); virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId); virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr); }; #endif
#include <utility> #include <fstream> #include "jsobject.h" #include "atlbase.h" #include <cstring> JSObject::JSObject() : ref(0) { idMap.insert(std::make_pair(L"TheFuncNoParam", DISPID_USER_TheFuncNoParam)); idMap.insert(std::make_pair(L"TheFuncHave2Params", DISPID_USER_TheFuncHave2Params)); } HRESULT STDMETHODCALLTYPE JSObject::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL; if (riid == IID_IUnknown || riid == IID_IDispatch) { *ppv = static_cast<IDispatch*>(this); } if (*ppv != NULL) { AddRef(); return S_OK; } return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE JSObject::AddRef() { return InterlockedIncrement(&ref); } ULONG STDMETHODCALLTYPE JSObject::Release() { int tmp = InterlockedDecrement(&ref); if (tmp == 0) { OutputDebugString(L"JSObject::Release(): delete this"); delete this; } return tmp; } HRESULT STDMETHODCALLTYPE JSObject::GetTypeInfoCount(UINT *pctinfo) { *pctinfo = 0; return S_OK; } HRESULT STDMETHODCALLTYPE JSObject::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { return E_FAIL; } HRESULT STDMETHODCALLTYPE JSObject::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { HRESULT hr = S_OK; for (UINT i = 0; i < cNames; i++) { std::map<std::wstring, DISPID>::iterator iter = idMap.find(rgszNames[i]); if (iter != idMap.end()) { rgDispId[i] = iter->second; } else { rgDispId[i] = DISPID_UNKNOWN; hr = DISP_E_UNKNOWNNAME; } } return hr; } HRESULT STDMETHODCALLTYPE JSObject::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { if (wFlags & DISPATCH_METHOD) { HRESULT hr = S_OK; std::string *args = new std::string[pDispParams->cArgs]; for (size_t i = 0; i < pDispParams->cArgs; ++i) { BSTR bstrArg = pDispParams->rgvarg[i].bstrVal; LPSTR arg = NULL; arg = BSTRToLPSTR(bstrArg, arg); args[pDispParams->cArgs - 1 - i] = arg; // also re-reverse order of arguments delete [] arg; } switch (dispIdMember) { case DISPID_USER_TheFuncNoParam: { //LSExecute(NULL, args[0].c_str(), SW_NORMAL); MessageBox(NULL,L"DISPID_USER_TheFuncNoParam",L"DISPID_USER_TheFuncNoParam",MB_OK); break; } case DISPID_USER_TheFuncHave2Params: { std::string strRet; strRet.append("return string is arg1="); strRet.append(args[0].c_str()); strRet.append(" arg2="); strRet.append(args[1].c_str()); char buf[256]; strncpy(buf, strRet.c_str(), sizeof(buf)); int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buf, -1, NULL, 0); BSTR bstrRet = SysAllocStringLen(0, lenW - 1); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buf, -1, bstrRet, lenW); pVarResult->vt = VT_BSTR; pVarResult->bstrVal = bstrRet; break; } default: hr = DISP_E_MEMBERNOTFOUND; } delete [] args; return hr; } return E_FAIL; } char *JSObject::BSTRToLPSTR(BSTR bStr, LPSTR lpstr) { int lenW = SysStringLen(bStr); int lenA = WideCharToMultiByte(CP_ACP, 0, bStr, lenW, 0, 0, NULL, NULL); if (lenA > 0) { lpstr = new char[lenA + 1]; // allocate a final null terminator as well WideCharToMultiByte(CP_ACP, 0, bStr, lenW, lpstr, lenA, NULL, NULL); lpstr[lenA] = '\0'; // Set the null terminator yourself } else { lpstr = NULL; } return lpstr; }