Kirk Evans

When they first asked for this, I said it couldn't be done. Then they showed me an app that could do it.

To simplify the discussion, lets say I want to perform a "special action" when a "special" key is pressed using the text that is highlighted in whatever window has focus, regardless of what the application is.

Put another way, suppose I have Notepad running, and in the text that it is displaying I hightlight the word "Hello". Then I press something like <ctrl><f12> and my program, which is running but is not the application with focus, responds to the keystroke by performing a special action where the parameter is the word "hello". (As a silly example, lets say it generates a text file, puts "hello" in it, and saves it. )

Now - I've seen an app do this (something very similar)! It extracted selected text from a simple app I wrote - so there's no special Office Automation magic or something like that going on.

The app that I saw do this isn't a dot net app, but hopefully it is still possible in dot net.

My only idea is to somehow loop through all the windows on the desktop, find the one with focus, and then extract whatever text is currently highlighted. Zowie! Easy to say, right

I also need to somehow capture the "special" keystroke no matter what application has focus.

I need help with every step I've mentioned.

... or maybe there's a better way to approach it

Help!

Kirk




Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Peter Ritchie

For highlighted text you could PInvoke GetForegroundWindow and send that window a EM_GETSEL message to get the currently selected text. You may have to find the window with focus once you get the foreground window, I think GetForegroundWindow gets the top-level application window with focus, not the child window with focus.

You'll have to implement a low-level keyboard hook to get filter keystrokes.




Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Kirk Evans

Thank you, Peter!

Based on your response, I am already much closer to my goal than I thought would be possible.

I've got my hot key working, and I'm enumerating child windows and displaying their text. ( Not selected text, but that will hopefully turn out to be a minor issue. - for some reason I can't find a one line snippet of code that calls EM_GetSelText and puts it into a string ( or stringbuilder or whatever ). Additionally, I'm not clear on the difference between EM_GetSel and EM_GetSelText )

The main sticking point now is figuring out which child window is the one with focus.

Anyone have any suggestions on that






Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Peter Ritchie

You can get the active window and the child window with focus with the GetGUIThreadInfo Win32 function. Or you can use the GetFocus Win32 function if you associate your window's message queue with that of the window found with GetForegroundWindow by using AttachThreadInput, as described in the documentation for GetFocus.






Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Kirk Evans

Peter,

I am trying to use the GetGUIThreadInfo Win32 function.

Here's my current code

//------------------------------------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------------------------

#warning THIS CODE DOES NOT WORK

public struct RECT {
public uint left;
public uint top;
public uint right;
public uint bottom;
}


public struct LPGUITHREADINFO {
public uint cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCapred;
public RECT rcCaret;
};

public LPGUITHREADINFO GetThreadInfo(uint tid) {
LPGUITHREADINFO tinfo = new LPGUITHREADINFO();
tinfo.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(tinfo);
GetGUIThreadInfo(tid, tinfo);
return tinfo;
}

void ShowFocusWindowText() {
LPGUITHREADINFO info = GetThreadInfo((uint)0);
StringBuilder bld = new StringBuilder(256);
GetWindowText(info.hwndFocus, bld, 256);
string text = bld.ToString();
MessageBox.Show(text);
}

private void button_Click(object sender, EventArgs e) {
ShowFocusWindowText();
}
//------------------------------------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------------------------

Needless to say, the code is a bit nonsensical since calling it in button_click would

mean that the button would have focus, but lets not worry about that.

My problem is that I get a "PInvokeStackImbalance was detected" message when I get to the

GetGuiThreadInfo call.

( details:

Message: A call to PInvoke function '<blah, blah,>::GetGUIThreadInfo' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
)

After some reseach, my best guess is that it has something to do with the way that either RECT or LPGUITHREADINFO is declared - but I am really not sure about that theory.






Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Peter Ritchie

What does you DllIImport for GetGUIThreadInfo look like






Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Peter Ritchie

Actually, looking at your call to GetGUIThreadInfo, it looks like you're missing an "out". This DllImport works for me:

Code Snippet

[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "GetGUIThreadInfo")]

private static extern bool GetGUIThreadInfo(int tId, out GUITHREADINFO threadInfo);

The GUITHREADINFO is being populated by GetGUIThreadInfo, so it needs the out keyword.






Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Kirk Evans

That was it! ( the "out" thing )

I did make one small change, declaring tId as a uint instead of an int.

I think uint is "more correct", but I'm not really sure - at any rate - it works!






Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Kirk Evans

(sigh)

So close, yet so far.

I've got all the technical details worked out. I many cases I can pull the highlighted text out of whatever window is the active window.

Now I'm hitting some unexpected roadblocks.

for instance:

*) I haven't been able to retreive text from an excel spreadsheet. WM_GETTEXT returns nothing.

**) The interaction between Notepad, Wordpad and EM_GETSEL is not consistant. I can paste some test text into a workpad window, and paste the exact same text into a notepad window, hightlight the exact same set of characters, and EM_GETSEL returns different values for the start and end of the text. It looks like in one case EM_GETSEL is counting a "\r\n" as one character, and in the other it is counting it as two.

WM_GETTEXT returns the same text from each window - what fouls me up is the indexing of the start and end of the selection.

Am I going to have to find some way to get the class of the window that I am pulling text from in order to analyze the results of the string returned by WM_GETTEXT

***) Having hit these difficulties after only an hour or so of testing, I'm wondering what else is lurking out there...






Re: Visual C# General Challenge: Extract Highlighted text from window with focus in any app on desktop!

Kirk Evans

For any of you out there besides me who are still interested in this - here's where it stands at 4:30 friday afternoon:

My problems with using EM_GETSEL and the different behaviors between notepad and wordpad have been solved by sending the window a WM_COPY and then grabbing the text from the clipboard. This also solves my problem with excel.

In fact, it has worked with almost everything I've tried.

My current problem is that WM_COPY doesn't seem to work on Internet Explorer, and when I tested the WM_GETTEXT and EM_GETSEL approach on a web page I got an "out of memory" error. apparently the amout of text on the web page was just too much.

I don't know of any way to just get a portion of the text from a page,

At this point, It looks like I'm going to have to find out how to get something along the lines of WM_COPY to work on internet explorer.

As always, I am very open to any suggestions.

Have a good weekend to all!