I have a windows form and I make the following call to open chrome up with a URL:
string uri = Uri.EscapeUriString(URL.ToString());
Process process = Process.Start("chrome", uri + " --new-window");
return process.Id;
The problem is that I get the error: "Process with an id of "xxxxxxx" is not running" when I call the following:
procsChrome = Process.GetProcessById(processID);
The processID is the one returned in the previous code snippet. Now, this WORKS when I have NO CHROME WINDOW OPEN.
But if I have another chrome window open, I get this error. I monitored the processes in Task Manager and when no chrome is open, a new process with the the process id returned from the code snippet 1 is created.
When one or more chrome windows are already open, I get a process id from code snippet 1, but the newly opened chrome window is running under some other id. Why is this happening?
Edit 2:
Here is the method I get the error on. The parameter int processID is the process.Id returned above from code snippet 1.
public static string GetCodeFromURL(int processID)
{
Process procsChrome = null;
try
{
if (processID == -1)
{
Console.WriteLine("-1 returned as ID");
return null;
}
procsChrome = Process.GetProcessById(processID); //I GET ERROR HERE
// the chrome process must have a window
if (procsChrome.MainWindowHandle == IntPtr.Zero)
MessageBox.Show("Process failed");
// to find the tabs we first need to locate something reliable - the 'New Tab' button
AutomationElement root = AutomationElement.FromHandle(procsChrome.MainWindowHandle);
var SearchBar = root.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
if (SearchBar != null)
{
bool noCode = false;
while (noCode == false)
{
string fullURL = (string)SearchBar.GetCurrentPropertyValue(ValuePatternIdentifiers.ValueProperty);
if (!(fullURL.Contains("code") && fullURL.Contains("state")))
{
if (procsChrome.HasExited)
{
Console.WriteLine("Process failed. User closed browser.");
procsChrome.Close();
noCode = true;
}
}
else
{
string stateToken = HttpUtility.ParseQueryString(fullURL.Substring(new[] { 0, fullURL.IndexOf('?') }.Max())).Get("state");
if (stateToken.Equals("296bc9a0-a2a2-4a57-be1a-d0e2fd9bb601"))
{
noCode = true;
string code = HttpUtility.ParseQueryString(fullURL.Substring(new[] { 0, fullURL.IndexOf('?') }.Max())).Get("code");
procsChrome.CloseMainWindow();
procsChrome.Close();
return code;
}
}
}
}
}
catch (Exception exception)
{
Console.WriteLine("An exception occured on getting the URL. Please try again. The exception is: " + exception.ToString());
return null;
}
return null;
}
Thanks.
Chrome seems to behave in this way by default, creating anothing process and closing the original one, which means you end up with an incorrect Process ID. And when you have multiple Chrome processes with the same website/title you end up having no control over it.
As some suggested using the parameter "--incognito" will solve it, whoever this would also create other unwanted behavioural issues.
I've looked at the Chrome parameters list and tried a few, using the parameter "--no-service-autorun" seems to have solved the issue.
Not sure why chrome is behaving like that. Can you try to have your code launch chrome in incognito mode?
Using the test code below i was able to launch 2 distinct incognito processes each with their own process id. Note: these launched in the same browser window as 2 tabs.
I think using --incognito will get you out of trouble.
public class LaunchChromeProof
{
private readonly ITestOutputHelper _output;
public LaunchChromeProof(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void CanLaunchChromeIcognito_AndFetchProcesses_ByID()
{
var chromePath = #"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe";
var chromeProcess = Process.Start(chromePath, "www.google.com --incognito");
Assert.NotEqual(0, chromeProcess.Id);
//launch a second session
var chrome2ndProcess = Process.Start(chromePath, "www.google.com --incognito");
Assert.NotEqual(0, chrome2ndProcess.Id);
_output.WriteLine($"Session 1 ProcessID: {chromeProcess.Id}");
_output.WriteLine($"Session 2 ProcessID: {chrome2ndProcess.Id}");
//check we can fetch the correct process by the process id for each session
var fetchProcess1 = Process.GetProcessById(chromeProcess.Id);
Assert.Equal(chromeProcess.Id, fetchProcess1.Id);
var fetchProcess2 = Process.GetProcessById(chrome2ndProcess.Id);
Assert.Equal(chrome2ndProcess.Id, fetchProcess2.Id);
_output.WriteLine($"Fetched Session 1 Process: {fetchProcess1.Id}");
_output.WriteLine($"Fetched Session 2 Process: {fetchProcess2.Id}");
}
Related
My question is, how to prevent Selenium from creating multiple chrome instances?
Details:
Using Selenium and chromedriver I created an automation testing program. Strangely, although most runs are as expected, about one out of twenty would create many chrome console (black, empty) windows, with one actual browser window. The browser window would finish the work but not disposed correctly, and no exceptions were thrown. Once I manually closed the only browser window, all other windows were closed too.
This time I caught it in visual studio debug mode, I found even my program paused at a breakpoint, the chrome console windows were still being spawned. In the task manager there were 17 chrome.exe sessions, and no chrome was created before my program started.
Out of all the console windows, only one (the leftmost one on screen, maybe the first one that was created) had some information and all others were blank:
[2400:1204:0412/171721.457:ERROR:gl_surface_egl.cc(808)] EGL Driver
message (Error) eglCreateContext: Requested GLES version (3.0) is
greater than max supported (2, 0).
[2400:1204:0412/171721.578:ERROR:gl_context_egl.cc(352)]
eglCreateContext failed with error EGL_SUCCESS
Then after the only browser window finished routine work, another spawned console window contained some additional information:
[8016:13204:0412/172631.461:ERROR:cache_util_win.cc(20)] Unable to
move the cache: Access is denied. (0x5)
[8016:13204:0412/172631.462:ERROR:cache_util.cc(146)] Unable to move
cache folder
C:\Users\cal\AppData\Local\Temp\scoped_dir2496_2059150988\Default\Cache\Cache_Data
to
C:\Users\cal\AppData\Local\Temp\scoped_dir2496_2059150988\Default\Cache\old_Cache_Data_000
[8016:13204:0412/172631.463:ERROR:disk_cache.cc(186)] Unable to create
cache
Below is my c# code for creating chrome browser:
public static ChromeDriver GetChromeBrowser(bool bHeadless = false, string sProxy = "", string chromeProfileDir = "")
{
var chromeoptions = GetChromeOptions(bHeadless, chromeProfileDir);
var chromeDriverService = ChromeDriverService.CreateDefaultService(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
// hide prompt window
chromeDriverService.HideCommandPromptWindow = true;
ChromeDriver browser = null;
int nCount = 0;
while (browser == null && nCount < 3)
{
try
{
browser = new ChromeDriver(chromeDriverService, chromeoptions, TimeSpan.FromSeconds(180));
}
catch (Exception ex)
{
// try a different port:
chromeoptions = GetChromeOptions(bHeadless, chromeProfileDir);
}
nCount++;
}
return browser;
}
private static ChromeOptions GetChromeOptions(bool bHeadless = false, string chromeProfileDir = "")
{
var chromeoptions = new ChromeOptions();
if (!string.IsNullOrEmpty(chromeProfileDir))
{
string sProfileFullPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), chromeProfileDir);
if (!Directory.Exists(sProfileFullPath))
{
try
{
Directory.CreateDirectory(sProfileFullPath);
}
catch (Exception)
{
}
}
chromeoptions.AddArguments("--profile-directory=" + sProfileFullPath);
}
chromeoptions.AddArguments("--disable-notifications");
chromeoptions.AddArguments("--no-sandbox");
chromeoptions.AddArguments("--disable-dev-shm-usage");
chromeoptions.UnhandledPromptBehavior = UnhandledPromptBehavior.Dismiss;
int nPortNumber = GetARandomPortNumber();
chromeoptions.AddArguments($"--remote-debugging-port={nPortNumber.ToString()}");
if (bHeadless)
{
chromeoptions.AddArguments("--headless");
chromeoptions.AddArguments("--disable-gpu");
// do not load images:
chromeoptions.AddArguments("--blink-settings=imagesEnabled=false");
}
return chromeoptions;
}
I have also made a screenshot to show how it look like. As you can see, many blank chrome windows were created.
The problem is highly intermittent and hard to reproduce. I don't know if it is enough to pinpoint the problem. Any suggestion is appreciated.
I have developed a launcher that updates/run our software in other companies enviroment. Most of the time the company approves the launcher but forgets about the actual application.
Currently im using Process.Start(procStart) to start the application, but that silently fails if applocker blocks the application.
So i was wondering if someone reliable way of detecting if applocker is active, and when it blocks my application( So i can provide a proper error message).
When the error happens my application seems idle to the user, a memory dump shows this:
Code note:
There is no exception handling or suppression of exceptions. If the launcher crashes i would expect to see it in the eventlog.
Added code:
private void StartzzzDesktop(int value)
{
var rel = Settings.zzzDesktopStore.GetReleaseInfo(Settings.ConnectionDetails.zzzDesktopID);
var proc = CreateProccess(rel);
if (proc == null)
{
Settings.LastError = zzzLauncherError.FatelErrorStartzzz;
Settings.EventManager.TriggerEvent(zzzDesktopStatus.FatalError);
return;
}
Logger.Log(EventLogEntryType.Information, $"Started zzz desktop and got PID {proc.Id} from {rel.GenerateExtrationPath()}");
Settings.EventManager.TriggerEventSync(zzzDesktopStatus.DeleteOldReleases);
Settings.EventManager.TriggerEvent(zzzDesktopStatus.ReleaseBackgroundWorkers);
GC.Collect();
var remoteStatus = new GetRemotezzzWebStatus();
while (!proc.HasExited)
{
Thread.Sleep(1000);
if(!remoteStatus.IsRemoteVersionCompatible())
{
proc.Kill();
Logger.Log(EventLogEntryType.Information, $"Detected that the remote website is no longer compatible with current runnign version, and we are killing desktop.");
}
}
if(proc.ExitCode != 0)
{
Settings.zzzDesktopStore.Delete(rel);
Logger.Log(EventLogEntryType.Warning, $"zzz exited with a none zero exit code ({proc.ExitCode}), the local cached installation will be deleted");
}
else
Logger.Log(EventLogEntryType.Information, $"zzz exited in a normal way with exitcode {proc.ExitCode}, running for {(DateTime.Now - proc.StartTime).ToString()} ");
CloseDown();
}
internal Process CreateProccess(zzzDesktopInfo release)
{
release = GetReleaseInfo(release.ID);
string pathzzzExe = Path.Combine(release.GenerateExtrationPath(), "zzz.exe");
var verifyStatus = UtilsVerifyFile.Verify(pathzzzExe);
if ( !File.Exists(pathzzzExe) || !verifyStatus.Verified)
{
Logger.Log(EventLogEntryType.Error, "Found zzz.exe in temp folder, but the certificate did not pass verification");
foreach (var logentry in verifyStatus.Logs)
Logger.Log(EventLogEntryType.Error, "Certificate verification log: " + logentry);
MarkDatabaseForPurge();
return null;
}
// Removed enterprise spesific code.
var procStart = new ProcessStartInfo();
procStart.FileName = pathzzzExe;
if (Settings.ConnectionDetails.zzzLoginToken != Guid.Empty )
{
procStart.Arguments = "/RefreshToken:" + Settings.ConnectionDetails.zzzLoginToken.ToString();
}
var process = Process.Start(procStart);
return process;
}
Im facing exactly the same issue as described here
but its a closed thread.
Im using selenium webdriver 2.48.2, on win7 IE 11.
The situation goes like this, I have a test that clicks on a button which is supposed to open a new experiment, this new experiment opens in new tab on chrome and in the same tab on firefox, but opens in new window on IE11 when it is run through selenium. But strange thing is that it does not open in new window when the browser was opened manually instead of through selenium script.
maybe the selenium script opens new webdriver? and script halts while searching for new page's elements. what the code does is, it checks if the new handle was opened or not, finds the new handle and then switches the window handle to newer one.
Here is the c# code snippet.
private static TResult TriggerAndWaitForNewWindow<TResult>(PageObject pageObject, Action action, int timeout = 30)
where TResult : PageObject, new()
{
IParent parent = pageObject.Driver;
List<String> existingHandles = pageObject.Driver.WindowHandles.ToList();
action();
string popupHandle = Wait.Until(() =>
{
string foundHandle = null;
List<string> currentHandles = pageObject.Driver.WindowHandles.ToList();
var differentHandles = GetDifference(existingHandles, currentHandles);
if (differentHandles.Count > 0)
{
Boolean hasSomeLength = differentHandles[differentHandles.Count-1].Length > 1;
if (hasSomeLength)
foundHandle = differentHandles[differentHandles.Count - 1];
}
return foundHandle;
}, "Waiting for new Window Handle to appear", timeout, 2000);
// Init the new page object but override the window handle
TResult page = PageObject.Init<TResult>(parent);
page.WindowHandle = popupHandle;
page.SwitchToMyWindow();
return page;
}
private static List<String> GetDifference(List<string> existingHandles, List<string> currentHandles)
{
System.Threading.Thread.Sleep(15000);
return currentHandles.Except(existingHandles).ToList();
}
Halts inside this function on IE11
public Boolean SwitchToMyWindow()
{
try
{
String windowHandle = this.WindowHandle; // must be the old handle
try
{
if (this.Driver.CurrentWindowHandle == windowHandle)
{
Log.Info("No need to cswitch window");
return true;
}
}
catch(Exception e)
{
Log.Warn("We have no current driver window, must have been closed");
}
Log.Info("Switching to Window Handle {0}", this.Driver.CurrentWindowHandle);
this.Driver.SwitchTo().Window(windowHandle); <---- Halts here on IE11
//Pause.milliSeconds(500);
Boolean switched = Wait.Until(() =>
this.Driver.CurrentWindowHandle == windowHandle, "Waiting for my window handle to be the active one", 5, 1000);
}
catch (OpenQA.Selenium.WebDriverTimeoutException tEx)
{
}
return true;
}
Did anyone else ever faced this issue? How can resolve it?
Can you verify if Selenium supports your target OS?
It is possible that Selenium is not fully supported on your Target OS.
Please check the following link for more details.
http://grokbase.com/t/gg/webdriver/1267fdkgaa/openqa-selenium-nosuchwindowexception-with-ie9-and-windows-2008
I am using Waitin RC2, WatiN-2.0.20.1089, Windows XP OS with IE8 With VS2008 and NUnit-2.5.7.10213. I have added the sites to the trusted list, I have thread sleeps, I have tried "WaitForComplete". yet when the script goes "back" I am still getting an unauthorized access exception.
Here is a chunk of my code, the exceptions are never caught inspite of the fact that most of the code is in try catch blocks.
public string FindAllLinks()
{
/*
* This function is designed to find and use all of the links on a given page.
* After clicking on a link it waits for 400 milliseconds on the page so the page
* has some time to load and then the function "hits the back button" reseting
* to the originating page.
* This function is not meant to be recursive.
*/
string message = "";
bool flag = true;
//Get a list of all links from the browser instance
foreach (Link link in browserInstance.Links)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine(link);
try
{//clicking on the link to make sure it leads somewhere
link.Click(); //If the click fails hopefull we will thrwo out of the try block and not execute the next two commands.
//Console.WriteLine(link);
}
catch (Exception)
{//OOPs we have an error let's log a message.
message = message + "The link titled " + link + " was not found, or did not work.\n";
flag = false;
}
if (flag)
{
System.Threading.Thread.Sleep(1000);
//browserInstance.WaitForComplete;
try { browserInstance.Back(); }
catch (UnauthorizedAccessException)
{
//do nothing
}
}//close if flag
}//close for each
//return the message
return (message);
}//Close function
[STAThread]
[Test]
public void TestTitleHomePage()
{
bool testPassed = false;
if (browserInstance.Title.Contains("<title>"))
{
string message = FindAllLinks();
if (message == "") { testPassed = true; }
}//close if
else { message = "The Title was not the same."; }
Assert.IsTrue(testPassed, message);
}// end TestTitleHomePage
I tried your code and I also get the exception. I think I understand what happens. When you first do Browser.Links, you get all the links of the current page, then you navigate to another page and return to the first page, but for WatiN it is a new page. So your enumeration cannot work because you enumerate though the links of the first page.
What I suggest you could do is to get all the Uri of the links, then try them one by one in a new browser
IEnumerable<Uri> uris = Browser.Links.Select(l => l.Uri);
foreach(Uri uri in Uris)
{
try
{
using(var browser = new IE(uri))
{
// do nothing or detect 404, 403, etc errors
}
// no error
}
catch(exception)
{
// log error
}
}
For a project I have to start an application in C#, rip out the AutomationElement tree related to the process, and then close the application and output the tree. I'm doing this by opening the application using Process.Start. Then I'm finding the AutomationElements related to the spawned process and walking the tree using a combination of TreeWalker and AutomationElement's FindFirst and FindAll methods.
This runs fine on my computer and runs correctly using NUnit locally. It also runs on the other people in my groups computers. The problem is that it never runs on our central testing server that's running Hudson. After some hours of debugging, I had a test on Hudson start the application and then print the first level of the AutomationTree. On my computer, this prints all of the windows I have on my desktop. On Hudson, this only prints the Desktop.
Thinking there might be multiple desktops, I tried using TreeWalker's GetNextSibling function on the RootElement. It still only reported one desktop.
Here's the code I'm using to start a process.
public bool connect(string[] args)
{
if (this.process != null) {
Console.WriteLine("ERROR: Process already connected");
return false;
}
if (!File.Exists(sApplicationPath)) {
Console.WriteLine(sApplicationPath + " does not exist");
return false;
}
// Turn the command arguments into a single string
string arguments = "";
foreach (string arg in args) {
arguments += arg + " ";
}
try {
// Start the application
ProcessStartInfo processStartInfo =
new ProcessStartInfo(sApplicationPath);
processStartInfo.Arguments = arguments;
this.process = Process.Start(processStartInfo);
// Must be a positive integer (non-zero)
if ( !( iInitialDelay > 0 ) ) {
Console.WriteLine("Invalid initial delay. " +
"Defaulting to 5 seconds.");
this.iInitialDelay = 5000;
}
Thread.Sleep(this.iInitialDelay);
} catch (Exception ex) {
Console.WriteLine("WGApplication.connect: " + ex.Message);
return false;
}
// Check if the process still exists
try {
/** This part does not return an error, so I think that means the process exists and is started */
Process check = Process.GetProcessById(process.Id);
} catch (ArgumentException ex) {
Console.WriteLine("The process expired before connection was complete");
Console.WriteLine("Make sure the process is not open anywhere else");
Console.WriteLine("and that it is able to execute on the host machine.");
return false;
}
// Check if the base automation element exists to verify open
AutomationElement rootWindow =
AutomationElement.RootElement.FindChildProcessById(process.Id);
/** This part returns null, so it can't find the window associated with this process id */
if (this.process == null) {
return false;
} else if (rootWindow == null) {
// A root window with this process id has not been found
Console.WriteLine("Cannot find the root window of the created " +
"process. Unknown error.");
return false;
} else {
// Everything is good to go
return true;
}
}
sApplicationPath is set to the absolute path of the executable. iInitialDelay is a delay to make sure the application has time to start. I'm running this on 'C:\Windows\System32\notepad.exe' on Windows Vista SP2 and compiling it with the v3.5 C# compiler.
FindChildProcessById is defined as follows:
public static AutomationElement FindChildProcessById(
this AutomationElement element, int processId)
{
var result = element.FindChildByCondition(
new PropertyCondition(AutomationElement.ProcessIdProperty,
processId));
return result;
}
Remember that this compiles and works on my computer. My test program on Hudson said that the RootElement had no children at all.
So I start the application, confirm it exists, and then I can't find any windows associated with the process. I can't find any windows associated with anything except the desktop.
Is this a problem with Hudson? Does Hudson work in some specific way that this code wouldn't work on it? Is it a problem with my code? The Hudson server is running on a Windows Server 2003 computer. Any help would be appreciated. I know this is a very specific problem which is a reason why I can't find any solutions online.
Is Hudson running as a service? If so, it may not have the necessary rights to show windows.