captcha image from WebBrowser Control into a picturebox - c#

I need to be able to place the captcha image into a picturebox on my form, the reason being that I need to zoom the captcha image for the visualy impaired users.
It appears to be such a simple task, just take the image from the web page and put it into a picturebox but it is turning out to be not so simple.
i have WebBrowser control in form and for registration in one of site, i need captcha image in picture box. problem is that captcha image is generated by JavaScript, when java script runs then it gives url of captcha image. but every time when java script runs, captcha image goes change. i just want that captcha image which is on WebBrowser control current page.
Any help would be greatly appreciated.
here is my code.
public void FacebookRegistration()
{
HTMLDoc = (mshtml.HTMLDocument)WBrowser.Document.DomDocument;
iHTMLCol = HTMLDoc.getElementsByTagName("input");
foreach (IHTMLElement iHTMLEle in iHTMLCol)
{
if (iHTMLEle.getAttribute("name", 0) != null)
{
strAttriName = iHTMLEle.getAttribute("name", 0).ToString();
if (strAttriName == "firstname")
{
iHTMLEle.setAttribute("value", FirstName, 0);
continue;
}
if (strAttriName == "lastname")
{
iHTMLEle.setAttribute("value", LastName, 0);
continue;
}
if (strAttriName == "reg_email__")
{
iHTMLEle.setAttribute("value", EmailID, 0);
continue;
}
if (strAttriName == "reg_passwd__")
{
string s = GetRandomString();
Random ran = new Random();
iHTMLEle.setAttribute("value", s+ran.Next(1111,9999), 0);
break;
}
}
}
iHTMLCol = HTMLDoc.getElementsByTagName("option");
foreach (IHTMLElement iHTMLEle in iHTMLCol)
{
try
{
if (iHTMLEle.innerText.Contains("Male"))
{
iHTMLEle.setAttribute("selected", "selected",0);
}
if (iHTMLEle.innerText.Contains("Jun"))
{
iHTMLEle.setAttribute("selected", "selected", 0);
}
Random ran = new Random();
if (iHTMLEle.innerText.Contains("4"))
{
iHTMLEle.setAttribute("selected", "selected", 0);
}
Random ran1 = new Random();
if (iHTMLEle.innerText.Contains(ran1.Next(1920,1985).ToString()))
{
iHTMLEle.setAttribute("selected", "selected", 0);
}
}
catch { }
}
iHTMLCol = HTMLDoc.getElementsByTagName("input");
int i = 0;
foreach (IHTMLElement iHTMLEle in iHTMLCol)
{
string s = iHTMLEle.className;
if (iHTMLEle.className == "UIButton_Text" && iHTMLEle.getAttribute("value", 0).ToString() == "Sign Up")
{
if (i != 0)
{
iHTMLEle.click();
break;
}
i++;
}
}
private void WBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (CurrentSocial == "facebook")
{
FacebookRegistration();
}
}
}
in the registration page of facebook.com, there is captcha and if you go to page source then you will see only this:
<input type="hidden" id="captcha_persist_data" name="captcha_persist_data" value="AAAAAQAQiCw5zhFGOsVF6TbDBX8d_wAAAGvqENqFy5KkvMip5AIv3QSF7BS7goiHfAC7fTkzr8hW61cq3s1d23Tw7m-WAi-21Uzt1l3frkLf4obBEuZZMwga_hbcUhnWXu4P382QsJ7J0WtAbo5USXWuVjzv_KD1SMyTWhf34AGorQd27dFqZc0a" /?;
and in this input tag, i found url of that javascript which gives captcha url
javascript url: http://api.recaptcha.net/challenge?k=6LezHAAAAAAAADqVjseQ3ctG3ocfQs2Elo1FTa_a&ajax=1&xcachestop=0.31520985781374&authp=nonce.tt.time.new_audio_default&psig=H48rD9d3_QogBfxxKAmzFZ7CG10&nonce=hl77BQn58EsYsPpPwQ2TIA&tt=r3zaWETv27-0igoIw5ndwnHt_W4&time=1256413208&new_audio_default=1
if you browse this url you will get captcha url like this:
var RecaptchaState = {
challenge : '02UflxsCli4nYg-oG48n5bNDm6ywMlvE62UwXQssF__eJAfSiv2TXuac-1tbu2FThwakgH65IdExWDy9qyr1sYbRuwyQFZD7Dk1eE_fXuoSn9tliqnYeMq__LEF6-GTEm0H6TChOtvpwL2G3C1BsBriw8FFaKqkaTwbNoJeAfzI_j9qYnPaqtHJYillevhRsxyaQVYfLvqai7p0Sfu3849BFpamlbfE3to3KTXi5cZ0xlmuGkMkuZhvq_GyK_z-ZXq9z_Ls8xZlywN0jlIOsSEvI9QJq_69X-X3Moq9lFBcmqWYaKbf7faRQt19aJGB4DdBC1PqQIC',
timeout : 25000,
server : 'http://api.recaptcha.net/',
site : '6LezHAAAAAAAADqVjseQ3ctG3ocfQs2Elo1FTa_a',
error_message : '',
programming_error : '',
is_incorrect : false
};
Recaptcha.challenge_callback();
and original captcha url look like this:
http://api.recaptcha.net/image?c=027CxC4LbBbzVJKy-1xX_wRBf7Gmi4AvgikDVaKeYjBCmiX4XBzGymWC7XRfWx4LLQgfscKnfeB7U305MhlVN0X4vAkrK84ac3jybRJ3UJPUQ8rnlJOS7lqNqpRpolYSd6WBxMShhrzqbx-5ScL0JAsN7cJRMLMqeQsPHg1QB7g4kp4KxKO1aEONsUibahnCC8baLHGSIYJ5Q1Gcr1MPvJ9i_a5qQCilT1tWXwAKE_fkVGi31_un3OxHbNm9UmMemRp7IZ9C9ZLU4IjMApxVJOWXMYqjt588z_ZVcYG2dtY6Dh0b4R1aAQcp0UXFTggdWtsjPw7wIC
then you will get captcha, but is is not what i want , because javascript everytime changes the capthca image. so i dont get captcha which is currently being shown in webbrowser

