http://www.codeproject.com/Articles/4411/IEHelper-Internet-Explorer-Helper-Class

IEHelper - Internet Explorer Helper Class

By Mustafa Demirhan, 21 Jun 2004
   4.78 (40 votes)

1

2

3

4

5
4.78/5 - 40 votes
3 removed
μ 4.43, σa 1.86 [?]
 
 
 

Introduction

The purpose of this article is to show how to use IWebBrowser2, IHTMLDocument2 and IHTMLElement objects.

Creating a new web browser object

Let's start with a very simple example: How to create a new Internet Explorer window. The code below shows how to do this:

Collapse | Copy Code
HRESULT hr;
IWebBrowser2* pWebBrowser = NULL;
hr = CoCreateInstance (CLSID_InternetExplorer, NULL,
CLSCTX_SERVER, IID_IWebBrowser2, (LPVOID*)&pWebBrowser); if (SUCCEEDED (hr) && (pWebBrowser != NULL))
{
m_pWebBrowser->put_Visible (VARIANT_TRUE);
// OK, we created a new IE Window and made it visible
// You can use pWebBrowser object to do whatever you want to do!
}
else
{
// Failed to create a new IE Window.
// Check out pWebBrowser object and
// if it is not NULL (should never happen), the release it!
if (pWebBrowser)
pWebBrowser->Release ();
}

Connecting to a running instance of IE

Creating a new IE window is a fairly easy task. But what if you want to use an existing Internet Explorer window, instead of creating a new IE window? Well, in this case, the task is more complicated. The function below finds an Internet Explorer window. sTitleToSearch is the title of the web page to be searched for. Usage of wildcard characters is allowed. If you want to find any IE window, then just enter "*" as the title.

Collapse | Copy Code
bool CMyInternetExplorer::FindUsingTitle
(const CString & sTitleToSearch)
{
if (m_pWebBrowser != NULL)
{
m_pWebBrowser->Release ();
m_pWebBrowser = NULL;
} HRESULT hr;
SHDocVw::IShellWindowsPtr spSHWinds;
hr = spSHWinds.CreateInstance (__uuidof(SHDocVw::ShellWindows)); if (FAILED (hr))
return false; ASSERT (spSHWinds != NULL); long nCount = spSHWinds->GetCount (); IDispatchPtr spDisp; for (long i = 0; i < nCount; i++)
{
_variant_t va (i, VT_I4);
spDisp = spSHWinds->Item (va); IWebBrowser2 * pWebBrowser = NULL;
hr = spDisp.QueryInterface (IID_IWebBrowser2, & pWebBrowser); if (pWebBrowser != NULL)
{
HRESULT hr;
IDispatch* pHtmlDocDispatch = NULL;
IHTMLDocument2 * pHtmlDoc = NULL; // Retrieve the document object.
hr = pWebBrowser->get_Document (&pHtmlDocDispatch); if (SUCCEEDED (hr) && (pHtmlDocDispatch != NULL))
{
// Query for IPersistStreamInit.
hr = pHtmlDocDispatch->QueryInterface
(IID_IHTMLDocument2, (void**)&pHtmlDoc);
if (SUCCEEDED (hr) && (pHtmlDoc != NULL))
{
CString sTitle; HWND hWnd = NULL;
pWebBrowser->get_HWND ((long*)(&hWnd));
if (::IsWindow (hWnd))
{
int nLen = ::GetWindowTextLength (hWnd);
::GetWindowText (hWnd,
sTitle.GetBufferSetLength (nLen),
nLen + 1);
sTitle.ReleaseBuffer ();
} // If I cannot get the window title
// (should never happen though)
// So, lets just use the title of the document
if (sTitle.IsEmpty ())
{
BSTR bstrTitle;
hr = pHtmlDoc->get_title (&bstrTitle);
if (!FAILED (hr))
{
sTitle = bstrTitle;
SysFreeString (bstrTitle);
}
} if (StringHelper::WildcardCompareNoCase
(sTitleToSearch, sTitle))
{
m_pWebBrowser = pWebBrowser;
pHtmlDoc->Release ();
pHtmlDocDispatch->Release ();
// Exit the method safely!
return true;
}
pHtmlDoc->Release();
}
pHtmlDocDispatch->Release ();
}
pWebBrowser->Release ();
}
} return false;
}

This approach is described in MSDN in more detail. Click here to get more information.

