分享

MFC C++代码与WebBrowser HTML的互动(还需完善)

 herowuking 2015-10-07

testWebBrowser.h

  1. // testWebBrowserDlg.h : 头文件  
  2. //  
  3.   
  4. #pragma once  
  5. #include "explorer1.h"  
  6.   
  7.   
  8. #import "C:\windows\system32\mshtml.tlb" // location of mshtml.tlb  
  9.   
  10. #include <map>  
  11.   
  12. #include <comdef.h>  
  13. #include <mshtml.h>  
  14. #include <mshtmdid.h>  
  15. /* 
  16. 标题:研究C++代码与WebBrowser HTML的互动 
  17. Author:Kagula 
  18. Date:2014-08-03 
  19. Test Env: Windows8.1、VS2013 Update2 
  20. 内容: 
  21. [1]如何拿到html中的elements,并取得它的属性! 
  22. [2]如何响应element激发的事件 
  23. [3]如何修改指定element的属性 
  24.  
  25. 参考资料 
  26. [1]《MFC中针对WebBrowser控件增加link链接点击事件监控》 
  27. http://www./wp/work/509.html 
  28. [2]《IWebBrowser2 interface》 
  29. http://msdn.microsoft.com/en-us/library/aa752127(VS.85).aspx 
  30. [3]《Handling HTML Element Events》 
  31. http://msdn.microsoft.com/en-us/library/bb508508(v=vs.85).aspx 
  32. [4]《如何从 VC web 浏览器应用程序中调用脚本函数》 
  33. http://support.microsoft.com/kb/q185127 
  34. [5]《MFC中针对WebBrowser控件增加link链接点击事件监控》 
  35. http://www./wp/work/509.html 
  36. [6]《How do I get the font color from a piece of HTML source code?》 
  37. http:///questions/7402347/how-do-i-get-the-font-color-from-a-piece-of-html-source-code 
  38. [7]《How to create a sink interface in a MFC-based COM client》 
  39. http://support.microsoft.com/default.aspx?scid=kb;en-us;181845 
  40. [8]《How To Use the Microsoft WebBrowser Control to Render HTML from Memory》 
  41. http://www./blog/2010/03/24/how-to-use-the-microsoft-webbrowser-control-to-render-html-from-memory/comment-page-1/ 
  42. [9]《How do I get the font color from a piece of HTML source code?》 
  43. http:///questions/7402347/how-do-i-get-the-font-color-from-a-piece-of-html-source-code 
  44. [10]《Using the WebBrowser control, simplified》 
  45. http://www./Articles/3919/Using-the-WebBrowser-control-simplified 
  46. [11]《Microsoft Internet Explorer 5.5 behaviors》 
  47. http://msdn.microsoft.com/en-us/magazine/cc301528.aspx 
  48. */  
  49.   
  50. namespace kagula  
  51. {  
  52.     struct ConnectionInfo  
  53.     {  
  54.         IDispatch* dispatch;  
  55.         IID iid;          
  56.         DWORD cookie;  
  57.   
  58.         ConnectionInfo() {}  
  59.         ConnectionInfo(IDispatch *dispatch, IID iid, DWORD cookie)  
  60.         {  
  61.             this->dispatch = dispatch, this->iid = iid, this->cookie = cookie;  
  62.         }  
  63.     };  
  64. }  
  65. // CtestWebBrowserDlg 对话框  
  66. class CtestWebBrowserDlg : public CDialogEx  
  67. {  
  68. // 构造  
  69. public:  
  70.     CtestWebBrowserDlg(CWnd* pParent = NULL);   // 标准构造函数  
  71.   
  72. // 对话框数据  
  73.     enum { IDD = IDD_TESTWEBBROWSER_DIALOG };  
  74.   
  75.     protected:  
  76.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  77.   
  78.   
  79. // 实现  
  80. protected:  
  81.     HICON m_hIcon;  
  82.   
  83.     // 生成的消息映射函数  
  84.     virtual BOOL OnInitDialog();  
  85.     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);  
  86.     afx_msg void OnPaint();  
  87.     afx_msg HCURSOR OnQueryDragIcon();  
  88.     DECLARE_MESSAGE_MAP()  
  89.   
  90. public:  
  91.     CExplorer1 m_webBrowser;  
  92.     std::map<IDispatch*, kagula::ConnectionInfo> m_mapElem2EventCookie;//用于释放Connection  
  93.     void ReleaseHTMLConnection();  
  94.   
  95.     void DemoGetElement(LPDISPATCH pDisp, VARIANT* URL);  
  96.     void DemoGetAllLinkElement(LPDISPATCH pDisp, VARIANT* URL);  
  97.   
  98.     void OnClick(MSHTML::IHTMLEventObj *pEvtObj);  
  99.     void OnMouseOver(MSHTML::IHTMLEventObj *pEvtObj);  
  100.   
  101.     afx_msg void OnBnClickedBtnGetall();  
  102.   
  103.     //added new three map macros  
  104.     DECLARE_EVENTSINK_MAP()  
  105.     DECLARE_DISPATCH_MAP()    
  106.     DECLARE_INTERFACE_MAP()  
  107.   
  108.     void BeforeNavigate2Explorer1(LPDISPATCH pDisp, VARIANT* URL, VARIANT* Flags, VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers, BOOL* Cancel);  
  109.     void DocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT* URL);  
  110.     afx_msg void OnClose();  
  111. };  

