Jump to content
Sign in to follow this  
KaineIHC

_winapi_read & _winapi_write

Recommended Posts

KaineIHC

Hi

I want to search a file for a specific string, then read in a portion of the file, alter it and then write it back to the file overwriting the original portion.

I have tried to use the fileread and filewrite commands but these do not allow me to write to a specific part of the file.

I have seen that this is possible using _winapi_readfile and _winapi_writefile but I can't get my head around how this code works.

Can anyone help?

Thanks

Share this post


Link to post
Share on other sites
PsaltyDS

I have seen that this is possible using _winapi_readfile and _winapi_writefile but I can't get my head around how this code works.

Where did you see it? What code?

I don't think you can write to the middle of a file. You would have to make the new data match the old in length byte-for-byte. Where have you seen that this is possible?

:D


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
KaineIHC

Where did you see it? What code?

I don't think you can write to the middle of a file. You would have to make the new data match the old in length byte-for-byte. Where have you seen that this is possible?

:)

Hmm, maybe I was mistaken, I was looking in the help files. I was thinkning that the pointer variable in _Winapi_writefile pointed to the file on the disk but it's the position in the buffer - Doh! Sorry

So is there any way of writing to a specific location in a file? I want to overwrite data at a specific point in a file, is there a way of setting the write pointer?

This seems like a simple function but there doesn't seem to be a way other than reading the whole file, making the changes then writting the whole file back!

Share this post


Link to post
Share on other sites
weaponx

After some testing it appears there is a limitation with _WinAPI_ReadFile that seems to make it useless in AutoIt. This function uses a byte array which I don't think is supported yet.

@PsaltyDS - Any clues? I found this god awful topic about byte array implementation:

http://www.autoitscript.com/forum/index.ph...;hl=byte++array

Here is the beginning of my function:

#Include <WinAPI.au3>
#include <array.au3>

;Const $GENERIC_WRITE = 0x40000000
;Const $GENERIC_READ = 0x80000000
;Const $FILE_ATTRIBUTE_NORMAL = 0x80
;Const $CREATE_ALWAYS = 2
;Const $OPEN_ALWAYS = 4
Const $INVALID_HANDLE_VALUE = -1

;$root = @DesktopDir

