none
Copy Selected Text from any window

    Question

  • Hi,

    I have a small COM application which is running in the background of my system. This application has to react when user selects a text and press a preconfigured global hot key. I am able to get a hook on the keyboard, but am not able to get the selected text from the window.

    In simple words, how do i get the selected text from any window? I dont want to use the Clipboard functionality as I dont want to have the global hot key as CTRL-C.

    I am working on C#, .Net Framework : 3.5. Any inputs of how to do this?

    - Cheers

    Elite Teuton

    Saturday, April 10, 2010 1:08 PM

Answers

  • Hi Elite,

    There are two steps to do this:

    1. Get the focused control. We can get the current activated window via GetForegroundWindow API, then call GetWindowThreadProcessId API to get the thread id of the current window. If it is not the current thread, call AttachThreadInput API to attach the thread to the current thread. With all these jobs done, we can call GetFocus API to get the focused control handle.

    2. Get the text of the focused control. We can call SendMessageW API to send a WM_GETTEXT message to do this.

    You can get detail from the code below:

            private System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();
    
            private void Form2_Load(object sender, EventArgs e)
            {
                //Initialize a timer to update the control text.
                _timer.Interval = 1000;
                _timer.Tick += new EventHandler(_timer_Tick);
            }
            void _timer_Tick(object sender, EventArgs e)
            {
                try
                {
                    textBox1.Text = GetTextFromFocusedControl();
                }
                catch (Exception exp)
                {
                    textBox1.Text += exp.Message;
                }
            }
    
            //Start to monitor and show the text of the related control.
            private void button1_Click(object sender, EventArgs e)
            {
                _timer.Start();
            }
    
            //Get the text of the focused control
            private string GetTextFromFocusedControl()
            {
                try
                {
                    int activeWinPtr = GetForegroundWindow().ToInt32();
                    int activeThreadId = 0, processId;
                    activeThreadId = GetWindowThreadProcessId(activeWinPtr, out processId);
                    int currentThreadId = GetCurrentThreadId();
                    if (activeThreadId != currentThreadId)
                        AttachThreadInput(activeThreadId, currentThreadId, true);
                    IntPtr activeCtrlId = GetFocus();
    
                    return GetText(activeCtrlId);
                }
                catch (Exception exp)
                {
                    return exp.Message;
                }
            }
    
            //Get the text of the control at the mouse position
            private string GetTextFromControlAtMousePosition()
            {
                try
                {
                    Point p;
                    if (GetCursorPos(out p))
                    {
                        IntPtr ptr = WindowFromPoint(p);
                        if (ptr != IntPtr.Zero)
                        {
                            return GetText(ptr);
                        }
                    }
                    return "";
                }
                catch (Exception exp)
                {
                    return exp.Message;
                }
            }
    
            //Get the text of a control with its handle
            private string GetText(IntPtr handle)
            {
                int maxLength = 100;
                IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2);
                SendMessageW(handle, WM_GETTEXT, maxLength, buffer);
                string w = Marshal.PtrToStringUni(buffer);
                Marshal.FreeHGlobal(buffer);
                return w;
            }
    
            [DllImport("user32.dll")]
            public static extern bool GetCursorPos(out Point pt);
    
            [DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
            public static extern IntPtr WindowFromPoint(Point pt);
    
            [DllImport("user32.dll", EntryPoint = "SendMessageW")]
            public static extern int SendMessageW([InAttribute] System.IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
            public const int WM_GETTEXT = 13;
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            internal static extern IntPtr GetForegroundWindow();
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            internal static extern IntPtr GetFocus();
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern int GetWindowThreadProcessId(int handle, out int processId);
    
            [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
            internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);
            [DllImport("kernel32.dll")]
            internal static extern int GetCurrentThreadId();
    
            [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);
    

    Let me know if this does not help.
    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    Wednesday, April 14, 2010 11:17 AM

All replies

  • Hi Elite,

    There are two steps to do this:

    1. Get the focused control. We can get the current activated window via GetForegroundWindow API, then call GetWindowThreadProcessId API to get the thread id of the current window. If it is not the current thread, call AttachThreadInput API to attach the thread to the current thread. With all these jobs done, we can call GetFocus API to get the focused control handle.

    2. Get the text of the focused control. We can call SendMessageW API to send a WM_GETTEXT message to do this.

    You can get detail from the code below:

            private System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();
    
            private void Form2_Load(object sender, EventArgs e)
            {
                //Initialize a timer to update the control text.
                _timer.Interval = 1000;
                _timer.Tick += new EventHandler(_timer_Tick);
            }
            void _timer_Tick(object sender, EventArgs e)
            {
                try
                {
                    textBox1.Text = GetTextFromFocusedControl();
                }
                catch (Exception exp)
                {
                    textBox1.Text += exp.Message;
                }
            }
    
            //Start to monitor and show the text of the related control.
            private void button1_Click(object sender, EventArgs e)
            {
                _timer.Start();
            }
    
            //Get the text of the focused control
            private string GetTextFromFocusedControl()
            {
                try
                {
                    int activeWinPtr = GetForegroundWindow().ToInt32();
                    int activeThreadId = 0, processId;
                    activeThreadId = GetWindowThreadProcessId(activeWinPtr, out processId);
                    int currentThreadId = GetCurrentThreadId();
                    if (activeThreadId != currentThreadId)
                        AttachThreadInput(activeThreadId, currentThreadId, true);
                    IntPtr activeCtrlId = GetFocus();
    
                    return GetText(activeCtrlId);
                }
                catch (Exception exp)
                {
                    return exp.Message;
                }
            }
    
            //Get the text of the control at the mouse position
            private string GetTextFromControlAtMousePosition()
            {
                try
                {
                    Point p;
                    if (GetCursorPos(out p))
                    {
                        IntPtr ptr = WindowFromPoint(p);
                        if (ptr != IntPtr.Zero)
                        {
                            return GetText(ptr);
                        }
                    }
                    return "";
                }
                catch (Exception exp)
                {
                    return exp.Message;
                }
            }
    
            //Get the text of a control with its handle
            private string GetText(IntPtr handle)
            {
                int maxLength = 100;
                IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2);
                SendMessageW(handle, WM_GETTEXT, maxLength, buffer);
                string w = Marshal.PtrToStringUni(buffer);
                Marshal.FreeHGlobal(buffer);
                return w;
            }
    
            [DllImport("user32.dll")]
            public static extern bool GetCursorPos(out Point pt);
    
            [DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
            public static extern IntPtr WindowFromPoint(Point pt);
    
            [DllImport("user32.dll", EntryPoint = "SendMessageW")]
            public static extern int SendMessageW([InAttribute] System.IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
            public const int WM_GETTEXT = 13;
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            internal static extern IntPtr GetForegroundWindow();
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            internal static extern IntPtr GetFocus();
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern int GetWindowThreadProcessId(int handle, out int processId);
    
            [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
            internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);
            [DllImport("kernel32.dll")]
            internal static extern int GetCurrentThreadId();
    
            [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);
    

    Let me know if this does not help.
    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    Wednesday, April 14, 2010 11:17 AM
  • I know this thread is a little old but I'm hoping you can still help me out.  I've tried this method and the string returned from GetTextFromFocusedControl is always :

     

    ī:\Windows\assembly\NativeImages_v4.0.30319_32\System\5286fe2d0167eb835a9f11025f1cb756\System.ni.dll
    Do you have any ideas about what is going wrong?
    Thanks!
    Thursday, November 17, 2011 5:03 PM
  • Code seems to be fine...but does not work! In my case, if I open the facebook in chrome and put some text into a text edit control, after selecting that text, this code does nothing when I run it, can you explain why?? 

    my code is as follows:

       if (e.KeyCode == Keys.B)
                {
                    
                    //SendKeys.Send("{BACKSPACE}");
                    textBoxExt1.Text = GetTextFromFocusedControl();
                    e.Handled = true;
                }
            }
            # endregion
    
    
            //Get the text of the focused control
            private string GetTextFromFocusedControl()
            {
                try
                {
                    int activeWinPtr = GetForegroundWindow().ToInt32();
                    int activeThreadId = 0, processId;
                    activeThreadId = GetWindowThreadProcessId(activeWinPtr, out processId);
                    int currentThreadId = GetCurrentThreadId();
                    if (activeThreadId != currentThreadId)
                        AttachThreadInput(activeThreadId, currentThreadId, true);
                    IntPtr activeCtrlId = GetFocus();
    
                    return GetText(activeCtrlId);
                }
                catch (Exception exp)
                {
                    return exp.Message;
                }
            }
    
           
    
            //Get the text of a control with its handle
            private string GetText(IntPtr handle)
            {
                int maxLength = 100;
                IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2);
                SendMessageW(handle, WM_GETTEXT, maxLength, buffer);
                string w = Marshal.PtrToStringUni(buffer);
                Marshal.FreeHGlobal(buffer);
                return w;
            }
    
            [DllImport("user32.dll")]
            public static extern bool GetCursorPos(out Point pt);
    
            [DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
            public static extern IntPtr WindowFromPoint(Point pt);
    
            [DllImport("user32.dll", EntryPoint = "SendMessageW")]
            public static extern int SendMessageW([InAttribute] System.IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
            public const int WM_GETTEXT = 13;
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            internal static extern IntPtr GetForegroundWindow();
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
            internal static extern IntPtr GetFocus();
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern int GetWindowThreadProcessId(int handle, out int processId);
    
            [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
            internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);
            [DllImport("kernel32.dll")]
            internal static extern int GetCurrentThreadId();
    
            [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);

    • Edited by 666999 Thursday, October 17, 2013 1:55 AM adding detail
    Thursday, October 17, 2013 1:50 AM
  • I am preety sure that what was written above applies to apps created by you and not to any app you will run on Windows. They can have separate hooks and also conflict with global ones. Consider app in which someone said that ctrl + c will do something else than copy - this is quite normal that suggested code in not working with Chrome etc.

    Look here: http://stackoverflow.com/questions/13667001/using-user32-dll-sendmessage-to-send-keys-with-alt-modifier

    and here http://stackoverflow.com/questions/21460943/how-to-get-selected-text-of-any-application-into-a-windows-form-application/21501291#21501291

    Hope that it will help :)

    • Edited by t-adszy Monday, May 19, 2014 2:31 PM
    Monday, May 19, 2014 2:29 PM