testWebBrowserDlg.h
// testWebBrowserDlg.h : 头文件 // #pragma once #include "explorer1.h" #import "C:\windows\system32\mshtml.tlb" // location of mshtml.tlb #include <map> #include <comdef.h> #include <mshtml.h> #include <mshtmdid.h> /* 标题:测试C++代码与WebBrowser HTML的互动 Author:Kagula Date:2014-08-20 版本号:3 Test Env: Windows8.1、VS2013 Update2 内容: [1]如何拿到html中的elements,取得它的属性! [2]如何响应element激发的事件 [3]如何修改指定element的属性 [4]如何Render内存中的html字符串 参考资料 [1]《MFC中针对WebBrowser控件增加link链接点击事件监控》 http://www.mworkbox.com/wp/work/509.html [2]《IWebBrowser2 interface》 http://msdn.microsoft.com/en-us/library/aa752127(VS.85).aspx [3]《Handling HTML Element Events》 http://msdn.microsoft.com/en-us/library/bb508508(v=vs.85).aspx [4]《如何从 VC web 浏览器应用程序中调用脚本函数》 http://support.microsoft.com/kb/q185127 [5]《Loading HTML content from a Stream》 http://msdn.microsoft.com/en-us/library/ie/aa752047%28v=vs.85%29.aspx [6]《How do I get the font color from a piece of HTML source code?》 http://stackoverflow.com/questions/7402347/how-do-i-get-the-font-color-from-a-piece-of-html-source-code [7]《How to create a sink interface in a MFC-based COM client》 http://support.microsoft.com/default.aspx?scid=kb;en-us;181845 [8]《How To Use the Microsoft WebBrowser Control to Render HTML from Memory》 http://www.nuonsoft.com/blog/2010/03/24/how-to-use-the-microsoft-webbrowser-control-to-render-html-from-memory/comment-page-1/ [9]《How do I get the font color from a piece of HTML source code?》 http://stackoverflow.com/questions/7402347/how-do-i-get-the-font-color-from-a-piece-of-html-source-code [10]《Using the WebBrowser control, simplified》 http://www.codeproject.com/Articles/3919/Using-the-WebBrowser-control-simplified [11]《Microsoft Internet Explorer 5.5 behaviors》 http://msdn.microsoft.com/en-us/magazine/cc301528.aspx [12]《Using IHTMLEditDesigner》 http://www.codeproject.com/Articles/6546/Using-IHTMLEditDesigner [13]《MFC C++ WebBrowser Control load HTML from a string》 http://stackoverflow.com/questions/9179179/mfc-c-webbrowser-control-load-html-from-a-string [14]VC++ webbrowser函数使用范例 [15]《【webbrowser使用】_webbrowser使用的相关文章,教程,源码》 http://www.xuebuyuan.com/zt/12577882.html */ namespace kagula { struct ConnectionInfo { IDispatch* dispatch; IID iid; DWORD cookie; ConnectionInfo() {} ConnectionInfo(IDispatch *dispatch, IID iid, DWORD cookie) { this->dispatch = dispatch, this->iid = iid, this->cookie = cookie; } }; } // CtestWebBrowserDlg 对话框 class CtestWebBrowserDlg : public CDialogEx { // 构造 public: CtestWebBrowserDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_TESTWEBBROWSER_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: CExplorer1 m_webBrowser; void SetElementAttribute(MSHTML::IHTMLDocument2Ptr htmlDoc,CString elementID,CString attributeName,CString value); std::map<IDispatch*, kagula::ConnectionInfo> m_mapElem2EventCookie;//用于释放Connection void ReleaseHTMLConnection(); void DemoGetElement(LPDISPATCH pDisp, VARIANT* URL); void DemoGetAllLinkElement(LPDISPATCH pDisp, VARIANT* URL); void OnClick(MSHTML::IHTMLEventObj *pEvtObj); void OnLostFocus(MSHTML::IHTMLEventObj *pEvtObj); void WriteHTML(const wchar_t* html); afx_msg void OnBnClickedMemoryRender(); //added new three map macros DECLARE_EVENTSINK_MAP() DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP() void BeforeNavigate2Explorer1(LPDISPATCH pDisp, VARIANT* URL, VARIANT* Flags, VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers, BOOL* Cancel); void DocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT* URL); afx_msg void OnBnClickedBtnSetspecifiedelementattr(); virtual void OnOK(); virtual void OnCancel(); };
testWebBrowserDlg.cpp
// testWebBrowserDlg.cpp : 实现文件 // #include "stdafx.h" #include "testWebBrowser.h" #include "testWebBrowserDlg.h" #include "afxdialogex.h" #include <string> #include <afxctl.h> #ifdef _DEBUG #define new DEBUG_NEW #endif // CtestWebBrowserDlg 对话框 CtestWebBrowserDlg::CtestWebBrowserDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CtestWebBrowserDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CtestWebBrowserDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_EXPLORER1, m_webBrowser); } BEGIN_MESSAGE_MAP(CtestWebBrowserDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_RENDERSTRING, &CtestWebBrowserDlg::OnBnClickedMemoryRender) ON_BN_CLICKED(IDC_BTN_SETSPECIFIEDELEMENTATTR, &CtestWebBrowserDlg::OnBnClickedBtnSetspecifiedelementattr) END_MESSAGE_MAP() // CtestWebBrowserDlg 消息处理程序 BOOL CtestWebBrowserDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 EnableAutomation();//没有这行代码会导致GetIDispatch(FALSE)失败! //m_webBrowser.Navigate(L"D:\\Workspace\\testWebBrowser\\testWebBrowser\\test.html",NULL,NULL,NULL,NULL); m_webBrowser.Navigate(L"about:blank", NULL, NULL, NULL, NULL); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CtestWebBrowserDlg::OnSysCommand(UINT nID, LPARAM lParam) { CDialogEx::OnSysCommand(nID, lParam); } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CtestWebBrowserDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CtestWebBrowserDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } //测试:Render内存中的HTML void CtestWebBrowserDlg::OnBnClickedMemoryRender() { m_webBrowser.Navigate(L"app://mymemory.page",NULL,NULL,NULL,NULL); } BEGIN_EVENTSINK_MAP(CtestWebBrowserDlg, CDialogEx) ON_EVENT(CtestWebBrowserDlg, IDC_EXPLORER1, 250, CtestWebBrowserDlg::BeforeNavigate2Explorer1, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL) ON_EVENT(CtestWebBrowserDlg, IDC_EXPLORER1, 259, CtestWebBrowserDlg::DocumentCompleteExplorer1, VTS_DISPATCH VTS_PVARIANT) END_EVENTSINK_MAP() /* 第二步:处理所有种类元素的事件 */ BEGIN_INTERFACE_MAP(CtestWebBrowserDlg, CCmdTarget) INTERFACE_PART(CtestWebBrowserDlg, DIID_HTMLElementEvents2, Dispatch) END_INTERFACE_MAP() /* 第三步: 某种事件(元素类型无关)和哪个响应函数连*/ BEGIN_DISPATCH_MAP(CtestWebBrowserDlg, CCmdTarget) DISP_FUNCTION_ID(CtestWebBrowserDlg, "HTMLELEMENTEVENTS2_ONCLICK", DISPID_HTMLELEMENTEVENTS2_ONCLICK, CtestWebBrowserDlg::OnClick, VT_EMPTY, VTS_DISPATCH) DISP_FUNCTION_ID(CtestWebBrowserDlg, "HTMLELEMENTEVENTS2_ONFOCUSOUT", DISPID_HTMLELEMENTEVENTS2_ONFOCUSOUT, CtestWebBrowserDlg::OnLostFocus, VT_EMPTY, VTS_DISPATCH) END_DISPATCH_MAP() void CtestWebBrowserDlg::BeforeNavigate2Explorer1(LPDISPATCH pDisp, VARIANT* URL, VARIANT* Flags, VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers, BOOL* Cancel) { CString strURL(URL->bstrVal); *Cancel = FALSE; if (strURL == _T("about:blank")) { *Cancel = FALSE; } else { if (strURL.Find(_T("ThePageNeverReach.htm")) > 0 ) {//阻止跳转到指定页面! *Cancel = TRUE; return; } } if (!(*Cancel)) { //进入新页面之前,先释放掉事件连接 ReleaseHTMLConnection(); } //演示,render内存中的html页面! if (strURL.Find(_T("app://mymemory.page")) >= 0) { *Cancel = TRUE; WriteHTML(L"<html><body><h1>My Header</h1><p>Some text below the header</p></body></html>"); return; } } void CtestWebBrowserDlg::DocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT* URL) { //DemoGetElement(pDisp, URL); DemoGetAllLinkElement(pDisp, URL); }//end func //演示:鼠标点击事件 void CtestWebBrowserDlg::OnClick(MSHTML::IHTMLEventObj *pEvtObj) { MSHTML::IHTMLElementPtr elem = pEvtObj->srcElement; CString cstrID = elem->Getid(); CString cstrTag = elem->GettagName();//标签的名字 if (cstrID.GetLength()<=0) { return; } _variant_t name = elem->getAttribute(_T("name"), 0); CString cstrName; if (name.vt != VT_NULL) { cstrName = name; } _variant_t href = elem->getAttribute(_T("value"), 0); CString cstrHref; if (href.vt != VT_NULL) { cstrHref = href.bstrVal; } CString msg; msg.Format(L"[id=%s][name=%s][tag=%s][value=%s]", cstrID.GetBuffer(), cstrName.GetBuffer(), cstrTag.GetBuffer(), cstrHref.GetBuffer(MAX_PATH)); TRACE(msg); } //演示:响应 标签 失去焦点事件 void CtestWebBrowserDlg::OnLostFocus(MSHTML::IHTMLEventObj *pEvtObj) { MSHTML::IHTMLElementPtr elem = pEvtObj->srcElement; CString cstrID = elem->Getid(); if (cstrID.GetLength()<=0) { return; } CString msg; msg.Format(L"OnLostFocus cstrID = [%s]", cstrID.GetBuffer()); AfxMessageBox(msg); } //演示:拿到指定ID的标签元素,并打印它的属性 void CtestWebBrowserDlg::DemoGetElement(LPDISPATCH pDisp, VARIANT* URL) { IWebBrowser2Ptr webBrowser(pDisp); IDispatchPtr htmlDocDisp; (*webBrowser).get_Document(&htmlDocDisp); MSHTML::IHTMLDocument2Ptr htmlDoc(htmlDocDisp); MSHTML::IHTMLElementCollectionPtr elements; (*htmlDoc).get_all(&elements); IDispatchPtr disp; _variant_t index(0L, VT_I4); do { disp = (*elements).item(_variant_t("myFontTag"), index); if (disp != NULL) { MSHTML::IHTMLElementPtr element(disp); variant_t vtValue = element->getAttribute("color", 0); CString cstr = vtValue; TRACE(L"mytag标签的color属性为%s\n", cstr.GetBuffer(MAX_PATH)); ++index.lVal; } } while (disp != NULL); } /* 拿到元素,并做链接 [1]《AfxConnectionAdvise》 http://msdn.microsoft.com/en-us/library/b9h84ebk.aspx [2]《How to create a sink interface in a MFC-based COM client》 http://support.microsoft.com/default.aspx?scid=kb;en-us;181845 [3]《同Document建立Connection》 http://www.popkistopki.ru/ch08e.htm */ void CtestWebBrowserDlg::DemoGetAllLinkElement(LPDISPATCH pDisp, VARIANT* URL) { // Get the HTML document. // IWebBrowser2Ptr webBrowser(pDisp); IDispatchPtr htmlDocDisp; (*webBrowser).get_Document(&htmlDocDisp); MSHTML::IHTMLDocument2Ptr htmlDoc(htmlDocDisp); if (htmlDoc == NULL) //URL属性为空 { return; } //打印HTML页面内容 MSHTML::IHTMLElementPtr body = htmlDoc->Getbody(); variant_t html = body->parentElement->outerHTML; //variant_t bodyHTML = body->GetouterHTML(); CString cstrBodyHTML = html; TRACE(L"cstrBodyHTML.GetBuffer()========\n%s\n", cstrBodyHTML.GetBuffer()); //取HTML中的元素 DWORD dwCookie = 0; // Get the collection of elements. MSHTML::IHTMLElementCollectionPtr elements; (*htmlDoc).get_all(&elements); IDispatchPtr disp; _variant_t index(0L, VT_I4); do { //Get all elements disp = (*elements).item(index, index); if (disp != NULL) { // Examine their action attribute to determine what should be done. IDispatchPtr element(disp); MSHTML::IHTMLElementPtr elemTag(disp); //第一步:建立Connection DWORD dwCookie = 0; BSTR name = NULL; elemTag->get_tagName(&name); if (name != NULL) { //is link!!!! LPUNKNOWN pUnkSink = GetIDispatch(FALSE); //关联全部类型元素 if (AfxConnectionAdvise(element, DIID_HTMLElementEvents2, pUnkSink, FALSE, &dwCookie)) { kagula::ConnectionInfo ci(element.GetInterfacePtr(), DIID_HTMLElementEvents2, dwCookie); m_mapElem2EventCookie[element.GetInterfacePtr()] = ci; } }//end if ++index.lVal; } } while (disp != NULL); } //释放同HTML的Connection void CtestWebBrowserDlg::ReleaseHTMLConnection() { std::map<IDispatch *, kagula::ConnectionInfo>::iterator itr; for (itr = m_mapElem2EventCookie.begin(); itr != m_mapElem2EventCookie.end(); itr++) { //DIID_HTMLDocumentEvents、DIID_HTMLAnchorEvents2、DIID_HTMLButtonElementEvents AfxConnectionUnadvise(itr->first, itr->second.iid, GetIDispatch(FALSE), FALSE, itr->second.cookie); } m_mapElem2EventCookie.clear(); } //测试,设置当前页面指定元素的属性 void CtestWebBrowserDlg::OnBnClickedBtnSetspecifiedelementattr() { CComPtr<IDispatch> spDisp = m_webBrowser.get_Application(); if (spDisp != NULL) { CComPtr<IWebBrowser2> spWeb; HRESULT hr = spDisp->QueryInterface(IID_IWebBrowser2, (void**)&spWeb); if (SUCCEEDED(hr)) { IDispatchPtr htmlDocDisp; spWeb->get_Document(&htmlDocDisp); MSHTML::IHTMLDocument2Ptr htmlDoc(htmlDocDisp); if (htmlDoc == NULL) //URL属性为空 { return; } SetElementAttribute(htmlDoc, L"firstname", L"value", L"Marcia"); SetElementAttribute(htmlDoc, L"lastname",L"value", L"JohnDoe"); SetElementAttribute(htmlDoc, L"female",L"checked", L"1"); SetElementAttribute(htmlDoc, L"bike",L"checked", L""); SetElementAttribute(htmlDoc, L"car",L"checked", L"1"); //演示,重定向到其它URL //CComVariant varURL("http://www.intel.com"); //spWeb->Navigate2(&varURL, NULL, NULL, NULL, NULL); } } } void CtestWebBrowserDlg::SetElementAttribute(MSHTML::IHTMLDocument2Ptr htmlDoc, CString elementID, CString attributeName, CString value) { MSHTML::IHTMLElementCollectionPtr elements; htmlDoc->get_all(&elements); IDispatchPtr disp; _variant_t index(0L, VT_I4); do { disp = (*elements).item(_variant_t(elementID.GetBuffer()), index); if (disp != NULL) { MSHTML::IHTMLElementPtr element(disp); element->setAttribute(attributeName.GetBuffer(), value.GetBuffer(),0); ++index.lVal; } } while (disp != NULL); } /*测试render内存中的html*/ void CtestWebBrowserDlg::WriteHTML(const wchar_t* html) { IDispatch* pHtmlDoc = m_webBrowser.get_Document(); /* 在调用这段代码之前,如果你还没有url需要navigate,就必须在 OnInitDialog中插入下面的代码,否则拿不到document! m_webBrowser.Navigate(L"about:blank",NULL,NULL,NULL,NULL); */ if (!pHtmlDoc) return; CComPtr<IHTMLDocument2> doc2; doc2.Attach((IHTMLDocument2*)pHtmlDoc); if (!doc2) return; // Creates a new one-dimensional array SAFEARRAY* psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1); if (!psaStrings) return; BSTR bstr = SysAllocString(html); if (bstr) { VARIANT* param; HRESULT hr = SafeArrayAccessData(psaStrings, (LPVOID*)¶m); if (SUCCEEDED(hr)) { param->vt = VT_BSTR; param->bstrVal = bstr; hr = SafeArrayUnaccessData(psaStrings); if (SUCCEEDED(hr)) { doc2->write(psaStrings); doc2->close(); } } } // SafeArrayDestroy calls SysFreeString for each BSTR! if (psaStrings) SafeArrayDestroy(psaStrings); } //退出前要释放链接 void CtestWebBrowserDlg::OnOK() { ReleaseHTMLConnection(); CDialogEx::OnOK(); } void CtestWebBrowserDlg::OnCancel() { ReleaseHTMLConnection(); CDialogEx::OnCancel(); }
test.html
<head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> </head> <body> <h1 id="myH1Tag">测试从H1标签能不能得到事件</h1> <font id="myFontTag" color=#5a6571>测试能不能从font标签得到事件</font> <br /> <br /> <br /> <a id="idOfA" name="nameOfA" href="file:D:\Workspace\testWebBrowser\testWebBrowser\ThePageNeverReach.htm">测试禁止页面跳转</a><br/> <a id="id2OfA" name="name2OfA" href="file:D:\Workspace\testWebBrowser\testWebBrowser\HTMLPage.htm">测试用户点击链接, C++后台得到消息!,并跳转到页面</a> <form> First name: <input id='firstname' type='text' name='firstname' /><br /> Last name: <input id='lastname' type='text' name='lastname' /><br /> Password: <input id='password' type='password' name='pwd' /><br><br /> <input type='radio' id='male' name='sex' value='male' />Male<br /> <input type='radio' id='female' name='sex' value='female' />Female<br /><br /> <input type='checkbox' id='bike' name='vehicle' value='Bike' />I have abdsmasterbike<br /> <input type='checkbox' id='car' name='vehicle' value='Car' />I have a car <br /><br /> <input type='button' id='ok' value='OK' /><br /> <input type='button' id='cancel' value='Cancel' /><br /><br /> </form> </body>
转载自:http://blog.csdn.net/lee353086/article/details/38537415