Obtain child window from Process.MainWindowHandle - c#

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);
}
}

Related

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;
}

Get Internet Explorer tab title

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 !

How to Click "Yes" button in order application with code

I have a code
private const int WM_CLOSE = 16;
private const int BN_CLICKED = 245;
[DllImport("User32.dll")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
public void Click(string _btnTitle)
{
int hwnd = 0;
IntPtr hwndChild = IntPtr.Zero;
//Get a handle for the Calculator Application main window
// foreach (Process p in Process.GetProcesses())
//{
hwnd = FindWindow(null, FrmTitle);
if (hwnd != 0)
{
hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Button", _btnTitle);
SendMessage((int)hwndChild, BN_CLICKED, 0, IntPtr.Zero);
}
}
I can't Click button "Yes" on MessageBox of application :(
Anyone got a tip? Tks
You aren't sending the correct message.
Try using BM_CLICK (0x00F5) in your call to SendMessage(). That should work provided that hwndChild is the window handle of the button, rather than the container dialog box.
BN_CLICKED doesn't work because that is a notification code, not a message.

Open Notepad and add Text not working

I just saw this snippet from the internet but it doesn't work from me.
It's suppose to open a new notepad application and add "asdf" into it.
Is there any wrong on the code?
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
void Test()
{
const int WM_SETTEXT = 0x000C;
ProcessStartInfo startInfo = new ProcessStartInfo("notepad.exe");
startInfo.UseShellExecute = false;
Process notepad = System.Diagnostics.Process.Start(startInfo);
SendMessage(notepad.MainWindowHandle, WM_SETTEXT, 0, "asdf");
}
To make sure that process is ready to accept input, call notepad.WaitForInputIdle(). And it is important to use MainWindowHandle of the process that was just created, not the any notepad process.
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
static void ExportToNotepad(string text)
{
ProcessStartInfo startInfo = new ProcessStartInfo("notepad");
startInfo.UseShellExecute = false;
Process notepad = Process.Start(startInfo);
notepad.WaitForInputIdle();
IntPtr child = FindWindowEx(notepad.MainWindowHandle, new IntPtr(0), null, null);
SendMessage(child, 0x000c, 0, text);
}
Following Code will do the trick for you,
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
private void button1_Click(object sender, EventArgs e)
{
Process [] notepads=Process.GetProcessesByName("notepad");
if(notepads.Length==0)return;
if (notepads[0] != null)
{
IntPtr child= FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000C, 0, textBox1.Text);
}
}
try this:
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
void Test()
{
ProcessStartInfo startInfo = new ProcessStartInfo("notepad.exe");
startInfo.UseShellExecute = false;
Process notepad = System.Diagnostics.Process.Start(startInfo);
//Wait Until Notpad Opened
Thread.Sleep(100);
Process[] notepads = Process.GetProcessesByName("notepad");
IntPtr child = FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000c, 0, "test");
}

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