1. 程式人生 > >VC6下CHtmlView中最簡單最全面的程式與網頁互動方法

VC6下CHtmlView中最簡單最全面的程式與網頁互動方法

簡單來說,終極目標------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,但是需要改寫。此種方法壓根就不需要進行特殊的擴充套件。