MFC对话框里利用CHtmlView加载界面(二)————MFC调用JaveScript

MFC对话框里利用CHtmlView加载界面(一)中,对如何利用CHtmlView加载网页进行了介绍。

本文,我们将在上一篇文章的基础上,对如何利用CHtmlView加载HTML,以及MFC如何调用JaveScript的方法进行讲解。

MFC对话框里利用CHtmlView加载界面(一)中,我们新建了一个继承自CHtmlView的CBaseHtmlView类,本文我们将继续在CBaseHtmlView中添加内容,以实现MFC调用JaveScript的方法。

一、关于MFC call HTML(JaveScript)涉及到的相关函数

1、获取IWebBrowser(ActiveX 插件) 初始化对象接口

LPDISPATCH GetHtmlDocument() const; 

示范:

CComPtr<IDispatch> spDisp = GetHtmlDocument(); //获取com 初始对象 接口指针
if (spDisp == NULL)
{
        ASSERT(FALSE);
	return FALSE;
}

2、根据1中的初始化接口, 获取组件的 IID_IHTMLDocument2 对象 接口m_spDoc

CComPtr<IHTMLDocument2>	m_spDoc = NULL;
spDisp->QueryInterface(IID_IHTMLDocument2, (void**)&m_spDoc);

3、根据2中的 m_spDoc接口 获取 组件的 Script接口

CComPtr<IDispatch> spDisp;
HRESULT hr = m_spDoc->get_Script(&spDisp); //获取com组件 Script接口
ATLASSERT(SUCCEEDED(hr));
return SUCCEEDED(hr);

4、利用 spDisp接口, 调用OLE自动化接口

HRESULT hr = spScript->GetIDsOfNames(IID_NULL, &bstrFunc, 1, LOCALE_SYSTEM_DEFAULT, &dispid);

//调用JaveScript接口
hr = spScript->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, &dispparams, &vaResult, &excepInfo, &nArgErr);
关于GetIDsOfNames和Invoke的解释,网上有大量相关知识,不了解的朋友可以自行百度。

以上就是在MFC 调用 JaveScript方法将要涉及到的函数。

 二、对MFC call HTML(JaveScript)函数的封装实现

有了一中的简单理解,我们需要将上述函数简单的封装到CBaseHtmlView类中,以便使用者的调用。

我们先看看CBaseHtmlView类中需要添加的声明:

/******************************************
****** MFC call Javascript 相关函数********
*******************************************/
	//MFC 通过com 调用 JavaScript接口
	CComPtr<IHTMLDocument2>	m_spDoc; //com组件的 IHTMLDocument2接口
	BOOL SetScriptDocument();  //获取IHTMLDocument2接口m_spDoc
	BOOL GetJScript(CComPtr<IDispatch>& spDisp);  //获取JScript接口
	const CString GetSystemErrorMessage(DWORD dwError);
	//无参调用
	BOOL CallJScript(const CString strFunc, _variant_t* pVarResult = NULL);
	//一个CString参数的调用
	BOOL CallJScript(const CString strFunc, const CString strArg1, _variant_t* pVarResult = NULL);
	//两个CString参数的调用
	BOOL CallJScript(const CString strFunc, const CString strArg1, const CString strArg2, _variant_t* pVarResult = NULL);
	//三个CString参数的调用
	BOOL CallJScript(const CString strFunc, const CString strArg1, const CString strArg2, const CString strArg3, _variant_t* pVarResult = NULL);
	//真正的调用JavaScript方法
	BOOL CallJScript(const CString strFunc, const CStringArray& paramArray, _variant_t* pVarResult = NULL);

我们声明了一个COM接口指针变量:CComPtr<IHTMLDocument2>    m_spDoc;

现在我们队上述的函数进行一一的说明和实现:

1、BOOL SetScriptDocument(); 

此函数的主要作用是 获取IHTMLDocument2接口m_spDoc。通常是指OnDocumentComplete函数中调用,以确保每次html或者网页加载完成后,第一时间刷新接口。

