Solved

Code works in .vbs not in C# app -- Open IE, log in to site, click item

Posted on 2016-10-12
9
66 Views
Last Modified: 2017-01-24
Experts,

I have the following code that logs in to an RWeb portal and clicks the RDP icon to launch it:

'Whatever you want to call this QA Activity:
QAName = "qatest" 

'URL to launch:
strURL = "http://qasite.wizmo.com"

'QA Username and Password:
QAUser = "qauser"
QAPass = "qapass"

'Comma separated list of the icons we are waiting to appear in the list of apps:
IconsToFind = "rdp"

'Icon we are actually going to launch. 0 = First Icon, 1 = Second, etc..
IconToLaunch = 0


'-----------------------------
'Generally no need to modify anything below this line.
'------------------------------

Set objIE = CreateObject("InternetExplorer.Application")
Set objWSH = WScript.CreateObject("WScript.Shell")
With objIE
   .Visible = True
   objWSH.AppActivate objIE
   .Navigate strURL
   '==No point in checking right away - give the page a chance to load
   WScript.Sleep 500
   '==Now check to see if we're done loading and we have the Sign In button available
   Do While .Busy or .readyState <> 4
      WScript.Sleep 500
   Loop
   Do Until (Instr(.Document.Body.InnerHTML,"Sign in") <> 0)
      WScript.Sleep 500
   Loop

   '==Fill out the form and login
   .Document.getElementsByName("DomainUserName").Item(0).Value = QAUser
   .Document.getElementsByName("UserPass").Item(0).Value = QAPass
   .Document.getElementsByName("btnSignIn").Item(0).Click
   '==Give the page a second to load before we start looking for things
   Do While .Busy or .readyState <> 4
      WScript.Sleep 500
   Loop
   WScript.Sleep 500
   Checks = 0
   bFound_RemoteDesktop = False
   iFoundCount = 0 
   'Check if all icons we are waiting for exist
   IconList = Split(IconsToFind, ",")
   For Each Icon in IconList
		If instr(.Document.Body.InnerHTML,Icon) <> 0 then
			iFoundCount = iFoundCount + 1
		End If
   Next
   'Msgbox "Icons found: " & iFoundCount	& " of " & ubound(IconList) + 1
   If iFoundCount = ubound(IconList) + 1  then 
		'Msgbox "All icons found"
   Else
		Msgbox "Some icons missing!!"
		WScript.Quit 0
   End If
  
   '==This will launch the first link
   .Document.getElementsByClassName("tswa_boss").Item(IconToLaunch).onMouseUp
   Msgbox "Click OK once you've finished Q/A of the desktop session"
   If instr(.Document.Body.InnerHTML,"Sign out") <> 0 Then
      '==User is still logged in, let's log them out
      .Document.getElementById("PORTAL_SIGNOUT").Click
      WScript.Sleep 1000
   End If
End With
objIE.Quit   
Msgbox "QA done for " & QAName

Open in new window


Users can run this manually, and it works with no issue.  But for our QA automation, I have a winform c# app that I want to do this login, and it gets through the login process but dies trying to find the class:
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Web;

using SHDocVw;
using System.Threading;


namespace ieapptest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string URL = "http://qasite.wizmo.com";
            string QAUser = "qauser";
            string QAPass = "qapass";
            string IconsToFind = "rdp";
            int IconToLaunch = 0;


            InternetExplorer qaBrowser = new InternetExplorer();
            qaBrowser.Visible = true;
            qaBrowser.Navigate(URL);
            Thread.Sleep(500);
            while (qaBrowser.Busy || qaBrowser.ReadyState != SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE)
            {
                Thread.Sleep(500);
            }

            qaBrowser.Document.GetElementsByName("DomainUserName").Item(0).Value = QAUser;
            qaBrowser.Document.GetElementsByName("UserPass").Item(0).Value = QAPass;
            qaBrowser.Document.GetElementsByName("btnSignIn").Item(0).Click();

            while (qaBrowser.Busy || qaBrowser.ReadyState != SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE)
            {
                Thread.Sleep(500);
            }

            string[] IconList = IconsToFind.Split(',');
            foreach (string icon in IconList)
            {
                //add check to make sure all expected icons are present.
            }

            Thread.Sleep(500);

            //qaBrowser.Document.GetElementByID("PORTAL_SIGNOUT").Click();
            
            qaBrowser.Document.GetElementsByClassName("tswa_boss");//[0].onmouseup();
            //qaBrowser.Document.GetElementByID("PORTAL_SIGNOUT").Click();

        }
    }
}

