I want to be able to change the directory of an existing explorer window. Is there an api call to send a "navigate there" message to a window (perhaps with a handle to it)?
First, add a reference to the Microsoft Internet Control library. Then you can use the following code, assuming you already know the window handle for your explorer window:
var shellWindows = new SHDocVw.ShellWindows();
var myFolder = "C:\\temp"; // folder name you want to navigate to
var myHwnd = 0; // whatever window handle you're looking for
foreach (SHDocVw.InternetExplorer shellWindow in shellWindows)
{
if (shellWindow.HWND == myHwnd)
{
shellWindow.Navigate(myFolder);
break;
}
}
Related
I am working on a C# project where I am trying to send a excel file by WhatsApp. The problem is that whenever I run the code a new instance of command window is open, and a new window is opened for chrome every time I ran the code. Before running the code, I have already log-in to my WhatsApp account and wants to use the same window and tab to avoid logging each time. I have tried to use several ways to stop this but failed to achieve the result. Please correct the code. Please don't mind my bad English.
var options = new ChromeOptions();
options.AddArguments(#"user-data-dir=C:\Users\Umesh Aggarwal\AppData\Local\Google\Chrome\User Data");
IWebDriver driver = new ChromeDriver(#"C:\Users\Umesh Aggarwal\Desktop\chromedriver_win32", options);
////// Navigate to Whatsapp web
driver.Navigate().GoToUrl("https://web.whatsapp.com/");
IReadOnlyCollection<string> windowHandles = driver.WindowHandles;
// Find already opened window with Chrome
string chromeWindow = "";
foreach (string window in windowHandles)
{
driver.SwitchTo().Window(window);
if (driver.Title.Contains("Google Chrome"))
{
chromeWindow = window;
break;
}
}
// Switch to Chrome window
driver.SwitchTo().Window(chromeWindow);
// Get all open tabs in Chrome window
IReadOnlyCollection<string> tabHandles = driver.WindowHandles;
// Find already opened tab of Whatsapp web
string whatsappTab = "";
foreach (string tab in tabHandles)
{
driver.SwitchTo().Window(tab);
if (driver.Title.Contains("Whatsapp"))
{
whatsappTab = tab;
break;
}
}
//// Switch to Whatsapp tab
driver.SwitchTo().Window(whatsappTab);
The DevTools that come with WebView2 can either be opened by the user e.g. by pressing the F12 key, and they also can be opened programatically from code.
What I do not know is how to determine whether the DevTools are currently being opened.
I want to store the state (opened/closed) upon the exit of my WPF application so that I can show them automatically upon the next start of my WPF application.
My question
How to get the current showing/not showing state of the WebView2 Developer Tools?
Update 1
I found a dirty hack because of the fact that the window title of the DevTools looks like this:
DevTools - localhost:38472/my/url
Whereas localhost:38472/my/url is the currently loaded URL of the WebView2.
So I'm doing the following.
With the help of this SO answer, I was able to create this method:
public static IEnumerable<string> GetAllDesktopMainWindowTitles()
{
// https://stackoverflow.com/a/7268375/107625
var processlist = Process.GetProcesses();
foreach (var process in processlist)
{
if (!string.IsNullOrEmpty(process.MainWindowTitle))
{
yield return process.MainWindowTitle;
}
}
}
I then can use it like this:
public static bool AreDevToolsOpen(this WebView2? webView)
{
var url = webView?.Source?.ToString();
if (string.IsNullOrEmpty(url)) return false;
url = url.Replace(#"https://", string.Empty).Replace(#"http://", string.Empty);
var titles = GetAllDesktopMainWindowTitles().ToList();
var devToolsOpen = titles.Any(t => t.Contains(#"DevTools") && t.Contains(url));
return devToolsOpen;
}
While this is a total hack, it seems to work good enough for now.
Still, I'm looking for a better way to do it.
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;
}
}
The exercise is to start a C# programm from the explorers context menu and the programm should know the path from the folder on with the context menu was opened.
What I did so fare: Add my programm to the explorers context menu and add this code:
SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindows();
string filename;
ArrayList windows = new ArrayList();
foreach (SHDocVw.InternetExplorer ie in shellWindows)
{
filename = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
if (filename.Equals("explorer"))
{
Console.WriteLine("Hard Drive: {0}", ie.LocationURL);
windows.Add(ie);
Shell shell = new Shell32.Shell();
foreach (SHDocVw.InternetExplorerMedium sw in shell.Windows())
{
Console.WriteLine(sw.LocationURL);
}
}
}
Basicaly this did work but only for the folder which is selected on the left tree view in explorer. And the next problem is when I use sw.LocationURL with the path "C:\C#" the result is "file:///C:/C%23".
Is there a simpler way to get the folder properties(path, name) on which I open the context menu to c#?
I can't speak to the first part of your question, because I haven't mucked around with shell extensions. But file:///C:/C%23 is the correct Url for the directory C:\C#, with urlencoding applied. If you want to turn this string into a filesystem path, you can do something like this:
var uri = new Uri("file:///C:/C%23");
var path = Uri.LocalPath;
I have my application which triggers Web Browser with specific URL .
After my program ends i want to close the web pages/tabs which i have opened..
By calling an EXE file with parameters a. Process Name b. String present in the URL
Detailed problem
How to kill firefox child process/tab from Java/C++
I used C# approach ...
I am able to find the process ID of all the tabs..
foreach (Process theprocess in processlist) {
if (theprocess.ProcessName == "iexplore") {
Console.WriteLine("Process: {0}\tID: {1}\tWindow name: {2}",
theprocess.ProcessName, theprocess.Id, theprocess.MainWindowTitle
);
}
}
Currently i can get only Window Title of the process....and in IE8 only one window title of main process is visible..
Provided i have the pids of each tabs,How to find the URL of the tab ...and kill only that tab ??
I got this help from
Access is denied - when trying to get the url (text) from address bar's handle
using SHDocVw;
.
.
foreach (InternetExplorer ieInst in new ShellWindowsClass())
Console.WriteLine(ieInst.LocationURL);
In IE7 and later versions, below code will kill only the tab which has matching string in its URL.
foreach (SHDocVw.InternetExplorer ieInst in new SHDocVw.ShellWindows())
{
String url = ieInst.LocationURL;
if (url.Contains("google"))
{
ieInst.Quit();
}
}
To focus a specific tab the code is :
foreach (SHDocVw.InternetExplorer ieInst in new SHDocVw.ShellWindows())
{
String url = ieInst.LocationURL;
if (url.Contains("google"))
{
int val = ieInst.HWND;
IntPtr hwnd = new IntPtr(val);
ShowWindow(hwnd, SW_MAXIMISE);
SetForegroundWindow(hwnd);
}
}
There is a way get the URL of each IExplorer instance !!
Add a reference "Microsoft Internet Controls" to the project.
The piece of code is
**foreach (SHDocVw.InternetExplorer ieInst in new SHDocVw.ShellWindowsClass())
{
System.Console.WriteLine(ieInst.LocationURL);
}**
Generate the exe and Interop.SHDocVw.dll
It will work ...:)