BOOL CBaseHtmlView::SetScriptDocument()
{
	CComPtr<IDispatch> spDisp = GetHtmlDocument(); //获取com 初始接口指针
	if (spDisp == NULL)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	m_spDoc = NULL;
	HRESULT hr = spDisp->QueryInterface(IID_IHTMLDocument2, (void **)&m_spDoc);
	if (FAILED(hr))
	{
		MessageBox(L"Failed to get HTML document COM object");
		return FALSE;
	}

	return TRUE;
}

2、BOOL GetJScript(CComPtr<IDispatch>& spDisp);

此函数的主要作用是获取JScript接口。

BOOL CBaseHtmlView::GetJScript(CComPtr<IDispatch>& spDisp)
{
	if (m_spDoc == NULL)
		return FALSE;

	HRESULT hr = m_spDoc->get_Script(&spDisp); //获取Script接口
	ATLASSERT(SUCCEEDED(hr));
	return SUCCEEDED(hr);
}

3、const CString GetSystemErrorMessage(DWORD dwError);

此函数的作用是解析错误信息。

const CString CBaseHtmlView::GetSystemErrorMessage(DWORD dwError)
{
	CString strError;
	LPTSTR lpBuffer;

	if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, dwError,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
		(LPTSTR)&lpBuffer, 0, NULL))
	{
		strError = "FormatMessage Netive Error";
	}
	else
	{
		strError = lpBuffer;
		LocalFree(lpBuffer);
	}
	return strError;
}

4、重载的5个CallJScript函数

此5个函数实现的MFC 调用 JaveScript的方法。方便用户调用。

主要的实现细节在BOOL CallJScript(const CString strFunc, const CStringArray& paramArray, _variant_t* pVarResult = NULL)函数中。

