测试WebBrwoser控件中JavaScript对C++函数的调用

给自己看的,方便以后查阅!对某些人,如果要加注释你才能看得懂,请绕行。


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;
}


你可能感兴趣的:(测试WebBrwoser控件中JavaScript对C++函数的调用)