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

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

// CDispatchObj方法實際上就是對IDispatch的invoke的簡單封裝 
CDispatchObj obj(ipDispatch.GetInterfacePtr()); 
_variant_t vt(bstrValue); 
obj.Invoke1_S(L"funcA", vt, 0);