How to get selected text from another windows program

I encountered this problem recently and despite many findings on the internet about the issue I couldn’t find any comprehensive solution, especially not for a WPF program. So I decided to summarize how I got it to work in my project.

AutomationElement

First we look at the AutomationElement. There is a very short simple code snippet which if it would work this would be a very short blog post. It works on some program (e g Word and Outlook) but not all (like Internet Explorer). The big advantage about AutomationElement over the copy solution which we will use when AutomationElement doesn’t work, is that we don’t tamper with the Clipboard. In the code below we start by getting an element. I have it easy because I reach my code before my program gets focus so I can just call:

If your program has focus you have to get your element elsewise. After you have your element you try to get a TextPattern and if that succeeds you’re done, just call GetSelection like the example below:

If TryGetCurrentPattern returns false you can´t use AutomationElement (not in any way I have found).

Copy command

The other way is to simulate the copy command and check the Clipboard for the text like so:

This does however not work even if it is a nice small piece of code. The problem is that even if we call the copy command with SendWait very often the actual command has not been executed before we check the Clipboard for its content. Perhaps one could try to fix this by using timers/delay of some kind but there is a more exact way. Set up your program to listen to the copy event. In this way we just send the copy command and will always catch it when it executes. Be careful though because your program will now catch every copy command sent, you probably just want to catch the one your code sent. My solution to this is to set a flag when I call copy and test for it when a copy command is executed.

To set up our program as a copy command listener we use the Win32 command SetClipboardViewer. An example how this can be done is given below:

Why we also listen to WM_CHANGECBCHAIN is described here. As you can see I call Clipboard.Clear() after Clipboard.GetText(), this because I don’t want the text to be left in the Clipboard. One could try to retrieve the content before the copy command and set it back afterwards but I haven’t found any good solution to this. What will you for example do if there is a large file in the Clipboard? Anyway I believe that if the user copies something to the Clipboard and doesn’t use it right away the user has forgotten about it anyway, and if the Clipboard is empty the user just has to fill it again. But I will still prefer to use the AutomationElement if it is possible just to avoid this problem.

Summary

To sum it up use AutomationElement where it works and otherwise use the copy command with the program set up as a Clipboard listener.

This Post Has 6 Comments

  1. hello

  2. Very good post. Thankssss.

  3. I’d like to know, is there an method to get text from pdf or word file, without Copy method?

  4. @Art I think that TextPattern works for Word. Unsure about PDF (Adobe) because it works differently from program to program. You should try the code above on your different programs to find out.

  5. very good post. FYI just adding a Thread.Sleep(100) just after sending the CTRL C keys, will give enough time to the clipboard to be set properly. At least it works for me.

  6. hello,
    very nice explanation.

    how would you implement this in a user control, since the WindowInteropHelper funcion accepts only a window as a parametter.

Leave a Reply

Close Menu