You can copy the image to the clipboard and read from there. Alternatively you can parse the page to get the image's URL and see if you can dig the image file out of the cache
How To Programmatically Copy an IMG Element to the Clipboard

Would it be possible to use reCaptcha.net instead? You register for free, add the script to your page and then they do the rest. They may not have zooming for the visually impaired, but they do have text-to-speech. No sense in reinventing the wheel if you don't have to. Of course you'd need access to the internet on your page so this could be a problem if your site is an intranet or private network of some sort. Hope that helps.

Related

How can I loop clicking on a button

I'm using GeckoFX and a regex in C# to make a YouTube video channel scraper. I want to get the URL of all videos from a selected channel.
I want to use GeckoFX (the Firefox rendering engine) to go to the videos section and click the Load more button until every video shows.
I am using this code to click Load more over and over:
javascript:(function() {
var LoadButton, IntervalCLB;
IntervalCLB = setInterval(_clickLoadButton, 100);
function _clickLoadButton() {
LoadButton = document.getElementsByClassName('load-more-button');
if (LoadButton.length > 0) {
LoadButton[0].click();
}
else {
clearInterval(IntervalCLB);
alert('Finished - Clicked all "Load More" Buttons.');
}
}
})();
I want to write something like that in C#.
My code looks like:
System.Threading.Thread.Sleep(1000);
GeckoDocument document = geckoWebBrowser1.Document;
GeckoHtmlElement Male = (GeckoHtmlElement)document.GetElementsByClassName("load-more-button")[0];
if ( Male != null ) {
Male.Click();
}
But that just clicks Load more once after one second.
How can I make it loop until the Load more button disappears?
Timer timer = new Timer(1000);
timer.Elapsed += ( sender, e ) => {
GeckoDocument document = geckoWebBrowser1.Document;
GeckoHtmlElement Male = (GeckoHtmlElement)document.GetElementsByClassName("load-more-button")[0];
if ( Male != null ) {
Male.Click();
}
};
timer.Start();
But from practical side I recommend you to look into YouTube API: https://developers.google.com/youtube/v3/code_samples/dotnet

Capture Video of an HTMLelement with webcontrol not showing on screen c#

