How to close tabs on Microsoft Edge programmatically - c#

I am trying to close all of the opened tabs on Microsoft Edge from c# code but can't get it working.
tried:
Process[] edgeProcessList = Process.GetProcessesByName("MicrosoftEdgeCP");
foreach (Process theprocess in edgeProcessList)
{
if (theprocess.MainWindowHandle != IntPtr.Zero)
{
SetForegroundWindow(theprocess.MainWindowHandle);
SendKeys.SendWait("^{W}");
Thread.Sleep(3000);
}
}
as well as:
foreach(Process proc in edgeProcessList.ToList())
{
proc.Kill();
}
but neither work. The processes do get killed But new ones re-appear at once.
Shows both in debug after:
Process[] newProcessList = Process.GetProcessesByName("MicrosoftEdgeCP");
as well as in the task manager.
Is there a way to do this that works?

the process is named "msedge"
Process[] Edge = Process.GetProcessesByName("msedge");
foreach (Process Item in Edge)
{
try
{
Item.Kill();
Item.WaitForExit(30000);
}
catch (Exception)
{
}
}

See WebDriver
That appears to be what "driver" in the incomplete answer is referencing.

Code to kill Edge browser instance
Process[] Edge = Process.GetProcessesByName("MicrosoftEdge");
foreach (Process Item in Edge)
{
try
{
Item.Kill();
Item.WaitForExit(3000);
}
catch (Exception)
{
}
}

using System.Windows.Automation and Keyboard Hook
Process[] procsEdge = Process.GetProcessesByName("msedge");
foreach (Process Edge in procsEdge)
{
if (Edge.MainWindowHandle != IntPtr.Zero)
{
AutomationElement root = AutomationElement.FromHandle(Edge.MainWindowHandle);
var tabs = root.FindAll(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem));
var elmUrl = root.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
foreach (AutomationElement tabitem in tabs)
{
if (elmUrl != null)
{
AutomationPattern[] patterns = elmUrl.GetSupportedPatterns();
if (patterns.Length > 0)
{
ValuePattern val = (ValuePattern)elmUrl.GetCurrentPattern(patterns[0]);
string url = val.Current.Value;
Console.WriteLine(url.Contains("bing.com"));
}
}
tabitem.SetFocus();
SendKeys.SendWait("{ALT+W}");
}
}
}

Figured it out and wrote some code that I got to work:
var tabs = driver.WindowHandles;
var x = Enumerable.Range(1, tabs.Count - 1).Reverse();
foreach(var i in Enumerable.Range(1, tabs.Count-1).Reverse())
{
Console.WriteLine(i);
driver.SwitchTo().Window(tabs[i]);
driver.Close();
driver.SwitchTo().Window(tabs[i - 1]);
}

Related

Kill a process that opened a file, after the file is closed by the user [WPF application]

