在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