Solved

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

Posted on 2016-10-12
8
44 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 19

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 19

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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
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 19

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

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

747 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

12 Experts available now in Live!

Get 1:1 Help Now