I am trying to white an application that gets a url and find out all html5 canvas advertisement (i found out that iframes is the best HTMLElement that I can get) and take a video screenshot of the element.
I have to render the page (because it uses javascript calls to create the final page) using an in memory webbrowser control and then I find all iframes from document of the Webbrowser control (objDoc in the sample).
var aColl = from HtmlElement p in objDoc.Body.All
where Configuration.lstCanvas.Contains(p.TagName.ToUpper())
select p;
For each element I have to capture a screenshot and a video of the content of the iframe or even an html file that can represent the video later.
In order to capture the image I use the following code (if i pass null to HTMLelement I get a full screen capture) as an extended metod of the webbrowser control.
public static Image GetElementImage(this WebBrowser web, HtmlElement elm = null)
{
try
{
IHTMLDocument2 idoc2 = web.Document.DomDocument as IHTMLDocument2;
if (idoc2 == null)
{
return null;
}
IHTMLElementCollection elementCollection = idoc2.all;
if (elementCollection == null)
{
return null;
}
IHTMLElementRender iHTMLElementRender;
if (elm != null)
{
iHTMLElementRender = (IHTMLElementRender)elm.DomElement;
if (iHTMLElementRender == null)
{
return null;
}
}
else {
iHTMLElementRender = idoc2.body as IHTMLElementRender;
if (iHTMLElementRender == null)
{
return null;
}
}
// get the location and size of the element and create a bitmap
// need a different interface
IHTMLElement element = iHTMLElementRender as IHTMLElement;
if (element == null)
{
return null;
}
int elementWidth = element.offsetWidth;
int elementHeight = element.offsetHeight;
// Create a bitmap and render the element to it.
Bitmap memoryBitmap = new Bitmap(elementWidth, elementHeight, PixelFormat.Format24bppRgb);
Graphics memGraphics = Graphics.FromImage(memoryBitmap);
IntPtr memDC = memGraphics.GetHdc();
iHTMLElementRender.DrawToDC(memDC);
memGraphics.ReleaseHdc(memDC);
Image r = (Image)memoryBitmap.Clone();
memGraphics.Dispose();
memoryBitmap.Dispose();
return r;
}
catch // (Exception ex)
{
return null;
}
}
I haven't found a way to take a video capture of the element.
I try to grab the content of the iframe as html (in order to save it and use it for latter) but I come out with some issues:
The url is not always an attribute of the iframe (it changes from the javascript)
Cross Domain scripting is not letting me to gram the html
The file that I download is not allways reproduces the content of the iframe
Do you have any suggestion either on getting the html code or the video?
Thanks in advance

How do I find out which button triggered the postback?

