Sign in to follow this  
Followers 0
gdev

AutoIt crashes when calling GetFullPathName using DllCall

20 posts in this topic

#1 ·  Posted (edited)

Hi,

I have found that calling this kernel32 function crashes autoit under some circumstances. I've narrowed it to calling DllCall from a function defined in an AutoIt file, when the main script includes that file and calls that function.

Here are the 2 required code files. A third file called "test_details.txt" is also required (it can be empty).

File "included.au3"

#include-once

; Returns the full path of a given file.
; @see http://msdn.microsoft.com/en-us/library/aa364963%28v=vs.85%29.aspx
Func _WinAPI_GetFullPathName( $path )
    InputBox( "","Querying", $path )
    Local $void = 0
    Local $fullPath = ""
    $res = DllCall( "kernel32.dll", "dword", "GetFullPathName", "str", $path, "dword", 255, "str", $fullPath, "str*", $void )
    MsgBox( 0, "Error after Querying", @error )
    Return $res[ 3 ]
EndFunc

$searchPath = @ScriptDir
$fileName = "test_details.txt"
MsgBox( 0, "Crash test", "This one doesn't crash" )
_WinAPI_GetFullPathName( $searchPath & "\" & $fileName )

File "test.au3"

#include <included.au3>

MsgBox( 0, "Crash test", "However, calling this will crash" )
_WinAPI_GetFullPathName( @ScriptDir & "\" & "test_details.txt" )

When you run test.au3, the function will be executed once (it is called in included.au3) without a problem. Then, it will be called a second time from test.au3, and it will crash when calling DllCall.

I can reproduce this crash on a Windows XP Pro machine, a virtual machine with the same OS and Windows x64 when running AutoIt in 32-bit mode. Under 64-bit mode, my function just crashes all the time.

I have reviewed the code several times, and I think it's OK, but I may have missed something that produces this behaviour. However, the AutoIt process should not crash if its a bug in the scripts, so I suspect it's a bug.

Edit: removed attached files, replaced by inline code.

Edited by gdev

Share this post


Link to post
Share on other sites



Doesn't crash for me under Windows 7 x86.


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

Have a look at _WinAPI_GetFullPathName in WinAPIEx by Yashied.


_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 04/09/2015

Share this post


Link to post
Share on other sites

Weird... using DllStructCreate('wchar[1024]') works. It's a workaround, but the question of why calling that dll function works in included.au3 and not in test.au3.

Share this post


Link to post
Share on other sites

I didn't test as I always use WinAPIEx or WinAPI when wanting to call API functions and if not included I post a request in WinAPIEx, which has only happened once if I'm honest, wait it was GetFullPathName in fact. :graduated:


_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 04/09/2015

Share this post


Link to post
Share on other sites

Because you wrong use the third parameter in this function. Read carefully MSDN.

$File = 'Test.txt'
$tPath = DllStructCreate("char[260]") ; MAX_PATH = 260
$Res = DllCall("kernel32.dll", "dword", "GetFullPathNameA", "str", $File, "dword", 260, "ptr", DllStructGetPtr($tPath), "ptr*", 0)
 
ConsoleWrite('Final path: ' & DllStructGetData($tPath, 1) & @CR)
ConsoleWrite('Directoty:  ' & StringLeft(DllStructGetData($tPath, 1), $Res[4] - DllStructGetPtr($tPath)) & @CR)

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

LPTSTR lpBuffer = LPWSTR = WCHAR*

or = LPSTR = unsigned char* (ANSII)

From autoit's help file entry of DllCall:

; Example 2 - calling a function that modifies parameters
$result = DllCall("user32.dll", "int", "GetWindowText", "hwnd", $hwnd, "str", "", "int", 32768)
msgbox(0, "", $result[0])   ; number of chars returned
msgbox(0, "", $result[2])   ; Text returned in param 2

That's why I'm not sending a struct as a parameter. And it works, I get the full path name. It just crashes when I call my custom function from another autoit file.

Edited by gdev

Share this post


Link to post
Share on other sites

Strings aren't variable length in C :graduated: If you pass a string of length 0 to be filled with 255 characters then there is going to be a problem.

Share this post


Link to post
Share on other sites

Sure I know that... But I got that from the example... It's passing an empty string as a return (out) parameter. The parameter gets modified by the function and returned in an array by DllCall.

And Mat, your answer does not explain why running included.au3 works.

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Strings aren't variable length in C Posted Image If you pass a string of length 0 to be filled with 255 characters then there is going to be a problem.

Mat, what are you talking about? Where is he doing that?

The only mistake in your code is the last parameter. Yashied is wrong about you being wrong.

The last parameter can receive 0, according to function documentation. That's when it will crash. "str*" is ok to use but not with NULL pointer.

edit: and please post this kind of code using code boxes or whatever instead of attaching files. Yes, and when I say please, I mean "do".

Edited by trancexx

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Mat, what are you talking about? Where is he doing that?

The only mistake in your code is the last parameter. Yashied is wrong about you being wrong.

The last parameter can receive 0, according to function documentation. That's when it will crash. "str*" is ok to use but not with NULL pointer.

edit: and please post this kind of code using code boxes or whatever instead of attaching files. Yes, and when I say please, I mean "do".

Thanks trancexx. That worked in 32-bit mode. I still get a crash (always, no matter which file I run) when running the 64-bit version.

Edit: I can't edit the OP, may I paste the code here?

Edited by gdev

Share this post


Link to post
Share on other sites

Edit: I can't edit the OP, may I paste the code here?

Unless the force would be disturbed.
1 person likes this

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Now I can edit, thanks :graduated:

Share this post


Link to post
Share on other sites

But where is the code after you changed it the way I told you.

You said that you still get crash. With what code?


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Ok, here it is:

#include-once
; Returns the full path of a given file.
; @see http://msdn.microsoft.com/en-us/library/aa364963%28v=vs.85%29.aspx
Func _WinAPI_GetFullPathName( $path )
InputBox( "","Querying", $path )
Local $void = 0
Local $fullPath = ""
$res = DllCall( "kernel32.dll", "dword", "GetFullPathName", "str", $path, "dword", 255, "str", $fullPath, "str*", 0 )
MsgBox( 0, "Error after Querying", @error )
Return $res[ 3 ]
EndFunc
$searchPath = @ScriptDir
$fileName = "test_details.txt"
MsgBox( 0, "Crash test", "This one doesn't crash" )
_WinAPI_GetFullPathName( $searchPath & "\" & $fileName )

Share this post


Link to post
Share on other sites

Do... not... use... "str*".


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Do... not... use... "str*".

Ooops, I forgot about that.

Thank you trancexx, it really works now.

$res = DllCall( "kernel32.dll", "dword", "GetFullPathName", "str", $path, "dword", 255, "str", $fullPath, "ptr", 0 )

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

Ooops, I forgot about that.

Thank you trancexx, it really works now.

$res = DllCall( "kernel32.dll", "dword", "GetFullPathName", "str", $path, "dword", 255, "str", $fullPath, "ptr", 0 )

Sure, no problem. Btw, don't forget to water the plants, feed your animals and other stuff. The nature will be grateful. Also, Yashied suggested that MAX_PATH is 260. Edited by trancexx

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

I'm using 1024 in my application, but more might be needed.

The Windows API has many functions that also have Unicode versions to permit an extended-length path for a maximum total path length of 32,767 characters.

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

I'm using 1024 in my application, but more might be needed.

Some functions will return the required buffer size, if called with an insufficient buffer.

e.g. _WinAPI_MultiByteToWideChar()

Or magic numbers are used, like the hated 4096 found in the UDFs.

Func _WinAPI_GetFullPathName($sFile)
;modified from WinAPIEx.au3 by Yashied
;In the ANSI version of this function, the name is limited to MAX_PATH characters.
;To extend this limit to 32,767 wide characters, call the Unicode version of the function
;and prepend "\\?\" to the path.
;http://msdn.microsoft.com/en-us/library/aa364963%28v=vs.85%29.aspx
 
;If the lpBuffer buffer is too small to contain the path, the return value is the size, in TCHARs,
;of the buffer that is required to hold the path and the terminating null character.
 
Local $Ret = DllCall('kernel32.dll', 'dword', 'GetFullPathNameW', 'wstr', $sFile, 'dword', 0, 'ptr', 0, 'ptr*', 0)
If (@error) Or (Not $Ret[0]) Then Return SetError(1, @error, '')
 
Local $tPath = DllStructCreate('wchar['&$Ret[0]&']')
$Ret = DllCall('kernel32.dll', 'dword', 'GetFullPathNameW', 'wstr', $sFile, 'dword', $Ret[0], 'ptr', DllStructGetPtr($tPath), 'ptr*', 0)
If (@error) Or (Not $Ret[0]) Then Return SetError(2, @error, '')
 
Return DllStructGetData($tPath, 1)
EndFunc   ;==>_WinAPI_GetFullPathName
Edited by rover

I see fascists...

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  
Followers 0