wpf htmldocument question

Hi guys,

Im trying to automatically log the user into this website, which I have in a WPF project in a browser window:

http://www.brokerforum.com/

I have the following code so far to populate the username and password

 HtmlDocument doc = (HtmlDocument)Enquiry_Sourcing_Netcomponents.Document;

                doc.GetElementById("Session_Username").SetAttribute("value", "USERNAME");
                doc.GetElementById("Session_Password").SetAttribute("value", "PASSWORD");
 

Open in new window


I now need to call the click button to login. The code (I believe) is...

doc.GetElementById("").InvokeMember("click");

Open in new window


However the click button has no id. So how do I call this?

The html / css behind the button is:

<div class="formActions">
                                <input src="/tbf/img/login-button-small-en.png" type="image" />
                            </div>

Open in new window


Thanks,
Dean
deanlee17Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Bob LearnedCommented:
You might be able to get a reference to the <input> element by using the HtmlDocument.GetElementsByTagName method, and checking the "src" attribute for the desired image name.
0
käµfm³d 👽Commented:
That's not a button, though--it's an image. You might need to invoke some Javascript on that one.
0
deanlee17Author Commented:
TheLearnedOne: Any idea how to code this?
0
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

deanlee17Author Commented:
HtmlDocument doc = (HtmlDocument)Enquiry_Sourcing_Netcomponents.Document;

            doc.GetElementById("Session_Username").SetAttribute("value", "XXXXX");
            doc.GetElementById("Session_Password").SetAttribute("value", "XXXXX");
            doc.GetElementById("").InvokeMember("click");

            HtmlElementCollection theElementCollection = doc.GetElementsByTagName("input");

            HtmlElementCollection elems = doc.GetElementsByTagName("input");

            foreach (HtmlElement elem in theElementCollection)
            {
                String nameStr = elem.GetAttribute("name");
                if (nameStr != null && nameStr.Length != 0)
                {
                    String contentStr = elem.GetAttribute("content");
                    System.Windows.MessageBox.Show("Document: " + Enquiry_Sourcing_Netcomponents.ToString() + "\nDescription: " + contentStr);
                }
            }

Open in new window


Throwing error on first line:

System.InvalidCastException was unhandled
  HResult=-2147467262
  Message=Unable to cast COM object of type 'mshtml.HTMLDocumentClass' to class type 'System.Windows.Forms.HtmlDocument'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.
0
Bob LearnedCommented:
Aah, yes, the ambiguous nature of HtmlDocument.  If that reference is an HTMLDocument, then you need to change some things around, and use different methods, which gets trickier, and a lot heavier.

Word of warning:  "If you are going to add a reference to mshtml, don't use a using mshtml; statement at the top of the module, since it will slow Intellisense to a crawl"
0
deanlee17Author Commented:
Ah ok, all ive added is 'using System.Windows.Forms;'

Now... Im stuck lol
0
Bob LearnedCommented:
Microsoft mshtml is COM library that is part of the .NET framework, but there is a managed wrapper available as a reference.

Example using mshtml:

  var htmlDoc = (HTMLDocument)webBrowser1.Document;

   //find the search text box..
   var searchTextBox = (HTMLInputElement)htmlDoc.all.item("p", 0);
   searchTextBox.value = "Search text goes here";

   //find the button
   var searchButton = (HTMLInputElement)htmlDoc.all.item("searchsubmit", 0);
   searchButton.click();

Open in new window

0
deanlee17Author Commented:
Ok that makes sense. So do I add a reference to 'mshtml.HTMLDocumentClass' in the right hand window but then don't include a 'using' statement at the top?

In your example, is 'searchsubmit' the actual id as the button I need to hit doesn't have the id. Im assuming we could do that search on the input source (button image)?
0
Bob LearnedCommented:
Here are some screen shots from Visual Studio 2012, on how to add a reference to the Microsoft.mshtml assembly.

Select Add Reference from Solution Explorer
 Add Reference Dialog
0
deanlee17Author Commented:
Ok cool, and im doing ok with the below code, it populates the input boxes, now I just need to find a way to click a button without an id or class attached...

            var htmlDoc = (HTMLDocument)LoginWebpage.Document;

            //find the search text box..

            var UsernameTextBox = (mshtml.HTMLInputElement)htmlDoc.all.item("Session_Username", 0);
            UsernameTextBox.value = "XXXXX";

            var PasswordTextBox = (mshtml.HTMLInputElement)htmlDoc.all.item("Session_Password", 0);
            PasswordTextBox.value = "XXXXX";

Open in new window