testWebBrowser.cpp

  1. // testWebBrowserDlg.cpp : 实现文件  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6.   
  7. #include "testWebBrowser.h"  
  8. #include "testWebBrowserDlg.h"  
  9. #include "afxdialogex.h"  
  10.   
  11. #include <string>  
  12.   
  13. #include <afxctl.h>  
  14.   
  15. #ifdef _DEBUG  
  16. #define new DEBUG_NEW  
  17. #endif  
  18.   
  19.   
  20. // CtestWebBrowserDlg 对话框  
  21. CtestWebBrowserDlg::CtestWebBrowserDlg(CWnd* pParent /*=NULL*/)  
  22.     : CDialogEx(CtestWebBrowserDlg::IDD, pParent)  
  23. {  
  24.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
  25. }  
  26.   
  27. void CtestWebBrowserDlg::DoDataExchange(CDataExchange* pDX)  
  28. {  
  29.     CDialogEx::DoDataExchange(pDX);  
  30.     DDX_Control(pDX, IDC_EXPLORER1, m_webBrowser);  
  31. }  
  32.   
  33. BEGIN_MESSAGE_MAP(CtestWebBrowserDlg, CDialogEx)  
  34.     ON_WM_SYSCOMMAND()  
  35.     ON_WM_PAINT()  
  36.     ON_WM_QUERYDRAGICON()  
  37.     ON_BN_CLICKED(IDC_BTN_GETALL, &CtestWebBrowserDlg::OnBnClickedBtnGetall)  
  38.     ON_WM_CLOSE()  
  39. END_MESSAGE_MAP()  
  40.   
  41.   
  42. // CtestWebBrowserDlg 消息处理程序  
  43.   
  44. BOOL CtestWebBrowserDlg::OnInitDialog()  
  45. {  
  46.     CDialogEx::OnInitDialog();  
  47.   
  48.     // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动  
  49.     //  执行此操作  
  50.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  51.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  52.   
  53.     // TODO:  在此添加额外的初始化代码  
  54.     EnableAutomation();//没有这行代码会导致GetIDispatch(FALSE)失败!  
  55.   
  56.     m_webBrowser.Navigate(L"D:\\Workspace\\testWebBrowser\\testWebBrowser\\test.html",NULL,NULL,NULL,NULL);  
  57.   
  58.     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE  
  59. }  
  60.   
  61. void CtestWebBrowserDlg::OnSysCommand(UINT nID, LPARAM lParam)  
  62. {  
  63.     CDialogEx::OnSysCommand(nID, lParam);  
  64. }  
  65.   
  66. // 如果向对话框添加最小化按钮,则需要下面的代码  
  67. //  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,  
  68. //  这将由框架自动完成。  
  69.   
  70. void CtestWebBrowserDlg::OnPaint()  
  71. {  
  72.     if (IsIconic())  
  73.     {  
  74.         CPaintDC dc(this); // 用于绘制的设备上下文  
  75.   
  76.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  
  77.   
  78.         // 使图标在工作区矩形中居中  
  79.         int cxIcon = GetSystemMetrics(SM_CXICON);  
  80.         int cyIcon = GetSystemMetrics(SM_CYICON);  
  81.         CRect rect;  
  82.         GetClientRect(&rect);  
  83.         int x = (rect.Width() - cxIcon + 1) / 2;  
  84.         int y = (rect.Height() - cyIcon + 1) / 2;  
  85.   
  86.         // 绘制图标  
  87.         dc.DrawIcon(x, y, m_hIcon);  
  88.     }  
  89.     else  
  90.     {  
  91.         CDialogEx::OnPaint();  
  92.     }  
  93. }  
  94.   
  95. //当用户拖动最小化窗口时系统调用此函数取得光标  
  96. //显示。  
  97. HCURSOR CtestWebBrowserDlg::OnQueryDragIcon()  
  98. {  
  99.     return static_cast<HCURSOR>(m_hIcon);  
  100. }  
  101.   
  102.   
  103.   
  104. void CtestWebBrowserDlg::OnBnClickedBtnGetall()  
  105. {  
  106.     // TODO: Add your control notification handler code here  
  107. }  
  108. BEGIN_EVENTSINK_MAP(CtestWebBrowserDlg, CDialogEx)  
  109.     ON_EVENT(CtestWebBrowserDlg, IDC_EXPLORER1, 250, CtestWebBrowserDlg::BeforeNavigate2Explorer1, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL)  
  110.     ON_EVENT(CtestWebBrowserDlg, IDC_EXPLORER1, 259, CtestWebBrowserDlg::DocumentCompleteExplorer1, VTS_DISPATCH VTS_PVARIANT)  
  111. END_EVENTSINK_MAP()  
  112.   
  113. /* 第三步: 某种事件(元素类型无关)和哪个响应函数连*/  
  114. BEGIN_DISPATCH_MAP(CtestWebBrowserDlg, CCmdTarget)  
  115.     DISP_FUNCTION_ID(CtestWebBrowserDlg, "HTMLELEMENTEVENTS2_ONCLICK", DISPID_HTMLELEMENTEVENTS2_ONCLICK, CtestWebBrowserDlg::OnClick, VT_EMPTY, VTS_DISPATCH)  
  116.     DISP_FUNCTION_ID(CtestWebBrowserDlg, "HTMLELEMENTEVENTS2_ONMOUSEOVER", DISPID_HTMLELEMENTEVENTS2_ONMOUSEOVER, CtestWebBrowserDlg::OnMouseOver, VT_EMPTY, VTS_DISPATCH)  
  117. END_DISPATCH_MAP()  
  118.   
  119. /* 第二步(方案一):处理所有种类元素的事件 */  
  120. BEGIN_INTERFACE_MAP(CtestWebBrowserDlg, CCmdTarget)  
  121.     INTERFACE_PART(CtestWebBrowserDlg, DIID_HTMLElementEvents2, Dispatch)  
  122. END_INTERFACE_MAP()  
  123. /* 第二步(方案二): 只处理两种元素的事件*/  
  124. //BEGIN_INTERFACE_MAP(CtestWebBrowserDlg, CCmdTarget)  
  125. //  INTERFACE_PART(CtestWebBrowserDlg, DIID_HTMLButtonElementEvents2, Dispatch)  
  126. //  INTERFACE_PART(CtestWebBrowserDlg, DIID_HTMLAnchorEvents2, Dispatch)      
  127. //END_INTERFACE_MAP()  
  128.   
  129. void CtestWebBrowserDlg::BeforeNavigate2Explorer1(LPDISPATCH pDisp, VARIANT* URL, VARIANT* Flags, VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers, BOOL* Cancel)  
  130. {  
  131.     // TODO: Add your message handler code here  
  132.     CString strURL(URL->bstrVal);  
  133.     *Cancel = FALSE;  
  134.     if (strURL == _T("about:blank"))  
  135.         *Cancel = FALSE;  
  136.     else  
  137.     {  
  138.         if (strURL.Find(_T("ThePageNeverReach.htm")) > 0 )  
  139.         {//阻止跳转到指定页面!  
  140.             *Cancel = TRUE;  
  141.             return;  
  142.         }  
  143.     }  
  144.   
  145.     if (!(*Cancel))  
  146.     {  
  147.         //进入新页面之前,先释放掉事件连接  
  148.         ReleaseHTMLConnection();  
  149.     }  
  150.   
  151.     //演示:HTML元素属性或内容替换  
  152. }  
  153.   
  154.   
  155. void CtestWebBrowserDlg::DocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT* URL)  
  156. {  
  157.     //DemoGetElement(pDisp, URL);  
  158.     DemoGetAllLinkElement(pDisp, URL);  
  159. }  
  160.   
  161. //演示:鼠标点击事件  
  162. void CtestWebBrowserDlg::OnClick(MSHTML::IHTMLEventObj *pEvtObj)  
  163. {  
  164.     MSHTML::IHTMLElementPtr elem = pEvtObj->srcElement;  
  165.     CString cstrID = elem->Getid();  
  166.     CString cstrTag = elem->GettagName();//标签的名字  
  167.       
  168.     _variant_t name = elem->getAttribute(_T("name"), 0);  
  169.     CString cstrName;  
  170.     if (name.vt != VT_NULL)  
  171.     {  
  172.         cstrName = name;  
  173.     }  
  174.   
  175.     _variant_t href = elem->getAttribute(_T("href"), 0);  
  176.     CString cstrHref;  
  177.     if (href.vt != VT_NULL)  
  178.     {  
  179.         cstrHref = href.bstrVal;  
  180.     }  
  181.   
  182.     CString msg;  
  183.     msg.Format(L"[id=%s][name=%s][tag=%s][href=%s]", cstrID.GetBuffer(),   
  184.         cstrName.GetBuffer(), cstrTag.GetBuffer(), cstrHref.GetBuffer(MAX_PATH));  
  185.     AfxMessageBox(msg);  
  186. }  
  187.   
  188. //演示:MouseOver事件  
  189. void CtestWebBrowserDlg::OnMouseOver(MSHTML::IHTMLEventObj *pEvtObj)  
  190. {  
  191.     MSHTML::IHTMLElementPtr elem = pEvtObj->srcElement;  
  192.   
  193.     CString cstrID = elem->Getid();  
  194.   
  195.     TRACE(L"OnMouseOver cstrID = [%s]", cstrID.GetBuffer());  
  196. }  
  197.   
  198. //演示:拿到指定ID的标签元素,并打印它的属性  
  199. void CtestWebBrowserDlg::DemoGetElement(LPDISPATCH pDisp, VARIANT* URL)  
  200. {  
  201.     // Get the HTML document.  
  202.     //IHTMLDocument2Ptr htmlDoc;  
  203.     //htmlDoc = m_browser.GetDocument();  
  204.     IWebBrowser2Ptr webBrowser(pDisp);  
  205.     IDispatchPtr htmlDocDisp;  
  206.     (*webBrowser).get_Document(&htmlDocDisp);  
  207.     MSHTML::IHTMLDocument2Ptr htmlDoc(htmlDocDisp);  
  208.   
  209.   
  210.     // Get the collection of elements.  
  211.     MSHTML::IHTMLElementCollectionPtr elements;  
  212.     (*htmlDoc).get_all(&elements);  
  213.   
  214.     //演示:如何拿到id属性为"myFontTag"的元素,并获取它的属性  
  215.     IDispatchPtr disp;  
  216.     _variant_t index(0L, VT_I4);  
  217.     do  
  218.     {  
  219.         disp = (*elements).item(_variant_t("myFontTag"), index);  
  220.         if (disp != NULL)  
  221.         {  
  222.             // Examine their action attribute to determine what should be done.  
  223.             MSHTML::IHTMLElementPtr element(disp);  
  224.   
  225.             //打印mytag标签color属性的值  
  226.             variant_t vtValue = element->getAttribute("color", 0);  
  227.             CString cstr = vtValue;  
  228.             TRACE(L"mytag标签的color属性为%s\n", cstr.GetBuffer(MAX_PATH));  
  229.   
  230.             ++index.lVal;  
  231.         }  
  232.     } while (disp != NULL);  
  233. }  
  234.   
  235. /* 
  236. 拿到元素,并做链接 
  237. [1]《AfxConnectionAdvise》 
  238. http://msdn.microsoft.com/en-us/library/b9h84ebk.aspx 
  239. [2]《How to create a sink interface in a MFC-based COM client》 
  240. http://support.microsoft.com/default.aspx?scid=kb;en-us;181845 
  241. [3]《同Document建立Connection》 
  242. http://www./ch08e.htm 
  243. */  
  244. void CtestWebBrowserDlg::DemoGetAllLinkElement(LPDISPATCH pDisp, VARIANT* URL)  
  245. {  
  246.     // Get the HTML document. //  
  247.     IWebBrowser2Ptr webBrowser(pDisp);  
  248.     IDispatchPtr htmlDocDisp;  
  249.     (*webBrowser).get_Document(&htmlDocDisp);  
  250.     MSHTML::IHTMLDocument2Ptr htmlDoc(htmlDocDisp);  
  251.   
  252.     if (htmlDoc == NULL) //URL属性为空  
  253.     {  
  254.         return;  
  255.     }  
  256.   
  257.   
  258.     DWORD dwCookie = 0;  
  259.     // Get the collection of elements.  
  260.     MSHTML::IHTMLElementCollectionPtr elements;  
  261.     (*htmlDoc).get_all(&elements);  
  262.   
  263.     IDispatchPtr disp;  
  264.     _variant_t index(0L, VT_I4);  
  265.     do  
  266.     {  
  267.         //Get all elements  
  268.         disp = (*elements).item(index, index);  
  269.         if (disp != NULL)  
  270.         {  
  271.             // Examine their action attribute to determine what should be done.  
  272.             IDispatchPtr element(disp);  
  273.             MSHTML::IHTMLElementPtr elemTag(disp);  
  274.   
  275.             //第一步:建立Connection  
  276.             DWORD dwCookie = 0;  
  277.             BSTR name = NULL;  
  278.             elemTag->get_tagName(&name);  
  279.             if (name != NULL)  
  280.             {  
  281.                 //is link!!!!  
  282.                 LPUNKNOWN pUnkSink = GetIDispatch(FALSE);  
  283.   
  284.                 //关联全部类型元素  
  285.                 if (AfxConnectionAdvise(element, DIID_HTMLElementEvents2, pUnkSink, FALSE, &dwCookie))  
  286.                 {  
  287.                     kagula::ConnectionInfo ci(element.GetInterfacePtr(), DIID_HTMLElementEvents2, dwCookie);  
  288.                     m_mapElem2EventCookie[element.GetInterfacePtr()] = ci;  
  289.                 }  
  290.   
  291.                 //只关联下面两种类型事件,解除注释  
  292.                 //if (_tcsicmp(name, _T("a")) == 0)  
  293.                 //{  
  294.                 //  if (AfxConnectionAdvise(element, DIID_HTMLAnchorEvents2, pUnkSink, FALSE, &dwCookie))  
  295.                 //  {  
  296.                 //      kagula::ConnectionInfo ci(element.GetInterfacePtr(), DIID_HTMLAnchorEvents2,dwCookie);  
  297.                 //      m_mapElem2EventCookie[element.GetInterfacePtr()] = ci;  
  298.                 //      if (name != NULL)  
  299.                 //      {                             
  300.                 //          std::wstring wsName = name;//打印调试信息  
  301.                 //          TRACE(L"get tag:%s, bind DIID_HTMLAnchorEvents2\n", wsName.c_str());  
  302.                 //      }  
  303.                 //  }  
  304.                 //}  
  305.                 //else if (_tcsicmp(name, _T("button")) == 0)  
  306.                 //{  
  307.                 //  if (AfxConnectionAdvise(element, DIID_HTMLButtonElementEvents2, pUnkSink, FALSE, &dwCookie))  
  308.                 //  {  
  309.                 //      kagula::ConnectionInfo ci(element.GetInterfacePtr(), DIID_HTMLButtonElementEvents2, dwCookie);  
  310.                 //      m_mapElem2EventCookie[element.GetInterfacePtr()] = ci;  
  311.                 //  }  
  312.                 //}  
  313.             }//end if  
  314.             ++index.lVal;  
  315.         }  
  316.     } while (disp != NULL);  
  317. }  
  318.   
  319. //释放同HTML的Connection  
  320. void CtestWebBrowserDlg::ReleaseHTMLConnection()  
  321. {  
  322.     std::map<IDispatch *, kagula::ConnectionInfo>::iterator itr;  
  323.     for (itr = m_mapElem2EventCookie.begin(); itr != m_mapElem2EventCookie.end(); itr++)  
  324.     {//DIID_HTMLDocumentEvents  
  325.         AfxConnectionUnadvise(itr->first,  itr->second.iid, GetIDispatch(FALSE), FALSE, itr->second.cookie);//DIID_HTMLAnchorEvents2,DIID_HTMLButtonElementEvents  
  326.     }  
  327.     m_mapElem2EventCookie.clear();  
  328. }  
  329.   
  330. void CtestWebBrowserDlg::OnClose()  
  331. {  
  332.     //在窗口关闭前,释放Connection,否则Process会挂掉  
  333.     ReleaseHTMLConnection();  
  334.   
  335.     CDialogEx::OnClose();  
  336. }  