BOOL CBaseHtmlView::CallJScript(const CString strFunc, const CStringArray& paramArray, _variant_t* pVarResult /*= NULL*/)
{
	CComPtr<IDispatch> spScript;
	if (!GetJScript(spScript))
	{
		MessageBox(L"函数GetJScrip调用失败!");
		return FALSE;
	}

	CComBSTR bstrFunc(strFunc);
	DISPID dispid = NULL;
	//根据名称strFunc 获取 ids
	HRESULT hr = spScript->GetIDsOfNames(IID_NULL, &bstrFunc, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
	if (FAILED(hr))
	{
		MessageBox(GetSystemErrorMessage(hr));
		return FALSE;
	}

	DISPPARAMS dispparams;
	memset(&dispparams, 0, sizeof dispparams);

	INT_PTR arraySize = paramArray.GetSize();
	dispparams.cArgs = (UINT)arraySize; //参数个数
	dispparams.rgvarg = new VARIANT[dispparams.cArgs]; 

	for (int i = 0; i < arraySize; i++)
	{
		CComBSTR bstr = paramArray.GetAt(arraySize - 1 - i); // back reading
		bstr.CopyTo(&dispparams.rgvarg[i].bstrVal);
		dispparams.rgvarg[i].vt = VT_BSTR;
	}
	dispparams.cNamedArgs = 0;

	EXCEPINFO excepInfo;
	memset(&excepInfo, 0, sizeof excepInfo);
	_variant_t vaResult;
	UINT nArgErr = (UINT)-1;  // initialize to invalid arg

	//调用JaveScript接口
	hr = spScript->Invoke(dispid, IID_NULL, 0,
		DISPATCH_METHOD, &dispparams, &vaResult, &excepInfo, &nArgErr);
	
	delete[] dispparams.rgvarg;
	if (FAILED(hr))
	{
		MessageBox(GetSystemErrorMessage(hr));
		return FALSE;
	}

	if (pVarResult)
	{
		*pVarResult = vaResult;
	}
	return TRUE;
}
在看看其他4个函数的实现:

BOOL CBaseHtmlView::CallJScript(const CString strFunc, _variant_t* pVarResult /*= NULL*/)
{
	CStringArray paramArray;
	return CallJScript(strFunc, paramArray, pVarResult);
}

BOOL CBaseHtmlView::CallJScript(const CString strFunc, const CString strArg1, _variant_t* pVarResult /*= NULL*/)
{
	CStringArray paramArray;
	paramArray.Add(strArg1);
	return CallJScript(strFunc, paramArray, pVarResult);
}

BOOL CBaseHtmlView::CallJScript(const CString strFunc, const CString strArg1, const CString strArg2, _variant_t* pVarResult /*= NULL*/)
{
	CStringArray paramArray;
	paramArray.Add(strArg1);
	paramArray.Add(strArg2);
	return CallJScript(strFunc, paramArray, pVarResult);
}

BOOL CBaseHtmlView::CallJScript(const CString strFunc, const CString strArg1, const CString strArg2, const CString strArg3, _variant_t* pVarResult /*= NULL*/)
{
	CStringArray paramArray;
	paramArray.Add(strArg1);
	paramArray.Add(strArg2);
	paramArray.Add(strArg3);
	return CallJScript(strFunc, paramArray, pVarResult);
}
它们都调用了BOOL CallJScript(const CString strFunc, const CStringArray& paramArray, _variant_t* pVarResult = NULL)函数。

好了,有了上面的函数,我们就实现了MFC 对JaveScript的调用。

三、MFC call HTML(JaveScript)的示范

1、在OnInitialUpdate()在加载的网页

我们将在MFC对话框里利用CHtmlView加载界面(一)中OnInitialUpdate()在加载的网页,改为我们需要加载的html文件:

void CBaseHtmlView::OnInitialUpdate()
{
	CHtmlView::OnInitialUpdate();

	// TODO: 在此添加专用代码和/或调用基类
	//Navigate2(L"http://blog.csdn.net/qq_20828983?viewmode=contents", NULL, NULL);
	Navigate2(L"E:\\代码\\CHTMLDome2\\IE2\\index.html", NULL, NULL);
}

2、在OnDocumentComplete中发送消息

在OnDocumentComplete中,发送消息,以通知主对话框加载完成,使主对话框调用JaveScript方法。

void CBaseHtmlView::OnDocumentComplete(LPCTSTR lpszURL)
{
	// TODO: 在此添加专用代码和/或调用基类
	CHtmlView::OnDocumentComplete(lpszURL);
	SetScriptDocument(); //初始化com组件 IID_IHTMLDocument2接口

	::PostMessage(GetParent()->GetSafeHwnd(), WM_MAINJS_INITDATA, NULL, NULL);
}

3、在主界面中实现消息响应

LRESULT CCHTMLDome2Dlg::OnInitData(WPARAM wParam, LPARAM lParam)
{
	CString szLineData;
	szLineData = L"{ \"code\" :\"1\",  \
				  	\"time\" : \"month\", \
					\"xAxis\" : [\"One\", \"Two\", \"Three\", \"Four\", \"Five\"], \
					\"data\" : [\"254\", \"545\", \"167\", \"92\", \"45\"]  }";

	CString szPieData;
	szPieData = L"{ \"code\" :\"1\",  \
				 	\"time\" : \"Fri\", \
					\"data\" : [ { \"value\":\"345\", \"name\" : \"Others\"},\
					{ \"value\":\"110\",  \"name\" : \"iTunes\" },\
					{ \"value\":\"234\",  \"name\" : \"Netflix\" },\
					{ \"value\":\"935\",  \"name\" : \"Dropbox\" },\
					{ \"value\":\"98\",   \"name \": \"Chrome\" } ] }"
		;

	mHtmlView.CallJScript(L"showLiner", szLineData);
	mHtmlView.CallJScript(L"showPie", szPieData);

	return 0;
}

这里我们通常以JSON格式传递信息给JaveScript。 如上述函数,我们传递了两个数据:szLineData和szPieData, 分别调用了JaveScript中名为:"showLiner" 和 "showPie"的方法。


上图中的曲线图、饼状图的数据就是MFC传递给JaveScript的。

本文示范Dome下载地址:http://download.csdn.net/detail/qq_20828983/9894706












猜你喜欢

转载自blog.csdn.net/qq_20828983/article/details/74938707