question

72906204 avatar image
0 Votes"
72906204 asked 72906204 commented

How to get SelectedText from other applications?

I'm looking for a way to get SelectedText from ForegroundWindow on WPF .NET.
What I want to get is the selected text within another application.
I'm trying to search, but I can't find the technique I'm looking for, only how to get SelectedText in WPF.
I got the ThreadProcessId using user32.dll, but I don't know what to do from here.

dotnet-csharpwindows-wpf
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

HuiLiu-MSFT avatar image
0 Votes"
HuiLiu-MSFT answered 72906204 commented

This code help you to get focused control text in focused window, i hope that helps :
1. Gain focus control. You could get the currently activated window through the GetForegroundWindow API, and then call the GetWindowThreadProcessId API to get the thread id of the current window. If it is not the current thread, the AttachThreadInput API is called to attach the thread to the current thread. After all this work, we can call the GetFocus API to get the focus control handle.

  1. Get the text of the focus control. You can do this by calling the SendMessageW API to send a WM_GETTEXT message.

MainWindow.xaml:

 <Grid>
         <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="123" Margin="138,20,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="280"/>
     </Grid>

MainWindow.xaml.cs:

 using System;
 using System.Runtime.InteropServices;
 using System.Windows;
 using System.Windows.Forms;
    
 namespace GetTextSelectedFromOtherApp
 {
   public partial class MainWindow : Window
   {
     public MainWindow()
     {
       InitializeComponent();
       Loaded+= new RoutedEventHandler(Window_Loaded);
      
     }
     private Timer _timer = new Timer();
     private void Window_Loaded(object sender, RoutedEventArgs e)
     {
       _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;
       }
     }
    
     private void button1_Click(object sender, EventArgs e)
     {
       _timer.Start();
     }
    
     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;
       }
     }
       
     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", 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();
    
   }
 }

The result:
200120-5.gif


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


5.gif (77.2 KiB)
· 7
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I'm sorry, I can't find the answer here because I don't understand English well, where can I get the answer?
Does that mean can't get it from an outside application without using the clipboard?
200149-image.png


0 Votes 0 ·
image.png (57.3 KiB)

Hi,@72906204. What kind of answer do you want to get? Is it possible to illustrate with an example? You could also try and see if the solutions here work for you。

1 Vote 1 ·

In the case of the image above, I need the string "e: Please ", but I can't find a function to get this.
I want to get it automatically without letting the user operate to get it.

MainWindow.xaml:

     <Grid>
         <TextBox x:Name="MainLine" HorizontalAlignment="Left" Margin="10,0,0,0" Text="TextBox" TextWrapping="Wrap" VerticalAlignment="Center" Width="250" Height="414" AcceptsReturn="True" AcceptsTab="True" AutoWordSelection="True" IsReadOnly="True" AutomationProperties.Name="MainLine" ScrollViewer.CanContentScroll="True" VerticalScrollBarVisibility="Auto"/>
     </Grid>
0 Votes 0 ·
Show more comments