Showing posts with label webbrowser-control. Show all posts
Showing posts with label webbrowser-control. Show all posts

Friday, April 14, 2017

Visual basic programmatically pass username and password to https url to make webbrowser display webpage and also download from webpage

Leave a Comment

With normal HTTP I can download upload and navigate to routers but I can't find any code to do any of that when the routers are on HTTPS.

To download I use this:

Try     My.Computer.Network.DownloadFile("http://" & "180.29.74.70" & "/cgi-bin/log.cgi", "C:\Users\ssb\Desktop\randomword.txt", "username", "password")     WebBrowser1.Refresh() Catch ex As Exception     MessageBox.Show("Router not sufficient for operation Return for Inspection cannot download log file") End Try 

To upload a file I use this:

  My.Computer.Network.UploadFile("C:\Users\ssb\Desktop\tomtn.txt", "http://" & "180.29.74.70" & "/cgi-bin/updateconfig.cgi", "username", "password") 

To navigate to a web page on HTTP I use this:

WebBrowser1.Navigate("https://username:password@180.29.74.70 ") 

But when I use HTTPS:

WebBrowser1.Navigate("https://username:password@180.29.74.70 ") 

I get this security alert:

Certificate Error

Then I click on yes and it goes to the page—but I need the code to bypass any security questions like these.

3 Answers

Answers 1

Even though they're loosely related, you've presented two separate questions here.

  1. Why is the call failing when I use the WebBrowser control to load a page via HTTPS?
  2. Why is the call failing when I use the DownloadFile() method to download a file via HTTPS?

First, you need to eliminate the possibility that your code is failing. Try both of the tasks above using public HTTPS URLs that are known to work correctly.

If you discover that the source of the problem is your private URL, you may want to consider whether you want to ignore SSL errors in your WebBrowser control.

You can do so using the (untested, translated to VB) code from this blog post:

Partial Public Class Form1   Inherits Form    Private WithEvents WebBrowser As New WebBrowser    Private Sub WebBrowser_DocumentCompleted(Sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser.DocumentCompleted     If e.Url.ToString() = "about:blank" Then       'create a certificate mismatch       WebBrowser.Navigate("https://74.125.225.229/")     End If   End Sub End Class    <Guid("6D5140C1-7436-11CE-8034-00AA006009FA")> <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> <ComImport> Public Interface UCOMIServiceProvider   <PreserveSig>   Function QueryService(<[In]> ByRef guidService As Guid, <[In]> ByRef riid As Guid, <Out> ByRef ppvObject As IntPtr) As <MarshalAs(UnmanagedType.I4)> Integer End Interface    <ComImport> <ComVisible(True)> <Guid("79eac9d5-bafa-11ce-8c82-00aa004ba90b")> <InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> Public Interface IWindowForBindingUI   <PreserveSig>   Function GetWindow(<[In]> ByRef rguidReason As Guid, <[In], Out> ByRef phwnd As IntPtr) As <MarshalAs(UnmanagedType.I4)> Integer End Interface    <ComImport> <ComVisible(True)> <Guid("79eac9d7-bafa-11ce-8c82-00aa004ba90b")> <InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> Public Interface IHttpSecurity   'derived from IWindowForBindingUI   <PreserveSig>   Function GetWindow(<[In]> ByRef rguidReason As Guid, <[In], Out> ByRef phwnd As IntPtr) As <MarshalAs(UnmanagedType.I4)> Integer   <PreserveSig>   Function OnSecurityProblem(<[In], MarshalAs(UnmanagedType.U4)> dwProblem As UInteger) As Integer End Interface    Public Class MyWebBrowser   Inherits WebBrowser   Public Shared IID_IHttpSecurity As New Guid("79eac9d7-bafa-11ce-8c82-00aa004ba90b")   Public Shared IID_IWindowForBindingUI As New Guid("79eac9d5-bafa-11ce-8c82-00aa004ba90b")   Public Const S_OK As Integer = 0   Public Const S_FALSE As Integer = 1   Public Const E_NOINTERFACE As Integer = &H80004002   Public Const RPC_E_RETRY As Integer = &H80010109      Protected Overrides Function CreateWebBrowserSiteBase() As WebBrowserSiteBase     Return New MyWebBrowserSite(Me)   End Function      Private Class MyWebBrowserSite     Inherits WebBrowserSite      Implements UCOMIServiceProvider     Implements IHttpSecurity     Implements IWindowForBindingUI      Private myWebBrowser As MyWebBrowser        Public Sub New(myWebBrowser As MyWebBrowser)       MyBase.New(myWebBrowser)       Me.myWebBrowser = myWebBrowser     End Sub        Public Function QueryService(ByRef guidService As Guid, ByRef riid As Guid, ByRef ppvObject As IntPtr) As Integer Implements UCOMIServiceProvider.QueryService       If riid = IID_IHttpSecurity Then         ppvObject = Marshal.GetComInterfaceForObject(Me, GetType(IHttpSecurity))         Return S_OK       End If       If riid = IID_IWindowForBindingUI Then         ppvObject = Marshal.GetComInterfaceForObject(Me, GetType(IWindowForBindingUI))         Return S_OK       End If       ppvObject = IntPtr.Zero       Return E_NOINTERFACE     End Function        Public Function GetWindow(ByRef rguidReason As Guid, ByRef phwnd As IntPtr) As Integer Implements IHttpSecurity.GetWindow, IWindowForBindingUI.GetWindow       If rguidReason = IID_IHttpSecurity OrElse rguidReason = IID_IWindowForBindingUI Then         phwnd = myWebBrowser.Handle         Return S_OK       Else         phwnd = IntPtr.Zero         Return S_FALSE       End If     End Function        Public Function OnSecurityProblem(dwProblem As UInteger) As Integer Implements IHttpSecurity.OnSecurityProblem       'ignore errors       'undocumented return code, does not work on IE6       Return S_OK     End Function   End Class End Class 

Regarding problem #2: It appears you may be confusing WebBrowser and DownloadFile(). As you've probably already discovered, the WebBrowser control doesn't download files. However, you can simulate the behavior using this technique:

Partial Public Class Form2   Inherits Form    Private Sub WebBrowser_Navigating(Sender As Object, e As WebBrowserNavigatingEventArgs) Handles WebBrowser.Navigating     Dim sFilePath As String     Dim oClient As Net.WebClient      ' This can be any conditional criteria you wish '     If (e.Url.Segments(e.Url.Segments.Length - 1).EndsWith(".pdf")) Then       SaveFileDialog.FileName = e.Url.Segments(e.Url.Segments.Length - 1)       e.Cancel = True        If SaveFileDialog.ShowDialog() = DialogResult.OK Then         sFilePath = SaveFileDialog.FileName         oClient = New Net.WebClient          AddHandler oClient.DownloadFileCompleted, New AsyncCompletedEventHandler(AddressOf DownloadFileCompleted)          oClient.DownloadFileAsync(e.Url, sFilePath)       End If     End If   End Sub      Private Sub DownloadFileCompleted(Sender As Object, e As AsyncCompletedEventArgs)     MessageBox.Show("File downloaded")   End Sub      Private WithEvents SaveFileDialog As New SaveFileDialog   Private WithEvents WebBrowser As New WebBrowser End Class 

In any event, the first step in solving this is to figure out whether it's your code or the private URL that's causing your issue.

Answers 2

The main thing needed here is to programatically download a file from a https url while using a username and password blocked by the security certificate issue

and the solution after searching for 2 weeks is

To Download a file you can disable the security cerificate request temporaraly with the following code then after the code ran it enables the security certicate again

First code you dont even need a browser it automatically saves the file to you desktop

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click         'check if a simular file doesnt exists so you can create a new file and deletes the file if it exists         If File.Exists("C:\pathtoyourfile\yourfilename.txt") Then             File.Delete("C:\pathtoyourfile\yourfilename.txt")         End If          'Type this before your download or hhtps request         'ByPass SSL Certificate Validation Checking         System.Net.ServicePointManager.ServerCertificateValidationCallback =   Function(se As Object,   cert As System.Security.Cryptography.X509Certificates.X509Certificate,   chain As System.Security.Cryptography.X509Certificates.X509Chain,   sslerror As System.Net.Security.SslPolicyErrors) True          'Call web application/web service with HTTPS URL here         '=========================================================================================         'ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications         Try             My.Computer.Network.DownloadFile("https://176.53.78.22/filenameonserveryouwanttodownload", "C:\pathtoyourfile\yourfilename.txt", "Yourusername", "yourpassword")             WebBrowser1.Refresh()         Catch ex As Exception             MessageBox.Show("message saying something didnt work")             'exit sub if it worked             Exit Sub         End Try         MessageBox.Show(" message saying it worked")         '=========================================================================================         'Restore SSL Certificate Validation Checking         System.Net.ServicePointManager.ServerCertificateValidationCallback = Nothing     End Sub 

then to browse to a webaddress the following code will popup and the security popup will popup but just select yes browsing on the webpage works normally

WebBrowser1.Navigate("https://username:password@180.29.74.70 ") 

Answers 3

As you said:

[...] I need the code to bypass any security questions like these.

In other word, you need to "automatically accept self signed SSL certificate", so in my opinion it is a duplicate question with : VB .net Accept Self-Signed SSL certificate, which may fit your needs.

and most especially slaks answer:

In VB.Net, you need to write:

ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications

Read More

Saturday, April 30, 2016

Obtain child anchor element within WebBrowser control

Leave a Comment

Preamble

I'm using the WebBrowser control, which a user will interact with, so a solution will need to work with a visible WebBrowser control.

Question

How do I check if an element has an anchor as a child? All browsers are able to distinguish that an element contains an anchor (<a href=""...), and offers "open in new tab" functionality. That is what I am attempting to replicate. However, when I right click on a HtmlElement I'm only able to obtain the parent element.

Example

Taking the BBC website as an example, when I right click on the highlighted element (picture below), my output is DIV, but viewing the source code there is an anchor element as a child of this div.

bbc homepage example

SSCCE

using System; using System.Diagnostics; using System.Windows.Forms;  namespace BrowserLinkClick {     public partial class Form1 : Form     {         private WebBrowser wb;         private bool firstLoad = true;          public Form1()         {             InitializeComponent();         }          private void Form1_Load(object sender, EventArgs e)         {             wb = new WebBrowser();             wb.Dock = DockStyle.Fill;             Controls.Add(wb);             wb.Navigate("http://bbc.co.uk");             wb.DocumentCompleted += wb_DocumentCompleted;         }          private void Document_MouseDown(object sender, HtmlElementEventArgs e)         {             if (e.MouseButtonsPressed == MouseButtons.Right)             {                 HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition));                 //I assume I need to check if this element has child elements that contain a TagName "A"                 if (element.TagName == "A")                     Debug.WriteLine("Get link location, open in new tab.");                 else                     Debug.WriteLine(element.TagName);             }         }           private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)         {             if (firstLoad)             {                 wb.Document.MouseDown += new HtmlElementEventHandler(Document_MouseDown);                 firstLoad = false;             }         }      } } 

Please test any proposed solution using the BBC website and the highlighted headline (the headline changes, but the DOM remains the same).

4 Answers

Answers 1

You have to get the child elements of element before checking if it's an anchor:

HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition)); foreach (HtmlElement child in element.Children) {     if (child.TagName == "A")         Debug.WriteLine("Get link location, open in new tab."); } 

Answers 2

To access the needed properties you need to cast the HtmlElement to one of the unmanaged MSHTML interfaces, e.g. IHTMLAnchorElement

You have to add Microsoft HTML Object Library COM reference to your project.
(The file name is mshtml.tlb.)

foreach (HtmlElement child in element.Children) {     if (String.Equals(child.TagName, "a", StringComparison.OrdinalIgnoreCase))     {         var anchorElement = (mshtml.IHTMLAnchorElement)child.DomElement;         Console.WriteLine("href: [{0}]", anchorElement.href);     } } 

There are plenty of such interfaces but MSDN will help you choose. :)

