1

My application auto fill almost 30 fields and leave only few for user and captcha to fill.

I need to get and display captcha from url.

I tried different way but none works as I need.

url is captcha link

with chrome you will get image directly, with IE you'll get a file to download.

First Attempt

Open url with WebBrowser control if you try to open url with WebBrowser you will get start with file download if you save it like cap.gif or JPG you'll get correct image.

at this point im trying to automated downloading task to avoid show a download dialog for users.

Like other SO answer Download file and automatically save it to folder i try to handle WebBrowser navigation

private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
    e.Cancel = true;
    WebClient client = new WebClient();

    client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
    client.DownloadDataAsync(e.Url);
}

or directly with WebClient

WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadFileAsync(new Uri(url), filepath);

on result's callback you will get image file empty (0 byte);

if you look at AsyncCompletedEventArgs e, it generate error regards to SSL/TSL.

The request was aborted: Could not create SSL/TLS secure channel.   
in System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
in System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
in System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)

Second Attempt

Include SSL/TSL stack to WebClient as SO answer The request was aborted: Could not create SSL/TLS secure channel

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AllwaysGoodCertificate);
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadFileAsync(new Uri(captchaUrl), filepath);

this will return same error on callback

Third Attempt Get image from WebBrowser control and convert tag to PictureBox

If I try to extract image on the main page content form, it allow me to get image follow SO answer How to copy the loaded image in webbrowser to picturebox

[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);

public Bitmap CaptureWindow(Control ctl)
{
    //Bitmap bmp = new Bitmap(ctl.Width, ctl.Height);  // includes borders
    Bitmap bmp = new Bitmap(ctl.ClientRectangle.Width, ctl.ClientRectangle.Height);  // content only
    using (Graphics graphics = Graphics.FromImage(bmp))
    {
        IntPtr hDC = graphics.GetHdc();
        try { PrintWindow(ctl.Handle, hDC, (uint)0); }
        finally { graphics.ReleaseHdc(hDC); }
    }
    return bmp;
}

//Methods to get Co-ordinates Of an Element in your webbrowser
public int getXoffset(HtmlElement el)
{
    int xPos = el.OffsetRectangle.Left;
    HtmlElement tempEl = el.OffsetParent;
    while (tempEl != null)
    {
        xPos += tempEl.OffsetRectangle.Left;
        tempEl = tempEl.OffsetParent;
    }
    return xPos;
}

public int getYoffset(HtmlElement el)
{
    int yPos = el.OffsetRectangle.Top;
    HtmlElement tempEl = el.OffsetParent;
    while (tempEl != null)
    {
        yPos += tempEl.OffsetRectangle.Top;
        tempEl = tempEl.OffsetParent;
    }
    return yPos;
}

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    // get captcha
    HtmlElement el = webBrowser1.Document.GetElementById("imgCaptcha");
    IHTMLImgElement img = (IHTMLImgElement)el.DomElement;
    Bitmap bmp = new Bitmap(img.width, img.height);

    int CaptchaWidth = getXoffset(el);
    int CaptchaHeight = getYoffset(el);
    Rectangle rect = new Rectangle(CaptchaWidth, CaptchaHeight, img.width, img.height);

    // with this image il always blank
    //webBrowser1.DrawToBitmap(bmp, rect);

    Bitmap bitmap = CaptureWindow(webBrowser1);
    Bitmap croppedImage = bitmap.Clone(rect, System.Drawing.Imaging.PixelFormat.Undefined);
    pictureBox1.BackgroundImage = croppedImage;
}

This work fine, but unfortunatelly this only works if you have WebBrowser control visible... :(

Any suggestion will be appreciate.

Community
  • 1
  • 1
Marco Luongo
  • 397
  • 4
  • 13

2 Answers2

1

After some work around I found one issue on SSL, server process protocol TSL 1.2 instead SSL3

just replace

//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

and now WebClient work well, but before give to myself a right answer, I wait if some one else have other implementation.

Marco Luongo
  • 397
  • 4
  • 13
1

The change I would make would be to use async/await so I wouldn't have to worry about setting the DownloadFileCompleted of WebClient

This part like you did,

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

use a async method

public async Task DownloadIt(string url ,string filename)
{
     using (var client = new WebClient())
     {
         await client.DownloadFileTaskAsync(new Uri(url), filename);
     }
}

call it like this whenever you need it.

await DownloadIt("https://www.com", @"C:\Path\To\Save");
Coolio
  • 169
  • 6