Thanks,
Dean
0
Bob LearnedCommented:
The HTMLDocument class has the getElementsByTagName.  

Here is one possible solution (untested)

    internal static class HtmlHelper
    {

        public static object GetElementByTagNameWithAttribute(
            mshtml.HTMLDocument document, string tagName, string attributeName, string attributeValue)
        {
            var elementList = document.getElementsByTagName(tagName);

            foreach (dynamic element in elementList)
            {
                var attributeList = (mshtml.IHTMLAttributeCollection)element.attributes;

                foreach (var attribute in attributeList)
                {
                    var htmlAttribute = (mshtml.IHTMLDOMAttribute)attribute;
                    if (htmlAttribute.nodeName == attributeName && htmlAttribute.nodeValue == attributeValue)
                        return element;
                }
            }

            return null;
        }

    }

Open in new window


Sample usage:

    var browser = new WebBrowser();
    var document = browser.Document;
    var htmlDocument = (mshtml.HTMLDocument)document.DomDocument;

    var buttonElement = (mshtml.HTMLInputElement)HtmlHelper.GetElementByTagNameWithAttribute(htmlDocument, 
                "input", "src", "/tbf/img/login-button-small-en.png");

    buttonElement.click();

Open in new window


Reference:

Working With Microsoft.mshtml.dll and SHDocVw.dll
http://www.codeproject.com/Articles/28094/Working-With-Microsoft-mshtml-dll-and-SHDocVw-dll
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
deanlee17Author Commented:
Where did HtmlHelper come from?

I get 'The name 'HtmlHelper' does not exist in the current context'

Does this require another include?
0
Bob LearnedCommented:
HtmlHelper is the class that I created and posted, starting with this line:

internal static class HtmlHelper
0
deanlee17Author Commented:
d'oh, I missed that.

Ok so implemented it and its throwing an error on

'var htmlDocument = (mshtml.HTMLDocument)document.DomDocument;'

saying....Object reference not set to an instance of an object?

Thanks,
Dean
0
deanlee17Author Commented:
Code so far:
  internal static class HtmlHelper
        {

            public static object GetElementByTagNameWithAttribute(
                mshtml.HTMLDocument document, string tagName, string attributeName, string attributeValue)
            {
                var elementList = document.getElementsByTagName(tagName);

                foreach (dynamic element in elementList)
                {
                    var attributeList = (mshtml.IHTMLAttributeCollection)element.attributes;

                    foreach (var attribute in attributeList)
                    {
                        var htmlAttribute = (mshtml.IHTMLDOMAttribute)attribute;
                        if (htmlAttribute.nodeName == attributeName && htmlAttribute.nodeValue == attributeValue)
                            return element;
                    }
                }

                return null;
            }

        } 

        private void btnCreateQuote_Click(object sender, RoutedEventArgs e)
        {

            var htmlDoc = (HTMLDocument)LoginWebpage.Document;


            var UsernameTextBox = (mshtml.HTMLInputElement)htmlDoc.all.item("Session_Username", 0);
            UsernameTextBox.value = "XXX";

            var PasswordTextBox = (mshtml.HTMLInputElement)htmlDoc.all.item("Session_Password", 0);
            PasswordTextBox.value = "XXX";


            var browser = new System.Windows.Forms.WebBrowser();
            var document = browser.Document;
            var htmlDocument = (mshtml.HTMLDocument)document.DomDocument;

            var buttonElement = (mshtml.HTMLInputElement)HtmlHelper.GetElementByTagNameWithAttribute(htmlDocument,
                        "input", "src", "/tbf/img/login-button-small-en.png");

            buttonElement.click(); 

}

Open in new window

0
Bob LearnedCommented:
Is that code working?
0
deanlee17Author Commented:
'var htmlDocument = (mshtml.HTMLDocument)document.DomDocument;'

saying....Object reference not set to an instance of an object?
0
Bob LearnedCommented:
If you got that code from me, that was meant to show you an example, using the WebBrowser control.  

I thought this is your HTMLDocument reference:

var htmlDoc = (HTMLDocument)LoginWebpage.Document;
0
deanlee17Author Commented:
Hmmm this is still erroring. Will provide furthur info shortly..
0
deanlee17Author Commented:
Hi The LearnedOne,

Sorry for the delay, I have been away from work for a while.

