views:

2060

answers:

7

Is there a way for a Windows application to access another applications data, more specifically a text input field in GUI, and grab the text there for processing in our own application?

If it is possible, is there a way to "shield" your application to prevent it?

EDIT: The three first answers seem to be about getting the another applications window title, not a specific text input field in that window.

I'm no Windows API expect, so could you be more exact how do I find a certain text field in that window, what are the prequisites for it (seems like knowing a window handle something is required, does it require knowing the text field handle as well? How do I get that? etc...)

Code snippets in C++ really would be really appreciated. MSDN help is hard to browse since Win32-API has such horrible naming conventions.

Completed! See my answer below for a how-to in C++.

A: 

Look at AutoHotkey. If you need an API for your application, look at their sources. To prevent it, use a custom widget instead of WinForms, MFC or Win32 API. That is not foolproof, but helps.

MZywitza
I have no idea what to search for in the sources, give me a pointer?
Tuminoid
A: 

Yes it is possible in many ways (one way is to use WINAPI GetWindow and GetWindowText).

First, get a handle to the textbox you want to retrieve text from (using FindWindow, EnumChildWindows and other APIs), then:

Old VB6-codeexample, declaration of API:

Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long  
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long

Code to extract text:

Dim MyStr As String
MyStr = String(GetWindowTextLength(TextBoxHandle) + 1, Chr$(0))
GetWindowText TextBoxHandle, MyStr, Len(MyStr)
MsgBox MyStr
Stefan
A: 

HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName );

http://msdn.microsoft.com/en-us/library/ms633499.aspx

abatishchev
A: 

About how to shield the application to prevent it, you could do many things. One way would be to have a own control to handle text input that build up the text from lets say a couple of labels placed where the text would be, or that draws the text graphically.

Stefan
+3  A: 

For reading text content from another application's text box you will need to get that text box control's window handle somehow. Depending on how your application UI is designed (if it has a UI that is) there are a couple of different ways that you can use to get this handle. You might use "FindWindow"/"FindWindowEx" to locate your control or use "WindowFromPoint" if that makes sense. Either way, once you have the handle to the text control you can send a "WM_GETTEXT" message to it to retrieve its contents (assuming it is a standard text box control). Here's a concocted sample (sans error checks):

HWND hwnd = (HWND)0x00310E3A;
char szBuf[2048];
LONG lResult;

lResult = SendMessage( hwnd, WM_GETTEXT, sizeof( szBuf ) / sizeof( szBuf[0] ), (LPARAM)szBuf );
printf( "Copied %d characters.  Contents: %s\n", lResult, szBuf );

I used "Spy++" to get the handle to a text box window that happened to be lying around.

As for protecting your own text boxes from being inspected like this, you could always sub-class your text box (see "SetWindowLong" with "GWL_WNDPROC" for the "nIndex" parameter) and do some special processing of the "WM_GETTEXT" message to ensure that only requests from the same process are serviced.

Ranju V
+2  A: 

OK, I have somewhat figured this out.

The starting point is now knowing the window handle exactly, we only know partial window title, so first thing to do is find that main window:

...
EnumWindows((WNDENUMPROC)on_enumwindow_cb, 0);
...

which enumerates through all the windows on desktop. It makes a callback with each of these window handles:

BOOL CALLBACK on_enumwindow_cb(HWND hwndWindow, LPARAM lParam) {
    TCHAR wsTitle[2048];
    LRESULT result;
result = SendMessage(hwndWindow, WM_GETTEXT, (WPARAM) 2048, (LPARAM) wsTitle);
    ...

and by using the wsTitle and little regex magic, we can find the window we want.

By using the before mentioned Spy++ I could figure out the text edit field class name and use it to find wanted field in the hwndWindow:

hwndEdit = FindWindowEx(hwndWindow, NULL, L"RichEdit20W", NULL);

and then we can read the text from that field:

result = SendMessage(hwndEdit, WM_GETTEXT, (WPARAM) 4096, (LPARAM) wsText);

I hope this helps anyone fighting with the same problem!

Tuminoid
A: 

You can also get text from a richedit control with EM_GETTEXTRANGE message, but it works only in the same process in which the control was created.

akalenuk
Unfortunately it isn't then usable in this case, as the whole point is to access another process UI.
Tuminoid