Solved

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

Posted on 2016-10-12
9
91 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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 13

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
MS Dynamics Made Instantly Simpler

Make Your Microsoft Dynamics Investment Count  & Drastically Decrease Training Time by Providing Intuitive Step-By-Step WalkThru Tutorials.

 
LVL 13

Author Comment

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

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 13

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 13

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 13

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

Revamp Your Training Process

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action.

Question has a verified solution.

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

In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…

695 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