Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I differentiate between an empty window text and an error with the GetWindowText API?

Tags:

windows

winapi

The GetWindowText function's return value is documented as follows:

If the function succeeds, the return value is the length, in characters, of the copied string, not including the terminating null character. If the window has no title bar or text, if the title bar is empty, or if the window or control handle is invalid, the return value is zero. To get extended error information, call GetLastError.

Now, when calling this method and receiving a return value of zero, how do I know whether GetLastError would return a sensible value? After all, zero is not only used to indicate failure, but could also mean that the window text is empty, in which case GetLastError would not return an undefined value.

My own ideas:

  • At first, I thought that maybe GetWindowText might set the last error to 0 on success. But testing shows it doesn't (and if it did, I couldn't rely on it anyway, since this isn't documented).
  • Then, I thought that maybe GetWindowText might leave the last error unchanged on success, so setting it to 0 myself before the call would allow me to check whether the last error has changed. Testing shows this might work, but since it's not doumented this way, I can't rely on it. (And I guess this would depend heavily on the concrete circumstances and implementation of GetWindowText.)
  • And, of course, I could first check the window text length using GetWindowTextLength and then call GetWindowText only if the length was greater than 0. However, what if the window changes its text between my calls to GetWindowTextLength and GetWindowText? I, again, couldn't rely on a return value of zero denoting an error.

So, what can I do to definitely decide whether GetWindowText failed?

like image 317
Fabian Schmied Avatar asked Oct 23 '12 09:10

Fabian Schmied


2 Answers

SetLastError(ERROR_SUCCESS) beforehand is perfectly safe and supported.

The documentation for last-error codes make it clear that a function may or may not clear the last-error value on success. What is certain, however, is that if a function succeeds, it will either leave the last-error value unchanged, or set it to zero, but never change it to an error value.

The implementation rules for WinAPI functions may be summarized as:

  1. Don't call SetLastError if no error occurs.
  2. If a helper function sets an error code, which does not cause failure of your API, call SetLastError(0) so the non-fatal internal error isn't visible to the caller, or call RestoreLastError and pass whatever GetLastError returned on entry to your API
  3. If your API fails without throwing an SEH exception, call SetLastError to report it (unless a helper function already did).

The documented behavior "some functions call SetLastError with a zero when they succeed" is a consequence of point #2.

like image 175
Ben Voigt Avatar answered Nov 14 '22 14:11

Ben Voigt


Yes, you are right, you cannot actually use GetLastError() to see the difference. Not pretty. The only workaround I can think of is to use IsWindow() afterward. If that returns TRUE then a zero return really means "empty string". That, however, doesn't deal with passing a bad buffer pointer, hopefully easily avoided in your code.

like image 42
Hans Passant Avatar answered Nov 14 '22 15:11

Hans Passant