I am trying to efficiently open-close-reopen a power bi file (.pbix) from a WPF application button click. My method starts by creating a process that opens the pbix file then kills the process when the file is closed and then when the button is clicked again creates a new process to re-open the file.
Kindly find below the code I use to execute the steps above.
namespace TestApp
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public int CheckFileIsOpen(string filenamepath)
{
try
{
using FileStream fs = new FileStream(filenamepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
return 0;
}
catch (Exception)
{
WindowEffect = new BlurEffect();
Mouse.OverrideCursor = null;
bool? Result = new CustomMessageBox($"File: {filenamepath.Split(#"\").Last()} in use!\nClose it and try again.", "File used by another process", MessageType.Error, MessageButtons.Ok).ShowDialog(); //this is a MessageBox object
if (Result.Value)
{
WindowEffect = null;
return 1;
}
else
{
WindowEffect = null;
return 2;
}
}
}
private void OpenOnlineLocally(bool open_local)
{
Process p = new Process();
string copy_name = "File_Copy.pbix";
string path = AppDomain.CurrentDomain.BaseDirectory; //the directory the .exe file runs.
try
{
Mouse.OverrideCursor = Cursors.Wait;
if (open_local == true)
{
int IsPBIFileOpen = CheckFileIsOpen($#"{path}{copy_name}");
if (new[] { 1, 2 }.Contains(IsPBIFileOpen))
{
return;
}
//Open the file using the system process
p.StartInfo = new ProcessStartInfo($"{path}{copy_name}")
{
UseShellExecute = true
};
p.Start();
}
else
{
OpenUrl("https://app.powerbi.com/...");
}
}
finally
{
if (p.HasExited) { p.Kill(); } //kill the process if the user closed the .pbix file
}
}
public ICommand ExportPowerBICommand //binded to a button click command in xaml
{
get { return new DelegateCommand<object>(FuncExportPowerBI); }
}
public void FuncExportPowerBI(object parameter)
{
Mouse.OverrideCursor = Cursors.Wait;
try
{
OpenOnlineLocally(true);
}
finally
{
Mouse.OverrideCursor = null;
}
}
}
}
The above code generates this error in the finally statement:
System.InvalidOperationException: 'No process is associated with this object.'
Some notes after experimentation:
The process should be killed when the user closes the .pbix file (i.e. clicks the X icon on top right corner of the desktop app). If the process is not killed and the user re-clicks the button to re-open the file then I get an error that the file is already opened and used by another process.
I prefer to avoid a solution that uses process.WaitForExit(), for two reasons. First, the application freezes while the file is used by the user. Second, it takes a couple of seconds for the desktop to realize that the process has exited so it can kill() it (not time efficient).
Since you're running .NET 5, there's an asynchronous method Process.WaitForExitAsync(). Async operation will not block the UI.
I've made the changes to two methods
private async Task OpenOnlineLocally(bool open_local)
{
Process p = new Process();
string copy_name = "File_Copy.pbix";
string dir = AppDomain.CurrentDomain.BaseDirectory; //the directory the .exe file runs.
string path = Path.Combine(dir, copy_name);
try
{
if (open_local == true)
{
int IsPBIFileOpen = CheckFileIsOpen(path);
if (IsPBIFileOpen != 0)
{
return;
}
//Open the file using the system process
p.StartInfo = new ProcessStartInfo(path)
{
UseShellExecute = true
};
p.Start();
await p.WaitForExitAsync();
}
else
{
OpenUrl("https://app.powerbi.com/...");
}
}
finally
{
if (!p.HasExited) { p.Kill(); } //kill the process if the user closed the .pbix file
}
}
public async void FuncExportPowerBI(object parameter)
{
Mouse.OverrideCursor = Cursors.Wait;
try
{
await OpenOnlineLocally(true);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message); // handle possible exception here
}
Mouse.OverrideCursor = null;
}

Getting URL list of all opened tabs in multiple windows using C#

I was working on a Team Tracking desktop application. I have implemented many
methods to track employees such as keylogging, idle time recording etc..
Now I am trying to find a way for recording URL of all chrome tabs with multiple chrome windows + incognito .
Found few codes but they get URL from only one chrome instance.
Any Solution for this problem?
static AutoResetEvent signal;
public static void Main()
{
Process[] procsChrome = Process.GetProcessesByName("chrome");
if (procsChrome.Length <= 0)
{
Console.WriteLine("Chrome is not running");
}
else
{
foreach (Process proc in procsChrome)
{
// the chrome process must have a window
if (proc.MainWindowHandle == IntPtr.Zero)
{
continue;
}
// to find the tabs we first need to locate something reliable - the 'New Tab' button
AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
// get the tabstrip by getting the parent of the 'new tab' button
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
// loop through all the tabs and get the names which is the page title
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
foreach (AutomationElement tabitem in elmTabStrip.FindAll(TreeScope.Children, condTabItem))
{
Console.WriteLine(tabitem.Current.Name);
}
}
}
Console.ReadKey();
}
public static void MyOnEntryWritten(object source, EntryWrittenEventArgs e)
{
Console.WriteLine("In event handler");
signal.Set();
}

selenium web scraping in c#