Scripting Object Interfaces (MSHTML)

Answers 3

I propose you the following solution:
url variable will have url of your desired output, you'll be able to see it in debugger window.

private void Document_MouseDown(object sender, HtmlElementEventArgs e) {         if (e.MouseButtonsPressed == MouseButtons.Right)         {             HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition));             //I assume I need to check if this element has child elements that contain a TagName "A"             if (element.TagName == "A")             {                 Debug.WriteLine("Get link location, open in new tab.");                 var urlRaw = element.OuterHtml;                 string hrefBegin = "href=";                 var idxHref = urlRaw.IndexOf(hrefBegin) + hrefBegin.Length + 1;                 var idxEnd = urlRaw.IndexOf("\"", idxHref + 1);                 var url = urlRaw.Substring(idxHref, idxEnd - idxHref);                 Debug.WriteLine(url);             }              else                 Debug.WriteLine(element.TagName);         }     } 

Answers 4

There has to be something else wrong with your program. On the BBC website your code works for the news articles (although I see the non UK version of the site). On other websites where there are anchor elements as children the code below works

 private void Document_MouseDown(object sender, HtmlElementEventArgs e)     {         if (e.MouseButtonsPressed == MouseButtons.Right)         {             HtmlElement element = wb.Document.GetElementFromPoint(PointToClient(MousePosition));             if (element.Children.Count > 0)             {                 foreach (HtmlElement child in element.Children)                 {                     if (child.TagName == "A")                         Debug.WriteLine("Get link location, open in new tab.");                 }             }             else             {                 //I assume I need to check if this element has child elements that contain a TagName "A"                 if (element.TagName == "A")                     Debug.WriteLine("Get link location, open in new tab.");                 else                     Debug.WriteLine(element.TagName);             }         }     } 
Read More