This approach uses SHDocVw.ShellWindows collection to enumerate all the instances of shell windows. The ShellWindows object represents a collection of the open windows that belong to the shell. In fact, this collection contains references to Internet Explorer as well as other windows belonging to the shell, such as the Windows Explorer. To differentiate between Internet Explorer and other shell windows, we just try to get the HTML document of the shell window. If we get the document successfully, then this instance of ShellWindow is in fact an Internet Explorer window.

Navigate to a web page

Now, after we get the web browser object and store it in the variable m_pWebBrowser, it is very easy to navigate to a web page.

Collapse | Copy Code
void CMyInternetExplorer::Navigate(LPCTSTR lpszURL, DWORD dwFlags /* = 0 */,
LPCTSTR lpszTargetFrameName /* = NULL */ ,
LPCTSTR lpszHeaders /* = NULL */, LPVOID lpvPostData /* = NULL */,
DWORD dwPostDataLen /* = 0 */)
{
CString strURL (lpszURL);
BSTR bstrURL = strURL.AllocSysString (); COleSafeArray vPostData;
if (lpvPostData != NULL)
{
if (dwPostDataLen == 0)
dwPostDataLen = lstrlen ((LPCTSTR) lpvPostData); vPostData.CreateOneDim (VT_UI1, dwPostDataLen, lpvPostData);
} m_pWebBrowser->Navigate (bstrURL,
COleVariant ((long) dwFlags, VT_I4),
COleVariant (lpszTargetFrameName, VT_BSTR),
vPostData, COleVariant (lpszHeaders, VT_BSTR)); SysFreeString (bstrURL);
}

Wait until the web page is loaded

After starting to load a web page using the function above, to wait until the web page to be completely loaded, we can use the READYSTATE property of IWebBrowser2 object.

Collapse | Copy Code
bool CMyInternetExplorer::WaitTillLoaded (int nTimeout)
{
READYSTATE result;
DWORD nFirstTick = GetTickCount (); do
{
m_pWebBrowser->get_ReadyState (&result); if (result != READYSTATE_COMPLETE)
Sleep (250); if (nTimeout > 0)
{
if ((GetTickCount () - nFirstTick) > nTimeout)
break;
}
} while (result != READYSTATE_COMPLETE); if (result == READYSTATE_COMPLETE)
return true;
else
return false;
}

This function waits until the web page is completely loaded or a timeout occurs. To wait indefinitely, set the nTimeout parameter to 0.

Find an anchor on a web page

The following function searches for the specified anchor in a web page. The anchor can be specified either by the name, outer text, tool tip or the URL. The anchor element has the following syntax:

Collapse | Copy Code
<a href = "anhor_URL" name ="anchor_name"
title = "anchor_tooltip">Outer Text</a>

If bClick parameter is set to true, then if the anchor is found, it will also be clicked on.