I am doing web scraping by using selenium dll's.But i face the problem when scrape the list of records. If I use the debugger it extract all the records, but if disable debugger and run the application it sometime display less records or sometime display no record.I want to know is there is any way to know that yet the page is fully loaded or not.
driver.FindElementsByClassName("search-result-gridview-item").ToList()
vary the record count.
driver.FindElementsByClassName("search-result-gridview-item").ToList().ForEach(x =>
{
objUPCProcess = new UPCProcessingModel();
try
{
objUPCProcess.Description = x.FindElement(By.ClassName("prod-ProductTitle")).Text;
objUPCProcess.Price = x.FindElement(By.ClassName("Price")).Text;
listOfProductDetails.Add(objUPCProcess);
if (i == 0)
{
log.Item = objUPCProcess.Description;
i++;
}
}
catch (OpenQA.Selenium.NoSuchElementException ex)
{
try
{
objUPCProcess.Description = x.FindElement(By.ClassName("prod-ProductTitle")).Text;
objUPCProcess.Price = ex.Message;
listOfProductDetails.Add(objUPCProcess);
}
catch
{
try
{
objUPCProcess.Price = x.FindElement(By.ClassName("Price")).Text;
objUPCProcess.Description = ex.Message;
listOfProductDetails.Add(objUPCProcess);
}
catch
{
objUPCProcess.Description = ex.Message;
objUPCProcess.Price = ex.Message;
log.Message = ex.Message;
listOfProductDetails.Add(objUPCProcess);
log.Status = "Error";
}
}
}
});
}
Looking at this case, I'm pretty sure this is caused by a synchronization issue (webdriver and page work at a different speed) with AJAX requests that actually populate the records. That's why
if disable debugger and run the application it sometime display less records or sometime display no record
I also don't see any explicit waits in your code. But you can implement a helper Utils method that will check
that yet the page is fully loaded or not
I've used the IScriptExecutor like so:
public void WaitSecondsForNewPageToLoad(int maxWaitTimeInSeconds)
{
string state = string.Empty;
bool jQueryActive = true;
try
{
WebDriverWait wait = new WebDriverWait(TestCaseContext.Driver,
TimeSpan.FromSeconds(maxWaitTimeInSeconds));
//Checks every 500 ms whether predicate returns true if returns exit otherwise keep trying till it returns true
wait.Until(d =>
{
try
{
state =
((IJavaScriptExecutor) TestCaseContext.Driver).ExecuteScript(
#"return document.readyState").ToString();
jQueryActive =
(bool)((IJavaScriptExecutor) TestCaseContext.Driver).ExecuteScript(
#"return jQuery.active == 0");
WindowsWhenSteps.WhenIFocusTheCurrentBrowserWindow();
}
catch (InvalidOperationException)
{
//Ignore
}
return (state.Equals("complete", StringComparison.InvariantCultureIgnoreCase) ||
state.Equals("loaded", StringComparison.InvariantCultureIgnoreCase)) &&
jQueryActive;
});
}
catch (TimeoutException)
{
//sometimes Page remains in Interactive mode and never becomes Complete, then we can still try to access the controls
if (!state.Equals("interactive", StringComparison.InvariantCultureIgnoreCase))
Assert.IsTrue(false);
}
catch (NullReferenceException)
{
//sometimes Page remains in Interactive mode and never becomes Complete, then we can still try to access the controls
if (!state.Equals("interactive", StringComparison.InvariantCultureIgnoreCase))
Assert.IsTrue(false);
}
catch (WebDriverException)
{
if (TestCaseContext.Driver.WindowHandles.Count == 1)
{
TestCaseContext.Driver.SwitchTo().Window(TestCaseContext.Driver.WindowHandles[0]);
}
state =
((IJavaScriptExecutor) TestCaseContext.Driver).ExecuteScript(
#"return document.readyState").ToString();
if (
!(state.Equals("complete", StringComparison.InvariantCultureIgnoreCase) ||
state.Equals("loaded", StringComparison.InvariantCultureIgnoreCase)))
Assert.IsTrue(false);
}
}
NOTE: You can lose some of the exception handling if it seems like an overhead, but I'm aiming at full answer in favor of the future readers too.
use the following code to check whether selenium is trigerred
/* * Created by SharpDevelop.
* User: sravanth
* Date: 2/2/2018
* Time: 1:33 AM *
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Support.UI;
using System.Diagnostics;
using Microsoft.VisualBasic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
//using System.Collections;
using System.Collections.Generic;
namespace sele
{
class Program
{
public static void Main(string[] args)
{
//Console.WriteLine("Hello World!");
// TODO: Implement Functionality Here
//Console.Write("Press any key to continue . . . ");
//Console.ReadKey(true);
//System.setProperty("webdriver.ie.driver", "C:\\Users/sravanth/Downloads/IEDriverServer_x64_3.8.0/IEdriver.exe");
// C:\Users\sravanth\Downloads\IEDriverServer_x64_3.8.0
IWebDriver driver;
// = new InternetExplorerDriver(#"C:\\Users/sravanth/Downloads/IEDriverServer_x64_3.8.0");
var service = InternetExplorerDriverService.CreateDefaultService(#"C:\\Users/sravanth/Downloads/IEDriverServer_x64_3.8.0");
//var service = InternetExplorerDriverService.CreateDefaultService(#"C:\\Users/sravanth/Downloads/chromedriver_win32");
// properties on the service can be used to e.g. hide the command prompt
var options = new InternetExplorerOptions { IgnoreZoomLevel = true, InitialBrowserUrl = "file:///C:/Users/sravanth/Desktop/a.html", IntroduceInstabilityByIgnoringProtectedModeSettings = true };
driver = new InternetExplorerDriver(service, options);
//driver = new ChromeDriver(#"C:\\Users/sravanth/Downloads/chromedriver_win32");
//driver.Navigate().GoToUrl("https://www.w3schools.com/js/tryit.asp?filename=tryjs_prompt");
driver.Url="file:///C:/Users/sravanth/Desktop/a.html";
//driver.Navigate().GoToUrl("file:///C:/Users/sravanth/Desktop/a.html");
driver.Navigate();
//IList links = driver.FindElements(By.TagName("button"));
// Console.WriteLine(links.Count);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
//IWebElement btn = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("btn")));
IWebElement btn=driver.FindElement(By.Id("btn"));
btn.Click();
// System.Threading.Thread.Sleep(5000);
Process[] processes = Process.GetProcessesByName("iexplore");
Console.WriteLine(processes.Length);
int i=0;
IntPtr windowHandle;
foreach (Process p in processes)
{
i=i+1;
Console.WriteLine(i);
windowHandle = p.MainWindowHandle;
Console.Write("iexplore");
Console.WriteLine(windowHandle.ToString());
// do something with windowHandle
if(i.Equals(1))
{
//Console.WriteLine("Reached If Loop");
SetForegroundWindow(windowHandle);
}
}
//System.Windows.Forms.SendKeys.SendWait("%{F4}");
Console.WriteLine(processes.Length);
Process.Start("notepad.exe");
var prc = Process.GetProcessesByName("notepad");
if (prc.Length > 0)
{
SetForegroundWindow(prc[0].MainWindowHandle);
}
//System.Windows.Forms.SendKeys.SendWait("%{F4}");
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
}
}

ArgumentNullException on System.Windows.Automation when trying to print open tabs in Chrome

This code should be working, at least it does for someone else but I keep getting the same ArgumentNullException was unhandled error? What could be the problem?
The app is supposed to print out the open tabs in google chrome.Try to run it and see if it works for you.
I imported UIAtomationClient.dll and UIAutomationTypes.dll
using System.Windows.Automation;
...
Process[] procsChrome = Process.GetProcessesByName("chrome");
if (procsChrome.Length <= 0)
{
Console.WriteLine("Chrome is not running");
}
else
{
foreach (Process proc in procsChrome)
{
// the chrome process must have a window
if (proc.MainWindowHandle == IntPtr.Zero)
{
continue;
}
// to find the tabs we first need to locate something reliable - the 'New Tab' button
AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
// get the tabstrip by getting the parent of the 'new tab' button
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab); // <- Error on this line
// loop through all the tabs and get the names which is the page title
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
foreach (AutomationElement tabitem in elmTabStrip.FindAll(TreeScope.Children, condTabItem))
{
Console.WriteLine(tabitem.Current.Name);
}
}
}
I'm not an expert on this Automation thing but here's working
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Automation;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Process[] procsChrome = Process.GetProcessesByName("chrome");
if (procsChrome.Length <= 0)
{
Console.WriteLine("Chrome is not running");
}
else
{
foreach (Process proc in procsChrome)
{
// the chrome process must have a window
if (proc.MainWindowHandle == IntPtr.Zero)
{
continue;
}
// to find the tabs we first need to locate something reliable - the 'New Tab' button
AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
Condition condTabs = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button);
//Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "new tab");
AutomationElementCollection col = root.FindAll(TreeScope.Descendants, condTabs);
AutomationElement elmNewTab = col[4]; // allways the position 4 is new tab button
// get the tabstrip by getting the parent of the 'new tab' button
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab); // <- Error on this line
// loop through all the tabs and get the names which is the page title
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
foreach (AutomationElement tabitem in elmTabStrip.FindAll(TreeScope.Children, condTabItem))
{
Console.WriteLine(tabitem.Current.Name);
}
Console.ReadKey();
}
}
}
}
}
I look for every button in the window and it turns out that the new tab is allways at position 4 before minimize, restore and close buttons. I know is not the cleanest solution to incorporate a magic number but it does the job.
Here you go! I tested it in VS2015

AutomationElement.FromHandle(IntPtr Handle) stops the application

private string GetCurrentChromeUrl()
{
try
{
string url = null;
int handle = GetForegroundWindow();
AutomationElement elm = AutomationElement.FromHandle((IntPtr)handle);
AutomationElement elmUrlBar = elm.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "Address and search bar"));
if (elmUrlBar != null)
{
AutomationPattern[] patterns = elmUrlBar.GetSupportedPatterns();
if (patterns.Length > 0)
{
ValuePattern val = (ValuePattern)elmUrlBar.GetCurrentPattern(patterns[0]);
url = val.Current.Value;
//break;
}
}
return url;
}
catch (Exception e1)
{
return "";
}
}
I'm trying to find the URL from google chrome browser.
And I'm using above code. It is work good in other application but in my case it stops my application.
But the main issue is that it will work fine when I'm debugging it, so what wrong when no debugging.
please give your solutions.
thanx in advance
I'm passing through this, it happen cause of the intptr type, it depends of the build of the machine, sometime the windowhandle is too big for an intptr of a 32bits machine.

Categories