How delegates and callback work? - c#

I don't fully understand these topics.
I work with several WinAPI methods
public delegate bool Win32Callback(IntPtr hwnd, ref IntPtr lParam);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
and
public static bool BrowserEnumChildrenCallback(IntPtr hWnd, ref IntPtr lParam)
{
if (hWndMeetsConditions)
return true;
//code
return false;
}
Is it possible get hWnd for which was returned true from BrowserEnumChildrenCallback?
Win32Callback callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
if (EnumChildWindows(hWnd, callBack, hWnd))
{
//here
}

Several problems:
The delegate declaration is wrong, the last argument is IntPtr, not ref IntPtr.
The callback should return true to continue iterating, you're doing it backwards
Write GC.KeepAlive(callBack) after the EnumChildWindows() call to prevent the delegate object from getting garbage collected.
Don't use the return value of EnumChildWindows(), the SDK docs note that it is unused. You detect failure by not finding the window.
Answering the actual question: store the window handle in a field of your class. Thus:
private IntPtr windowFound;
private void iterateChildWindows(IntPtr parent) {
windowFound = IntPtr.Zero;
var callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
EnumChildWindows(parent, callBack, IntPtr.Zero);
GC.KeepAlive(callBack);
if (windowFound != IntPtr.Zero) {
// etc..
}
}
private bool BrowserEnumChildrenCallback(IntPtr hWnd, IntPtr lParam)
{
if (hWndMeetsConditions(hWnd)) {
windowFound = hWnd;
return false;
}
return true;
}
A lambda works well too.

List<IntPtr> _hwnds = new List<IntPtr>();
public static bool BrowserEnumChildrenCallback(IntPtr hWnd, ref IntPtr lParam)
{
if (hWndMeetsConditions)
{
_hwnds.Add( hWnd );
return true;
}
//code
return false;
}
Win32Callback callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
if (EnumChildWindows(hWnd, callBack, hWnd))
{
// here
// you have it in _hwnd
}

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

Get All Children Window Handles [duplicate]

I have the handle for a given window. How can I enumerate its child windows?
Here you have a working solution:
public class WindowHandleInfo
{
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
private IntPtr _MainHandle;
public WindowHandleInfo(IntPtr handle)
{
this._MainHandle = handle;
}
public List<IntPtr> GetAllChildHandles()
{
List<IntPtr> childHandles = new List<IntPtr>();
GCHandle gcChildhandlesList = GCHandle.Alloc(childHandles);
IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(this._MainHandle, childProc, pointerChildHandlesList);
}
finally
{
gcChildhandlesList.Free();
}
return childHandles;
}
private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
{
GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);
if (gcChildhandlesList == null || gcChildhandlesList.Target == null)
{
return false;
}
List<IntPtr> childHandles = gcChildhandlesList.Target as List<IntPtr>;
childHandles.Add(hWnd);
return true;
}
}
How to consume it:
class Program
{
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
static void Main(string[] args)
{
Process[] anotherApps = Process.GetProcessesByName("AnotherApp");
if (anotherApps.Length == 0) return;
if (anotherApps[0] != null)
{
var allChildWindows = new WindowHandleInfo(anotherApps[0].MainWindowHandle).GetAllChildHandles();
}
}
}
Using:
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
you will get callbacks on the function you pass in.
I've found the best solution to be Managed WindowsAPI. It had a CrossHair control that could be used to select a window(not part of the question), and a method AllChildWindows to get all child windows which likely wrapped the EnumChildWindows function. Better not to reinvent the wheel.
Use EnumChildWindows, with p/invoke. Here's an interesting link about some of it's behavior: https://blogs.msdn.microsoft.com/oldnewthing/20070116-04/?p=28393
If you don't know the handle of the window, but only it's title, you'll need to use EnumWindows. http://pinvoke.net/default.aspx/user32/EnumWindows.html
Here is a managed alternative to EnumWindows, but you will still need to use EnumChildWindows to find the handle of the child window.
foreach (Process process in Process.GetProcesses())
{
if (process.MainWindowTitle == "Title to find")
{
IntPtr handle = process.MainWindowHandle;
// Use EnumChildWindows on handle ...
}
}

Error : CallbackOnCollectedDelegate - how to find the exact collected item?