test.html

  1. <head>  
  2.     <title></title>  
  3. </head>  
  4. <body>  
  5.     <h1 id="myH1Tag">这是主页面,用于测试C++得到事件</h1>  
  6.     <font id="myFontTag" color=#5a6571>这是我的标签</font> <br />  
  7.     <input id="myInputTag" type="button" value="这里元素不会响应button类型事件"/><br/>  
  8.     <button id="myButtonTag" type="button">测试点击事件</button>  
  9.     <br />  
  10.     <br />  
  11.     <a id="idOfA" name="nameOfA" href="file:D:\Workspace\testWebBrowser\testWebBrowser\ThePageNeverReach.htm">测试禁止页面跳转</a><br/>  
  12.     <a id="id2OfA" name="name2OfA" href="file:D:\Workspace\testWebBrowser\testWebBrowser\HTMLPage.htm">测试用户点击链接, C++后台得到消息!</a>  
  13. </body>  

ThePageNeverReach.html

  1. <HTML>  
  2. <HEAD>  
  3. <META NAME="GENERATOR" Content="Microsoft Visual Studio">  
  4. <TITLE></TITLE>  
  5. </HEAD>  
  6. <BODY>  
  7.     <h1>不会跳转到这个页面!</h1>  
  8. </BODY>  
  9. </HTML>  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多