Jump to content

AutoIt hard crash in x64 with simple folder monitor


Go to solution Solved by binhnx,

Recommended Posts

I have just spent hours laboring over some older code that I was upgrading to AutoIt v3.3.12.0
However, I have come to realize that this does not appear to be "my" problem, but a problem with AutoIt or its includes. Now, I am not so arrogant as to admit if I made a mistake in my coding, but I have tried 4 different file system monitors on this forum, all using ShChangeNotifyMsg. All of them blow up on Windows 8.1, 64-bit. I have not tried my Windows 7, 64-bit system. When I view the event logs and use WinDBG (I am a novice with this), the error message indicates that shell32.dll reports "An unhandled exception was encountered during a user callback." After debugging, I can find that _WinAPI_ShellGetPathFromIDList is where the crash occurs. However, I can't debug further. I don't know how to solve this or if it can be solved without repairing AutoIt. This is an example code.

#AutoIt3Wrapper_UseX64=y
#include <WinAPI.au3>
#include <WinAPIShellEx.au3>

Global $fm_callback, $fm_registration

_Folder_Monitor("C:\", FolderChange, BitOR($SHCNE_RENAMEFOLDER, $SHCNE_DRIVEADD, $SHCNE_DRIVEREMOVED, $SHCNE_MKDIR, $SHCNE_RMDIR))

While 1
    Sleep(1000)
WEnd

Func _Folder_Monitor($sFolder, $fCallback, $iEvents = $SHCNE_ALLEVENTS, $hGui = GUICreate(""))
    Local $notify = _WinAPI_RegisterWindowMessage("shchangenotifymsg")
    GUIRegisterMsg($notify, _Folder_Monitor_SHNOTIFY)
    $fm_registration = _WinAPI_ShellChangeNotifyRegister($hGui, $notify, $iEvents, BitOR($SHCNRF_INTERRUPTLEVEL, $SHCNRF_SHELLLEVEL), $sFolder, 1)
    $fm_callback = $fCallback
    OnAutoItExitRegister(_Folder_Monitor_Exit)
EndFunc

Func _Folder_Monitor_Exit()
    _WinAPI_ShellChangeNotifyDeregister($fm_registration)
EndFunc

Func _Folder_Monitor_SHNOTIFY($hWnd, $Msg, $wParam, $lParam)
    Local $path, $dw1, $dw2
    $path = DllStructCreate('dword Item1; dword Item2', $wParam)
    $dw1 = _WinAPI_ShellGetPathFromIDList(DllStructGetData($path, 'Item1'))
    $dw2 = _WinAPI_ShellGetPathFromIDList(DllStructGetData($path, 'Item2'))
    If IsFunc($fm_callback) Then $fm_callback($lParam, $dw1, $dw2)
EndFunc

Func FolderChange($iEvent, $sFolder, $sFolderNew)
    Switch $iEvent
        Case $SHCNE_RENAMEFOLDER
            dbg($sFolder & " is renamed to " & $sFolderNew)
        Case $SHCNE_MKDIR
            dbg($sFolder & " is newly created")
        Case $SHCNE_RMDIR
            dbg($sFolder & " has been deleted")
        Case $SHCNE_DRIVEADD
            dbg("Drive has been added: " & $sFolder)
        Case $SHCNE_DRIVEREMOVED
            dbg("Drive has been removed: " & $sFolder)
    EndSwitch
EndFunc   ;==>FolderChange

Func dbg($sMsg)
    ConsoleWrite($sMsg & @CRLF)
EndFunc

After starting this script from SciTE, create or delete a folder, and watch AutoIt crash and burn.

If someone can help me, I would truly appreciate it. I have pulled my hair out over this for hours and am no closer to a solution. Also, before you ask, yes - I do need to monitor the whole drive for these changes.

Who else would I be?
Link to comment
Share on other sites

not going to guarantee if this going to work, but you can try adding

#RequireAdmin

below #includes

Edited by asianqueen

Msgbox(0, "Hate", "Just hate it when I post a question and find my own answer after a couple tries. But if I don't post the question, I can't seem to resolve it at all.")
Link to comment
Share on other sites

  • Solution

Your script has a mistake:

You use an x64 Windows version. In x64, INT_PTR is 8-byte-long, not 4 bytes. So, INT_PTR is not DWORD, its a LONG.

The best practice is not try modifying native type when using DllCall, if the type is INT_PTR, do not change it to DWORD, leave it 'INT_PTR'

So this line:

$path = DllStructCreate('dword Item1; dword Item2', $wParam)

should be change to 

$path = DllStructCreate('INT_PTR Item1; INT_PTR Item2', $wParam)

May be it is the reason that makes your script crash.

Edit: Btw, I doubt that the reason of crashing is not in your script but in the UDF itself. If the above change won't work, try using a custom WinAPI function like this:

Func _Binhnx_WinAPI_ShellGetPathFromIDList($pPIDL) ; :) choose another function name
    As stated in MSDN document, the buffer must have atleast MAX_PATH (=260) character length!
    Local $sBuf = DllStructCreate('WCHAR[' & 65535 & ']')
    Local $aRet = DllCall('shell32.dll', 'bool', 'SHGetPathFromIDListW', 'ptr', $pPIDL, 'ptr', DllStructGetPtr($sBuf))

    If @error Or Not $aRet[0] Then Return SetError(@error, @extended, '')
    ; If Not $aRet[0] Then Return SetError(1000, 0, 0)

    Return DllStructGetData($sBuf, 1)
EndFunc   ;==>_WinAPI_ShellGetPathFromIDList
Edited by binhnx

99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Link to comment
Share on other sites

 

Your script has a mistake:

You use an x64 Windows version. In x64, INT_PTR is 8-byte-long, not 4 bytes. So, INT_PTR is not DWORD, its a LONG.

The best practice is not try modifying native type when using DllCall, if the type is INT_PTR, do not change it to DWORD, leave it 'INT_PTR'

So this line:

$path = DllStructCreate('dword Item1; dword Item2', $wParam)

should be change to 

$path = DllStructCreate('INT_PTR Item1; INT_PTR Item2', $wParam)

May be it is the reason that makes your script crash.

Edit: Btw, I doubt that the reason of crashing is not in your script but in the UDF itself. If the above change won't work, try using a custom WinAPI function like this:

Func _Binhnx_WinAPI_ShellGetPathFromIDList($pPIDL) ; :) choose another function name
    As stated in MSDN document, the buffer must have atleast MAX_PATH (=260) character length!
    Local $sBuf = DllStructCreate('WCHAR[' & 65535 & ']')
    Local $aRet = DllCall('shell32.dll', 'bool', 'SHGetPathFromIDListW', 'ptr', $pPIDL, 'ptr', DllStructGetPtr($sBuf))

    If @error Or Not $aRet[0] Then Return SetError(@error, @extended, '')
    ; If Not $aRet[0] Then Return SetError(1000, 0, 0)

    Return DllStructGetData($sBuf, 1)
EndFunc   ;==>_WinAPI_ShellGetPathFromIDList

AWESOME! Not knowing how the original scripts I was copying were malformed prevented me from seeing this! Thank you so very much.  :huggles:

This has prevented the crash.

Edited by this-is-me
Who else would I be?
Link to comment
Share on other sites

@binhnx, it appears that your ShellGetPathFromIDList mod is unecessary. From the help file on DllCall:

WSTR a UNICODE wide character string (a minimum of 65536 chars is allocated).

 

So the "mod" is already included in AutoIt. However, the int_ptr DID fix the crashes, so kudos to you on that one.

Who else would I be?
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...