Click here to Skip to main content
16,017,623 members
Articles / Desktop Programming / MFC
Article

IEHelper - Internet Explorer Helper Class

Rate me:
Please Sign up or sign in to vote.
4.74/5 (44 votes)
21 Jun 2004CPOL4 min read 670K   3.6K   140   83
This article show how to use IWebBrowser2, IHTMLDocument2 and IHTMLElement objects.

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:

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.

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.

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.

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:

HTML
<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.

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:

HTML
<input type="input_type" value="input_value" name="input_name">
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 :-)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHow do I create a new browser object from existing web object ? Pin
Yariv17-Jan-05 9:43
Yariv17-Jan-05 9:43 
GeneralWhy should we use IDispatch::Release() function. Pin
sfirouza2-Jan-05 18:00
sfirouza2-Jan-05 18:00 
Generalis it possible to check the ready state of the normal window or any apllication programmatically Pin
1lokii28-Dec-04 18:49
1lokii28-Dec-04 18:49 
Generalis it possible to create object for the explorer which is on focus Pin
1lokii23-Dec-04 19:31
1lokii23-Dec-04 19:31 
GeneralRe: is it possible to create object for the explorer which is on focus Pin
1lokii26-Dec-04 22:20
1lokii26-Dec-04 22:20 
Questionwhat is m_pWebBrowser? Pin
1lokii22-Dec-04 2:16
1lokii22-Dec-04 2:16 
QuestionHow to get multi frame objects? Pin
newro18-Oct-04 18:32
newro18-Oct-04 18:32 
AnswerRe: How to get multi frame objects? Pin
Mustafa Demirhan18-Oct-04 21:48
Mustafa Demirhan18-Oct-04 21:48 
Ok here is what you need to do:

Lets say you want to modify the FindInput method and make it work with framed pages. When you find a Frame element (IHTMLFrameElement), you should recursively call the function with the Document of the frame itself.

You need to make some modifications in the beginning of the function. And you need to change the middle of the function like this:

if (sTempTagName == _T ("frame"))
{
    IHTMLFrameBase2* pFrameBase = NULL;
    hr = pElemDispatch->QueryInterface (IID_IHTMLFrameBase2,                                   (void**)&pFrameBase);
    if (SUCCEEDED (hr) && (pFrameBase!= NULL))
    {
         IHTMLDocument * pDoc = NULL;
         IHTMLWindow2 * pWnd = NULL;
         pBase->get_contentWindow (&wnd);
         pWnd->get_document (&pDoc);
         // CALL THE FUNCTION RECURSIVELY HERE!
         FindInput (WITH pDoc SUPPLIED AS A PARAMETER)
    }
    pFrameBase->Release ();
    ....
    ....




Mustafa Demirhan
http://www.macroangel.com

"What we do in life echoes in eternity" - Gladiator
It's not that I'm lazy, it's just that I just don't care

GeneralRe: How to get multi frame objects? Pin
newro18-Oct-04 23:33
newro18-Oct-04 23:33 
GeneralRe: How to get multi frame objects? Pin
Mich2620-Jan-06 6:17
Mich2620-Jan-06 6:17 
GeneralFind a &lt;td&gt; element Pin
Mav Rossi24-Jun-04 23:41
Mav Rossi24-Jun-04 23:41 
GeneralRe: Find a &lt;td&gt; element Pin
Mustafa Demirhan25-Jun-04 10:51
Mustafa Demirhan25-Jun-04 10:51 
GeneralWaitTillLoaded is very wasteful Pin
casperOne22-Jun-04 2:31
casperOne22-Jun-04 2:31 
GeneralRe: WaitTillLoaded is very wasteful Pin
Mustafa Demirhan22-Jun-04 10:17
Mustafa Demirhan22-Jun-04 10:17 
GeneralRe: WaitTillLoaded is very wasteful Pin
Eclypce27-Jun-04 14:56
sussEclypce27-Jun-04 14:56 
GeneralRe: WaitTillLoaded is very wasteful Pin
Eclypce28-Jun-04 16:56
sussEclypce28-Jun-04 16:56 
GeneralRe: WaitTillLoaded is very wasteful Pin
Armen Hakobyan30-Jun-04 12:36
professionalArmen Hakobyan30-Jun-04 12:36 
GeneralRe: WaitTillLoaded is very wasteful Pin
Emmanuel14-Feb-05 4:56
Emmanuel14-Feb-05 4:56 
GeneralRe: WaitTillLoaded is very wasteful Pin
JabbaDaHutt6-Feb-06 9:50
JabbaDaHutt6-Feb-06 9:50 
GeneralRe: WaitTillLoaded is very wasteful Pin
John T20-Jul-06 15:47
John T20-Jul-06 15:47 
GeneralRe: WaitTillLoaded is very wasteful Pin
Sam Hobbs24-May-11 15:03
Sam Hobbs24-May-11 15:03 
GeneralA suggestion to select input items Pin
Enrico Detoma25-Mar-04 21:06
Enrico Detoma25-Mar-04 21:06 
GeneralRe: A suggestion to select input items Pin
Mustafa Demirhan26-Mar-04 21:48
Mustafa Demirhan26-Mar-04 21:48 
Questionhow to measure IE Page load time. Pin
Member 95043116-Mar-04 17:13
Member 95043116-Mar-04 17:13 
AnswerRe: how to measure IE Page load time. Pin
Mustafa Demirhan26-Mar-04 21:54
Mustafa Demirhan26-Mar-04 21:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.