Link to home
Start Free TrialLog in
Avatar of skneife
skneife

asked on

SetFocus to a specific child window in a foreign process

i have a C# application that use processWT.Start(); to start a foreign process.
My needs is touse the windows API SetFocus to drop the focus in a specific chidl window in this lunched process for sending keys.
The SetFocus API can't be used to target to another process that the current we owned.
it seems that we must use the windows api AttachThreadInput, following MSDN:
"By using the AttachThreadInput function, a thread can attach its input processing to another thread. This allows a thread to call SetFocus to set the keyboard focus to a window attached to another thread's message queue. "

Have you a sample code for doing that ?

Regards,

Sam

Avatar of bigbadger1
bigbadger1

Here is the core code I wrote to do what you are asking. I'm listing out all the available windows into a single select listview and I have a button on the form that when clicked will give focus to the window selected in the listview. Since you started the process directly I assume you know the name of the process and could bypass some of my code using:

  [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr FindWindow(string className, string windowName);
using System.Runtime.InteropServices;
 
namespace SetFocusOnExternalProcessWindow
{
    public partial class Form1 : Form
    {
        delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
 
        [DllImport("USER32.DLL")]
        static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
 
        [DllImport("USER32.DLL")]
        static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
 
        [DllImport("USER32.DLL")]
        static extern int GetWindowTextLength(IntPtr hWnd);
 
        [DllImport("USER32.DLL")]
        static extern bool IsWindowVisible(IntPtr hWnd);
 
        [DllImport("USER32.DLL")]
        static extern IntPtr GetShellWindow();
 
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        static extern Int32 SetForegroundWindow(IntPtr hwnd);
 
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        static extern Int32 SetActiveWindow(IntPtr hwnd);
 
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private class HwndItem : ListViewItem
        {
            private IntPtr hwnd;
            private string title;
 
            public HwndItem(IntPtr handle, string title) : base(title) 
            {
                hwnd = handle;
            }
 
            public IntPtr HWND
            { get { return hwnd; } set { hwnd = value; } }
            public string Title
            { get { return title; } set { title = value;}}
            
        }
 
 
        private void Form1_Load(object sender, EventArgs e)
        {
            HwndItem listViewItem;
 
            foreach(KeyValuePair<IntPtr, string> window in GetOpenWindows())
            {
                listViewItem = new HwndItem( window.Key, window.Value );
                listView1.Items.Add(listViewItem);
            }
 
        }
 
        public static IDictionary<IntPtr, string> GetOpenWindows()
        {
            IntPtr windowPtr = GetShellWindow();
            Dictionary<IntPtr, string> windows = new Dictionary<IntPtr, string>();
 
            EnumWindows(delegate(IntPtr hWnd, int lParam)
            {
                if (hWnd == windowPtr) return true;
                if (!IsWindowVisible(hWnd)) return true;
 
                int length = GetWindowTextLength(hWnd);
                if (length == 0) return true;
 
                StringBuilder lBuilder = new StringBuilder(length);
                GetWindowText(hWnd, lBuilder, length + 1);
 
                windows[hWnd] = lBuilder.ToString();
                return true;
                
            }, 0);
 
            return windows;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count > 0)
            {
                HwndItem selectedItem = listView1.SelectedItems[0] as HwndItem;
                SetForegroundWindow(selectedItem.HWND);
                SetActiveWindow(selectedItem.HWND);
            }
        }
    }
}

Open in new window

Avatar of skneife

ASKER

Hi,

Thank you for your reply.
The solution you provide me doesn't respond to my request.
My needs is to call the windows API SetFocus(...) to drop the focus on a child window that belong a foreign process (process I have lunch before).
In your code you have used the SetActiveWindow and not the setFocus windows API.
In MSDN it says that SetActivewindow doesn't work on foreign process:
"If the window identified by the hWnd parameter was created by the calling thread, the active window status of the calling thread is set to hWnd. Otherwise, the active window status of the calling thread is set to NULL."

Example:
Suppose your application A (winform) lunch another application B.
In B you have a listView and a rtftextbox.
My need is from A drop the focus on ListView or RtfTextBox for sending keystroke.
The SetFocus windows API as the same issue than SetActivewindow, it doesn't work if the caller is not the owner of the process.

Does this sound clear ?

Regards.

Sam

