Get Internet Explorer tab title - c#

I am trying to get a list of all the open IE tab titles or search for a specific tab title.
I've been using this but does not work for every tab for some reason:
// Get a handle to an application window.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
IntPtr explorerHandle = FindWindow("IEFrame", "Google - Internet Explorer");
// Verify that we found the Window.
if (explorerHandle == IntPtr.Zero)
{
MessageBox.Show("Didn't find an instance of IE");
return;
}
I am particularly looking for tabs which have "This page can’t be displayed" in the title.
Any suggestions?

The last time I needed to do something like that I used this code: (It's working !)
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static public extern IntPtr GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
list.Add(handle);
return true;
}
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
Win32Callback childProc = new Win32Callback(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
public static string GetWinClass(IntPtr hwnd)
{
if (hwnd == IntPtr.Zero)
return null;
StringBuilder classname = new StringBuilder(100);
IntPtr result = GetClassName(hwnd, classname, classname.Capacity);
if (result != IntPtr.Zero)
return classname.ToString();
return null;
}
public static IEnumerable<IntPtr> EnumAllWindows(IntPtr hwnd, string childClassName)
{
List<IntPtr> children = GetChildWindows(hwnd);
if (children == null)
yield break;
foreach (IntPtr child in children)
{
if (GetWinClass(child) == childClassName)
yield return child;
foreach (var childchild in EnumAllWindows(child, childClassName))
yield return childchild;
}
}
And to use it :
IntPtr handle = FindWindow("IEFrame", "Google");
var hwndChilds = EnumAllWindows(handle, "Frame Tab");
hwndChilds is a list of IntPtr to all of Frame Tab.
EDIT :
I complete my answer with the next steps to get the title of your tabs.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [Out] StringBuilder lParam);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);
public static string GetWindowTextRaw(IntPtr hwnd)
{
uint WM_GETTEXT = 0x000D;
uint WM_GETTEXTLENGTH = 0x000E;
// Allocate correct string length first
int length = (int)SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, null);
StringBuilder sb = new StringBuilder(length + 1);
SendMessage(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
You can test it with :
static void Main(string[] args)
{
IntPtr handle = FindWindow("IEFrame", "Google");
var hwndChild = EnumAllWindows(handle, "Frame Tab");
foreach (var intPtr in hwndChild)
{
var ptr = GetParent(intPtr);
var text = GetWindowTextRaw(ptr);
Console.WriteLine(text);
}
Console.ReadLine();
}
and the result :
If you need more explanations don't hesitate to ask.
You can find all pInvoke signatures on http://www.pinvoke.net/
Have a great day !

Related

Get handle of child window to postmessage in C#

im looking how to get handle of child window and postmessage there.
My code:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//This send postmessage to window "192.168.0.94 - Remote Desktop Connection"//
IntPtr hwnd10 = FindWindow(null, "192.168.0.94 - Remote Desktop Connection");
Point location = new Point(636, 324);
PostMessage(hwnd10, WM_MOUSEMOVE, 0, MAKELPARAM(location.X, location.Y));
PostMessage(hwnd10, WM_LBUTTONDOWN, 0x1, MAKELPARAM(location.X, location.Y));
PostMessage(hwnd10, WM_LBUTTONUP, 0, MAKELPARAM(location.X, location.Y));
// But now how can i do the same to child window "Input Capture Window"?
I do some research and i found [pageenumchildwindows][1] but don't know exacly how can i use it in my example.
Screenshoot to see what window exacly am i looking for :
OK i found solution thanks to Oguz Ozgul.
I did it by FindWindowEx like :
IntPtr child = FindWindowEx(hwnd10, IntPtr.Zero, "TscShellAxHostClass", null);
//check if window is caught
if(child!=IntPtr.Zero)
{
Console.WriteLine("Findow TscShellAxHostClass found!!!");
child = FindWindowEx(child, IntPtr.Zero, "ATL:00007FFC92EAF400", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow ATL:00007FFC92EAF400 found!!!");
child = FindWindowEx(child, IntPtr.Zero, "UIMainClass", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow UIMainClass found!!!");
child = FindWindowEx(child, IntPtr.Zero, "UIContainerClass", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow UIContainerClass found!!!");
child = FindWindowEx(child, IntPtr.Zero, "IHWindowClass", null);
if (child != IntPtr.Zero)
{
Console.WriteLine("Findow IHWindowClass found!!!");
}
}
}
}
}
Here is another implementation, using EnumWindows and EnumChildWindows.
This answer is not meant to be marked, but shows a different approach to the same problem.
It searches for a depth of 3, which can be increased in the code or even can be got as a constructor or method parameter.
It works.
public class RecursiveWindowSearcher
{
public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32")]
public extern static int EnumWindows(EnumWindowsProc lpEnumFunc, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private IntPtr windowParent;
private string windowName;
private IntPtr windowPointer;
public RecursiveWindowSearcher(string windowName, IntPtr windowParent)
{
this.windowName = windowName;
this.windowParent = windowParent;
}
public bool WinApiCallback(IntPtr hwnd, IntPtr lParam)
{
Console.WriteLine("Window: {0}", hwnd);
StringBuilder windowNameFar = new StringBuilder(256);
GetWindowText(hwnd, windowNameFar, 256);
if (windowNameFar.ToString() == windowName)
{
windowPointer = hwnd;
return false;
}
Console.WriteLine("Name: {0}", windowNameFar);
if(indent == 6)
{
return false;
}
indent += 2;
EnumChildWindows(hwnd, WinApiCallback, IntPtr.Zero);
indent -= 2;
return true;
}
public IntPtr Find()
{
this.windowPointer = IntPtr.Zero;
if (windowParent == IntPtr.Zero)
{
EnumWindows(WinApiCallback, 0);
}
else
{
EnumChildWindows(windowParent, WinApiCallback, IntPtr.Zero);
}
return windowPointer;
}
}
And the usage is simple enough:
The second constructor parameter is a pointer to an existing window to search starting from. If you have this handle, you can pass it to narrow the search scope to a specific window and its children.
static void Main()
{
IntPtr windowFound = new RecursiveWindowSearcher("Skype for Business ", IntPtr.Zero).Find();
Console.ReadLine();
}

Can't toggle 'Align icons to grid' on the desktop

Here's the code I'm using:
private void Button_Click(object sender, RoutedEventArgs e) {
SendMessage(GetDesktopWindow(), LVM_ARRANGE, LVA_SNAPTOGRID, 0);
}
public const uint LVM_ARRANGE = 0x1000 + 22;
public const int LVA_SNAPTOGRID = 0x0005;
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
Nothing happens when I run it. Code is borrowed from https://www.codeproject.com/Messages/1168961/Re-Auto-Arrange-desktop-icons.aspx
Tried different Windows versions too.
This code worked for me. Note that it doesn't appear to change the options, so although it arranges to the grid for me the View->Align Icons To Grid is still unchecked. The issue is outlined here: How do I get the window handle of the desktop?
Your problem results from a fairly widespread confusion over what the
desktop window actually is. The GetDesktopWindow function does
precisely what it's documented to do: it returns a handle to the
desktop window. This, however, is not the same window that contains
the desktop icons.
So I used the answer here: Get handle to desktop / shell window but with replacing or adding methods and p/invoke calls until I had everything necessary because that link only gives method calls and not the dll imports (I may have left some superfluous stuff in here).
static void Main()
{
SendMessage(GetDesktopWindow(DesktopWindow.SysListView32), LVM_ARRANGE, LVA_SNAPTOGRID, 0);
Console.ReadLine();
}
public const int LVM_ARRANGE = 4118;
public const int LVA_SNAPTOGRID = 5;
[DllImport("user32.dll")]
static extern IntPtr GetShellWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowTextLength(IntPtr hWnd);
public enum DesktopWindow
{
ProgMan,
SHELLDLL_DefViewParent,
SHELLDLL_DefView,
SysListView32
}
public static IntPtr GetDesktopWindow(DesktopWindow desktopWindow)
{
IntPtr _ProgMan = GetShellWindow();
IntPtr _SHELLDLL_DefViewParent = _ProgMan;
IntPtr _SHELLDLL_DefView = FindWindowEx(_ProgMan, IntPtr.Zero, "SHELLDLL_DefView", null);
IntPtr _SysListView32 = FindWindowEx(_SHELLDLL_DefView, IntPtr.Zero, "SysListView32", "FolderView");
if (_SHELLDLL_DefView == IntPtr.Zero)
{
EnumWindows((hwnd, lParam) =>
{
if (GetWindowText(hwnd) == "WorkerW")
{
IntPtr child = FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null);
if (child != IntPtr.Zero)
{
_SHELLDLL_DefViewParent = hwnd;
_SHELLDLL_DefView = child;
_SysListView32 = FindWindowEx(child, IntPtr.Zero, "SysListView32", "FolderView"); ;
return false;
}
}
return true;
}, IntPtr.Zero);
}
switch (desktopWindow)
{
case DesktopWindow.ProgMan:
return _ProgMan;
case DesktopWindow.SHELLDLL_DefViewParent:
return _SHELLDLL_DefViewParent;
case DesktopWindow.SHELLDLL_DefView:
return _SHELLDLL_DefView;
case DesktopWindow.SysListView32:
return _SysListView32;
default:
return IntPtr.Zero;
}
}
public static string GetWindowText(IntPtr hWnd)
{
int size = GetWindowTextLength(hWnd);
if (size > 0)
{
var builder = new StringBuilder(size + 1);
GetWindowText(hWnd, builder, builder.Capacity);
return builder.ToString();
}
return String.Empty;
}

Obtain child window from Process.MainWindowHandle

I want to get a textbox handle from process name. I checked it with Spy++ (it's an exe found in the internet, so nothing special):
now i want to get this TEdit, but it always return NULL. What am I doing wrong?
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);
private static void Main(string[] args)
{
var processes = Process.GetProcesses();
var proc = Array.Find(processes, x => string.Equals(x.MainWindowTitle, "ExeLock", StringComparison.OrdinalIgnoreCase));
var handle = proc.MainWindowHandle;
//IntPtr edit = FindWindowEx(handle, IntPtr.Zero, "TEdit", null);
IntPtr hwndparent = handle, hwndchild = IntPtr.Zero;
do
{
hwndchild = FindWindowEx(hwndparent, hwndchild, null, null);
} while (hwndchild != IntPtr.Zero);
}
I didn't found it because it creates multiple windows and some of them are hidden (including "main window"). Here is screenshot:
So I just enum every window of a process, find TFormPassDialog and then everything works fine. Here is my code:
class ExeLockFounder
{
const uint WM_SETTEXT = 0x000C;
delegate bool EnumDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
private static IntPtr GetWindowByClassName(IEnumerable<IntPtr> windows, string className)
{
foreach (var window in windows)
{
var sb = new StringBuilder(256);
GetClassName(window, sb, sb.Capacity);
if (sb.ToString() == className)
return window;
}
return IntPtr.Zero;
}
static IEnumerable<IntPtr> EnumerateProcessWindowHandles(Process process)
{
var handles = new List<IntPtr>();
foreach (ProcessThread thread in process.Threads)
EnumThreadWindows(thread.Id, (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
return handles;
}
private readonly IntPtr _editHandle;
public ExeLockFounder()
{
var processes = Process.GetProcessesByName("Setup");
var proc = Array.Find(processes, x => string.Equals(x.MainWindowTitle, "ExeLock", StringComparison.OrdinalIgnoreCase));
var windows = EnumerateProcessWindowHandles(proc);
var hWnd = GetWindowByClassName(windows, "TFormPassDialog");
_editHandle = FindWindowEx(hWnd, IntPtr.Zero, "TEdit", null);
}
public void SendText(string message)
{
SendMessage(_editHandle, WM_SETTEXT, IntPtr.Zero, message);
}
}

Get the focused window name

I'm trying to get the name of the current focused window. Thanks to my research, I have this code :
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private static bool IsFocused(string name)
{
StringBuilder buffer = new StringBuilder(256);
if (GetWindowText(GetForegroundWindow(), buffer, buffer.Length + 1) > 0)
{
if (buffer.ToString() == name)
{
return true;
}
}
return false;
}
I've checked, the handle returned by GetForegoundWindow() is the correct one. But GetWindowText() always returns a null or negative value.
You need to get the length of the text
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
private static bool IsFocused(string name)
{
var handle = GetForegroundWindow();
var length = GetWindowTextLength(handle);
var builder = new StringBuilder(length + 1);
GetWindowText(handle, builder, builder.Capacity);
return builder.ToString() == name;
}

Windows 7 left click on clock popup

When left single click on the clock in the taskbar on Windows 7 (maybe Vista too) a popup opens showing calender and clock(s) (thus not the date and time adjust window). How do I open this window myself (preferred in C#)?
I was hoping timedate.cpl would call this, but this opens the date and time adjust window.
To show the clock you need to send the appropriate window message to the tray window. This can be done using the Windows API function SendMessage:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
class ShowCalendar
{
private delegate bool EnumChildCallback(IntPtr hwnd,
ref IntPtr lParam);
[DllImport("User32.dll")]
private static extern bool EnumChildWindows(IntPtr hWndParent,
EnumChildCallback lpEnumFunc,
ref IntPtr lParam);
[DllImport("User32.dll")]
private static extern int GetClassName(IntPtr hWnd,
StringBuilder lpClassName,
int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd,
UInt32 Msg,
IntPtr wParam,
IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd,
out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private static readonly string TrayWndClassName = "Shell_TrayWnd";
private static readonly string TrayNotifyWndClassName = "TrayNotifyWnd";
private static readonly string ClockWndClassName = "TrayClockWClass";
private static readonly uint WM_NCLBUTTONDOWN = 0x00A1;
private static readonly uint HTCAPTION = 2;
private static bool EnumChildProc(IntPtr hwndChild, ref IntPtr lParam)
{
StringBuilder className = new StringBuilder(128);
GetClassName(hwndChild, className, 128);
if (className.ToString() == ClockWndClassName)
{
lParam = hwndChild;
return false;
}
return true;
}
static void Main(string[] args)
{
IntPtr hWndTray = FindWindow(TrayWndClassName, string.Empty);
if (hWndTray == IntPtr.Zero)
{
throw new Win32Exception();
}
IntPtr hWndTrayNotify = FindWindowEx(hWndTray,
IntPtr.Zero,
TrayNotifyWndClassName,
string.Empty);
if (hWndTrayNotify == IntPtr.Zero)
{
throw new Win32Exception();
}
// search clock window
EnumChildCallback cb = new EnumChildCallback(EnumChildProc);
IntPtr hWndClock = IntPtr.Zero;
EnumChildWindows(hWndTray, cb, ref hWndClock);
if (hWndClock == IntPtr.Zero)
{
throw new Win32Exception();
}
// get clock window position
RECT rect;
if (!GetWindowRect(hWndClock, out rect))
{
throw new Win32Exception();
}
// send click, lParam contains window position
IntPtr wParam = new IntPtr(HTCAPTION);
IntPtr lParam = new IntPtr(rect.Top << 16 | rect.Left);
SendMessage(hWndTray, WM_NCLBUTTONDOWN, wParam, lParam);
}
}

Categories