Have been struggling with this for the past 5 days so have decided to post this issue.
I have an application that is attached to a IE toolbar (IE Addon). If one instance of IE is opened (without any tabs), application works fine. However, if we have more than one tabs opened, it will try to process all the Tabs rather than the one the button was clicked within.
The problem being that the HWND (from IE.HWND) value generated by all the tabs are the same including the parent tabs.
This is the check I'm performing before launching the application:
Dim SWs As New SHDocVw.ShellWindows
Dim IE As SHDocVw.InternetExplorer
Dim mhWnd As Long
myhWnd = GetForegroundWindow()
For Each IE In SWs
If Strings.Left(IE.LocationURL, 4) = "http" Then 'if the document is IE then proceed because EXPLORER window returns in the same group
Set Doc = IE.document
MsgBox ("Debugging 3 IE.hwnd :" & IE.hwnd & "myHwnd : " & myhWnd)
If (IE.hwnd = myhWnd ) Then
'application launch code
Each time the above runs, it tries to process all the opened tabs which on the contrary, I'm only interested in the tab the user is currently on.
Have tried to use IAccessibility to identify the current tab but IAccessible keeps returning null. Please see IAccessibility code below:
using System;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using SHDocVw;
using Accessibility;
using System.Windows.Forms;
namespace FinWindowsTab
{
public class FindWindowsTab
{
public enum OBJID : uint
{
OBJID_WINDOW = 0x00000000,
}
private const int IE_ACTIVE_TAB = 2097154;
private const int CHILDID_SELF = 0;
private IAccessible accessible;
private FindWindowsTab[] Children;
public static void Main(String[] args)
{
// InternetExplorer IE = new InternetExplorer();
ShellWindows SW = new ShellWindows();
try
{
foreach (InternetExplorer IE in SW)
{
if (IE.Name == "Windows Internet Explorer")
{
string urlOfTabToActivate = IE.LocationURL;
var directUi = GetDirectUIHWND((IntPtr)IE.HWND);
var iacc = AccessibleObjectFromWindow(directUi);
var tabRow = FindAccessibleDescendant(iacc, "Tab Row");
var tabs = AccChildren(tabRow);
int tc = tabs.Count;
int k = 0;
// walk through the tabs and tick the chosen one
foreach (var candidateTab in tabs)
{
k++;
// the last tab is "New Tab", which we don't want
if (k == tc) continue;
// the URL on *this* tab
string localUrl = UrlForTab(candidateTab);
MessageBox.Show("Local Url :" + localUrl);
// same? if so, tick it. This selects the given tab among all
// the others, if any.
if (urlOfTabToActivate != null && localUrl.Equals(urlOfTabToActivate))
{
candidateTab.accDoDefaultAction(0);
return;
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("An exception has occured : " + ex.Message);
}
}
private static IntPtr GetDirectUIHWND(IntPtr ieFrame)
{
// try IE 9 first:
IntPtr intptr = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", null);
if (intptr == IntPtr.Zero)
{
// IE8 and IE7
intptr = FindWindowEx(ieFrame, IntPtr.Zero, "CommandBarClass", null);
}
intptr = FindWindowEx(intptr, IntPtr.Zero, "ReBarWindow32", null);
intptr = FindWindowEx(intptr, IntPtr.Zero, "TabBandClass", null);
intptr = FindWindowEx(intptr, IntPtr.Zero, "DirectUIHWND", null);
return intptr;
}
private static IAccessible AccessibleObjectFromWindow(IntPtr hwnd)
{
Guid guid = new Guid("{2359BD84-0175-4783-8909-CBD181217D3C}"); // IAccessible
object obj = null;
uint id = 0U;
int num = AccessibleObjectFromWindow(hwnd, id, ref guid, ref obj);
var acc = (IAccessible)obj;
return acc;
}
private static object[] GetAccessibleChildren(IAccessible ao)
{
var childs = 0;
object[] ret = null;
int count = 0;
count = ao.accChildCount;
MessageBox.Show("Count value : " + count);
if (count > 0)
{
ret = new object[count];
AccessibleChildren(ao, 0, count, ret, out childs);
}
return ret;
}
private static IAccessible FindAccessibleDescendant(IAccessible parent, String strName)
{
int c = 0;
c = parent.accChildCount;
if (c == 0)
return null;
var children = AccChildren(parent);
foreach (var child in children)
{
if (child == null) continue;
if (strName.Equals(child.get_accName(0)))
return child;
var x = FindAccessibleDescendant(child, strName);
if (x != null) return x;
}
return null;
}
private static List<IAccessible> AccChildren(IAccessible accessible)
{
object[] res = GetAccessibleChildren(accessible);
var list = new List<IAccessible>();
if (res == null) return list;
foreach (object obj in res)
{
IAccessible acc = obj as IAccessible;
if (acc != null) list.Add(acc);
}
return list;
}
private static string UrlForTab(IAccessible tab)
{
try
{
var desc = tab.get_accDescription(0);
if (desc != null)
{
if (desc.Contains("\n"))
{
string url = desc.Substring(desc.IndexOf("\n")).Trim();
return url;
}
else
{
return desc;
}
}
}
catch { }
return "??";
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow
(IntPtr hwnd, uint id, ref Guid iid,
[In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);
[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);
}
}
Please any help will be appreciated.
Resolved this issue. Just incase anyone found themselves in this scenario, this helped me http://www.codeproject.com/Articles/204929/Getting-current-browser-URL-with-VB-NET