;Filename, creation, access
;$handle = _WinAPI_CreateFile($root & "\" & $filename, 2, 2)

ReadStringFromFile(@DesktopDir & "\" & "test.txt")

Func ReadStringFromFile($FileName)
    ;'***************************************************************
    ;'PURPOSE:  READS STRING DATA FROM FILE USING READFILE API
    ;
    ;'PARAMETERS:    FileName: Name Of File
    ;
    ;'RETURNS:       Contents of file as a string
    ;
    ;'EXAMPLE:       dim sAns as String
    ;'               sAns = ReadStringFromFile("C:\MyFile.txt")
    ;'**************************************************************
    ;On Error GoTo ErrorHandler

    Dim $lHandle ;As Long
    Dim $lSuccess ;As Long
    Dim $lBytesRead ;As Long
    Dim $lBytesToRead ;As Long
    Dim $bytArr[1] ;As Byte
    Dim $sAns ;As String

    $lBytesToRead = FileGetSize($FileName)
    
    ;ReDim $bytArr[$lBytesToRead] ;As Byte
    ;'Get a handle to file
    $lHandle = _WinAPI_CreateFile($FileName, 2,2)
    If $lHandle <> $INVALID_HANDLE_VALUE Then
        
        ConsoleWrite("File opened successfully" & @CRLF)

        ;'read file contents into a bytearray and convert to string
        $lSuccess = _WinAPI_ReadFile($lHandle, $bytArr, $lBytesToRead, $lBytesRead)
        If $lSuccess Then
           ConsoleWrite("ReadFile SUCCESSFUL" & @CRLF)
        Else
           ConsoleWrite("ReadFile FAILED" & @CRLF)
        EndIf
       
       ;_ArrayDisplay($bytArr)
       
       $sAns = ByteArrayToString($bytArr)
       
       ConsoleWrite($sAns)
       
       _WinAPI_CloseHandle($lHandle)
       
       Return $sAns
    EndIf
    ;ErrorHandler:
    
EndFunc
Edited by weaponx

Share this post


Link to post
Share on other sites
weaponx

Perhaps ignore the last post. I found a way to use the returned byte array.

#Include <WinAPI.au3>
#include <array.au3>

Const $INVALID_HANDLE_VALUE = -1

$result = ReadStringFromFile(@DesktopDir & "\" & "test.txt")
MsgBox(0,"File contents", $result)

Func ReadStringFromFile($FileName)

Dim $lHandle ;As Long
    ;Dim $lSuccess ;As Long
    Dim $lBytesRead = 0;As Long
    Dim $lBytesToRead = 0;As Long
    ;Dim $bytArr[1] ;As Byte
    Dim $sAns = "" ;As String

    $lBytesToRead = FileGetSize($FileName)
    
    ;ReDim $bytArr[$lBytesToRead] ;As Byte
    ;'Get a handle to file
    $lHandle = _WinAPI_CreateFile($FileName, 2,2)
    If $lHandle <> $INVALID_HANDLE_VALUE Then
        
        ConsoleWrite("File opened successfully" & @CRLF)

        $tBuffer = DllStructCreate("char Text[" & $lBytesToRead & "]")

        ;'read file contents into a bytearray and convert to string
        $lSuccess = _WinAPI_ReadFile($lHandle, DllStructGetPtr($tBuffer), $lBytesToRead, $lBytesRead)
        If $lSuccess Then
           ConsoleWrite("ReadFile OK" & @CRLF)
           $sAns = DllStructGetData($tBuffer,1)
        Else
           ConsoleWrite("ReadFile FAIL" & @CRLF)
        EndIf
       
       _WinAPI_CloseHandle($lHandle)
       
       Return $sAns
    EndIf    
EndFunc

Share this post


Link to post
Share on other sites
PsaltyDS

After some testing it appears there is a limitation with _WinAPI_ReadFile that seems to make it useless in AutoIt. This function uses a byte array which I don't think is supported yet.

@PsaltyDS - Any clues? I found this god awful topic about byte array implementation:

http://www.autoitscript.com/forum/index.ph...;hl=byte++array

I created Bug Trac #50 on that, and it is listed as a Feature Request owned by Valik now. Valik was sympathetic to adding it, some day, but not as a priority based on how busy he is, and how few requirements they see for this feature. You might prod Valik with your interest and maybe it will get bumped up the priority list some.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
KaineIHC

couldnt you just use _FileReadToArray ( $sFilePath, $aArray ) ?

Share this post


Link to post
Share on other sites
weaponx

couldnt you just use _FileReadToArray ( $sFilePath, $aArray ) ?

Yes but I thought we were trying to tail write a file without opening it like RandallC's TailRW UDF.

Share this post


Link to post
Share on other sites
KaineIHC

Yes but I thought we were trying to tail write a file without opening it like RandallC's TailRW UDF.

Yeah I am, my response was in reply to your 1st post:

"I'm trying to convert this script from VB but i'm not having much success:

http://www.freevbcode.com/ShowCode.Asp?ID=1689"

Sorry if I sound like a bit of a noob, er, that's cos I am - lol

The code you posted just reads the file doesn't it, reading it isnt the problem I can use fileread and read it byte by byte until the point I am looking for, it's writing the data back to that same point thats the problem.

Share this post


Link to post
Share on other sites
weaponx

Yeah I am, my response was in reply to your 1st post:

"I'm trying to convert this script from VB but i'm not having much success:

http://www.freevbcode.com/ShowCode.Asp?ID=1689"

Sorry if I sound like a bit of a noob, er, that's cos I am - lol

The code you posted just reads the file doesn't it, reading it isnt the problem I can use fileread and read it byte by byte until the point I am looking for, it's writing the data back to that same point thats the problem.

I was only showing that function as a test, I wasn't sure if we could actually write to specific position in the file. I'm still not really sure if we can.

If we could create a byte array the same same size as the file to be written, we might be able to insert the data we want written into the array and write it., kind of like a mask, it won't allow the filesize to change, just overwrite. I have doubts that WinAPI is the proper method for this.

Edited by weaponx

Share this post


Link to post
Share on other sites
PsaltyDS

Perhaps ignore the last post. I found a way to use the returned byte array.

#Include <WinAPI.au3>
#include <array.au3>

Const $INVALID_HANDLE_VALUE = -1

$result = ReadStringFromFile(@DesktopDir & "\" & "test.txt")
MsgBox(0,"File contents", $result)

Func ReadStringFromFile($FileName)

Dim $lHandle ;As Long
    ;Dim $lSuccess ;As Long
    Dim $lBytesRead = 0;As Long
    Dim $lBytesToRead = 0;As Long
    ;Dim $bytArr[1] ;As Byte
    Dim $sAns = "" ;As String

    $lBytesToRead = FileGetSize($FileName)
    
    ;ReDim $bytArr[$lBytesToRead] ;As Byte
    ;'Get a handle to file
    $lHandle = _WinAPI_CreateFile($FileName, 2,2)
    If $lHandle <> $INVALID_HANDLE_VALUE Then
        
        ConsoleWrite("File opened successfully" & @CRLF)

        $tBuffer = DllStructCreate("char Text[" & $lBytesToRead & "]")

        ;'read file contents into a bytearray and convert to string
        $lSuccess = _WinAPI_ReadFile($lHandle, DllStructGetPtr($tBuffer), $lBytesToRead, $lBytesRead)
        If $lSuccess Then
           ConsoleWrite("ReadFile OK" & @CRLF)
           $sAns = DllStructGetData($tBuffer,1)
        Else
           ConsoleWrite("ReadFile FAIL" & @CRLF)
        EndIf
       
       _WinAPI_CloseHandle($lHandle)
       
       Return $sAns
    EndIf    
EndFunc
I'm not an expert in this by any means, but I don't think what you have there is technically a Byte-array. JPM and ptrex know a lot more about it than I do, and using a DLL struct was tried and rejected for working with what I understood to be "real" Byte-arrays (which I believe were binary, not char, in the context we were working with).

:)

As for writing to the middle of the file, you would still be reading the entire file into some kind of structure in memory, modifying it in memory, and then writing the whole thing back, wouldn't you? The OP seemed to want to write only to a specific location in the file, without having to re-write the unmodified data that followed, and this is part that I don't think you can do from Windows APIs or AutoIt. Perhaps with low-level disk driver stuff, I don't know.

:(


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
KaineIHC

I've just searched for tailRW and it looks like it may do what I am wanting. I'll give it a try later, thanks for your help.

Share this post


Link to post
Share on other sites
weaponx

I'm not an expert in this by any means, but I don't think what you have there is technically a Byte-array. JPM and ptrex know a lot more about it than I do, and using a DLL struct was tried and rejected for working with what I understood to be "real" Byte-arrays (which I believe were binary, not char, in the context we were working with).

:)

As for writing to the middle of the file, you would still be reading the entire file into some kind of structure in memory, modifying it in memory, and then writing the whole thing back, wouldn't you? The OP seemed to want to write only to a specific location in the file, without having to re-write the unmodified data that followed, and this is part that I don't think you can do from Windows APIs or AutoIt. Perhaps with low-level disk driver stuff, I don't know.

:(

I think you are correct in saying this isn't technically a byte array. This method is no good for reading in binary data. Also _WinAPI_WriteFile doesn't know what the hell to do with the struct when you pass it back.

Project status - FAILURE

Edited by weaponx

Share this post


Link to post
Share on other sites
Polyphem

...reading it isnt the problem I can use fileread and read it byte by byte until the point I am looking for, it's writing the data back to that same point thats the problem.

I'm just digging into this because I want to read only at specific points... found a function which "might" (dont know :) ) help you too....

_WinAPI_SetFilePointer($lHandle, $bytes_read_start_at) ; File-Handle as input, success changes the file-handle pointer position

Func _WinAPI_SetFilePointer($hFile, $pmove = 0)
    Local $aResult
    $aResult = DllCall("Kernel32.dll", "int", "SetFilePointer", "hwnd", $hFile, "int", $pmove, "int", "NULL", "int", 0)
    Return SetError(_WinAPI_GetLastError(), 0, $aResult[0] <> 0)
    Return $aResult

#cs
http://msdn.microsoft.com/en-us/library/aa365541(VS.85).aspx

DWORD WINAPI SetFilePointer(
  __in         HANDLE hFile,
  __in         LONG lDistanceToMove,
  __inout_opt  PLONG lpDistanceToMoveHigh,
  __in         DWORD dwMoveMethod
);

Parameters
hFile
    A handle to the file.
    The file handle must be created with the GENERIC_READ or GENERIC_WRITE access right. For more information, see File Security and Access Rights.
lDistanceToMove
    The low order 32-bits of a signed value that specifies the number of bytes to move the file pointer.
    If lpDistanceToMoveHigh is not NULL, lpDistanceToMoveHigh and lDistanceToMove form a single 64-bit signed value that specifies the distance to move.
    If lpDistanceToMoveHigh is NULL, lDistanceToMove is a 32-bit signed value. A positive value for lDistanceToMove moves the file pointer forward in the file, and a negative value moves the file pointer back.
lpDistanceToMoveHigh
    A pointer to the high order 32-bits of the signed 64-bit distance to move.
    If you do not need the high order 32-bits, this pointer must be set to NULL.
    When not NULL, this parameter also receives the high order DWORD of the new value of the file pointer. For more information, see the Remarks section in this topic.
dwMoveMethod
    The starting point for the file pointer move.
    This parameter can be one of the following values.
    Value   Meaning
    FILE_BEGIN      The starting point is zero (0) or the beginning of the file.
    0
    FILE_CURRENT    The starting point is the current value of the file pointer.
    1
    FILE_END        The starting point is the current end-of-file position.
    2

If the function succeeds and lpDistanceToMoveHigh is NULL, the return value is the low-order DWORD of the new file pointer.

#ce

EndFunc   ;==>_WinAPI_SetFilePointer

This post will be edited again by Polyphem: Tomorrow, 11:55 AM

Share this post


Link to post
Share on other sites
PsaltyDS

I'm just digging into this because I want to read only at specific points... found a function which "might" (dont know :) ) help you too....

_WinAPI_SetFilePointer($lHandle, $bytes_read_start_at); File-Handle as input, success changes the file-handle pointer position

Func _WinAPI_SetFilePointer($hFile, $pmove = 0)
    Local $aResult
    $aResult = DllCall("Kernel32.dll", "int", "SetFilePointer", "hwnd", $hFile, "int", $pmove, "int", "NULL", "int", 0)
    Return SetError(_WinAPI_GetLastError(), 0, $aResult[0] <> 0)
    Return $aResult
EndFunc ;==>_WinAPI_SetFilePointer
Where did you find your version? I like adding some error handling to the wrapper.

This DLL call is also already in randallc's ApiTailRW.au3 UDF. He in turn got it from Larry:

;===============================================================================
;
; Function Name:      _FileSetPosAPI(); ( <FileHandle>, <Position in the file to read/write to/from> )
; Description:    Sets pointer position in file
; Parameter(s):  $hFile             - FileHandle of open (API) file
; Requirement(s):   Requires AutoIT 3.2 minimum
; Return Value(s):  On Success - value from SetFilePointer api;the return value is nonzero
;                  On Failure   - ?** not set - value from SetFilePointer api;;the return value is zero
; Author(s):        Larry
;
;===============================================================================
Func _FileSetPosAPI($hFile, $nPos)
    Local $FILE_BEGIN = 0
    Local $AFSP_r = DllCall("kernel32.dll", "long", "SetFilePointer", "hwnd", $hFile, "long", $nPos, "long_ptr", 0, "long", $FILE_BEGIN)
    Return $AFSP_r[0]
EndFunc ;==>_FileSetPosAPI

:P

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

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  

×