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. System.Data.SqlClient.SqlError: 对文件……的目录查找失败[转]

    System.Data.SqlClient.SqlError: 对文件……的目录查找失败,出现操作系统错误 3 的处理办法 在还原SQL SERVER数据库时出现了查找目录失败的原因,困扰了我一个多小 ...

  2. C# 打印多页tif

    注意点: 1.计算image对象总页数 image.GetFrameCount(FrameDimension.Page); 2.初始化当前页,并获取指定页内容 image.SelectActiveFr ...

  3. iBeacon 开发笔记

    iBeacon开发笔记 2015.10.19 airlocate ========= airlocate显示如何使用这个监控范围clbeaconregions. 代码还提供了一个例子,你如何能校准和配 ...

  4. jquery之each

    $.each()与$(selector).each()不同, 后者专用于jquery对象的遍历, 前者可用于遍历任何的集合(无论是数组或对象),如果是数组,回调函数每次传入数组的索引和对应的值(值亦可 ...

  5. 关于Ionic的安装

    Ionic是一个前端的框架,帮助开发者使用HTML5, CSS3和JavaScript做出原生应用. http://ionicframework.com/getting-started/ 这里介绍了如 ...

  6. mysql innodb 数据打捞(三)innodb 簇不连接页的扫描提取(计划)

    操作系统簇大小一般是4K,而innoDB的页大小一般是16K,那么就有可能16K的页没有存储在连续的簇中,这样扫描软件就不会扫描出来这样的页面.为了解决这个问题,决定给软件增加半页扫描功能. 在第一次 ...

  7. CruiseControl.NET : Configuration Preprocessor

    Original link: http://build.sharpdevelop.net/ccnet/doc/CCNET/Configuration%20Preprocessor.html http: ...

  8. 第32条:用EnumSet代替位域

    如果一个枚举类型的元素主要用在集合中,一般使用int枚举模式,将2的不同倍数赋予每个常量: public class Text { public static final int STYLE_BOLD ...

  9. 尚学堂JavaEE项目备选

    偶然得知:记下待练 微博 软件人才网 论坛 博客系统 京东网上商城 赶集网 拉手网 优酷视频 百度知道(问答) 生产管理系统 房屋租赁网 金融股票

  10. MVC-Html.Label(TextBox、TextArea、RadioButton、CheckBox)

    红色表示可选参数. @Html.Label("name", "value", new { @class = "class", @style ...