Copying Selected Text From an External Program

mithrandiir42

Member
Joined
Mar 7, 2006
Messages
16
Programming Experience
3-5
Hi everyone,
I've been been beating my head against the wall trying to get at the selected text of an external program. Basically my program will run in the background and wait for a hotkey to be pressed. When that happenes, I want to retrieve the selected text from whatever program i'm working in.

My first approach was to simulate keystrokes to simulate a ctrl+c which I suppose is still a possibility but it seems like there should be a much cleaner way to do this by using SendMessage to the active text box or something like that. I'm also want to steer away from using keystrokes because i'm worried it might interfere with what the user is doing.

If anyone knows of a good way to go about this, I'd really appreciate any help.

Thanks a lot in advance!

-Jeremy
 
Ctrl+c is the cleanest way, because it will work on any text control (surprisingly many actually...) for the active application. Remember Ctrl+c is a system hotkey for copy, and if overridden in app it usually means the same. Here is the code to send the key combination, then you get the text from clipboard.
VB.NET:
SendKeys.SendWait("^c")
You could also use SendMessage with WM_COPY, but it's not clean because you have get handle to the text window first (not app window), this means user have to mouse hover over the text area to get the exact handle.
 
No, m_ogden, you can't make another process execute that code.
 
Hey guys, thanks a lot for your input. John, I'm using SendWait like you suggested and it works... sometimes (it seems to depend on what keys i used to activate it). I think the problem i'm having is that the keys I pressed to call SendWait are still down so it interferes with the ^C or ^V that i'm sending with SendWait. I'm thinking about using keybd_event to simulate releasing the keys I pressed to activate the SendWait. Do you think that's the best way to go about it? I'm still not *entirely* sure that really is the problem but it seems pretty likely that's what's going on.

Thanks again,

Jeremy
 
I don't think the keys are interfering, but there could be a focus problem. The textcontrol with some selected text will have to be in focus like any normal manual ctrl-c copy operation.
 
Okay after a lot of playing around with sendkeys I've pretty much gotten my program to copy the selected text out of another program. I ended up having to send a keyup for the keys i pressed to trigger the hotkey. I wasn't sure if that was causing a problem but it didn't work quite right until I did that.

Anyway now i'm faced with a different problem now that i have the data on the clipboard. What i want to do it basically make a copy of the clipboard and save it in an array of IDataObjects to restore at a latertime using Clipboard.SetDataObject(mySavedClipboard); The only problem is that when i restore it, the clipboard ends up being empty.

I've also tried looping through the list of data formats in the stored clipboard and then adding just that specific data back to the clipboard. the only problem with that is, i seem to lose a lot of the functionality.. for example if i copy some html from IE, i can't paste it into notepad, or if i copy some rich text, i can't paste it into a regular textbox.

I'd like my stored clipboard to work just like the regular clipboard and be able to convert the data from html to text automatically.

Any ideas on how i could go about achieving this?

Thanks again,
Jeremy
 
There no problems with saving the return of Clipboard.GetDataObject in an array of IDataObjects, and later putting a specific instance into clipboard with the SetDataObject method. I just tested this and all formats stored was retained fine.
 
Wow ok, that's good to know it's possible. still really baffled why it's not working for me though. I'm starting to think it's my version of VS (2002) or maybe that i'm using v1.0 of the .Net framework giving me problem.. or that i'm actually using C#.
I'm going to try to do some updating and then see how things work.. and maybe switch over to VB if it's the only place i can get it to work.
 
Testing code, it's working for me.
VB.NET:
Sub putdata1()
  Dim data_object As New DataObject
  ' Add the data in various formats.
  data_object.SetData(DataFormats.Rtf, "some rtf 1")
  data_object.SetData(DataFormats.Text, "some text 1")
  data_object.SetData(DataFormats.Html, "some html 1")
  ' Place the data in the Clipboard.
  Clipboard.SetDataObject(data_object)
End Sub
 
