Get selected items of folder with WinAPI - c#

I try to get the selected files of a folder which the user is using. I have the following code which is already running, but only on desktop files:
private string selectedFiles()
{
// get the handle of the desktop listview
IntPtr vHandle = WinApiWrapper.FindWindow("Progman", "Program Manager");
vHandle = WinApiWrapper.FindWindowEx(vHandle, IntPtr.Zero, "SHELLDLL_DefView", null);
vHandle = WinApiWrapper.FindWindowEx(vHandle, IntPtr.Zero, "SysListView32", "FolderView");
//IntPtr vHandle = WinApiWrapper.GetForegroundWindow();
//Get total count of the icons on the desktop
int vItemCount = WinApiWrapper.SendMessage(vHandle, WinApiWrapper.LVM_GETITEMCOUNT, 0, 0);
//MessageBox.Show(vItemCount.ToString());
uint vProcessId;
WinApiWrapper.GetWindowThreadProcessId(vHandle, out vProcessId);
IntPtr vProcess = WinApiWrapper.OpenProcess(WinApiWrapper.PROCESS_VM_OPERATION | WinApiWrapper.PROCESS_VM_READ |
WinApiWrapper.PROCESS_VM_WRITE, false, vProcessId);
IntPtr vPointer = WinApiWrapper.VirtualAllocEx(vProcess, IntPtr.Zero, 4096,
WinApiWrapper.MEM_RESERVE | WinApiWrapper.MEM_COMMIT, WinApiWrapper.PAGE_READWRITE);
try
{
for (int j = 0; j < vItemCount; j++)
{
byte[] vBuffer = new byte[256];
WinApiWrapper.LVITEM[] vItem = new WinApiWrapper.LVITEM[1];
vItem[0].mask = WinApiWrapper.LVIF_TEXT;
vItem[0].iItem = j;
vItem[0].iSubItem = 0;
vItem[0].cchTextMax = vBuffer.Length;
vItem[0].pszText = (IntPtr)((int)vPointer + Marshal.SizeOf(typeof(WinApiWrapper.LVITEM)));
uint vNumberOfBytesRead = 0;
WinApiWrapper.WriteProcessMemory(vProcess, vPointer,
Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0),
Marshal.SizeOf(typeof(WinApiWrapper.LVITEM)), ref vNumberOfBytesRead);
WinApiWrapper.SendMessage(vHandle, WinApiWrapper.LVM_GETITEMW, j, vPointer.ToInt32());
WinApiWrapper.ReadProcessMemory(vProcess,
(IntPtr)((int)vPointer + Marshal.SizeOf(typeof(WinApiWrapper.LVITEM))),
Marshal.UnsafeAddrOfPinnedArrayElement(vBuffer, 0),
vBuffer.Length, ref vNumberOfBytesRead);
string vText = Encoding.Unicode.GetString(vBuffer, 0,
(int)vNumberOfBytesRead);
string IconName = vText;
//Check if item is selected
var result = WinApiWrapper.SendMessage(vHandle, WinApiWrapper.LVM_GETITEMSTATE, j, (int)WinApiWrapper.LVIS_SELECTED);
if (result == WinApiWrapper.LVIS_SELECTED)
{
return vText;
}
}
}
finally
{
WinApiWrapper.VirtualFreeEx(vProcess, vPointer, 0, WinApiWrapper.MEM_RELEASE);
WinApiWrapper.CloseHandle(vProcess);
}
return String.Empty;
}
I tried to get the window handle with GetForegroundWindow() and then call the SHELLDLL_DefView without success.
So how can I change the first 3 rows to get me the handle of the current folder in use?

That's a lot of hacking to do something that is explicitly supported by the various shell objects and interfaces. Granted the documentation doesn't make it easily discoverable, but the functionality is there. Raymond Chen wrote a great article about using these interfaces. There doesn't appear to be a way to get the "current" folder, though I guess you could get the HWNDs and see if any is the foreground window.

thank you very much. You gave me the right direction. It is possible to get the selected files of a folder:
/// <summary>
/// Get the selected file of the active window
/// </summary>
/// <param name="handle">Handle of active window</param>
/// <returns></returns>
public String getSelectedFileOfActiveWindow(Int32 handle)
{
try
{
// Required ref: SHDocVw (Microsoft Internet Controls COM Object)
ShellWindows shellWindows = new SHDocVw.ShellWindows();
foreach (InternetExplorer window in shellWindows)
{
if (window.HWND == handle)
return ((Shell32.IShellFolderViewDual2)window.Document).FocusedItem.Path;
}
}
catch (Exception)
{
return null;
}
return null;
}

