VC6下CHtmlView中最簡單最全面的程式與網頁互動方法
阿新 • • 發佈:2018-12-27
簡單來說,終極目標------VC6和網頁相互呼叫對方的資料和方法;而呼叫方法時重點要捕獲返回值。
VC6下遠沒有VC7及其之後提供的操作豐富方便。一些深度應用的破解方法,鑽進應用的原理中,解釋起來很繁瑣;同時操作起來也非常麻煩。能夠達到同樣的功能,但是程式碼越少,使用起來越方便,可能這就是追求目標。通過如下的一些小技巧來達成目標,可以成系列的解決所有問題。
1. VC6獲取網頁DOM
網頁的模型就是DOM。主要就是對ChtmlView的功能進行增強,增強對DOM元素的取設、查詢等操作。
說明:要識別IHTMLDocument2,必須 #include “comdef.h”
1.1 獲取 document.body-
IHTMLElementPtr CHtmlViewEx::sIE_GetBody() { IHTMLElementPtr ipBody; IHTMLDocument2Ptr ipDocument = GetHtmlDocument(); if(ipDocument==NULL) return ipBody; ipDocument->get_body(&ipBody); return ipBody; }
1.2 實現該功能 document.getElementByID()-
//-js中的這個可以用, //-是因為dispinterface DispHTMLDocument 中有getElementByID 該方法- //- IHTMLDocument2 中沒有而IHTMLDocument3有。 //-考慮到我們最簡單的使用,我們不會引入IHTMLDocument3,而直接實現- IHTMLElementPtr CHtmlViewEx::sIE_GetElementByID(LPCTSTR strID) { IHTMLElementPtr ipElement; IHTMLDocument2Ptr ipDocument = GetHtmlDocument(); if(ipDocument==NULL) return ipElement; IHTMLElementCollectionPtr ipSet; ipDocument->get_all(&ipSet); if(ipSet==NULL) return ipElement; IDispatchPtr ipDispatch; _variant_t vtIndex; _bstr_t bstrName(strID); _variant_t vtName = bstrName; ipSet->item(vtName, vtIndex, &ipDispatch); ipElement = ipDispatch; return ipElement; }
1.3 獲取特定值,其實都是com的方法呼叫-
IHTMLElementPtr ipBody = sIE_GetBody();
_bstr_t bstrName(L"title");
_variant_t vtValue;
ipBody->getAttribute(bstrName, 0, &vtValue);
CString strTitle(vtValue.bstrVal);
2. VC6呼叫網頁JS函式和方法
2.1 獲取指令碼總的物件
IDispatchPtr CHtmlViewEx::sIE_GetScript()
{
IDispatchPtr ipDispatch;
IHTMLDocument2Ptr ipDocument = GetHtmlDocument();
if(ipDocument==NULL)
return ipDispatch;
HRESULT hr = ipDocument->get_Script(&ipDispatch);
return ipDispatch;
}
2.2 呼叫方法,注意方法可能存在引數的先後順序
// CDispatchObj方法實際上就是對IDispatch的invoke的簡單封裝
CDispatchObj obj(ipDispatch.GetInterfacePtr());
_variant_t vt(bstrValue);
obj.Invoke1_S(L"funcA", vt, 0);
3. 網頁呼叫VC6方法:協議擴充套件
網頁尾本中要呼叫VC6的方法時,都通過擴充套件協議來實現;然後VC6來解析該協議。
3.1 網頁呼叫協議iitp:
var trm_view = function() //檢視
{
var strUrl = "iitp://mydo/view.do";
document.location.href = strUrl;
}
3.2 VC6:截獲連結並特殊處理協議iitp
注意*pbCancel = TRUE避免連結進行了跳轉
void CHtmlViewEx::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags,
LPCTSTR lpszTargetFrameName,
CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel)
{
CString strUrl = lpszURL;
CString strProtcl = _T("iitp://mydo/");
if(strUrl.CompareNoCase(strProtcl)>0 )
{
CString strCmd = _T("iitp://mydo/view.do");
//檢視
if(strUrl.CompareNoCase(strCmd)==0)
{
//--todo my function--
UpdateWindow();
}
//-注意避免跳轉頁面-
*pbCancel = TRUE;
}
else
{
CHtmlView::OnBeforeNavigate2(lpszURL, nFlags,
lpszTargetFrameName, baPostedData,lpszHeaders, pbCancel);
}
}
4. 網頁呼叫VC6的資料和方法:功能擴充套件
4.1 直接將資料繫結在某一DOM上
_RecordsetPtr ipRst;
_variant_t vtRst(ipRst, true);
ipBody->setAttribute(L"rst", vtRst, 0);
以後網頁尾本中就可以使用document.body.rst來呼叫ipRst的各種方法了。
4.2.1 給網頁擴充套件一個IDispatch物件
如果是MFC,則可以直接使用MFC 自動化物件,避免寫元件
class CMyHtmlView : public ChtmlView { …… //{{AFX_DISPATCH(CMyHtmlView) afx_msg BSTR GetVersion(); afx_msg void SetVersion(LPCTSTR lpszNewValue); afx_msg BSTR SayIt(long num); //}}AFX_DISPATCH DECLARE_DISPATCH_MAP() }; CMyHtmlView::CMyHtmlView() { EnableAutomation(); } BEGIN_DISPATCH_MAP(CMyHtmlView, CHtmlView) //{{AFX_DISPATCH_MAP(CMyHtmlView) DISP_PROPERTY_EX(CMyHtmlView, "version", GetVersion, SetVersion, VT_BSTR) DISP_FUNCTION(CMyHtmlView, "SayIt", SayIt, VT_BSTR, VTS_I4) //}}AFX_DISPATCH_MAP END_DISPATCH_MAP() BSTR CMyHtmlView::SayIt(long num) { CString strResult; strResult.Format("num = %d", num*2); return strResult.AllocSysString(); } void CMyHtmlView::DocumentComplete(LPDISPATCH pDisp, VARIANT* URL) { CHtmlView::DocumentComplete(pDisp, URL); IHTMLDocument2Ptr ipDocument = GetHtmlDocument(); if(ipDocument) { IHTMLElementPtr ipBody; ipDocument->get_body(&ipBody); LPDISPATCH pDispatch = GetIDispatch(TRUE); HRESULT hr = ipBody->setAttribute(L"external", _variant_t(pDispatch, false), 0); } }
4.2.2 指令碼中就可以呼叫:
function test()
{
var rtn = document.body.external.SayIt(6);
alert(rtn);
}
雖然最通用的方法是使用window.external,但是需要改寫。此種方法壓根就不需要進行特殊的擴充套件。