I am using the WebBrowser control.
This works fine most of the time however wehn navigating to a new page or waiting for a new page to load can sometimes hangs.
Is there a way to catch this? i.e. if the page is failing to navigate or load after a certain amount of time then kill the process?
I am using the - webBrowser1_DocumentCompleted event to pick up ertain behaviours when the page loads/navigates as expected however not sure how to catch if a page is hanging??
Maby you should try to implement some kind of timeout logic? There are quite many samples in web about this. F.e. this one
Also you might be interested in this event of WebBrowserControl ProgressChanged
This is due to that webbrowser component is very basic model of internet explorer, and it get stuck at ajax pages. You can fix this problem explicitly to use latest version of internet explorer... Using this code...
try
{
string installkey = #"SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION";
string entryLabel = "YourExe.exe";
string develop = "YourExe.vshost.exe";//This is for Visual Studio Debugging...
System.OperatingSystem osInfo = System.Environment.OSVersion;
string version = osInfo.Version.Major.ToString() + '.' + osInfo.Version.Minor.ToString();
uint editFlag = (uint)((version == "6.2") ? 0x2710 : 0x2328); // 6.2 = Windows 8 and therefore IE10
Microsoft.Win32.RegistryKey existingSubKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(installkey, false); // readonly key
if (existingSubKey.GetValue(entryLabel) == null)
{
existingSubKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(installkey, true); // writable key
existingSubKey.SetValue(entryLabel, unchecked((int)editFlag), Microsoft.Win32.RegistryValueKind.DWord);
}
if (existingSubKey.GetValue(develop) == null)
{
existingSubKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(installkey, true); // writable key
existingSubKey.SetValue(develop, unchecked((int)editFlag), Microsoft.Win32.RegistryValueKind.DWord);
}
}
catch
{
MessageBox.Show("You Don't Have Admin Previlege to Overwrite System Settings");
}
}
Right Click Both your Exe. And vshost.exe and Run as Administrator To Update Registry for this Application....
Related
I'm using AutoUpdater.NET for updating my applications. It's a great library. My program collects data for inventory system-data, sent it to database and than close the application.
this.Close();
The problem is, that the program also close, if an update is available. I want, that the application stay open, until the user update or cancel. I know that I have to check, if update is available or update-form is open, but I don't know how. Could someone please help? (Sorry, I'm beginner)
AutoUpdater.Start(updatePath);
AutoUpdater.ShowSkipButton = false;
AutoUpdater.ShowRemindLaterButton = false;
AutoUpdater.Mandatory = true;
//AutoUpdater.UpdateMode = Mode.Forced;
AutoUpdater.RunUpdateAsAdmin = false;
var currentDirectory = new DirectoryInfo(Environment.CurrentDirectory);
if (currentDirectory.Parent != null)
{
AutoUpdater.InstallationPath = currentDirectory.FullName;
}
The solution (in my case) was to replace Environment.CurrentDirectory with Application.StartupPath
I don't want to use SetForegroundWindow(), sending keyboard keys or similar techniques, because that can cause issues (unexpected behaviour) in my software.
I have tried to find the title using Cheat Engine program (but haven't found anything useful as Google Chrome seems to work "upside-down").
So I went step ahead, using Process Hacker program I have realized that there is a parent (chrome.exe) process with a valid window handle to the current active tab and all other chrome processes are children of it a.k.a. background processes (with invalid window handle).
By browsing deeper into windows of chrome.exe (parent process), I have found the class name of the window handle being "Chrome_WidgetWin_1" and current active tab's title/text.
Here's a picture of Google Chrome's Task Manager.
I'm looking for a function in C# or C or C++ that will take an integer (process ID) and return a string (tab title/text).
static string GetChromeTabTitle(uint processId)
{
// Assuming I call this function with valid process identifier (PID).
// What do I do next, here??
}
The best way I have found is by using the System.Windows.Automation library. It allows interacting with an application (primarily for accessibility purposes), but you can use it for other purposes like getting Chrome tabs.
Note that this will only work when the Chrome windows is not minimized.
The process is not exactly simple, if you want you can look how I did it in my own project, though it's not something you can just copy it paste, you'll find what you need in the ChromeTabsFinder: https://github.com/christianrondeau/GoToWindow/blob/master/GoToWindow.Plugins.ExpandBrowsersTabs/Chrome/ChromeTabsFinder.cs
Here's the code (you'll need the automation librairies):
public IEnumerable<ITab> GetTabsOfWindow(IntPtr hWnd)
{
var cacheRequest = new CacheRequest();
cacheRequest.Add(AutomationElement.NameProperty);
cacheRequest.Add(AutomationElement.LocalizedControlTypeProperty);
cacheRequest.Add(SelectionItemPattern.Pattern);
cacheRequest.Add(SelectionItemPattern.SelectionContainerProperty);
cacheRequest.TreeScope = TreeScope.Element;
AutomationElement tabBarElement;
using (cacheRequest.Activate())
{
var chromeWindow = AutomationElement.FromHandle(hWnd);
var mainElement = chromeWindow.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
if (mainElement == null)
yield break;
tabBarElement = mainElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "tab"));
}
if(tabBarElement == null)
yield break;
var tabElements = tabBarElement.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "tab item"));
for (var tabIndex = 0; tabIndex < tabElements.Count; tabIndex++)
{
yield return "Tab: " + tabElements[tabIndex].Current.Name + ", Index: " + tabIndex + 1;
}
}
I have a site where I'm trying to deliver files via WriteFile and they work fine in Chrome and Firefox, but in IE I have to hit "Retry" once or twice to actually make the file download.
Here is the code:
public class DownloadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var r = context.Response;
r.Clear();
r.ClearContent();
r.ContentType = "application/octet-stream";
string path = "";
try
{
if (HttpContext.Current.Request.QueryString["n"] != null)
{
var file = HttpContext.Current.Request.QueryString["n"].ToString();
var type = HttpContext.Current.Request.QueryString["t"].ToString();
r.AddHeader("Content-Disposition", "attachment; filename=" + file.Substring(file.IndexOf('_')+1));
string folder = "";
switch (type.ToLower())
{
case "public":
folder = ConfigurationManager.AppSettings["BCD_PublicDocsLoc"];
break;
case "private":
folder = ConfigurationManager.AppSettings["BCD_PrivateDocsLoc"];
break;
case "internal":
folder = ConfigurationManager.AppSettings["BCD_InternalDocsLoc"];
break;
}
path = folder + "/" + file;
r.WriteFile(path);
r.Flush();
r.Close();
r.End();
}
}
catch (Exception ex)
{
r.Flush();
r.Close();
r.End();
context.Response.Redirect("Error.aspx?err=301");
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
If anyone has any advice as to why this is happening, it would be greatly appreciated. Thanks!
Try substituting the HttpResponse's Close() and End() calls with HttpApplication.CompleteRequest().
Read here why, there are examples too.
Also, this solution was suggested here(in the first answer) for a situation similar to yours.
As was hinted that a small explanation in this post would be convenient, due to the possibility of the links going dead in the future, here it goes:
In short: IE seems to have problems with the HttpResponse.Close and HttpResponse.End methods. Aside of that, anyways, Microsoft recommends in most cases the use of HttpApplication.CompleteRequest over the former two, because:
-HttpResponse.Close() terminates the connection abruptly, dropping buffered data and is not intended for normal HTTP use in which a response to the client is desired
-HttpResponse.End() exists for compatibility reasons with the older ASP technology. It calls the EndRequest event directly and no further code after the End call is executed which is inconvenient in many cases
-HttpApplication.CompleteRequest(): also executes the EndRequest event and it does allow the execution of the code that following the CompleteRequest call, which makes it more appropriate to handle most situations.
Just a hunch but it sounds like an I.E. caching issue to me...
if I.E is set to automatically check for newer pages 'every time i go to the website.' (in [tools\internet options\general\ browsing history\settings]) then you wont have a cache issue.
Like I say, only a hunch, but give it a whirl.
If you want to get around this [*1], add a guid to your Query string.[*2]
[*1] The cache setting is a user by user setting, you can never pre-empt the users settings, so work with them instead
[*2] The nocache value is always different, the browser will never have a cached version to go to.
I use something like this...
protected void Page_PreRender(object sender, EventArgs e)
{
if (HttpContext.Current.Request.QueryString["FirstRun"] == "1")
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.Url.Query);
nvc.Remove("FirstRun");
string url = Request.Url.AbsolutePath;
for (int i = 0; i < nvc.Count; i++)
url += string.Format("{0}{1}={2}", (i == 0 ? "?" : "&"), nvc.Keys[i], nvc[i]);
Response.Redirect(string.Format("{1}&NoCache={0}",System.Guid.NewGuid().ToString().Replace("-",""),url));
}
}
Any links/redirects to this page need ?FirstRun=1 (or &FirstRun=1) appended to the querystring. The page reload cycles itself once adding a &noCache value to the querystring.
Note:
Because you added FirstRun=1, it will always execute twice serverside, but appear like a single load to your user, and the browser.
If you don't add FirstRun=1, it will behave like a normal request as it never gets into the condition.
When IE opens a second browser window using onclick.window.open() I need to do some processing on the second window and then close the window.
I have tried the following recomendations found on stackoverflow regarding window handles:
string popupHandle = string.Empty;
ReadOnlyCollection<string> windowHandles = selObj.Driver.WindowHandles;
foreach (string handle in windowHandles)
{
if (handle != originalHandle)
{
popupHandle = handle;
break;
}
}
selObj.Driver.SwitchTo().Window((popupHandle));
selObj.Driver.Close();
selObj.Driver.SwitchTo().Window(originalHandle);
Before I execute this code I attempt to click on a control of the new window to change focus.
Webdriver cannot locate the control (I also tried to use the WebDriverWait class to wait for the second browse to fully load.
WebDriverWait also throws an exception after the wait seconds.
Upon attempting to execute the:
selObj.Driver.SwitchTo().Window((popupHandle));
I receive the following exception:
No response from server for url http://
I know this is C# and IE, wondering if anyone has found a work around for this?
Thanks
My trio C#+WebDriver+Ie works fine.
Yes - IE has to be focused.
Please, Try my code. Code works with IE, Chrome and Firefox
protected void SwitchToWindow(string name)
{
foreach (string item in _driver.WindowHandles)
{
if (_driver.SwitchTo().Window(item).Title.Contains(name))
{
_driver.SwitchTo().Window(item);
break;
}
}
}
Where _driver is selObj.Driver for your case.
A little bit late but can be effective :
var ieOptions = new InternetExplorerOptions
{
IntroduceInstabilityByIgnoringProtectedModeSettings = true
};
ieOptions.ForceCreateProcessApi = true;
ieOptions.BrowserCommandLineArguments = "-private";
driver = new InternetExplorerDriver(IE_DRIVER_PATH, ieOptions);
You have to set ForceCreateProcessApi at true. It's only with IE that you have to set this kind of options.
And if the program threw an other error like :
"This issue occurs when the following registry entry is set to 0:
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\TabProcGrowth"
You will have to create a key in register (using regedit) and set this key
to 0 (Type: REG_DWORD and Value Type: Decimal).
I need to use the WinForms WebBrowser control in an ASP.NET application in order to take screenshots of webpages.
I'd much rather run it in a console app, and communicate to the app via the ASP.NET application, but it's not my call, I've been told it has to run as part of the website.
It all pretty much works apart from every call to navigate starts fresh with a new session, it's like the cookies aren't being persisted. As an experiment, I changed my IIS application pool to run as me rather than NETWORK_SERVICE, and it all works fine. So it's something strange about it running as network service.
I'm guessing that the network service account doesn't have the permissions to keep track of the ASP.NET_SessionId cookie and the auth cookie, but both these are non-persistent cookies, so I don't know why that would be.
Here is some simplified code so you can get the gist of what I'm doing. There is a bunch of logging and storing of images that I cut out, so it's not complete code. Basically a developer/tester/admin can run this code once (task kicked off via webpage), it will generate bitmaps of every page in the system, they can release a new version of the website and then run it again, it will tell you the differences (new pages, pages removed, pages changed).
public void Run()
{
var t = new Thread(RunThread);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private void RunThread()
{
try
{
using (var browser = new WebBrowser())
{
browser.DocumentCompleted += BrowserDocumentCompleted;
if (!VisitPage(browser, "special page that sets some session flags for testing - makes content predictable")))
throw new TestRunException("Unable to disable randomness");
foreach (var page in pages)
{
VisitPage(browser, page);
}
}
}
// An unhandled exception in a background thread in ASP.NET causes the app to be recycled, so catch everything here
catch (Exception)
{
Status = TestStatus.Aborted;
}
}
private bool VisitPage(WebBrowser browser, string page)
{
finishedEvent.Reset();
var timeout = false;
stopwatch = new Stopwatch();
browser.Navigate(page);
stopwatch.Start();
while (!timeout && !finishedEvent.WaitOne(0))
{
Application.DoEvents();
if (stopwatch.ElapsedMilliseconds > 10000)
timeout = true;
}
Application.DoEvents();
if (timeout)
{
if (resource != null)
ShopData.Shop.LogPageCrawlTestLine(testRunID, resource, sequence++, (int)stopwatch.ElapsedMilliseconds, null);
}
browser.Stop();
return !timeout;
}
private void BrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
try
{
var browser = (WebBrowser)sender;
var width = browser.Document.Body.ScrollRectangle.Width;
var height = browser.Document.Body.ScrollRectangle.Height;
var timeTaken = (int)stopwatch.ElapsedMilliseconds;
if ((width == 0) || (height == 0))
{
return;
}
browser.Width = width;
browser.Height = height;
byte[] buffer;
using (var bitmap = new Bitmap(width, height))
using (var memoryStream = new MemoryStream())
{
browser.DrawToBitmap(bitmap, new Rectangle(0, 0, width, height));
bitmap.Save(memoryStream, ImageFormat.Bmp);
buffer = memoryStream.ToArray();
}
// stores image
}
finally
{
finishedEvent.Set();
}
}
So in summary:
The above code is started by a ASP.NET page and it runs in the backgound
It works fine if I run it in an IIS application pool set to run as a proper user
If I run it in an IIS application pool as NETWORK_SERVICE then every navigate has a new session, rather than persisting a session for the lifetime of the WebBrowser.
I can get it working fine outside of ASP.NET, but that is not an option for me currently, it has to run inside this ASP.NET application.
//Update
On the advice of my colleague I'm using impersonation in the background thread where I'm creating the WebBrowser, running as a local user. This works fine and I'm pretty happy with this solution. He's a stackoverflow user so I'll let him post the answer and get the credit :)
Using impersonation in the background thread would allow the WebBrowser to run as a user with permissions to run IE and thus store cookies, instead of it running as the Application Pool user (NETWORK_SERVICE).
You can setup the Impersonation in the web.config or programatically to restrict it to a specific thread.
not offcially supported due to its usage of WinInet. see http://support.microsoft.com/kb/238425 for limitations of WinInet in a service.
Do you see the session cookie in the requests coming from the WebBrowser control? I cannot find anything on how this control is supposed to handle cookies - if it ignores them you would get the behavior you are describing