We could use two sets of functions with hex or with binary buffers, whichever fits the task better, or we can use the binary buffer version only, with simple functions converting binary data to hex and vice versa. The original functions should be renamed to HexWrite and HexRead.
Again, there are calling examples below. The conversion functions are simple enough (but tricky) that they did not deserve the fancy header, but you can add your own. The binary file I/O functions now store/load the data only to/from special AHK variables, which may contain NULL characters, therefore, they must not be manipulated as ordinary strings. Not even assignments or StrLen is allowed. If these variables are used as function parameters, they must be defined as ByRef, otherwise the strings get truncated at the first NULL.
file = c:\z.dat FileDelete %file% IfNotEqual ErrorLevel,0, MsgBox Can't delete file "%file%"`nErrorLevel = "%ErrorLevel%" Hex2Bin(b,"000102030405060708090a0b0c0d0e0f00") res := BinWrite(file,b,17) MsgBox ErrorLevel = %ErrorLevel%`nBytes Written = %res% res := BinRead(file,data) MsgBox ErrorLevel = %ErrorLevel%`nBytes Read = %res% Bin2Hex(h,data,res) MsgBox Data = "%h%" Hex2Bin(b,"aa00bb") res := BinWrite(file,b,3,-2) MsgBox ErrorLevel = %ErrorLevel%`nBytes Written = %res% res := BinRead(file,data) MsgBox ErrorLevel = %ErrorLevel%`nBytes Read = %res% Bin2Hex(h,data,res) MsgBox Data = "%h%" ExitApp Bin2Hex(ByRef h, ByRef b, n=0) ; n bytes binary data -> stream of 2-digit hex { ; n = 0: all (SetCapacity can be larger than used!) format = %A_FormatInteger% ; save original integer format SetFormat Integer, Hex ; for converting bytes to hex m := VarSetCapacity(b) If (n < 1 or n > m) n := m Address := &b h = Loop %n% { x := *Address ; get byte in hex StringTrimLeft x, x, 2 ; remove 0x x = 0%x% ; pad left StringRight x, x, 2 ; 2 hex digits h = %h%%x% Address++ } SetFormat Integer, %format% ; restore original format } Hex2Bin(ByRef b, h, n=0) ; n hex digit-pairs -> binary data { ; n = 0: all. (Only ByRef can handle binaries) m := Ceil(StrLen(h)/2) If (n < 1 or n > m) n := m Granted := VarSetCapacity(b, n, 0) IfLess Granted,%n%, { ErrorLevel = Mem=%Granted% Return } Address := &b Loop %n% { StringLeft x, h, 2 StringTrimLeft h, h, 2 x = 0x%x% DllCall("RtlFillMemory", "UInt", Address, "UInt", 1, "UChar", x) Address++ } } /* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinWrite ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | - Open binary file | - (Over)Write n bytes (n = 0: all) | - From offset (offset < 0: counted from end) | - Close file | (Binary)data -> file[offset + 0..n-1], rest of file unchanged | Return #bytes actually written */ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinWrite(file, ByRef data, n=0, offset=0) { ; Open file for WRITE (0x40..), OPEN_ALWAYS (4): creates only if it does not exists h := DllCall("CreateFile","str",file,"Uint",0x40000000,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0) IfEqual h,-1, SetEnv, ErrorLevel, -1 IfNotEqual ErrorLevel,0,Return,0 ; couldn't create the file m = 0 ; seek to offset IfLess offset,0, SetEnv,m,2 r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m) IfEqual r,0, SetEnv, ErrorLevel, -3 IfNotEqual ErrorLevel,0, { t = %ErrorLevel% ; save ErrorLevel to be returned DllCall("CloseHandle", "Uint", h) ErrorLevel = %t% ; return seek error Return 0 } m := VarSetCapacity(data) ; get the capacity ( >= used length ) If (n < 1 or n > m) n := m result := DllCall("WriteFile","UInt",h,"Str",data,"UInt",n,"UInt *",Written,"UInt",0) if (!result or Written < n) ErrorLevel = -3 IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel% h := DllCall("CloseHandle", "Uint", h) IfEqual h,-1, SetEnv, ErrorLevel, -2 IfNotEqual t,,SetEnv, ErrorLevel, %t%-%ErrorLevel% Return Written } /* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinRead ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | - Open binary file | - Read n bytes (n = 0: file size) | - From offset (offset < 0: counted from end) | - Close file | (Binary)data (replaced) <- file[offset + 0..n-1] | Return #bytes actually read */ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinRead(file, ByRef data, n=0, offset=0) { h := DllCall("CreateFile","Str",file,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0) IfEqual h,-1, SetEnv, ErrorLevel, -1 IfNotEqual ErrorLevel,0,Return,0 ; couldn't open the file m = 0 ; seek to offset IfLess offset,0, SetEnv,m,2 r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m) IfEqual r,0, SetEnv, ErrorLevel, -3 IfNotEqual ErrorLevel,0, { t = %ErrorLevel% ; save ErrorLevel to be returned DllCall("CloseHandle", "Uint", h) ErrorLevel = %t% ; return seek error Return 0 } m := DllCall("GetFileSize","UInt",h,"Int64 *",r) If (n < 1 or n > m) n := m Granted := VarSetCapacity(data, n, 0) IfLess Granted,%n%, { ErrorLevel = Mem=%Granted% Return 0 } result := DllCall("ReadFile","UInt",h,"Str",data,"UInt",n,"UInt *",Read,"UInt",0) if (!result or Read < n) t = -3 IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel% h := DllCall("CloseHandle", "Uint", h) IfEqual h,-1, SetEnv, ErrorLevel, -2 IfNotEqual t,,SetEnv, ErrorLevel, %t%-%ErrorLevel% Return Read }Edit 2005.07.03: StrLen and assignment don’t work with binary buffers. We cannot even compare them, If (a=... only compares the data until the first NULL, and ignores the rest. We have to use DLL calls to copy or compare buffers, or Bin2Hex, Hex2Bin combinations and work with the hex strings in between.