In asp.net (c#) how can I find out which asp:button triggered the postback?
I am using it for dynamic controls and want to do a different process on pageload for different buttons. I have tried looking at __EVENTARGUMENTS etc. but they didnt work.
I am looking to do something like this:
Page_load
Case:
Button 1 clicked
//Do something
Button 2 clicked
//Do something
Use the below code.
public static string GetPostBackControlId(this Page page)
{
if (!page.IsPostBack)
return string.Empty;
Control control = null;
// first we will check the "__EVENTTARGET" because if post back made by the controls
// which used "_doPostBack" function also available in Request.Form collection.
string controlName = page.Request.Params["__EVENTTARGET"];
if (!String.IsNullOrEmpty(controlName))
{
control = page.FindControl(controlName);
}
else
{
// if __EVENTTARGET is null, the control is a button type and we need to
// iterate over the form collection to find it
// ReSharper disable TooWideLocalVariableScope
string controlId;
Control foundControl;
// ReSharper restore TooWideLocalVariableScope
foreach (string ctl in page.Request.Form)
{
// handle ImageButton they having an additional "quasi-property"
// in their Id which identifies mouse x and y coordinates
if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
{
controlId = ctl.Substring(0, ctl.Length - 2);
foundControl = page.FindControl(controlId);
}
else
{
foundControl = page.FindControl(ctl);
}
if (!(foundControl is Button || foundControl is ImageButton)) continue;
control = foundControl;
break;
}
}
return control == null ? String.Empty : control.ID;
}
Calling this function:
I have included the above function in a static class UtilityClass.
String postBackControlId = UtilityClass.GetPostBackControlId(this);
The code has been referenced from Mahesh's Blog.

Sitecore Rich Text editor customisation of link Insertions

When a user uses the "Insert Link" feature on the RTE to create stories, we get something like...<Item-Name-Of-Story
Instead of taking the Item name I would like to use another field called "Headline"
Does anyone know how to do this?...
Headline-Of-Story
Any help will be much appreciated. Thanks
First of all, you need need to look at this class with Reflector or DotPeek : Sitecore.Shell.Controls.RichTextEditor.InsertLink.InsertLinkForm and to modify it with your own class.
You need to modify just this method,I tested and works fine :
protected override void OnOK(object sender, EventArgs args)
{
Assert.ArgumentNotNull(sender, "sender");
Assert.ArgumentNotNull((object) args, "args");
string displayName;
string text;
if (this.Tabs.Active == 0 || this.Tabs.Active == 2)
{
Item selectionItem = this.InternalLinkTreeview.GetSelectionItem();
if (selectionItem == null)
{
SheerResponse.Alert("Select an item.", new string[0]);
return;
}
else
{
displayName = selectionItem["Headline"];
if (selectionItem.Paths.IsMediaItem)
text = CustomInsertLinkForm.GetMediaUrl(selectionItem);
else if (!selectionItem.Paths.IsContentItem)
{
SheerResponse.Alert("Select either a content item or a media item.", new string[0]);
return;
}
else
{
LinkUrlOptions options = new LinkUrlOptions();
text = LinkManager.GetDynamicUrl(selectionItem, options);
}
}
}
else
{
MediaItem mediaItem = (MediaItem) this.MediaTreeview.GetSelectionItem();
if (mediaItem == null)
{
SheerResponse.Alert("Select a media item.", new string[0]);
return;
}
else
{
displayName = mediaItem.DisplayName;
text = CustomInsertLinkForm.GetMediaUrl((Item) mediaItem);
}
}
if (this.Mode == "webedit")
{
SheerResponse.SetDialogValue(StringUtil.EscapeJavascriptString(text));
base.OnOK(sender, args);
}
else
SheerResponse.Eval("scClose(" + StringUtil.EscapeJavascriptString(text) + "," + StringUtil.EscapeJavascriptString(displayName) + ")");
}
After you modify this class you need to modify next file:
\sitecore\shell\Controls\Rich Text Editor\InsertLink\InsertLink.xml where you need to change codeBeside section
<CodeBeside Type="Sitecore.Shell.Controls.RichTextEditor.InsertLink.InsertLinkForm,Sitecore.Client"/>
with something like :
<CodeBeside Type="YourNameSpace.YourInsertLinkForm,YourAssembly"/>
The simplest way around this would be to type the desired link text, then select this before clicking 'insert link' - this way your hyperlink will have the text of whatever you entered, instead of defaulting to the item name.
If you want to modify how Sitecore renders links in RTE fields, you would need to modify the <renderField> pipeline - if you search for this in the web.config, you will see the different classes involved here. Using dotPeek you can decompile the Sitecore source to see how this works. Potentially you could then create your own renderField pipeline handler to change the link rendering behaviour and then reference this new class in your web.config.

How can I disallow WebView to open links on the browser in WinRT( target=_blank links )?

I have a WebView on my app and I can't change the html file("target=_blank" link types). But some links on the page makes my app open them on the system browser. How can I disallow this action?
Thanks.
In the NavigationCompleted event handler run this script:
webView.InvokeScriptAsync("eval", new[]
{
#"(function()
{
var hyperlinks = document.getElementsByTagName('a');
for(var i = 0; i < hyperlinks.length; i++)
{
if(hyperlinks[i].getAttribute('target') != null)
{
hyperlinks[i].setAttribute('target', '_self');
}
}
})()"
});
On Windows 10, you can use WebView.NewWindowRequested:
private void WebView1_NewWindowRequested(
WebView sender,
WebViewNewWindowRequestedEventArgs args)
{
Debug.WriteLine(args.Uri);
args.Handled = true; // Prevent the browser from being launched.
}
There is a navigation starting event. It have a cancel property that can be used to cancel the navigation. Maybe this will work for you?
http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.webview.navigationstarting
Stumbled on this myself recently, and I want to add that even though user2269867's answer is a viable solution, it might not work in certain situations.
For example, system browser will not only open if user click a link with target="_blank" attribute, but also if window.open() function called in javascript. Moreover, even removing all 'target' attributes won't work if a page loading some content dynamically and changing DOM after your script is already finished executing.
To solve all problems above, you need to override window.open function and also check for 'target' attribute not once, but every time user click something. Here is script that covers those cases:
function selfOrParentHasAttribute(e, attributeName) {
var el = e.srcElement || e.target;
if (el.hasAttribute(attributeName)) {
return el;
}
else {
while (el = el.parentNode) {
if (el.hasAttribute(attributeName)) {
return el;
}
}
}
return false;
}
var targetAttributeName = "target";
document.addEventListener("click", function (e) {
var el = selfOrParentHasAttribute(e, targetAttributeName);
if (el) {
if ((el.getAttribute(targetAttributeName) == "_blank") ||
(el.getAttribute(targetAttributeName) == "_new"))
{
el.removeAttribute(targetAttributeName);
}
}
});
window.open = function () {
return function (url) {
window.location.href = url;
};
}(window.open);
My js skills aren't ideal, so feel free to modify.
Also don't forget that, as kiewic mentioned, for Windows 10 there is WebView.NewWindowRequested event which solves this issue more natural.
If you just want to show the page and not allow any action to be done on that page I would look into WebViewBrush. The WebViewBrush will basically screenshot the website and the users will not be able to use any links or anything else on that page, it will turn into a read-only page. I believe this is what you are asking for.
More info on WebViewBrush can be found here: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.webviewbrush
If you can edit HTML of the page and NavigateToString(), then add <base target='_blank'/> in the <head>

Categories

Resources