Open in new window


This is the hill it dies on:
  qaBrowser.Document.GetElementsByClassName("tswa_boss")

Open in new window

with an HRESULT exception.

But the code works just fine in VB...?

The class name for the element is "tswa_boss".  Any ideas what the problem might be?
0
Comment
Question by:Dustin Saunders
  • 6
  • 3
9 Comments
 
LVL 20

Expert Comment

by:Daniel Van Der Werken
ID: 41840862
My guess is that it's a case-sensitivity issue. What's the actual HTML look like that you're working against?
0
 
LVL 12

Author Comment

by:Dustin Saunders
ID: 41840875
Here's the table:
webPageName.png
0
 
LVL 20

Expert Comment

by:Daniel Van Der Werken
ID: 41842123
Okay. That was a try. I was assuming all the Interop was done correctly, but I don't think it is. The way Interop is done betwixt C# and VB.NET is very different. VB.NET lets you be lazy and C# doesn't. Give me a while and I'll get back to this.
0
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 
LVL 12

Author Comment

by:Dustin Saunders
ID: 41842140
Thanks Daniel, I appreciate your time.
0
 
LVL 12

Author Comment

by:Dustin Saunders
ID: 41848404
I'm getting back around to trying to figure this out today, was wondering if you were able to figure anything out (if not, no worries, but I'm still stumped).
0
 
LVL 20

Accepted Solution

by:
Daniel Van Der Werken earned 500 total points
ID: 41848718
I didn't get very far myself. The key to Interop with C# is that you can't ignore the parameters that you can ignore with VB .NET.

In my test windows forms app, I set up a class-wide variable like this:

public SHDocVw.InternetExplorer ie = null;

Open in new window


Then, in the class initializer, I simply did this:

            ie = new InternetExplorer();
            ie.DocumentComplete += Ie_DocumentComplete;
            ie.Navigate("www.google.com", Type.Missing, Type.Missing, Type.Missing, Type.Missing);

Open in new window


Note that I specifically set up my ability to hook into the document complete event. Therefore, in my code, I also have this:

        private void Ie_DocumentComplete(object pDisp, ref object URL)
        {
            object op = pDisp;
            object u = URL;
        }

Open in new window


Where I just added the object op = pDisp and such so I could look at it in the debugger. Sure enough, this event fires for me, and pDisp is something COM related. I don't know what though. I would imagine we could hook into it via a cast or a late binding to do what we need. I would need to know what type that object is first.

Notice though, by hooking that event, I got around the whole Thread.Sleep() stuff you were doing. The second thing is that we now have something.

Likewise, according to Microsoft, the pDisp is the top-level WebBrower frame, so we should be able to work with that.

So, that event turns into this:

        private void Ie_DocumentComplete(object pDisp, ref object URL)
        {
            SHDocVw.WebBrowser wbObj = (SHDocVw.WebBrowser)pDisp;

            object iweDoc = wbObj.GetType().InvokeMember("IWebBrowser_Document", BindingFlags.GetField | BindingFlags.GetProperty, Type.DefaultBinder, null, null);
             

            object u = URL;
        }

Open in new window


Note that my InvokeMember() fails because I really don't know anything about the WebBrowser object. Maybe you know more. But, I think we need to work with late binding here, which is what the InvokeMember() allows us to do.

That's where I left of. Does this help?
1
 
LVL 12

Author Comment

by:Dustin Saunders
ID: 41854251
Thanks for the information, I'll touch this again over the weekend and let you know what I find.
0
 
LVL 12

Author Closing Comment

by:Dustin Saunders
ID: 41864281
So far as I can tell the problem comes from security with the way .NET interacts with the IE object and the way VBS does.  I couldn't find a good way around it, but I automated the process in a different way (using Powershell instead for the process to launch the .VBS and then look at our SQL login tables to confirm the login worked) but I appreciate your time testing this problem.
0
 
LVL 12

Author Comment

by:Dustin Saunders
ID: 41977981
I finally got back around to looking at this.  Found the problem.

qaBrowser.Document.GetElementsByClassName("tswa_boss")

Open in new window


Should be
qaBrowser.Document.DocumentElement.GetElementsByClassName("tswa_boss")

Open in new window

0

Featured Post

The New “Normal” in Modern Enterprise Operations

DevOps for the modern enterprise offers many benefits — increased agility, productivity, and more, but digital transformation isn’t easy, especially if you’re not addressing the right issues. Register for the webinar to dive into the “new normal” for enterprise modern ops.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

792 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question