Sorry, I've been building my new system. Ok... so you need to send the focus to a control on the form.... I've added a bit more code to list the subWindows and then select from them. To test this I created a separate application with 4 TextBoxes which when entered (gain focus) fire an event and update the text in the box. I added a second listview to list the sub windows contained by the window selected in my first list box. I then changed out the code to drive off the handles to the sub windows
using System.Runtime.InteropServices;
 
 
namespace SetFocusOnExternalProcessWindow
{
    public partial class Form1 : Form
    {
 
        delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
        delegate bool EnumSubWindowProc(IntPtr hWnd, IntPtr parameter);
 
        [DllImport("USER32.DLL")]
        static extern IntPtr EnumChildWindows(IntPtr parentHandle, EnumSubWindowProc callback, IntPtr lParam);
 
        [DllImport("USER32.DLL")]
        static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
 
        [DllImport("USER32.DLL")]
        static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
 
        [DllImport("USER32.DLL")]
        static extern int GetWindowTextLength(IntPtr hWnd);
 
        [DllImport("USER32.DLL")]
        static extern bool IsWindowVisible(IntPtr hWnd);
 
        [DllImport("USER32.DLL")]
        static extern IntPtr GetShellWindow();
 
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        static extern Int32 SetForegroundWindow(IntPtr hwnd);
 
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        static extern Int32 SetActiveWindow(IntPtr hwnd);
 
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private class HwndItem : ListViewItem
        {
            private IntPtr hwnd;
            private string title;
 
            public HwndItem(IntPtr handle, string title) : base(title)
            {
                hwnd = handle;
            }
 
            public IntPtr HWND
            { get { return hwnd; } set { hwnd = value; } }
            public string Title
            { get { return title; } set { title = value; } }
 
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            HwndItem listViewItem;
 
            foreach (KeyValuePair<IntPtr, string> window in GetOpenWindows())
            {
                listViewItem = new HwndItem(window.Key, window.Value);
                listView1.Items.Add(listViewItem);
            }
 
        }
 
        public static IDictionary<IntPtr, string> GetOpenWindows()
        {
            IntPtr windowPtr = GetShellWindow();
            Dictionary<IntPtr, string> windows = new Dictionary<IntPtr, string>();
 
            EnumWindows(delegate(IntPtr hWnd, int lParam)
            {
                if (hWnd == windowPtr) return true;
                if (!IsWindowVisible(hWnd)) return true;
 
                int length = GetWindowTextLength(hWnd);
                if (length == 0) return true;
 
                StringBuilder lBuilder = new StringBuilder(length);
                GetWindowText(hWnd, lBuilder, length + 1);
 
                windows[hWnd] = lBuilder.ToString();
                return true;
 
            }, 0);
 
            return windows;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            if (listView2.SelectedItems.Count > 0)
            {
                HwndItem selectedItem = listView2.SelectedItems[0] as HwndItem;
                SetForegroundWindow(selectedItem.HWND);
                SetActiveWindow(selectedItem.HWND);
            }
 
 
        }
 
        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count > 0)
            {
                listView2.Items.Clear();
                HwndItem selectedItem = listView1.SelectedItems[0] as HwndItem;
                HwndItem listViewItem;
                foreach (KeyValuePair<IntPtr, string> window in GetChildWindows(selectedItem.HWND))
                {
                    listViewItem = new HwndItem(window.Key, window.Value);
                    listView2.Items.Add(listViewItem);
                }
            }
        }
 
        public static IDictionary<IntPtr, string> GetChildWindows(IntPtr parent)
        {
            Dictionary<IntPtr, string> childHandles = new Dictionary<IntPtr, string>();
            EnumChildWindows(parent, 
                delegate(IntPtr handle, IntPtr pointer)
                {
                    if (!IsWindowVisible(handle)) return true;
 
                    int length = GetWindowTextLength(handle);
                    if (length == 0) return true;
                    
                    StringBuilder lBuilder = new StringBuilder(length);
                    GetWindowText(handle, lBuilder, length + 1);
 
                    childHandles[handle] = lBuilder.ToString();
                    return true;
                }
                , IntPtr.Zero);
            return childHandles;
        }
 
    }
}

Open in new window

Avatar of skneife

ASKER

Please focus on my needs.
I need to use the windows API SetFocus(hwnd AChildwindowFromAForeignProcess).
Msdn library tells that SetFocus will failed if you call it for a external process.
The same commentary as been written for SetActiveWindow API.
In MSDN:
"If the window identified by the hWnd parameter was created by the calling thread, the active window status of the calling thread is set to hWnd. Otherwise, the active window status of the calling thread is set to NULL."

That is my needs !

Regards.
ASKER CERTIFIED SOLUTION
Avatar of bigbadger1
bigbadger1

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial