Solved

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

Posted on 2016-10-12
8
53 Views
Last Modified: 2016-10-28
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
  • 5
  • 3
8 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
 
LVL 12

Author Comment

by:Dustin Saunders
ID: 41842140
Thanks Daniel, I appreciate your time.
0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
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

Featured Post

3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

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…
More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
As a trusted technology advisor to your customers you are likely getting the daily question of, ‘should I put this in the cloud?’ As customer demands for cloud services increases, companies will see a shift from traditional buying patterns to new…

920 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now