Pinvoke SetFocus to a particular control

Jordan picture Jordan · Feb 29, 2012 · Viewed 8.5k times · Source

Simple question: is it possible to set focus on another application's textbox (using it's ClassName). I have the window as an "intptr" etc etc 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!

Answer

NSGaga-mostly-inactive picture NSGaga-mostly-inactive · Mar 3, 2012

...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 PInvoke 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

EDIT: I clarified a bit for your specific case and child focus
EDIT (2):
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 PInvoke signatures for windows API and native calls (similar to MS.Win32.UnsafeNativeMethods) and it's a static class (see that class or http://pinvoke.net/ - also Accessing Microsoft.Win32.UnsafeNativeMethods?), should be named (Safe/Unsafe)NativeMethods (http://msdn.microsoft.com/en-us/library/ms182161.aspx) - 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).