Related

How to activate a Google Chrome tab item using UI Automation

I am using this code from a C# application to find a tab in Google Chrome:
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome)
{
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero)
{
continue;
}
AutomationElement root = AutomationElement.FromHandle(chrome.MainWindowHandle);
/*
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "Nueva pestaƱa");
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 root.FindAll(TreeScope.Descendants, condTabItem))
{
Console.WriteLine(tabitem.Current.Name);
// I NEED TO ACTIVATE THE TAB HERE
break;
}
Condition condUrl = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);
foreach (AutomationElement edit in root.FindAll(TreeScope.Descendants, condUrl))
{
string value = ((System.Windows.Automation.ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value;
Console.WriteLine(value);
}
}
I need to select certain tab item using UI Automation. How can I do it?
For those desperate souls, still searching for an answer. Here is my method, based solely on UI Automation API, without focusing windows and sending click events or hotkeys. To use the code below you need to use interop reference for UIAutomationCore.dll as described by Guy Barker.
Process[] allChromeProcesses = Process.GetProcessesByName("chrome");
Process[] mainChromes = allChromeProcesses.Where(p => !String.IsNullOrEmpty(p.MainWindowTitle)).ToArray();
//...
//Here you need to check if you have found correct chrome instance
//...
var uiaClassObject = new CUIAutomation();
IUIAutomationElement chromeMainUIAElement = uiaClassObject.ElementFromHandle(mainChromes[0].MainWindowHandle);
//UIA_ControlTypePropertyId =30003, UIA_TabItemControlTypeId = 50019
IUIAutomationCondition chromeTabCondition = uiaClassObject.CreatePropertyCondition(30003, 50019);
var chromeTabCollection = chromeMainUIAElement.FindAll(TreeScope.TreeScope_Descendants, chromeTabCondition);
//UIA_LegacyIAccessiblePatternId = 10018, 0 -> Number of Chrome tab you want to activate
var lp = chromeTabCollection.GetElement(0).GetCurrentPattern(10018) as IUIAutomationLegacyIAccessiblePattern;
lp.DoDefaultAction();
The only thing you need to remember is that searching of tabs for minimized Chrome window is impossible.
I needed to solve similar problem. Since Chrome doesn't fully implement Windows Automation features, it has to be implemented differently.
Thanks to this GitHub project I was able to activate the correct Chrome tab. The trick is to press Ctrl+tab index to activate the tab in the case its position is between 1 and 8 (9 switches to the last tab, see Chromebook keyboard shortcuts). For tabs appearing further in the collection Ctrl+Tab is pressed repeatedly until the desired tab is reached.
However, it is not that easy, since sometimes the tabs can appear in the UI automation collection out of order. I have fixed this by calling the TryGetClickablePoint method for each tab and sorting the tabs by the X coordinate of the point returned.
bool ActivateChromeTab(string title)
{
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process proc in procsChrome)
{
if (proc.MainWindowHandle == IntPtr.Zero)
{
continue;
}
AutomationElement root = AutomationElement.FromHandle(proc.MainWindowHandle);
Condition condNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
AutomationElement elmNewTab = root.FindFirst(TreeScope.Descendants, condNewTab);
TreeWalker treewalker = TreeWalker.ControlViewWalker;
AutomationElement elmTabStrip = treewalker.GetParent(elmNewTab);
Condition condTabItem = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
var index = 0;
var tabItems = elmTabStrip.FindAll(TreeScope.Children, condTabItem);
var coll = new List<AutomationElement>();
foreach (AutomationElement element in tabItems)
{
coll.Add(element);
}
bool NameMatch(string name)
{
return name == title || name.StartsWith(title + " ");
}
// short-circuit the search when no searched string cannot be found
if (!coll.Any(e => NameMatch(e.Current.Name)))
{
continue;
}
var t = new Stopwatch();
t.Start();
var withPoints = coll.AsParallel().Select(e =>
{
var point = new System.Windows.Point(int.MaxValue, int.MaxValue);
if (e.TryGetClickablePoint(out point))
{
}
return new
{
Name = e.Current.Name,
Element = e,
Point = point
};
}).OrderBy(e => e.Point.X);
foreach (var tabItem in withPoints)
{
index++;
var name = tabItem.Name;
if (NameMatch(name))
{
SetForegroundWindow(proc.MainWindowHandle); // activate window
Select(index); // select tab
return true;
}
}
}
return false;
}
And the method to select the tab:
public void Select(int tabIndex)
{
const int maxShortcutNumber = 8;
if (tabIndex <= 0) { return; }
KeyDown(LCtrl);
if (tabIndex <= maxShortcutNumber)
{
KeyPress(GetKeyNumber(tabIndex));
}
else
{
KeyPress(GetKeyNumber(maxShortcutNumber));
for (var i = 0; i < tabIndex - maxShortcutNumber; i++)
{
i.Dump();
const int timeToDigestPreviousKeyPress = 75;
Thread.Sleep(timeToDigestPreviousKeyPress);
KeyPress(Tab);
}
}
KeyUp(LCtrl);
}
And keyboard handling methods (adapted from KeyboardSend class)
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public static byte GetKeyNumber(int number)
{
if (number < 0 || number > 9)
throw new ApplicationException("Invalid number for key press.");
return (byte)(0x30 + number);
}
public static void KeyDown(byte vKey)
{
keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY, 0);
}
public static void KeyUp(byte vKey)
{
keybd_event(vKey, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
public static void KeyPress(byte vKey)
{
KeyDown(vKey);
KeyUp(vKey);
}
public static byte LCtrl = 0xA2; //VK_LCONTROL
public static byte LWin = 0x5B; //VK_LWIN
public static byte LAlt = 0xA4; //VK_LMENU
public static byte Tab = 0x09; //VK_TAB
private const int KEYEVENTF_EXTENDEDKEY = 1;
private const int KEYEVENTF_KEYUP = 2;

How to get the PIDL of any folder to use in RegisterChangeNotify

I want to watch a folder (for example 'c:\test') for changes.
I found the following piece of code but I don't know how to get to the FolderPIDL for any given folder.
public ulong RegisterChangeNotify(IntPtr hWnd, IntPtr FolderPIDL, bool Recursively)
{
if(notifyid != 0) return(0);
SHChangeNotifyEntry changeentry = new SHChangeNotifyEntry();
changeentry.pIdl = FolderPIDL;
changeentry.Recursively = Recursively;
notifyid = SHChangeNotifyRegister(
hWnd,
SHCNF.SHCNF_TYPE | SHCNF.SHCNF_IDLIST,
SHCNE.SHCNE_ALLEVENTS | SHCNE.SHCNE_INTERRUPT,
WM_SHNOTIFY,
1,
ref changeentry);
return(notifyid);
}
Any ideas?
Thanks
You can find a PIDL from a path with the ILCreateFromPath method (for a real file/folder path):
IntPtr pidl = ILCreateFromPath(#"c:\path\file.ext");
if (pidl != IntPtr.Zero)
try
{
// do something
}
finally
{
Marshal.FreeCoTaskMem(pidl);
}

Check if a Winform CheckBox is checked through WINAPI only

my problem goes like this :
I need to check if a winform checkbox from a different program is checked or not by WINAPI only.
here how I catch the underlyined C# HWND:
first I get all the HWND's of the desktop with EnumWindows and then EnumChildWindows , then I go on each one and with GetWindowText compares my wanted text to the window text and if there is a match - I return it.
just to make things clear - I can catch the underlying HWND. if I print its text and the class name it is the winform checkbox wanted.
now, the checkbox I want to check has WindowsForm.10.BUTTON.app.0.33c0d9d5 class name. with this function I ask it if its a valid checkbox:
bool isValid(){
if(!handleToControl) return false;
LONG_PTR styles = GetWindowLongPtr(handleToControl, GWL_STYLE);
bool isCheckBox = ((styles & BS_AUTO3STATE) == BS_AUTO3STATE);
isCheckBox = isCheckBox || ((styles & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX);
isCheckBox = isCheckBox || ((styles & BS_CHECKBOX) == BS_CHECKBOX);
return isCheckBox;
}
now, the function does work (I checked it on many native checkboxes and also winform checkboxes) and it can validate if it's a valid checkbox or not (including the checkbox I want to check)
then , I try to see if the winform checkbox is checked or not with this function:
bool isChecked(){
LRESULT _isChecked = SendMessage(handleToControl, BM_GETCHECK, 0, 0);
bool ic = !(_isChecked == BST_UNCHECKED);
if (ic)
return ic;
ic = ((Button_GetState(handleToControl) & BST_CHECKED) == BST_CHECKED);
if (ic)
return ic;
return false;
}
but I fail miserably. can someone see what's wrong with my idea / code or suggest a different solution?
Is using IAccessibility an option?
e.g.
(taken from http://bytes.com/topic/net/answers/637107-how-find-out-if-check-box-checked)
[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);
internal enum OBJID : uint
{
WINDOW = 0x00000000,
SYSMENU = 0xFFFFFFFF,
TITLEBAR = 0xFFFFFFFE,
MENU = 0xFFFFFFFD,
CLIENT = 0xFFFFFFFC,
VSCROLL = 0xFFFFFFFB,
HSCROLL = 0xFFFFFFFA,
SIZEGRIP = 0xFFFFFFF9,
CARET = 0xFFFFFFF8,
CURSOR = 0xFFFFFFF7,
ALERT = 0xFFFFFFF6,
SOUND = 0xFFFFFFF5,
}
public const long UNCHECKED = 1048576;
public const long CHECKED = 1048592;
public const long UNCHECKED_FOCUSED = 1048580; // if control is focused
public const long CHECKED_FOCUSED = 1048596; // if control is focused
private static bool IsChecked(IntPtr handle) {
Guid guid = new Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}");
Object obj = null;
int retValue = AccessibleObjectFromWindow(handle, (uint) OBJID.CLIENT, ref guid, ref obj);
if (obj is IAccessible) {
IAccessible accObj = (IAccessible) obj;
Object result = accObj.get_accState(0);
if (result is int) {
int state = (int) result;
return (state == CHECKED || state == CHECKED_FOCUSED);
}
}
return false;
}

Monitor (Display) Names and Bounds

My app has the ability to use a dual monitor configuration. In the app's settings I list the available displays where the user will choose his secondary screen.
I'm getting the (real) monitor device names using:
http://msdn.microsoft.com/en-us/library/aa394122%28VS.85%29.aspx
SelectQuery q = new SelectQuery("SELECT Name, DeviceID, ScreenHeight, ScreenWidth FROM Win32_DesktopMonitor");
using (ManagementObjectSearcher mos = new ManagementObjectSearcher(q))
{
foreach (ManagementObject mo in mos.Get())
{
...
}
}
But I also need the display bounds (top, left, etc) which this doesn't give me. But System.Windows.Forms.Screen does give me bounds but not real device names. I could use these together if I am certain that they return the devices in the same order every time. Will both of these always return "Device 1", "Device 2", etc in chronological order every time? Or is there a way that contains all my needed information?
[edit]
Hmm. Win32_DesptopMonitor isnt giving me my secondary monitors name. Its just calling it Default Monitor. And it's listing it before my primary.
[edit2]
Ok it's got the names and their resolutions messed up..... Anyone know whats going on here?
I have done this before using Win API calls. I pasted bits of the code below, which might be helpful to you...
public void Store()
{
Screens.Clear();
uint iAdaptorNum = 0;
Win.User32.DISPLAY_DEVICE adaptor = new Win.User32.DISPLAY_DEVICE();
adaptor.cb = (short)Marshal.SizeOf(adaptor);
Win.User32.DISPLAY_DEVICE dd = new Win.User32.DISPLAY_DEVICE();
dd.cb = (short)Marshal.SizeOf(dd);
while (Win.User32.EnumDisplayDevices(null, iAdaptorNum, ref adaptor, Win.User32.EDD_GET_DEVICE_INTERFACE_NAME))
{
uint iDevNum = 0;
while (Win.User32.EnumDisplayDevices(adaptor.DeviceName, iDevNum, ref dd, Win.User32.EDD_GET_DEVICE_INTERFACE_NAME))
{
log.WriteFormat(LogLevel.Debug, "Adaptor {0}:{1} {2}='{3}', Device {4}='{5}', State flags = {4}",
iAdaptorNum, iDevNum, adaptor.DeviceName, adaptor.DeviceString, dd.DeviceName, dd.DeviceString, dd.StateFlags);
if ((dd.StateFlags & Win.User32.DisplayDeviceStateFlags.AttachedToDesktop) > 0)
Screens.Add(new ScreenInfo(adaptor, dd));
iDevNum++;
}
iAdaptorNum++;
}
}
And this is what gets called behind new ScreenInfo:
public void StoreScreen(Win.User32.DISPLAY_DEVICE Adaptor, Win.User32.DISPLAY_DEVICE Device)
{
adaptor = Adaptor.DeviceName;
device = Device.DeviceName;
name = string.Format("{0} on {1}", Device.DeviceString, Adaptor.DeviceString);
Win.User32.DEVMODE dm = newDevMode();
if (Win.User32.EnumDisplaySettings(Adaptor.DeviceName, Win.User32.ENUM_CURRENT_SETTINGS, ref dm) != 0)
{
isAttached = (Adaptor.StateFlags & Win.User32.DisplayDeviceStateFlags.AttachedToDesktop) > 0;
isPrimary = (Adaptor.StateFlags & Win.User32.DisplayDeviceStateFlags.PrimaryDevice) > 0;
mode = findMode(Adaptor.DeviceName, dm);
if ((dm.dmFields & Win.User32.DM.PelsWidth) > 0) width = dm.dmPelsWidth;
if ((dm.dmFields & Win.User32.DM.PelsHeight) > 0) height = dm.dmPelsHeight;
if ((dm.dmFields & Win.User32.DM.BitsPerPixel) > 0) bpp = dm.dmBitsPerPel;
if ((dm.dmFields & Win.User32.DM.Orientation) > 0) orientation = dm.dmOrientation;
if ((dm.dmFields & Win.User32.DM.DisplayFrequency) > 0) frequency = dm.dmDisplayFrequency;
if ((dm.dmFields & Win.User32.DM.DisplayFlags) > 0) flags = dm.dmDisplayFlags;
if ((dm.dmFields & Win.User32.DM.Position) > 0)
{
posX = dm.dmPosition.x;
posY = dm.dmPosition.y;
}
}
}
private static Win.User32.DEVMODE newDevMode()
{
Win.User32.DEVMODE dm = new Win.User32.DEVMODE();
dm.dmDeviceName = new String(new char[31]);
dm.dmFormName = new String(new char[31]);
dm.dmSize = (short)Marshal.SizeOf(dm);
return dm;
}

Setting focus to already opened Tab of Internet Explorer from C# program using .net 2.0

I have two questions.
How can I set focus to already opened Tab of Internet Explorer from C# program using .net 2.0.
How can I open a new URL in a new Tab of running Internet Explorer instance (not in new window.) from C# program.
I can only use .net up to 2.0.
Your help will be appreciated.
Here is the code how to activate tab based on URL address of the tab. I tested and it works fine. You can add your functionality how to activate tab based on Text/Description, etc. If you need have it running under .net 2.0 then change var to specific type.
Here is an actual code itself. I wrapped it in separate class.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Accessibility;
namespace IETabsInteraction
{
internal class TabActivator
{
#region Nested type: OBJID
private enum OBJID : uint
{
OBJID_WINDOW = 0x00000000,
}
#endregion
#region Declarations
private const int CHILDID_SELF = 0;
private readonly IntPtr _hWnd;
private IAccessible _accessible;
[DllImport("oleacc.dll")]
private static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid,
[In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object
ppvObject);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
string lpszWindow);
[DllImport("oleacc.dll")]
private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] object[] rgvarChildren, out int pcObtained);
#endregion
#region Constructors
internal TabActivator(IntPtr ieHandle)
{
_hWnd = ieHandle;
AccessibleObjectFromWindow(GetDirectUIHWND(ieHandle), OBJID.OBJID_WINDOW, ref _accessible);
CheckForAccessible();
}
private TabActivator(IAccessible acc)
{
if (acc == null)
throw new Exception("Could not get accessible");
_accessible = acc;
}
#endregion
private TabActivator[] Children
{
get
{
var num = 0;
var res = GetAccessibleChildren(_accessible, out num);
if (res == null)
return new TabActivator[0];
var list = new List<TabActivator>(res.Length);
foreach (object obj in res)
{
var acc = obj as IAccessible;
if (acc != null)
list.Add(new TabActivator(acc));
}
return list.ToArray();
}
}
private int ChildCount
{
get { return _accessible.accChildCount; }
}
/// <summary>
/// Gets LocationUrl of the tab
/// </summary>
private string LocationUrl
{
get
{
var url = _accessible.accDescription[CHILDID_SELF];
if (url.Contains(Environment.NewLine))
url = url.Split('\n')[1];
return url;
}
}
private void CheckForAccessible()
{
if (_accessible == null)
throw new Exception("Could not get accessible. Accessible can't be null");
}
internal void ActivateByTabsUrl(string tabsUrl)
{
var tabIndexToActivate = GetTabIndexToActivate(tabsUrl);
AccessibleObjectFromWindow(GetDirectUIHWND(_hWnd), OBJID.OBJID_WINDOW, ref _accessible);
CheckForAccessible();
var index = 0;
var ieDirectUIHWND = new TabActivator(_hWnd);
foreach (var accessor in ieDirectUIHWND.Children)
{
foreach (var child in accessor.Children)
{
foreach (var tab in child.Children)
{
if (tabIndexToActivate >= child.ChildCount - 1)
return;
if (index == tabIndexToActivate)
{
tab.ActivateTab();
return;
}
index++;
}
}
}
}
private void ActivateTab()
{
_accessible.accDoDefaultAction(CHILDID_SELF);
}
private int GetTabIndexToActivate(string tabsUrl)
{
AccessibleObjectFromWindow(GetDirectUIHWND(_hWnd), OBJID.OBJID_WINDOW, ref _accessible);
CheckForAccessible();
var index = 0;
var ieDirectUIHWND = new TabActivator(_hWnd);
foreach (var accessor in ieDirectUIHWND.Children)
{
foreach (var child in accessor.Children)
{
foreach (var tab in child.Children)
{
var tabUrl = tab.LocationUrl;
if (!string.IsNullOrEmpty(tabUrl))
{
if (tab.LocationUrl.Contains(tabsUrl))
return index;
}
index++;
}
}
}
return -1;
}
private IntPtr GetDirectUIHWND(IntPtr ieFrame)
{
// For IE 8:
var directUI = FindWindowEx(ieFrame, IntPtr.Zero, "CommandBarClass", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "ReBarWindow32", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "TabBandClass", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "DirectUIHWND", null);
if (directUI == IntPtr.Zero)
{
// For IE 9:
//directUI = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", "Navigation Bar");
directUI = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "ReBarWindow32", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "TabBandClass", null);
directUI = FindWindowEx(directUI, IntPtr.Zero, "DirectUIHWND", null);
}
return directUI;
}
private static int AccessibleObjectFromWindow(IntPtr hwnd, OBJID idObject, ref IAccessible acc)
{
var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessibleobject obj = null;
object obj = null;
var num = AccessibleObjectFromWindow(hwnd, (uint) idObject, ref guid, ref obj);
acc = (IAccessible) obj;
return num;
}
private static object[] GetAccessibleChildren(IAccessible ao, out int childs)
{
childs = 0;
object[] ret = null;
var count = ao.accChildCount;
if (count > 0)
{
ret = new object[count];
AccessibleChildren(ao, 0, count, ret, out childs);
}
return ret;
}
}
}
To execute this code use:
var hWnd = (IntPtr)ie.HWND;
new TabActivator(hWnd).ActivateByTabsUrl("www.stackoverflow.com");
To answer your second question. You will need to find ie that you have already running:
private static void OpenTabInExistingIE()
{
var shellWindows = new ShellWindows();
// check if IE is open
if (shellWindows.Count > 0)
((InternetExplorer)shellWindows.Item(0)).Navigate2("www.stackoverflow.com", 2048);
}
For all these code you will have to add reference to SHDocVw.dll and
#using SHDocVw;
Here are flags for Navigate2 method
Enum BrowserNavConstants
navOpenInNewWindow = 1
navNoHistory = 2
navNoReadFromCache = 4
navNoWriteToCache = 8
navAllowAutosearch = 16
navBrowserBar = 32
navHyperlink = 64
navEnforceRestricted = 128
navNewWindowsManaged = 256
navUntrustedForDownload = 512
navTrustedForActiveX = 1024
navOpenInNewTab = 2048
navOpenInBackgroundTab = 4096
navKeepWordWheelText = 8192
navVirtualTab = 16384
navBlockRedirectsXDomain = 32768
navOpenNewForegroundTab = 65536
End Enum

Categories