Jump to content
Sign in to follow this  
funkey

Bug or feature? DllClose sets last Windows error to zero

Recommended Posts

funkey

DllClose makes the function _WinAPI_GetLastError() return zero. OK that would not be a problem and I understand why this is as it is. But if I make a DllCall without DLL handle but with DLL name, then DllOpen and DllCose is automatically called. And then _WinAPI_GetLastError() always returns zero. I now use 3.3.8.1 and can not test on newer version, but I think it's the same result.

 

Here is an example:

#include <WinAPI.au3>

Global Const $tagDATA_BLOB = "DWORD cbData;ptr pbData;"

; DllClose sets last Windows error to zero

_BugTest()
_WorkingTest()

Func _BugTest()
    Local $bData = Binary("0x1234567890")
    Local $tDataBuf = DllStructCreate($tagDATA_BLOB)
    Local $tDataIn = __DataToBlob($bData)
    Local $aRet = DllCall("crypt32.dll", "BOOL", "CryptUnprotectData", "struct*", $tDataIn, "ptr*", 0, "ptr", 0, "ptr", 0, "ptr", 0, "DWORD", 0, "struct*", $tDataBuf)
    If $aRet[0] = 0 Then ;of cource this fails
        MsgBox(16, "BugTest", "Last Windows error: " & _WinAPI_GetLastError())
    Else
        _WinAPI_LocalFree(DllStructGetData($tDataBuf, "pbData"))
    EndIf

    _WinAPI_LocalFree(DllStructGetData($tDataIn, "pbData"))
EndFunc

Func _WorkingTest()
    Local $bData = Binary("0x1234567890")
    Local $tDataBuf = DllStructCreate($tagDATA_BLOB)
    Local $tDataIn = __DataToBlob($bData)
    Local $hDLL_Crypt32 = DllOpen("crypt32.dll")
    Local $aRet = DllCall($hDLL_Crypt32, "BOOL", "CryptUnprotectData", "struct*", $tDataIn, "ptr*", 0, "ptr", 0, "ptr", 0, "ptr", 0, "DWORD", 0, "struct*", $tDataBuf)
;~  DllClose($hDLL_Crypt32)
    If $aRet[0] = 0 Then ;of cource this fails
        MsgBox(16, "WorkingTest", "Last Windows error: " & _WinAPI_GetLastError())
    Else
        _WinAPI_LocalFree(DllStructGetData($tDataBuf, "pbData"))
    EndIf
    DllClose($hDLL_Crypt32)
    _WinAPI_LocalFree(DllStructGetData($tDataIn, "pbData"))
EndFunc


Func __DataToBlob($data)
    ;funkey 2014.08.11th
    Local $iLen, $tDataIn, $tData, $aMem
    Local Const $LMEM_ZEROINIT = 0x40
    Select
        Case IsString($data)
            $iLen = StringLen($data)
        Case IsBinary($data)
            $iLen = BinaryLen($data)
        Case Else
            Return SetError(1, 0, 0)
    EndSelect

    $tDataIn = DllStructCreate($tagDATA_BLOB)
    $aMem = DllCall("Kernel32.dll", "handle", "LocalAlloc", "UINT", $LMEM_ZEROINIT, "UINT", $iLen)
    $tData = DllStructCreate("byte[" & $iLen & "]", $aMem[0])

    DllStructSetData($tData, 1, $data)
    DllStructSetData($tDataIn, "cbData", $iLen)
    DllStructSetData($tDataIn, "pbData", DllStructGetPtr($tData))

    Return $tDataIn
EndFunc   ;==>__DataToBlob

What do you think about it?


Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Share this post


Link to post
Share on other sites
funkey

GetLastError is used everywhere in the WinAPI-UDF. But I found out, that there is no problem if the dll is already used by AutoIt internally (see sample code).

Can't we store the last error after function call and then set it after closing dll handle before returning to script? This would give the expected behaviour with winapi dll calls.

#include <WinAPI.au3>

Global $hFile = 0 ;invalid file pointer

Global $iRes = _WinAPI_SetFilePointer($hFile, 1, 2)
If $iRes = $INVALID_SET_FILE_POINTER Then
    ConsoleWrite("Last Windows error: " &  _WinAPI_GetLastError() & @LF)    ; 6 = ERROR_INVALID_HANDLE
EndIf

Global $hDllKernel32 = DllOpen("kernel32.dll")
Global $iRes2 = _Winapi_SetFilePointerViaDllHandle($hDllKernel32, $hFile, 1, 2)
DllClose($hDllKernel32)
If $iRes = $INVALID_SET_FILE_POINTER Then
    ConsoleWrite("Last Windows error: " &  _WinAPI_GetLastError() & @LF)    ; 6 = ERROR_INVALID_HANDLE
EndIf


Func _WinAPI_SetFilePointerViaDllHandle($hDLL, $hFile, $iPos, $iMethod = 0)
    Local $aResult = DllCall($hDLL, "INT", "SetFilePointer", "handle", $hFile, "long", $iPos, "ptr", 0, "long", $iMethod)
    If @error Then Return SetError(@error, @extended, -1)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_SetFilePointer

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×