Is it safe to assume that this means "If and only if the function fails, the return value is NULL"?
Pretty safe. Usually MSDN tells you explicitly to check with GetLastError if zero as regular return value makes sense (a rare case anyway).
Never assume anything. GlobalFree returns NULL on success!!! There are a few API calls that return NULL on success. Just read the documentation for the function.
Gunner is right. Here is another example :
RegOpenKeyEx
RegQueryValueEx
RegCloseKey
All those three functions are returning ERROR_SUCCESS on success :
ERROR_SUCCESS equ 0
I didn't phrase my question clearly enough. It is a question about the wording of the Microsoft documentation.
In using the API and its documentation, I am not interested in determining the return based on success or failure; I am interested in determinimg success or failure based on the return. Logically, the quoted language authorizes only the first (uninteresting) determination - unless the "if" is interpreted as "only if" or "if and only if".
Sometimes,.but not always, the quoted the quoted language is accompanied by something like
Quote"If the function succeeds, the return is a pointer ..."
. Together the 2 statements do authorize the interesting determinations, but only on the (very reasonable) assumption that a function succeds if and only if it does not fail.
if the documentation states "If the function fails, the return value is zero."
then, yes - it is "if and only if"
Jochen found a case the other day that seemed a little odd with SendMessage
however, the return value for SendMessage varies with different messages
also - it may depend on how well the WndProc for the hWnd was written :P
because it determines what value is returned
one that i find particularly odd is SetFilePonter :bg
i think they had too many martinis at lunch, then came back and defined the behaviour of that function - lol
i generally write a "wrapper" function that calls it and hides all the clumsiness
Quote from: Gunner on March 11, 2012, 06:47:58 PM
Never assume anything. GlobalFree returns NULL on success!!! There are a few API calls that return NULL on success. Just read the documentation for the function.
Gunner,
As the thread title says, Robert means calls where MSDN clearly states "if it fails, it returns zero". However, there are a handful of cases (and I don't have any at hand) where zero is
also a valid return value. In these cases, MSDN tells you to check if GetLastError flags an error. If it doesn't, then zero is your valid return value.
I would suggest that there is no single return value that is universal, in every instance you need to look at the documentation for the function is to get the return value significance.
Take a common sort comparison result, > 0, 0 and < 0. There are in fact many others and it depends on what the function is performing as to what the return value may happen to be. 0 is often a successful return value so it is not wise to assume that it always indicates an error.
Quote from: raleeper on March 11, 2012, 06:01:09 PM
Is it safe to assume that this means "If and only if the function fails, the return value is NULL"?
You can assume exactly the opposite in COM, if the function succeeds the return value is always S_OK (0). For Flat API functions 0 means failure as often as it means success, however if a flat API function succeeds GetLastError will return 0 (ERROR_SUCCESS). There are a few cases such as CreateMutex where a partial success will not return 0 from GetLastError such as when an attempt is made to create a named mutex that already exists, the mutex handle is still returned but GetLastError returns ERROR_ALREADY_EXISTS. So, you must read the API documentation and treat each API as a unique case, except when using COM, it always returns 0 for success.
Quote from: donkey on March 12, 2012, 02:30:19 AMhowever if a flat API function succeeds GetLastError will return 0 (ERROR_SUCCESS).
There are many functions that do
not change GetLastError if they succeed. However, if
1. Microsoft says "if it fails, it returns zero"
2. A zero may nonetheless be a valid "successful" return value
then you need a call to GetLastError to verify whether the zero is an error or not.
Quote from: Gunner on March 11, 2012, 06:47:58 PM
Never assume anything. GlobalFree returns NULL on success!!! There are a few API calls that return NULL on success. Just read the documentation for the function.
Yes, but GlobalFree returns a handle/pointer, so NULL would be correct.
Generally, if you expect a handle or a pointer as a return value, NULL means failure. Of course, check the documentation before assuming...
Quote from: jj2007 on March 12, 2012, 06:19:21 AM
There are many functions that do not change GetLastError if they succeed.
True, my mistake. I tend to forget about the functions that don't set the last error code, its rare that I bother to check it except where it is used to specify that there is more data like FindNextFile or for CreateMutex where it is used for exclusion. Mostly I use the RTFM method and can just do a case by case check of the return value.
Quote from: jj2007 on March 12, 2012, 06:19:21 AM
Quote from: donkey on March 12, 2012, 02:30:19 AMhowever if a flat API function succeeds GetLastError will return 0 (ERROR_SUCCESS).
There are many functions that do not change GetLastError if they succeed. However, if
1. Microsoft says "if it fails, it returns zero"
2. A zero may nonetheless be a valid "successful" return value
then you need a call to GetLastError to verify whether the zero is an error or not.
Let me see if I have this right.
Quote1. Microsoft says "if it fails, it returns zero"
2. A zero may nonetheless be a valid "successful" return value
So if I get a zero I still need (to be completely safe) to call GetLastError.
But if
QuoteThere are many functions that do not change GetLastError if they succeed
how do I know whether the return from GetLastError pertains to the function just called. or is left over from a previous function.
The function that started me thinking about this was GetOpenFileName, which returns 0
QuoteIf the user cancels or closes the Open dialog box or an error occurs
(from MSDN}. So here the documentation alerts the programmer that 0 does not always mean failure for this function.
I think I will assume that a 0 means failure (when Microsoft says "if it fails, it returns zero") and rely on MS not to say "if it fails, it returns zero" unless this means "if and only if it fails, it returns zero"
Thanks, robert
Quote from: raleeper on March 12, 2012, 12:55:25 PM
The function that started me thinking about this was GetOpenFileName, which returns 0 QuoteIf the user cancels or closes the Open dialog box or an error occurs
(from MSDN}. So here the documentation alerts the programmer that 0 does not always mean failure for this function.
Robert,
In 99% of those cases where the docu says "zero on error", you don't need an extra check. In the remaining 1% of cases, the last error code MUST be set by the API to ensure the users knows the reason (either valid zero, or an error). The docu will invite the user explicitly to use GetLastError.
GetOpenFileName is indeed one of those stupid examples where you better check if the user aborted (0) or whether there was a crash somewhere (0). In both cases, you can't open the file in lpstrFile...
If the docs say a function returns NULL on failure, then NULL will be returned only in the event of failure, otherwise you can expect a legitimate usable value. But not all functions return NULL to indicate failure.
For those functions that return a pointer, then the failure value is usually NULL, since that's not a valid pointer reference (by convention.) Whereas, functions that return a numeric value could legitimately return zero and so they must have some other way to indicate failure (sometimes another value, sometimes setting 'last-error.')
But there's no strict consistency for indicating success/failure, so it's advisable to check the docs for each and every function. ::)
Quote from: Tedd on March 12, 2012, 02:53:00 PM
If the docs say a function returns NULL on failure, then NULL will be returned only in the event of failure, otherwise you can expect a legitimate usable value.
Tedd,
I am afraid it is not that simple.
MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724385%28v=vs.85%29.aspx):
QuoteIf the function succeeds, the return value is the requested ... setting.
If the function fails, the return value is 0. GetLastError does not provide extended error information.
Wow...! This is probably the worst case, but it's a real case. I tested this function on my puter, and got zero returned for more than a quarter of the requested settings. You all know the function - test yourself :green
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=12460)
; ####### Create a list with the SM_xxx codes of GetSystemMetrics ##########
Init
Let esi=FileRead$("sysinfo.txt") ; any file with copy & pasted stuff containing the SM_ codes
Let edi="SysMetrics.lst" ; the file with codes ready for use with a psm macro
Open "O", #1, edi
void Instr_(esi, "SM_") ; set a seed for repeated Instr
.Repeat
lea ecx, [eax+3] ; isolate the SM_x element
.Repeat
inc ecx
.Until byte ptr [ecx]<"0" ; SM_...
sub ecx, eax
PrintLine #1, "psm ", Left$(eax, ecx)
.Until !Instr_(0, esi, "SM_")
Close
Recall edi, L$() ; get the file as a string array
push eax
QSort L$() ; we want a sorted list
Open "O", #1, edi
mov esi, L$(0) ; seed string for duplicates test
pop eax
For_ ebx=0 To eax
.if StringsDiffer(esi, L$(ebx)) ; avoid duplicates
PrintLine #1, esi
mov esi, L$(ebx)
.endif
Next
Close
Inkey "Copy to clipboard (c) or launch notepad (n)?", CrLf$
.if eax=="n"
Launch Cat$("Notepad.exe "+edi)
.elseif eax=="c"
SetClip$ Cat$(FileRead$(edi))
PrintLine "SM list on clipboard"
.endif
Inkey "ok"
Exit
end start
Full example attached. For the lazy ones: MySystemMetrics.exe generates results for your puter. Very useful for software development on different machines, by the way :bg
Quote from: jj2007 on March 12, 2012, 11:38:27 PM
I am afraid it is not that simple.
MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724385%28v=vs.85%29.aspx):
QuoteIf the function succeeds, the return value is the requested ... setting.
If the function fails, the return value is 0. GetLastError does not provide extended error information.
Wow...! This is probably the worst case, but it's a real case. I tested this function on my puter, and got zero returned for more than a quarter of the requested settings.
I'll be accused of being picky here, but there is an important distinction -- NULL and zero are not the same.
NULL equates to zero, but the meaning is different. Zero means a numeric value of zero, NULL means a pointer with no value (the binary value for which happens to be 0 so it's easy to check.)
So, if the docs say NULL (not zero) is returned on failure, then NULL is an otherwise invalid value and should not be returned in any other case. Whereas if the docs say zero is returned on failure, then it may also be the case that zero could be a valid return value in the case of success - in this case there should be some other indication of failure (to double-check.)
Obviously GetSystemMetrics distorts all of this, but I suspect the only failure case for this function is passing in an invalid SM_ code and then zero is returned as a default; in all other cases the function succeeds and zero is a valid return value. But setting LastError would have been thoughtful. :lol
i think GetSystemMetrics returns 0 if the requested index is unsupported, as well
since there is no indication of function failure, it might be interpreted as an ambiguity
The question is, why GetSystemMetrics should fail. The only reason I can think of, is that the current OS doesn't support requested property. But this should not be a problem, because it is documented which version are not supported.
Quote from: Tedd on March 14, 2012, 04:54:35 PM
I'll be accused of being picky here, but ... NULL means a pointer
I might be accused of being picky here, but ... NULL is not necessarily a pointer :green
(besides, the distinction between 0 and zero and NULL is pretty academic - try handling it programmatically in assembler ::))