Opened 6 years ago
Closed 5 years ago
#3697 closed Bug (Fixed)
_WinAPI_GetOverlappedResult fails to set the [out] parameter $iBytes in some cases
Reported by: | AlanParry | Owned by: | Jpm |
---|---|---|---|
Milestone: | 3.3.15.3 | Component: | Standard UDFs |
Version: | 3.3.14.5 | Severity: | None |
Keywords: | _WinAPI_GetOverlappedResult $ERROR_MORE_DATA | Cc: |
Description
_WinAPI_GetOverlappedResult does not set the $iBytes [out] parameter in the case where GetOverlappedResult() returns False.
However the $iBytes has a meaningful value in the case when it returns False and GetLastError()==ERROR_MORE_DATA
which can occur when using Named Pipes in message mode (see here if you wish to read about named pipes:[ https://docs.microsoft.com/en-us/windows/desktop/ipc/named-pipe-client]).
Note though that it should return the value for all cases regardless of the reason for the error.
The code back 3.3.8.1 was correct
In at least the following versions it isn't: 3.3.9.22, 3.3.12.0, 3.3.13.19, 3.3.14.5, 3.3.15.0, 3.3.15.1
The incorrect code is
Func _WinAPI_GetOverlappedResult($hFile, $tOverlapped, ByRef $iBytes, $bWait = False) Local $aResult = DllCall("kernel32.dll", "bool", "GetOverlappedResult", "handle", $hFile, "struct*", $tOverlapped, "dword*", 0, _ "bool", $bWait) If @error Or Not $aResult[0] Then Return SetError(@error, @extended, False) $iBytes = $aResult[3] Return $aResult[0] EndFunc ;==>_WinAPI_GetOverlappedResult
The old 3.3.8.1 CORRECT code (though missing the struct* change) was
Func _WinAPI_GetOverlappedResult($hFile, $pOverlapped, ByRef $iBytes, $fWait = False) Local $aResult = DllCall("kernel32.dll", "bool", "GetOverlappedResult", "handle", $hFile, "ptr", $pOverlapped, "dword*", 0, "bool", $fWait) If @error Then Return SetError(@error, @extended, False) $iBytes = $aResult[3] Return $aResult[0] EndFunc ;==>_WinAPI_GetOverlappedResult
Regards
Alan Parry
Attachments (0)
Change History (10)
comment:1 Changed 6 years ago by AlanParry
comment:2 Changed 6 years ago by Jpm
Hi,
I cannot undzrstand why passing a ptr instead of a struct can set $iBytes. But well can you post an example that reproduce the pb so I can analyse more carefully
Thanks for the help
comment:3 Changed 6 years ago by Jpm
- Component changed from AutoIt to Standard UDFs
comment:4 Changed 6 years ago by anonymous
The Struct/ptr code change is not the problem (that change since 3.3.8.1 is fine and wanted)
The problem is that:
If @error Then Return SetError(@error, @extended, False)
was changed to
If @error Or Not $aResult[0] Then Return SetError(@error, @extended, False)
So if $aResult[0] is False then the $iBytes = $aResult[3] statement doesn't get done.
The issue is just that the ByRef parameter needs to be assigned whatever is set by the DllCall in all cases, not just when the result is True.
An example would be long and complex but could be done, but hoping you don't need it.
Alan
comment:5 Changed 6 years ago by Jpm
Thanks,
the MSDN DOC does not describe how the ibyte parameter is set <hen the return result is set to zero.
So after the _WinAPI_GetOverlappedResult() return false you call the Getlasterror==ERROR_MORE_DATA then you need to use the nbbyte you use in the function that initiated the transfert _WinAPI-ReadFile() or other related function you use.
Perhaps it was working with the old coding but as it is not described in the MSDN DOC I will not change it
Cheers
comment:6 Changed 6 years ago by anonymous
Indeed MSDN doc is lacking <- nothing new there.
In the MSDN example at the end of what I linked to in the first post, just how many chars does the _tprintf statement output anyway???
BUT:- as MSDN does NOT document how and when it sets the $iBytes parameter, why should the UDF decide to discard the value set by Microsoft, based on some unnecessary and arbitrary logic in the UDF. Why discard the value if the return is False but use it when it returns True. Surely the UDF should pass back whatever the Dll call sets!
A look at Wine's implementation https://source.winehq.org/source/dlls/kernel32/file.c#0610 shows that it always sets the $iBytes value regardless of the return code or GetLastError() value.
But it's up to you whether you fix this bug or not. AS you say there are workarounds.
comment:7 Changed 6 years ago by Jpm
Hi,
For me it is not a workaraound as if MS make some internal changes the UDF still work
I leave to Jon the final answer on this Ticket
Cheers
comment:8 Changed 6 years ago by anonymous
Not sure why I'm persevering but it has occurred to me that what you said about MS not documenting it is not actually true.
The MSDN documentation says:
lpNumberOfBytesTransferred - A pointer to a variable that receives the number of bytes that were actually transferred by a read or write operation.
It doesn't say "but only in the case when GetOverlappedResult is True otherwise it can't be bothered to tell you how many bytes were successfully transferred"
When GetOverlappedResult returns False and GetLastError()==ERROR_MORE_DATA The Read/Write operation has transferred a whole buffer, and *lpNumberOfBytesTransferred is set to tell us how many that is - exactly as MSDN documents.
The UDF then discards the value leaving junk in $iBytes
(Also if an operation is aborted part way through, then it tells you how many where transferred - though I can't believe that's very reliable for Write).
Anyway this is absolutely my last comment on the matter, a workaround is too easy for all this effort.
Alan
comment:9 Changed 5 years ago by Jpm
- Owner set to Jpm
- Status changed from new to assigned
comment:10 Changed 5 years ago by Jpm
- Milestone set to 3.3.15.3
- Resolution set to Fixed
- Status changed from assigned to closed
Fixed by revision [12312] in version: 3.3.15.3
Guidelines for posting comments:
- You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
- In-depth discussions should take place on the forum.
For more information see the full version of the ticket guidelines here.
Sorry - should have set component to Standard UDFs