GetLastError returning ERROR_SUCCESS after calling ConnectNamedPipe - winapi

When I call ConnectNamedPipe with an OVERLAPPED structure and check GetLastError afterwards, I often see GetLastError return ERROR_SUCCESS. The way I'm reading the documentation, that should never happen. My understanding is that if a client has already connected, ERROR_PIPE_CONNECTED should be set, not ERROR_SUCCESS.
Has anyone else seen this? The OS is 32-bit Windows 7.

That's typical for OVERLAPPED. It tells whether the parameters are okay before connecting, assuming an asynchronous socket. Once a connection completes or fails, then GetOverlappedResult() returns the proper status. So I guess this is a minor documentation error.

Try calling GetLastError() immediately after ConnectNamedPipe.
Don't call any API in between.

Related

How can you tell if SendMessage() was successful (message was delivered)?

is it possible to determine if a SendMessage() call was successful and delivered my message to the target window?
The SendMessage() description in the Windows API seems quiet on this and only says the following:
The return value specifies the result of the message processing; it depends on the message sent.
This obviously refers to the fact that the return code reflects the value returned by the wndproc of the target window.
But what will the return code be if the message wasn't delivered at all (e.g. due to access control, or due to the window having been destoroyed in the meantime)? How can I detect such situations?
There is no way to reliably tell, whether a call to SendMessage succeeded or failed. After all, it only has a single return value, and the entire range of values is used. There is no designated error value.
Playing tricks with the calling thread's last error code won't work either. The scheme proposed in this answer (clearing the last error code prior to the call and evaluating it after the call) is brittle. It's easy to see that it can fail, when sending a message to a window owned by the calling thread (as that window's window procedure is at liberty to change the last error any way it sees fit).
It's not quite as well known, that this can also fail when sending a message to a window owned by a different thread. The code suggests, that no intervening API call can happen in the calling thread. Yet in that scenario, SendMessage will also dispatch incoming cross-thread messages (see When can a thread receive window messages?), allowing the thread's last error code to change.
The only option then is to use SendMessageTimeoutW, as that API reports both the result of the call, as well as an error/success indicator. Passing the SMTO_NOTIMEOUTIFNOTHUNG flag makes sure that an arbitrarily chosen timeout will not adversely affect the outcome.
if SendMessage fail, it set last win32 error code, which we can get back via call GetLastError(). and returned error code, in case fail, never will be 0 (NOERROR) despite this is clear not documented. but how detect that SendMessage is fail ? here we can not base on return value. but we can SetLastError(NOERROR) before call SendMessage and check GetLastError() after:
if SendMessage fail - value returned by GetLastError() will be
not 0. (most common in this case ERROR_INVALID_WINDOW_HANDLE or
ERROR_ACCESS_DENIED).
if we still got 0 as last error - this mean that message was
delivered with no error.
however, possible case, when during SendMessage call, some window procedure
in current thread will be called and
code inside window procedure, set last error to non 0 value. so we
get finally not 0 last error, but not because SendMessage fail.
distinguish between these two cases very problematic
-
SetLastError(NOERROR);
LRESULT lr = SendMessageW(hwnd, *, *, *);
ULONG dwErrorCode = GetLastError();
if (dwErrorCode == NOERROR)
{
DbgPrint("message was delivered (%p)\n", lr);
}
else
{
DbgPrint("fail with %u error\n", dwErrorCode);
}

GetMenuItemCount returning -1

Under what conditions the Win32 call GetMenuItemCount can return -1, except of providing an invalid handle to the menu?
All you can assume is that GetMenuItemCount returns -1 on failure.
Specific reasons why this API call can fail are not documented—i.e., they are not part of the published contract. They are implementation details that can change over time, so your code cannot rely upon them.
If you need to get additional information in the event of a failure, call GetLastError as the documentation advises.

InternetReadFile() reads data but returns false and sets number of bytes read to zero

Making an asynchronous request with Wininet, when the status callback function is called with INTERNET_STATUS_REQUEST_COMPLETE, I get the http status code.
result = HttpQueryInfo(
this->requestHandle,
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
&value,
&sizeofDword,
&index);
The status code returned is 200. After that, I call InternetReadFile().
result = InternetReadFile(
this->requestHandle,
((char*)(this->buffer)) + this->totalBytesReceived,
this->bufferSize - this->totalBytesReceived,
&bytesRead);
this->totalBytesReceived += bytesRead;
It returns true and sets lpNumberOfBytesRead to zero. GetLastError() returns ERROR_IO_PENDING, then I wait the callback function is called again with INTERNET_STATUS_REQUEST_COMPLETE.
When that occurs, InternetReadFile() returns true and again sets lpNumberOfBytesRead to zero.
If I debug the application, I can see after the first InternetReadFile() that the response data is already on the lpBuffer. Moreover, if I call Sleep() for one second before InternetReadFile(), InternetReadFile() works correctly.
Sleep(1000);
result = InternetReadFile( ...
Am I missing any step?
I've encountered similar problem, and still the same even using Sleep(1000). I was connecting to a 3rd party camera stream, I've tried it on debug version, which worked perfectly. But when I went back to release version, it just wouldn't work.
I fixed it by changing HttpOpenRequest's lplpszAcceptTypes to NULL, then everything started working to work.
Seems like when WinINet dealing with internet connection, with different type of mobile phone / os /debug or release binary version/ have some kind of different operation which we can not possibly know.

Correct return value of "WindowProc" in a Win32 application

In MSDN's Win32-Api documentation (at http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx) on the WindowProc, it states: The return value is the result of the message processing and depends on the message sent.
Since I have to implement this (callback) procedure, I'd like to know what it depends on, and what I have to return. Can someone shed some light on this?
It is dependent on the exact message you are processing. You need to refer to the documentation for that message to see the expected values and meanings of the return value.
For instance, for WM_CREATE, you should return zero to continue window creation, and -1 to fail and destroy the window. For WM_GETICON, you should return a handle to the icon for your window.
For messages that you do not explictly handle, you should call DefWindowProc, passing to it all the parameters to your window proc, and return its return value to the caller.
Michael's answer answers the question perfectly, but just for reference, the usual return value will always be 0.
For most messages it means that your application has processed the message. But always consult the MSDN page for the actual message to know for sure.

Why would WaitForSingleObject return WAIT_FAILED

MSDN says
If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.
The code is:
HANDLE m_mutex_handle; /**< m_mutex_handle. The handle to the created mutex. */
m_mutex_handle = ::CreateMutex( 0, false, NULL );
::WaitForSingleObject( m_mutex_handle, INFINITE );
But what are the reasons that could happen?
If you lack the SYNCHRONIZE privilege on the object, then you cannot wait. WAIT_FAILED will be returned.
Passing in a bogus object might cause that.
Closing a handle while the handle is being waited on can also cause undefined behaviour.
I got WAIT_FAILED from WaitForMultipleObjects when passing in an array of thread handles as one of them was a pseudo handle. As ever the immortal Raymond Chen explained, and provided the fix: https://devblogs.microsoft.com/oldnewthing/20141015-00/?p=43843

Resources