Sub testdata()
  'array
  Dim data_object(0) As IDataObject
 
  'put some specific data 
  putdata1()
 
  'get data
  data_object(0) = Clipboard.GetDataObject
 
  'get/set some again for testing
  Clipboard.SetDataObject(data_object(0))
  data_object(0) = Clipboard.GetDataObject
 
  'display data to verify
  Dim sb As New StringBuilder
  If data_object(0).GetDataPresent(DataFormats.Html) = True Then
    sb.Append(data_object(0).GetData(DataFormats.Html) & vbNewLine)
  End If
  If data_object(0).GetDataPresent(DataFormats.Text) = True Then
    sb.Append(data_object(0).GetData(DataFormats.Text) & vbNewLine)
  End If
  If data_object(0).GetDataPresent(DataFormats.Rtf) = True Then
    sb.Append(data_object(0).GetData(DataFormats.Rtf) & vbNewLine)
  End If
  MsgBox(sb.ToString)
End Sub
 
Thanks alot for the your code. That should help me quite a bit. It looks similar to mine but i'm going to sit down later tonight once i get home from work to see if i can find any difference in the way i'm trying to do it.
 
Everything works fine the way you do it in your example but that's only as long as the clipboard that it first retrieves and puts into the array was generated by the program. If i change it so that it does it with clipboard data that was placed there with ctrl+c, the program crashes. Here's the code i was working with. I'm no longer using the array just for simplicity.. it's now just a public IDataObject.

TestGet_Click and TestSet_Click are on two seperate buttons. when i run the program, i copy some text to the clipboard, then press TestGet to get the clipboard and store it in the program. Then i would copy some text into the clipboard from notepad to something just so i know the clipboard contains different data. then i'd Press the TestSet button to copy the saved data back to the clipboard and verify it's still there.

Oh.. i just noticed that it only seems to crash if i copy text from a textbox or notepad. If i copy text from IE, it doesn't crash. and everything works.

right now i'm getting around this by creating a new IDataObject and copying all the dataformats from the clipboard into that object and saving that into my array.. This seems to work for most situations but it feels like a dirty workaround and would like it best if i could just store the actual clipboard object and set it back later.

I hope that all made sense:)

VB.NET:
    Public data_object As IDataObject

    Sub putdata1()
        Dim data_object As New DataObject
        ' Add the data in various formats.
        data_object.SetData(DataFormats.Rtf, "some rtf 1")
        data_object.SetData(DataFormats.Text, "some text 1")
        data_object.SetData(DataFormats.Html, "some html 1")
        ' Place the data in the Clipboard.
        Clipboard.SetDataObject(data_object)
    End Sub

    Private Sub TestGet_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles testget.Click
        'If I uncomment putdata1() everything works
        'putdata1()
        data_object = Clipboard.GetDataObject()
    End Sub

    Private Sub TestSet_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TestSet.Click

        'get/set some again for testing
        Clipboard.SetDataObject(data_object)
        Dim data_test = Clipboard.GetDataObject

        'display data to verify
        Dim sb As New System.text.StringBuilder
        If data_test.GetDataPresent(DataFormats.Html) = True Then
            sb.Append(data_test.GetData(DataFormats.Html) & vbNewLine)
        End If
        If data_test.GetDataPresent(DataFormats.Text) = True Then
            sb.Append(data_test.GetData(DataFormats.Text) & vbNewLine)
        End If
        If data_test.GetDataPresent(DataFormats.Rtf) = True Then
            sb.Append(data_test.GetData(DataFormats.Rtf) & vbNewLine)
        End If
        MsgBox(sb.ToString)

        ''Dim fmt As String
        ''For Each fmt In data_test.getformats()
        ''output.Text += data_test.getdata(fmt) & ControlChars.NewLine
        ''Next
    End Sub
 
I can't reproduce the problem you describe. Getting data from clipboard works here.
 
another glance... you do something strange in this code, mixing different variables and variable types..
VB.NET:
Clipboard.SetDataObject(data_object)
Dim data_test = Clipboard.GetDataObject
 
Back
Top