0

I'm trying to get data from another program. And... it's giving me an error all the time! Is there something wrong?

HWND hWnd = FindWindow(NULL, L"MyProgram");

    if (hWnd) 
    {
        HWND TPageControl = FindWindowEx(hWnd, NULL, L"TPageControl", NULL); 
        TPageControl = FindWindowEx(hWnd, TPageControl, L"TPageControl", NULL);

        HWND TTabSheet = FindWindowEx(TPageControl, NULL, L"TTabSheet", NULL); 

        HWND TEdit = FindWindowEx(TTabSheet, NULL, L"TEdit", NULL);

        int editlength = SendMessage(TEdit, WM_GETTEXTLENGTH, 0, NULL);                                     

        TCHAR* Targets = new TCHAR( editlength + 1 );

        int count = SendMessage(TEdit, EM_GETLINE, editlength + 1, (LPARAM) Targets);                   

        std::wcout << Targets << "\n";

        //delete Targets;
    }

but if i'm debugging, it's working.

pmr
  • 58,701
  • 10
  • 113
  • 156
Sergey
  • 140
  • 9
  • 1
    http://stackoverflow.com/a/3635180/2604492 – Paul Dec 04 '13 at 20:01
  • `EM_GETLINE` is probably the wrong message. This is a single line Delphi VCL `TEdit`. Get its text with `WM_GETTEXT`. – David Heffernan Dec 04 '13 at 20:47
  • @David I don't think this is a VCL control. The `TEdit` is a misnomer; it's a `HWND` after all. You are right, though, that this is a single-line edit control. The code - as posted - will fail for pretty much any multi-line edit control, due to the wrong `WPARAM` for `EM_GETLINE`. – IInspectable Dec 04 '13 at 21:45
  • @IInspectable As an active VCL programmer, I guarantee this is a VCL TEdit. That's just a loose wrapper around a Win32 EDIT though, but it most definitely is a VCL control. – David Heffernan Dec 04 '13 at 22:00

2 Answers2

4

You are not following the documentation for EM_GETLINE. The first parameter specifies the line index. I'm assuming you are sending this message to a single-line edit control, and it simply gets ignored. The second parameter must hold the length of the buffer:

Before sending the message, set the first word of this buffer to the size, in TCHARs, of the buffer.

The remarks for edit controls are also relevant:

The copied line does not contain a terminating null character.

While parameters for EM_GETLINE get automatically marshaled across process boundaries (like all message parameters for messages in the range 0 to W_USER-1), you might want to consider sending WM_GETTEXT instead, if you are dealing with a single-line edit control:

int editlength = SendMessage(TEdit, WM_GETTEXTLENGTH, 0, NULL);
TCHAR* Targets = new TCHAR[editlength + 1];
int count = SendMessage(TEdit, WM_GETTEXT, editlength + 1, (LPARAM) Targets);
// NUL-terminate buffer in case the text did not fit
Targets[count] = _T('\0');
std::wcout << Targets << "\n";

If you are sending WM_GETTEXT to a hung application your application will hang as well. Call GetWindowText to work around this. The secret life of GetWindowText has additional background information.

If you need to retrieve a specific line from a multi-line edit control the following is more appropriate. In contrast to your code it sends an EM_LINEINDEX and EM_LINELENGTH message to retrieve the appropriate buffer size:

int characterIndex = SendMessage(TEdit, EM_LINEINDEX, lineIndex, 0);
int lineLength = SendMessage(TEdit, EM_LINELENGTH, characterIndex, 0);
TCHAR* pBuffer = new TCHAR[lineLength + 1];
// Set the size of the buffer
*(WORD*)pBuffer = lineLength + 1;
// Retrieve the line
int characterCount = SendMessage(TEdit, EM_GETLINE, lineIndex, (LPARAM)pBuffer);
// NUL-terminate buffer
pBuffer[characterCount] = _T('\0');

A word on why the initial code appears to work when run under a debugger: It's not the debugger, that makes a difference. It's the Debug Build that does. A debug configuration will fill allocated memory with specific byte patterns (0xCD for operator new[]()). The effect of this is that the buffer passed when sending EM_GETLINE is interpreted as having size 0xCDCD (52685 in decimal). In a release configuration on the other hand, the buffer contents are usually 0x00, i.e. the buffer is interpreted as having size 0. This is not to say that the debug build works. It merely masks an error.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • I thought that message below WM_USER were marshaled. EM_GETLINE should be, specially if OP says that his code is working under debugger. – manuell Dec 04 '13 at 20:16
  • @manuell True, `EM_GETLINE` is below `WM_USER`, so you do not need to do any parameter marshalling. Will update the answer. – IInspectable Dec 04 '13 at 20:38
0

I used GetWindowText, works like a sharm I did't want to use fancy calculations. The error really only appears on multiline text, since the buffer size would be calculated correctly. MS Documentation GetWindowText

Martin Lietz
  • 113
  • 2
  • 8