zed12 Posted September 16, 2018 Posted September 16, 2018 Brand new to AutoIt, fairly new to the Win32 API, and very experienced with linux C++. I'm trying to use DllCall's to write a binary file. As a proof of concept, I'm trying the below code. As it's written, $buffer isn't initialized, so I understand would write garbage to the file. The script successfully creates the file, but it remains 0 bytes. WriteFile is returning 0. Curiously, _GetLastError() is printing "The operation completed successfully." I originally tried WriteFile with 0 for lpNumberOfBytesWritten, but in this version I do give it a variable to write to, but that had no effect. I also tried "'dword*', $bytesWritten, _" for that line. Giving null here seems to indicate for it to be an asynchronous write, and I'm not sure if going that way then immediately closing causes the OS to wait for the write or to preempt it. That's the only reason (and for debugging purposes) that I'm not using 0 there. expandcollapse popup#include <MsgBoxConstants.au3> Func _GetLastErrorMessage($DisplayMsgBox="") Local $ret,$s Local $p = DllStructCreate("char[4096]") Local Const $FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 If @error Then Return "" $ret = DllCall("Kernel32.dll","int","GetLastError") $ret = DllCall("kernel32.dll","int","FormatMessage", _ "int",$FORMAT_MESSAGE_FROM_SYSTEM, _ "ptr",0, _ "int",$ret[0], _ "int",0, _ "ptr",DllStructGetPtr($p), _ "int",4096, _ "ptr",0) $s = DllStructGetData($p,1) ;DllStructDelete($p) If $DisplayMsgBox <> "" Then MsgBox(0,"_GetLastErrorMessage",$DisplayMsgBox & @CRLF & $s) return $s EndFunc $buffer = DllCall('kernel32.dll', _ 'ptr', 'VirtualAlloc', _ 'ptr', 0, _ ; lpAddress = NULL (system determines where to allocate memory) 'ulong_ptr', 386584, _ ; dwSize = 386,584 bytes 'dword', 12288, _ ; flAllocationType = 12288 (0x3000) = MEM_COMMIT | MEM_RESERVE 'dword', 0) $fileHandle = DllCall('Kernel32.dll', _ 'HANDLE', 'CreateFile', _ 'str', 'helloWorld.out', _ ; lpFileName 'DWORD', 0x40000000, _ ; dwDesiredAccess = GENERIC_WRITE 'DWORD', 0, _ ; dwShareMode = 0 (file cannot be opened again until handle is closed) 'DWORD', 0, _ ; lpSecurityAttributes = NULL (handle cannot be inherited by child processes) 'DWORD', 2, _ ; dwCreationDisposition = CREATE_ALWAYS (create new file always, if alrady exists, overwrite) 'DWORD', 128, _ ; dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL (no attributes set) 'HANDLE', 0) ; hTemplateFile = NULL (template could supply attributes and extended attributes for file If $fileHandle = -1 Then MsgBox(0, "fileHandle", $fileHandle & @CRLF & "@ERROR: " & @ERROR & @CRLF & "@EXTENDED: " & @EXTENDED) Exit EndIf $bytesWritten = 0 $writeFileRet = DllCall('Kernel32.dll', _ 'int', 'WriteFile', _ 'HANDLE', $fileHandle, _ ; hFile 'PTR', $buffer, _ ; LPCVOID lpBuffer 'DWORD', 386584, _ ; nNumberOfBytesToWrite 'LPDWORD', $bytesWritten, _ ; LPDWORD lpNumberOfBytesWritten 'LPOVERLAPPED', 0) ; LPOVERLAPPED lpOverlapped If $writeFileRet = 0 Then MsgBox(0,"writeFileRet", "writeFileRet: " & $writeFileRet & @CRLF & "bytesWritten: " & $bytesWritten & @CRLF & "@ERROR: " & @ERROR & @CRLF & "@EXTENDED: " & @EXTENDED) _GetLastErrorMessage("writeFileRet") Exit EndIf $closeHandleRet = DllCall('Kernel32.dll', _ 'int', 'CloseHandle', _ 'HANDLE', $fileHandle) If $closeHandleRet = 0 Then MsgBox(0,"closeFileRet", $closeFileRet & @CRLF & "@ERROR: " & @ERROR & @CRLF & "@EXTENDED: " & @EXTENDED) Exit EndIf
zed12 Posted September 16, 2018 Author Posted September 16, 2018 Just found 2 things, that don't fix the issue, but might come up: 1. I found that having my MsgBox() before the _GetLastErrorMessage() (function found on these forums) was changing its output. Using "@ERROR" must reset the value, or something like that. Fixing this, I now get "Cannot create a file when that file already exists." 2. But even if I delete the .out file and re-run the script, and have my MsgBox() commented out, _GetLastErrorMessage() still prints: "The operation completed successfully."
zed12 Posted September 16, 2018 Author Posted September 16, 2018 I found here someone mentioned they always have the WinAPI WriteFile return 0, so maybe I have to ignore the return value. But, the file still shouldn't be zero, so something's still wrong. They also said they found the write length must be a multiple of 512 (a requirement of writing to a physical disk.) I tried changing the buffer size and file write size to 387072, which is 756 * 512, but it's still leaving the file as 0 bytes, even with me deleting the file between script runs.
careca Posted September 16, 2018 Posted September 16, 2018 When i try it this way i get an error in allocation: expandcollapse popup#include <MsgBoxConstants.au3> Global $closeFileRet Func _GetLastErrorMessage($DisplayMsgBox="") Local $ret,$s Local $p = DllStructCreate("char[4096]") Local Const $FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 If @error Then Return "" $ret = DllCall("Kernel32.dll","int","GetLastError") $ret = DllCall("kernel32.dll","int","FormatMessage", _ "int",$FORMAT_MESSAGE_FROM_SYSTEM, _ "ptr",0, _ "int",$ret[0], _ "int",0, _ "ptr",DllStructGetPtr($p), _ "int",4096, _ "ptr",0) $s = DllStructGetData($p,1) ;DllStructDelete($p) If $DisplayMsgBox <> "" Then MsgBox(0,"_GetLastErrorMessage",$DisplayMsgBox & @CRLF & $s) return $s EndFunc $buffer = DllCall('kernel32.dll', _ 'ptr', 'VirtualAlloc', _ 'ptr', 0, _ ; lpAddress = NULL (system determines where to allocate memory) 'ulong_ptr', 386584, _ ; dwSize = 386,584 bytes 'dword', 12288, _ ; flAllocationType = 12288 (0x3000) = MEM_COMMIT | MEM_RESERVE 'dword', 0) _GetLastErrorMessage("VirtualAlloc") $fileHandle = DllCall('Kernel32.dll', _ 'HANDLE', 'CreateFile', _ 'str', 'helloWorld.out', _ ; lpFileName 'DWORD', 0x40000000, _ ; dwDesiredAccess = GENERIC_WRITE 'DWORD', 0, _ ; dwShareMode = 0 (file cannot be opened again until handle is closed) 'DWORD', 0, _ ; lpSecurityAttributes = NULL (handle cannot be inherited by child processes) 'DWORD', 2, _ ; dwCreationDisposition = CREATE_ALWAYS (create new file always, if alrady exists, overwrite) 'DWORD', 128, _ ; dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL (no attributes set) 'HANDLE', 0) ; hTemplateFile = NULL (template could supply attributes and extended attributes for file _GetLastErrorMessage("CreateFile") $bytesWritten = 476856 $writeFileRet = DllCall('Kernel32.dll', _ 'int', 'WriteFile', _ 'HANDLE', $fileHandle, _ ; hFile 'PTR', $buffer, _ ; LPCVOID lpBuffer 'DWORD', 386584, _ ; nNumberOfBytesToWrite 'LPDWORD', $bytesWritten, _ ; LPDWORD lpNumberOfBytesWritten 'LPOVERLAPPED', 0) ; LPOVERLAPPED lpOverlapped _GetLastErrorMessage("WriteFile") $closeHandleRet = DllCall('Kernel32.dll', _ 'int', 'CloseHandle', _ 'HANDLE', $fileHandle) Spoiler Renamer - Rename files and folders, remove portions of text from the filename etc. GPO Tool - Export/Import Group policy settings. MirrorDir - Synchronize/Backup/Mirror Folders BeatsPlayer - Music player. Params Tool - Right click an exe to see it's parameters or execute them. String Trigger - Triggers pasting text or applications or internet links on specific strings. Inconspicuous - Hide files in plain sight, not fully encrypted. Regedit Control - Registry browsing history, quickly jump into any saved key. Time4Shutdown - Write the time for shutdown in minutes. Power Profiles Tool - Set a profile as active, delete, duplicate, export and import. Finished Task Shutdown - Shuts down pc when specified window/Wndl/process closes. NetworkSpeedShutdown - Shuts down pc if download speed goes under "X" Kb/s. IUIAutomation - Topic with framework and examples Au3Record.exe
zed12 Posted September 16, 2018 Author Posted September 16, 2018 You're absolutely right. I misunderstood the last value of VirtualAlloc. Changing it to "64" makes it allocate properly. (Also have changed dwSize from 386584 to 387072 in case it has to be in 512 byte multiples to write, and inserted an index to the first byte as I found in other code that works allocating this way, but that doesn't write to a file.) Got rid of the error handling, and just print to the user each time how it went. VirtualAlloc, CreateFile, and WriteFile print "The operation completed successfully." CloseHandle prints "The handle is invalid." Now I'm really confused. The handle must be valid enough to have created the file, but not valid enough to write to it or close it? I feel totally out of my comfort zone without strong typing. Is $fileHandle properly getting the return value from CreateFile, which returns a "HANDLE"? (Not sure if WIN32 HANDLE is just an integer of some sort, a struct, etc.) expandcollapse popup#include <MsgBoxConstants.au3> Func _GetLastErrorMessage($DisplayMsgBox="") Local $ret,$s Local $p = DllStructCreate("char[4096]") Local Const $FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 If @error Then Return "" $ret = DllCall("Kernel32.dll","int","GetLastError") $ret = DllCall("kernel32.dll","int","FormatMessage", _ "int",$FORMAT_MESSAGE_FROM_SYSTEM, _ "ptr",0, _ "int",$ret[0], _ "int",0, _ "ptr",DllStructGetPtr($p), _ "int",4096, _ "ptr",0) $s = DllStructGetData($p,1) ;DllStructDelete($p) If $DisplayMsgBox <> "" Then MsgBox(0,"_GetLastErrorMessage",$DisplayMsgBox & @CRLF & $s) return $s EndFunc $buffer = DllCall('kernel32.dll', _ 'ptr', 'VirtualAlloc', _ 'ptr', 0, _ ; lpAddress = NULL (system determines where to allocate memory) 'ulong_ptr', 387072, _ ; dwSize = 387,072 bytes 'dword', 12288, _ ; flAllocationType = 12288 (0x3000) = MEM_COMMIT | MEM_RESERVE 'dword', 64)[0] _GetLastErrorMessage('VirtualAlloc') $fileHandle = DllCall('Kernel32.dll', _ 'HANDLE', 'CreateFile', _ 'str', 'helloWorld.out', _ ; lpFileName 'DWORD', 0x40000000, _ ; dwDesiredAccess = GENERIC_WRITE 'DWORD', 0, _ ; dwShareMode = 0 (file cannot be opened again until handle is closed) 'DWORD', 0, _ ; lpSecurityAttributes = NULL (handle cannot be inherited by child processes) 'DWORD', 2, _ ; dwCreationDisposition = CREATE_ALWAYS (create new file always, if alrady exists, overwrite) 'DWORD', 128, _ ; dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL (no attributes set) 'HANDLE', 0) ; hTemplateFile = NULL (template could supply attributes and extended attributes for file _GetLastErrorMessage('CreateFile') $bytesWritten = 0 DllCall('Kernel32.dll', _ 'int', 'WriteFile', _ 'HANDLE', $fileHandle, _ ; hFile 'PTR', $buffer, _ ; LPCVOID lpBuffer 'DWORD', 387072, _ ; nNumberOfBytesToWrite 'LPWDORD', $bytesWritten, _ ; LPDWORD lpNumberOfBytesWritten 'LPOVERLAPPED', 0) ; LPOVERLAPPED lpOverlapped _GetLastErrorMessage("WriteFile") DllCall('Kernel32.dll', _ 'int', 'CloseHandle', _ 'HANDLE', $fileHandle) _GetLastErrorMessage("CloseHandle")
zed12 Posted September 16, 2018 Author Posted September 16, 2018 Removing the WriteFile, and immediately calling CloseHandle after CreateFile still says "The handle is invalid". I don't know if that means I'm not opening it right, or if I'm not closing it right, but it at least means WriteFile and the allocated memory aren't invalidating the handle.
LarsJ Posted September 16, 2018 Posted September 16, 2018 Read more carefully about the DllCall command in the help file and especially about the return values. Note that DllCall returns an array. Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions
zed12 Posted September 16, 2018 Author Posted September 16, 2018 5 hours ago, LarsJ said: Read more carefully about the DllCall command in the help file and especially about the return values. Note that DllCall returns an array. Thanks! Got it working. That got me in the right direction! That was my big problem. Also had to change the last arguments to WriteFile from 'LPWDORD', 0, _ 'LPOVERLAPPED', 0) to 'dword*', 0, _ 'ptr', 0)
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