As per your code and comments above, for the line below:

 var htmlDocument = (mshtml.HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.DomDocument;

I get the error:

'System.Windows.Controls.WebBrowser' does not contain a definition for 'DomDocument' and no extension method 'DomDocument'

Complete code as it stands....

 internal static class HtmlHelper
        {

            public static object GetElementByTagNameWithAttribute(
                mshtml.HTMLDocument document, string tagName, string attributeName, string attributeValue)
            {
                var elementList = document.getElementsByTagName(tagName);

                foreach (dynamic element in elementList)
                {
                    var attributeList = (mshtml.IHTMLAttributeCollection)element.attributes;

                    foreach (var attribute in attributeList)
                    {
                        var htmlAttribute = (mshtml.IHTMLDOMAttribute)attribute;
                        if (htmlAttribute.nodeName == attributeName && htmlAttribute.nodeValue == attributeValue)
                            return element;
                    }
                }

                return null;
            }

        } 


        private void EnquirySave_Click(object sender, RoutedEventArgs e)
        {
 
            //ascentEntities.SaveChanges();
            var htmlDoc = (HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.Document;


            var UsernameTextBox = (mshtml.HTMLInputElement)htmlDoc.all.item("Session_Username", 0);
            UsernameTextBox.value = "XXX";

            var PasswordTextBox = (mshtml.HTMLInputElement)htmlDoc.all.item("Session_Password", 0);
            PasswordTextBox.value = "XXX";


            var browser = new System.Windows.Forms.WebBrowser();
            var document = browser.Document;
            var htmlDocument = (mshtml.HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.DomDocument;


            var buttonElement = (mshtml.HTMLInputElement)HtmlHelper.GetElementByTagNameWithAttribute(htmlDocument,
                        "input", "src", "/tbf/img/login-button-small-en.png");

            buttonElement.click(); 



        }

Thanks

Open in new window

0
Bob LearnedCommented:
This line should be changed:

 var htmlDocument = (mshtml.HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.DomDocument;


to

 var htmlDocument = (mshtml.HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.Document.DomDocument;
0
deanlee17Author Commented:
Attached
error.png
0
Bob LearnedCommented:
What is the type for "WebBrowser_Sourcing_BrokerForum_Enquiry"?
0
deanlee17Author Commented:
It's WebBrowser
0
Bob LearnedCommented:
Can you show me the declaration, and tell me what version of the .NET IDE that you are using?
0
deanlee17Author Commented:
.net 4.5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using DevExpress.Xpf.Core;
using DevExpress.Xpf.Ribbon;
using DevExpress.Xpf.Bars;
using DevExpress.Xpf.Layout.Core;
using DevExpress.Xpf.Docking;
using System.Data.OleDb;
using System.Data;
using DevExpress.Xpf.Grid;
using System.Data.SqlClient;
using System.IO;
using System.Globalization;
using DevExpress.XtraPrinting;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.Data.Filtering;
using System.Collections;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.Xpf.Map;
using System.Windows.Forms;
using DevExpress.Xpf.Editors;
0
Bob LearnedCommented:
Not the using statements, the declaration in the .Designer.cs file.
0
deanlee17Author Commented:
In model1.designed.cs?

I don't know what you want from in there.
0
Bob LearnedCommented:
I am confused, because I have 2012 IDE, a Windows Forms 4.5 application, and the System.Windows.Forms.WebBrowser.Document has the DomDocument property, as shown in the attached snapshot.

HtmlDocument.DomDocument property
0
deanlee17Author Commented:
It's a WPF application, would that make a difference?
0
Bob LearnedCommented:
That is what I was trying to get straight.  So, you are using the System.Windows.Controls.WebBrowser, and not the System.Windows.Forms.WebBrowser.

Try this instead:

 var htmlDocument = (mshtml.HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.Document;

Open in new window

0
deanlee17Author Commented:
Got there in the end:

 try
            {


                var htmlDoc1 = (HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.Document;


                var UsernameTextBox = (mshtml.HTMLInputElement)htmlDoc1.all.item("Session_Username", 0);
                UsernameTextBox.value = "XXXXX";

                var PasswordTextBox = (mshtml.HTMLInputElement)htmlDoc1.all.item("Session_Password", 0);
                PasswordTextBox.value = "XXXXX";



                foreach (mshtml.HTMLInputElement HTMLI in ((mshtml.HTMLDocument)WebBrowser_Sourcing_BrokerForum_Enquiry.Document).getElementsByTagName("input"))
                {

                    if (HTMLI.getAttribute("type").Equals("image"))
                    {
                        if (HTMLI.src == "http://www.brokerforum.com/tbf/img/login-button-en.png")
                        {

                            HTMLI.click();
                            return;
                        }
                    }


                }
            }

            catch (Exception) { }

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.