Collapse | Copy Code
bool CMyInternetExplorer::FindAnchor (bool bClick, bool bFocus,
bool bName, bool bOuterText, bool bTooltip, bool bURL,
LPCTSTR sName, LPCTSTR sOuterText, LPCTSTR sTooltip, LPCTSTR sURL)
{
ASSERT (m_pWebBrowser != NULL);
if (m_pWebBrowser == NULL)
return false; HRESULT hr;
IDispatch* pHtmlDocDispatch = NULL;
IHTMLDocument2 * pHtmlDoc = NULL;
bool bSearch = true; // Retrieve the document object.
hr = m_pWebBrowser->get_Document (&pHtmlDocDispatch);
if (SUCCEEDED (hr) && (pHtmlDocDispatch != NULL))
{
hr = pHtmlDocDispatch->QueryInterface
(IID_IHTMLDocument2, (void**)&pHtmlDoc);
if (SUCCEEDED (hr) && (pHtmlDoc != NULL))
{
IHTMLElementCollection* pColl = NULL;
hr = pHtmlDoc->get_all (&pColl); if (SUCCEEDED (hr) && (pColl != NULL))
{
// Obtained the Anchor Collection...
long nLength = 0;
pColl->get_length (&nLength); for (int i = 0; i < nLength && bSearch; i++)
{
COleVariant vIdx ((long)i, VT_I4); IDispatch* pElemDispatch = NULL;
IHTMLElement * pElem = NULL; hr = pColl->item (vIdx, vIdx, &pElemDispatch); if (SUCCEEDED (hr) &&
(pElemDispatch != NULL))
{
hr = pElemDispatch->QueryInterface
(IID_IHTMLElement, (void**)&pElem); if (SUCCEEDED (hr) && (pElem != NULL))
{
BSTR bstrTagName;
CString sTempTagName;
if (!FAILED (pElem->get_tagName
(&bstrTagName)))
{
sTempTagName = bstrTagName;
SysFreeString (bstrTagName);
} if (sTempTagName == _T ("a") ||
sTempTagName == _T ("A"))
{
IHTMLAnchorElement * pAnchor = NULL;
hr = pElemDispatch->QueryInterface
(IID_IHTMLAnchorElement,
(void**)&pAnchor); if (SUCCEEDED (hr) &&
(pAnchor != NULL))
{
BSTR bstrName, bstrOuterText,
bstrURL, bstrTooltip;
CString sTempName, sTempOuter,
sTempURL, sTempTooltip; if (!FAILED (pElem->get_outerText
(&bstrOuterText)))
{
sTempOuter = bstrOuterText;
SysFreeString (bstrOuterText);
}
if (!FAILED
(pElem->get_title
(&bstrTooltip)))
{
sTempTooltip = bstrTooltip;
SysFreeString (bstrTooltip);
}
if
(!FAILED (pAnchor->get_name
(&bstrName)))
{
sTempName = bstrName;
SysFreeString (bstrName);
}
if (!FAILED (pAnchor->get_href
(&bstrURL)))
{
sTempURL = bstrURL;
SysFreeString (bstrURL);
} // Do the comparison here!
bool bMatches = true;
if (bMatches && bName)
{
if
(!StringHelper::WildcardCompareNoCase
(sName, sTempName))
bMatches = false;
}
if (bMatches && bOuterText)
{
if
(!StringHelper::WildcardCompareNoCase
(sOuterText, sTempOuter))
bMatches = false;
}
if (bMatches && bURL)
{
if
(!StringHelper::WildcardCompareNoCase
(sURL, sTempURL))
bMatches = false;
}
if (bMatches && bTooltip)
{
if
(!StringHelper::WildcardCompareNoCase
(sTooltip, sTempTooltip))
bMatches = false;
} if (bMatches)
{
// No need to search more!
bSearch = false; if (bFocus)
pAnchor->focus ();
if (bClick)
pElem->click ();
}
pAnchor->Release ();
}
}
pElem->Release ();
}
pElemDispatch->Release ();
}
}
pColl->Release ();
}
pHtmlDoc->Release();
}
pHtmlDocDispatch->Release ();
} if (bSearch == false)
return true; return false;
}

The idea here is very simple. We first enumerate all IHTMLElement objects using get_all function of IHTMLDocument2. Then we check all of the elements to see whether it is an anchor object (IHTMLAnchorElement) or not, by checking its tag name. If it is an "a" or an "A", then it is an anchor object. Then I try to get the IHTMLAnchor object by using the QueryInterface function. The reason that I check the name instead of just using QueryInterface function is performance related. I guess it is much faster to check a tag's name than trying to get IHTMLAnchorElement by using QueryInterface function.

Fill a form on a web page

The idea here is similar to the one above. Instead of finding the anchor element, I try to find all the input elements and then do the same operations. The syntax for an input element is a follows:

Collapse | Copy Code
<input type="input_type" value="input_value" name="input_name">
Collapse | Copy Code
bool CMyInternetExplorer::FindInput  (bool bClick, bool bSelect,
bool bChangeValue, bool bSetCheck,
bool bType, bool bName, bool bValue,
LPCTSTR sTypeToLook, LPCTSTR sNameToLook,
LPCTSTR sValueToLook,
bool bNewCheckValue, LPCTSTR sNewValue)
{
ASSERT (m_pWebBrowser != NULL);
if (m_pWebBrowser == NULL)
return false; HRESULT hr;
IDispatch* pHtmlDocDispatch = NULL;
IHTMLDocument2 * pHtmlDoc = NULL;
bool bSearch = true; // Retrieve the document object.
hr = m_pWebBrowser->get_Document (&pHtmlDocDispatch);
if (SUCCEEDED (hr) && (pHtmlDocDispatch != NULL))
{
hr = pHtmlDocDispatch->QueryInterface
(IID_IHTMLDocument2, (void**)&pHtmlDoc);
if (SUCCEEDED (hr) && (pHtmlDoc != NULL))
{
IHTMLElementCollection* pColl = NULL;
hr = pHtmlDoc->get_all (&pColl); if (SUCCEEDED (hr) && (pColl != NULL))
{
// Obtained the Anchor Collection...
long nLength = 0;
pColl->get_length (&nLength); for (int i = 0; i < nLength && bSearch; i++)
{
COleVariant vIdx ((long)i, VT_I4); IDispatch* pElemDispatch = NULL;
IHTMLElement * pElem = NULL; hr = pColl->item (vIdx, vIdx, &pElemDispatch); if (SUCCEEDED (hr) && (pElemDispatch != NULL))
{
hr = pElemDispatch->QueryInterface
(IID_IHTMLElement, (void**)&pElem); if (SUCCEEDED (hr) && (pElem != NULL))
{
BSTR bstrTagName;
CString sTempTagName;
if (!FAILED (pElem->get_tagName
(&bstrTagName)))
{
sTempTagName = bstrTagName;
sTempTagName.MakeLower ();
//AfxMessageBox (sTempTagName);
SysFreeString (bstrTagName);
}
if (sTempTagName == _T ("input"))
{
IHTMLInputElement * pInputElem = NULL;
hr = pElemDispatch->QueryInterface
(IID_IHTMLInputElement,
(void**)&pInputElem); if (SUCCEEDED (hr) &&
(pInputElem != NULL))
{
BSTR bstrType, bstrName, bstrValue;
CString sTempType,
sTempName, sTempValue; if (!FAILED
(pInputElem->get_type
(&bstrType)))
{
sTempType = bstrType;
SysFreeString (bstrType);
}
if (!FAILED (pInputElem->get_name
(&bstrName)))
{
sTempName = bstrName;
SysFreeString (bstrName);
}
if (!FAILED
(pInputElem->get_value
(&bstrValue)))
{
sTempValue = bstrValue;
SysFreeString (bstrValue);
}
// Do the comparison here!
bool bMatches = true;
if (bMatches && bType)
{
if
(!StringHelper::WildcardCompareNoCase
(sTypeToLook, sTempType))
bMatches = false;
}
if (bMatches && bName)
{
if
(!StringHelper::WildcardCompareNoCase
(sNameToLook, sTempName))
bMatches = false;
}
if (bMatches && bValue)
{
if
(!StringHelper::WildcardCompareNoCase
(sValueToLook, sTempValue))
bMatches = false;
} if (bMatches)
{
// No need to search more!
bSearch = false; if (bSetCheck)
{
if (bNewCheckValue)
pInputElem->put_checked
(VARIANT_TRUE);
else
pInputElem->put_checked
(VARIANT_FALSE);
}
if (bChangeValue)
{
CString sTemp (sNewValue);
BSTR bstrNewValue =
sTemp.AllocSysString ();
pInputElem->put_value
(bstrNewValue);
SysFreeString
(bstrNewValue);
}
if (bSelect)
pInputElem->select (); if (bClick)
pElem->click ();
}
pInputElem->Release ();
}
}
pElem->Release ();
}
pElemDispatch->Release ();
}
}
pColl->Release ();
}
pHtmlDoc->Release();
}
pHtmlDocDispatch->Release ();
} if (bSearch == false)
return true; return false;
}

Some points that you should keep in mind

  • The attached source code includes a few more functions to fill the forms on web pages.
  • The source code above does not search inside Frame objects. However, this should not be a hard task. The frame objects should be enumerated and then the IHTMLDocument2 of each frame should be checked recursively. May be I will implement this in the next update.
  • In order to use IHTMLInputElement object, you need at least Internet Explorer 5.0
  • I am not an expert Internet Explorer programmer. Lately, I needed to automate Internet Explorer and then wrote these functions. I wrote most of them on my own, and they may have some bug fixes in it.
  • Please do not ask me why I used MFC, not ATL. The reason is that I don't know ATL However, if you guys help me to convert this code into ATL, I would be very glad. I may even start learning ATL

