Search code examples
c#.netwinapipinvokesetfocus

P/Invoke SetFocus to a particular control


Is it possible to set focus on another application's textbox (using its ClassName). I have the window handle as an IntPtr. But just need some guidance as to what functions/APIs are available for this!

Issue is, I use the SetForegroundWindow API to get window focus, but it wouldn't let me send the Ctrl+L keys to focus on the textbox!

Any help would be great!


Solution

  • ...as far as I recall, this is the code I had to use to make that work – and that worked well on my apps, and newer Windows etc.

    void SetFocus(IntPtr hwndTarget, string childClassName)
    {
        // hwndTarget is the other app's main window 
        // ...
        IntPtr targetThreadID = WindowsAPI.GetWindowThreadProcessId(hwndTarget, IntPtr.Zero); //target thread id
        IntPtr myThreadID = WindowsAPI.GetCurrentThread(); // calling thread id, our thread id
        try
        {
            bool lRet = WindowsAPI.AttachThreadInput(myThreadID, targetThreadID, -1); // attach current thread id to target window
    
            // if it's not already in the foreground...
            lRet = WindowsAPI.BringWindowToTop(hwndTarget);
            WindowsAPI.SetForegroundWindow(hwndTarget);
    
            // if you know the child win class name do something like this (enumerate windows using Win API again)...
            var hwndChild = EnumAllWindows(hwndTarget, childClassName).FirstOrDefault();
    
            if (hwndChild == IntPtr.Zero)
            {
                // or use keyboard etc. to focus, i.e. send keys/input...
                // SendInput (...);
                return;
            }
    
            // you can use also the edit control's hwnd or some child window (of target) here
            WindowsAPI.SetFocus(hwndChild); // hwndTarget);
        }
        finally
        {
            bool lRet = WindowsAPI.AttachThreadInput(myThreadID, targetThreadID, 0); //detach from foreground window
        }
    }
    

    ...so something along those lines (it does what you need and in the right order, don't forget to detach etc. – but you'd need to adjust it for your specific conditions, control/edit hwnd etc. – and still you might have other issues related to the target window/app, this works for most, but not in all cases, that's a long story and as I said depends on your specific scenario),

    (WindowsAPI are typical P/Invoke wrappers I believe) basically you need to attach to another thread for 'input' operations, I believe this is an official explanation "This also allows threads to share their input states, so they can call the SetFocus function to set the keyboard focus to a window of a different thread." Google for "AttachThreadInput" for more info (to know the reasons), and it's also often associated with the SetFocus and other input/keyboard operations. Also the Automation API could help as suggested – that's the 'cleanest' way to do it – but depends if a target app exposes and handles that properly – which still "isn't there" for most of them, not consistent etc. – if you want to handle your "own application" that's different then, you need to ask yourself what's the best scenario etc. hope this helps

    Note: there must be a dozen links to similar solutions (and on SO) as this is quite a known thing, but I'm unable to find a right link

    The code is an example for this spec. case and based on working code – but might need testing and working out some details (which seem out of the scope for this question), e.g...
    WindowsAPI holds the P/Invoke signatures for Windows API and native calls (similar to MS.Win32.UnsafeNativeMethods) and it's a static class (see that class or https://pinvoke.net/ – also Accessing Microsoft.Win32.UnsafeNativeMethods?), should be named (Safe/Unsafe)NativeMethods (https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/code-quality/ca1060-move-p-invokes-to-nativemethods-class) – and also see IntPtr, SafeHandle and HandleRef - Explained (IntPtr is a bit 'old' style)
    EnumAllWindows uses EnumChildWindows and GetClassName Win API (and it's for another question I guess) and requires a wrapper method for it to be useful (which EnumAllWindows is – it just enumerates thru windows recursively checking for class names).