After few minutes of successfull running I get this error in my application.
A callback was made on a garbage collected delegate of type
'myApp!myApp.globalKeyboardHook+keyboardHookProc::Invoke'.
I know this is because the garbage collector has killed an object or something else and my code is still referring the same thing.
If that is the case which object or component is more likely to be collected by the GC. How can I overcome this error. (having a ref ??)
Since I cant figure out which part of the code is in responsible for this issue, I'm posting the complete class here. (I guess it has no issue with my other classes)
class globalKeyboardHook
{
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public struct keyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
IntPtr hInstance;
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr hhook = IntPtr.Zero;
// Events
public event KeyEventHandler KeyDown;
public globalKeyboardHook()
{
hook();
}
~globalKeyboardHook()
{
unhook();
}
public void hook()
{
hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(hhook);
}
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (1 == 1)
{
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
// DLL imports
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
}
}
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
You'll certainly have trouble finding the collected item, it is not visible in your program. The C# language is a bit too friendly here. You are relying on its syntax sugar to automagically create a delegate object for hookProc. This code is compiled to:
keyboardHookProc $unspeakable = new keyboardHookProc(hookProc);
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, $unspeakable, hInstance, 0);
Which is a problem in pinvoke, the garbage collector has no idea that the $unspeakable delegate object is actually being used by native code. It can only see managed references to objects. So it collects the object as soon as a gen #0 garbage collection occurs. Kaboom when Windows makes the hook callback.
It is up to you to ensure that this delegate object cannot be collected. Use GCHandle.Alloc(). Or the simple way, storing it in a variable explicitly. Which is fine here since you let the finalizer destroy the hook:
IntPtr hhook = IntPtr.Zero;
keyboardHookProc callback;
public void hook()
{
if (callback != null) throw new InvalidOperationException("Hook already installed");
if (hInstance == IntPtr.Zero) hInstance = LoadLibrary("User32");
callback = new keyboardHookProc(hookProc);
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, callback, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(hhook);
callback = null;
}

Get all window handles for a process

Using Microsoft Spy++, I can see that the following windows that belong to a process:
Process XYZ window handles, displayed in tree form just like Spy++ gives me:
A
B
C
D
E
F
G
H
I
J
K
I can get the process, and the MainWindowHandle property points to the handle for window F. If I enumerate the child windows using I can get a list of window handles for G through K, but I can't figure out how to find the window handles for A through D. How can I enumerate windows that are not children of the handle specified by MainWindowHandle of the Process object?
To enumerate I'm using the win32 call:
[System.Runtime.InteropServices.DllImport(strUSER32DLL)]
public static extern int EnumChildWindows(IntPtr hWnd, WindowCallBack pEnumWindowCallback, int iLParam);
Pass IntPtr.Zero as hWnd to get every root window handle in the system.
You can then check the windows' owner process by calling GetWindowThreadProcessId.
For everyone still wondering, this is the answer:
List<IntPtr> GetRootWindowsOfProcess(int pid)
{
List<IntPtr> rootWindows = GetChildWindows(IntPtr.Zero);
List<IntPtr> dsProcRootWindows = new List<IntPtr>();
foreach (IntPtr hWnd in rootWindows)
{
uint lpdwProcessId;
WindowsInterop.User32.GetWindowThreadProcessId(hWnd, out lpdwProcessId);
if (lpdwProcessId == pid)
dsProcRootWindows.Add(hWnd);
}
return dsProcRootWindows;
}
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
WindowsInterop.Win32Callback childProc = new WindowsInterop.Win32Callback(EnumWindow);
WindowsInterop.User32.EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
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);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}
for WindowsInterop:
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
for WindowsInterop.User32:
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
Now one can simply get every root window by GetRootWindowsOfProcess, and their children by GetChildWindows.
You can use EnumWindows to get every top-level window, and then filter the results based on GetWindowThreadProcessId.

Collect all windows handlers

How do I collect all windows handlers in C#.
I need all the windows (not just the parents)
Thanks,
Try the following utility class. Given a handle to a window it will return all of the associated child windows.
public class WindowFinder
{
private class Helper
{
internal List<IntPtr> Windows = new List<IntPtr>();
internal bool ProcessWindow(IntPtr handle, IntPtr parameter)
{
Windows.Add(handle);
return true;
}
}
private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);
public static List<IntPtr> GetChildWindows(IntPtr parentWindow)
{
var helper = new Helper();
EnumChildWindows(parentWindow, helper.ProcessWindow, IntPtr.Zero);
return helper.Windows;
}
}

Categories