IEHelper - Internet Explorer Helper Class的更多相关文章

  1. 如何使用BHO定制你的Internet Explorer浏览器

    原文出处:Browser Helper Objects: The Browser the Way You Want It一.简介 有时,你可能需要一个定制版本的浏览器.在这种情况下,你可以自由地把一些 ...

  2. 企业IT管理员IE11升级指南【1】—— Internet Explorer 11增强保护模式 (EPM) 介绍

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  3. 企业IT管理员IE11升级指南【2】—— Internet Explorer 11 对Adobe Flash的支持

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  4. 企业IT管理员IE11升级指南【6】—— Internet Explorer 11面向IT专业人员的常见问题

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  5. IE中无法执行JS脚本 解决WINDOWS SERVER 2008弹出INTERNET EXPLORER增强安全配置正在阻止来自下列网站的内容

    在默认状态下,使用Windows Server 2008系统自带的IE浏览器访问网页内容时,我们时常发现“Internet Explorer增强安全配置正在阻止来自下列网站的内容”的提示导致不能打开网 ...

  6. Fix Internet Explorer Crashes with SharePoint 2013 Online Presence Indicators

    IE中,只要是鼠标浮动到人名字上面的状态的时候,这个状态是与Lync相连接的,IE就会出现停止工作. 以下是解决方法. Until the other day when I figured this ...

  7. Selenium2学习-037-WebUI自动化实战实例-IE浏览器显示比例问题:org.openqa.selenium.remote.SessionNotFoundException: Unexpected error launching Internet Explorer. Browser zoom level was set to 94%. It should be set to 100%

    好久没有写博文了,今天在给部门新人演示 Selenium WebDriver 启动其支持的各种浏览器时,启动 IE 时总是无法打开对应的百度网址,页面如下所示:

  8. Internet Explorer 无法启用 JavaScript 怎么办?

    在 Internet Expllorer 8/9 中,有些同学在浏览网页时,收到提示:“需要启用 JavaScript …”,并且会发现网页上某些功能不能用了,比如点击网页里的按钮没反应等等. 怎么启 ...

  9. How to Enable 64-bit Processes for Enhanced Protected Mode in Internet Explorer 11 (IE11)

       Information Enhanced Protected Mode (EPM) adds additional security to Protected Mode and includes ...

随机推荐

  1. SharePoint 学习记事(一)

    记录背景: 随着公司业务的拓展,为拿到更多的项目,让原本不太信任我们的美国大佬相信我们的实力,让在美国的销售发挥他的能力,所以公司在13年下半年筹划收购了一家美国本土的公司.大约400人的规模,这个公 ...

  2. java中的异常处理机制_finally的使用

    finally总结: finally代码块:定义一定执行的代码 通常用于关闭资源或者某些一定执行的代码 实例1:finally功能演示 class FuShuException extends Exc ...

  3. There is no Action mapped for namespace [/] and action name [user] associated with context path

    从c++转到java,初学struts,竟然碰到一个因写错单词而造成的错误,structs --> struts

  4. Integer ,==,int 的使用

    面试比较常见的题目:自己也经常忘记,所以就记下来了 上代码: Integer a = ,b=; Integer c = ,d=; System.out.println(a==b); System.ou ...

  5. <<深入Java虚拟机>>-虚拟机类加载机制-学习笔记

    类加载的时机 遇到new.getstatic.putstatic或invokestatic这4个字节码指令时,如果类没有进行过初始化,则需要先触发其初始化.生成这4条指令最常见的Java场景是:使用n ...

  6. ubuntu系统根目录下各个目录用途说明

    1./ 根目录     --------- 所有目录挂在其下 2./boot     --------- 存放Ubuntu内核和系统启动文件.系统启动时这些文件先被装载. 3./etc    ---- ...

  7. centos 安装php ide (eclipse + php 插件)

    1.检查更新并安装eclipse  yum check-update  yum install eclipse*此时的 eclipse 已经安装好了,默认是在/usr/lib/下的,可以通过cd /u ...

  8. 推荐一个优秀的前端框架——Bootstrap

    Bootstrap是Twitter推出的一个开源的用于前端开发的工具包.它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架.Bootstra ...

  9. Fluid Shopping Website 开发阶段性总结——第一周

    开发目的: 可链接微信公众号,无论是桌面端.移动端完美兼容,给用户提供不逊于原生App的用户体验.作为一个软件,有充分的可扩展性,便于未来增强开发.同时给一些正在尝试做OTO的朋友们提供一个平台,因为 ...

  10. 求给定数据中最小的K个数

    public class MinHeap { /* * * Top K个问题,求给定数据中最小的K个数 * * 最小堆解决:堆顶元素为堆中最大元素 * * * */ private int MAX_D ...