Holy cow, I wrote a book!
GetWindowText() is more complicated than you think. The documentation tries to explain its complexity with small words, which is great if you don't understand long words, but it also means that you're not getting the full story.
Here's an attempt to give the full story.
There are two ways window classes can manage their text. They can either do it manually or they can let the system do it. The default is to let the system do it.
If a window class lets the system manage its text, the system will do the following:
On the other hand, if a window class manages its window text manually, the system will not do any special handling, and it is the window class's responsibility to respond to the WM_GETTEXT/WM_SETTEXT messages and return/save the strings explicitly.
Frame windows typically let the system manage their window text. Custom controls typically manage their window text manually.
GetWindowText has a problem: Window text needs to be readily available without hanging. FindWindow() needs to get window text in order to find a window. Task-switching applications need to get window text so they can display the window title in the switcher window. It should not be possible for a hung application to clog up other applications. This is particularly true of the task switcher scenario.
This argues against sending WM_GETTEXT messages, because the target window of the WM_GETTEXT might be hung. Instead, GetWindowText should use the "special place" since that cannot be affected by hung applications.
On the other hand, GetWindowText is used to retrieve text from controls on a dialog, and those controls frequently employ custom text management. This argues for sending WM_GETTEXT messages, because that is the only way to retrieve custom-managed text.
So GetWindowText strikes a compromise.
According to the first rule, if you are trying to get text from a window in your own process, and the window is hung, then GetWindowText() will also hang. But since the window belongs to your process, it's your own fault and you deserve to lose. Sending the WM_GETTEXT message ensures that text from windows that do custom text management (typically, custom controls) are properly retrieved.
According to the second rule, if you are trying to get text from a window in another process, then GetWindowText() will not send a message; it will just retrieve the string from the "special place". Since the most common reason for getting text from a window in another process is to get the title of the frame, and since frame windows typically do not do custom window text manipulation, this usually gets the right string.
The documentation simplifies this as "GetWindowText() cannot retrieve text from a window from another application."
Note, however, that if the target window is hung, your application will also hang since SendMessage() will not return until the target window responds.
Note also that since WM_GETTEXT is in the system message range (0 to WM_USER-1), you do not need to do any parameter marshalling (and in fact, you shouldn't). USER will do the marshalling for you.
SampleWndProc(...) { case WM_GETTEXT: lstrcpyn((LPTSTR)lParam, "Booga!", (int)wParam); return lstrlen((LPTSTR)lParam); case WM_GETTEXTLENGTH: return 7; // lstrlen("Booga!") + null ... }
hwnd = CreateWindow("Sample", "Frappy", ...);
TCHAR szBuf[80]; GetWindowText(hwnd, szBuf, 80);
SendMessage(hwnd, WM_GETTEXT, 80, (LPARAM)szBuf);