this-is-me Posted November 18, 2014 Share Posted November 18, 2014 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. expandcollapse popup#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 More sharing options...
Queener Posted November 18, 2014 Share Posted November 18, 2014 (edited) not going to guarantee if this going to work, but you can try adding #RequireAdmin below #includes Edited November 18, 2014 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 More sharing options...
Solution binhnx Posted November 18, 2014 Solution Share Posted November 18, 2014 (edited) 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 November 18, 2014 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 More sharing options...
this-is-me Posted November 18, 2014 Author Share Posted November 18, 2014 (edited) 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. This has prevented the crash. Edited November 18, 2014 by this-is-me Who else would I be? Link to comment Share on other sites More sharing options...
this-is-me Posted November 18, 2014 Author Share Posted November 18, 2014 @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 More sharing options...
binhnx Posted November 19, 2014 Share Posted November 19, 2014 Ahhh, I didn't read the help file carefully. My bad. Glad to see your problem solved 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now