Jump to content

Locking a Text FIle


Recommended Posts

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

Oh. Ascend4nt. -> $iNumBytesHigh=DllStructCreate($stSplit,2)

Ah, thanks - good catch. I just fixed that typo.

I see you incorporated the -4294967296 value in one function but not the other (probably just an oversight). Well at least I think you get the gist of it (subtract 1 from it and the upper 32-bits are altered, and if its only a 32-bit internal value it will be always be greater than -4294967296 - which means expanding it to 64-bits would have the upper 32-bits all set anyway). And yes, I suppose I was wrong in saying "(you set $iHigh32 to -1, which is wrong)". At the time I wasn't clear on what you were trying to capture with "<0x80000000".

Ahh, and the Int() function's return, what I meant with that is you'll wind up with a signed 64-bit number if the uppermost bit is set. But now you've changed the Mod/Floor calculations to strip those out anyway.

However, your Mod/Floor functions will fail as they are now on negative numbers (it will return a negative number and keep it internally as 64-bits), so its not really cutting values into 32 bits unless you use some truncation method after. Using your original "Int('0x' & Hex($iLow32, 8))" after the calculation would however clear the upper 32-bits and effectively make a 32-bit value (no matter how it is internally represented).

Another truncation method would be passing a value to a DLLStruct or DLLCall in which there is a defined 32-bit datatype. In fact, that actually makes my function simpler in that I would just have to pass the whole $iOffset and $iNumBytes as the low parts (which would be truncated), thereby skipping the DLLStructGet() on them, and only using DLLStructGet() for the upper 32-bits. :mellow:

*edit: actually I forgot - if you want to preserve the sign bit in the final 32-bit value, and keep it 32-bits, the Bit* functions will work here. Just wrap it like this: BitOR(Mod($i64, 4294967296),0). It even makes it an internal 32-bit datatype. Of course, if the Bit* functions change in the future to support 64-bits (or don't assume signed 32-bit values), this won't work.

Edited by Ascend4nt
Link to comment
Share on other sites

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

  • Moderators

I'm pretty sure I remember seeing yashields winapiex.au3 had a call for lockfile and unlockfile with proper formatting for offsets.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Link to comment
Share on other sites

MvGulik, thanks for the explanations, and good job with a nice final version of that function :P .

Oy, and it figures that Yashied has those functions in his UDF. I hardly ever look to his UDF because its so huge and all bundled into one file.:mellow:

Link to comment
Share on other sites

Thanks guys for all the help. I will implement the function this week and if any issues I will post back. I have read the thread like 10 times trying to understand the whole thing but still it's not too clear to me. I hope you guys won't mind if I have any stupid question about your code. Thanks!!

Link to comment
Share on other sites

This should work, but you'll need a valid file handle returned from 'CreateFile' (not FileOpen). I think there's probably example code somewhere on how to call CreateFile.

; Author: Ascend4nt
Func _LockFile($hFile,$iOffset,$iNumBytes)
    Local $stTemp,$stSplit,$iOffsetLow,$iOffsetHigh,$iNumBytesLow,$iNumBytesHigh
    $stTemp=DllStructCreate("int64")
    $stSplit=DllStructCreate("dword;dword",DllStructGetPtr($stTemp))
    DllStructSetData($stTemp,1,$iOffset)
    $iOffsetLow=DllStructGetData($stSplit,1)
    $iOffsetHigh=DllStructGetData($stSplit,2)
    DllStructSetData($stTemp,1,$iNumBytes)
    $iNumBytesLow=DllStructGetData($stSplit,1)
    $iNumBytesHigh=DllStructGetData($stSplit,2)

    Local $aRet=DllCall("kernel32.dll","bool","LockFile","handle",$hFile,"dword",$iOffsetLow,"dword",$iOffsetHigh,"dword",$iNumBytesLow,"dword",$iNumBytesHigh)
    If @error Then Return SetError(@error,0,False)
    Return $aRet[0]
EndFunc

Note the reason for the structures is because Bit* functions don't work with 64-bit numbers, and if you have a 64-bit number that has the upper bit set, you'd have to do some fancy arithmetic. This way it's just plain simpler.

*edit: code tag, typo, and added author name (me). arggh.. too much on the mind

*2nd edit: $iNumBytesHigh used the wrong DLLStruct* call. oops!

Ascend4nt, when you say Bit* functions don't work with 64-bit numbers do you mean the length of the filename has to be 32 bit for the function to work?. To find out the length of a filename I just convert that into binary and do a "AND" operation on it? or am I getting this all wrong?
Link to comment
Share on other sites

From the Help file:

Function BitOR

"Bit operations are performed as 32-bit integers."

This is why you can't get the high 32-bits of a value using them. And about 64-bit file sizes, the function has code in it specifically to get the low and high words. No need to read anything further into that. MvGulik's last implementation of the function should work for you as well, and that's without creating a DLLStruct.

Link to comment
Share on other sites

From the Help file:

Function BitOR

"Bit operations are performed as 32-bit integers."

This is why you can't get the high 32-bits of a value using them. And about 64-bit file sizes, the function has code in it specifically to get the low and high words. No need to read anything further into that. MvGulik's last implementation of the function should work for you as well, and that's without creating a DLLStruct.

Thanks Ascend4nt, So this is what I got so far. What should be the offset and Numbytes for _Lockfile. Sorry still trying to learn. And this function should lock a file even if it's on a network drive right?

; Author: Ascend4nt & MvGulik

#include <File.au3>

TextFromFile()

Func TextFromFile()
$File1 = "c:\data\data.txt"
_LockFile($File1)
    $i = FileReadLine($File1,1)
    sleep(50000)
    $n = _FileWriteToLine($File1,1,"",1)
        ClipPut($i)
    ;_WinAPI_UnlockFile($File1)
MsgBox(0, "Text", $i)
EndFunc


Func _LockFile($hFile, $iOffset, $iNumBytes)
    Local $iOffsetLow = $iOffset, $iOffsetHigh, $iNumBytesLow = $iNumBytes, $iNumBytesHigh
    $iOffsetHigh = Floor($iOffset / 4294967296)
    $iNumBytesHigh = Floor($iNumBytes / 4294967296)
    Local $aRet = DllCall("kernel32.dll", "bool", "LockFile", "handle", $hFile, "dword", $iOffsetLow, "dword", $iOffsetHigh, "dword", $iNumBytesLow, "dword", $iNumBytesHigh)
    If @error Then Return SetError(@error, 0, False)
    Return $aRet[0]
EndFunc
Link to comment
Share on other sites

Thanks Ascend4nt, So this is what I got so far. What should be the offset and Numbytes for _Lockfile. Sorry still trying to learn. And this function should lock a file even if it's on a network drive right?

First off, you must have missed this part of my first reply:

This should work, but you'll need a valid file handle returned from 'CreateFile' (not FileOpen). I think there's probably example code somewhere on how to call CreateFile.

You need to use CreateFile. While FileOpen() uses the same API call, the handle AutoIt gives you is NOT a legitimate File handle (it's an internal AutoIt pseudo-handle). So you need to explicitly call CreateFile and use that handle to call _Lockfile (which can't be sent a filename!). Do a search on CreateFile, you'll come up with a few examples of it.

As for the number of bytes and offset, it depends - do you want to lock the whole file? If so (which would proably be the norm), you can use 0 as the Offset and for the number of bytes, use what you get from FileGetSize().

I'm assuming it will work across a network if you format it correctly ("\\PCNAME\filetolock.txt"), but I can not test that myself.

Edited by Ascend4nt
Link to comment
Share on other sites

Thanks you so much for your help!!!. I think I have a working code now!!!. I found the CreateFile in WinAPI UDF!!

; Author: Ascend4nt & MvGulik

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

TextFromFile()

Func TextFromFile()
$File1 = "c:\data\data.txt"
$hFile=_WinAPI_CreateFile($File1, 2, 4, 4)
$size = FileGetSize($File1)

_LockFile($hFile, 0, $size)
    $i = FileReadLine($File1,1)
    sleep(50000)
    $n = _FileWriteToLine($File1,1,"",1)
        ClipPut($i)
    ;_WinAPI_UnlockFile($File1)
MsgBox(0, "Text", $i)
    
   
EndFunc

 Func _LockFile($hFile, $iOffset, $iNumBytes)
    Local $iOffsetLow = $iOffset, $iOffsetHigh, $iNumBytesLow = $iNumBytes, $iNumBytesHigh
    $iOffsetHigh = Floor($iOffset / 4294967296)
    $iNumBytesHigh = Floor($iNumBytes / 4294967296)
    Local $aRet = DllCall("kernel32.dll", "bool", "LockFile", "handle", $hFile, "dword", $iOffsetLow, "dword", $iOffsetHigh, "dword", $iNumBytesLow, "dword", $iNumBytesHigh)
    If @error Then Return SetError(@error, 0, False)
    Return $aRet[0]
EndFunc

EDIT: Should I also try to find the unlockFile or you think just let it unlock itself automatically when the function is done?

EDIT2: oops, I think I messed up. How will it read the file if it's locked? I want only one user to read the file and lock it for others. So basically open the file for editing for one user only. Something wrong with my logic here lol.

Edited by Jat421
Link to comment
Share on other sites

First off - again, you are passing a filename to _Lockfile after I just said not to:

So you need to explicitly call CreateFile and use that handle to call _Lockfile (which can't be sent a filename!).

The correct way to do this is:

$hFile=_WinAPI_CreateFile($File1, 2, 4, 4)
$size = FileGetSize($File1)
_LockFile($hFile, 0, $size)

And the file will *only* be available to the process calling it on the computer the process is running. Here's the quote from MSDN:

"Locks the specified file for exclusive access by the calling process"

And yes, you need to call UnlockFile eventually to give access back to others. If you can't figure that function out, just use Yashied's massive WinAPIEx module.

Link to comment
Share on other sites

sorry about that, my mistake. I have made the changes but still the messagebox doesn't display from the text file if I use the LockFile Function. There is something else that I am doing wrong aswell. Really appreciate your help!!

Edit: Would you be able to test the code for me please. I have Windows 7 maybe that's what causing issues. Thanks!

Edited by Jat421
Link to comment
Share on other sites

worked fine for me on XP SP3. Your Sleep() is excessive.. nearly a minute. Maybe thats why you aren't seeing the box if you are exiting the script forcefully.

By the way, there's a way to allow users to read from a file while you have exclusive write access - that'd be the 'Ex' version (LockFileEx)

Link to comment
Share on other sites

worked fine for me on XP SP3. Your Sleep() is excessive.. nearly a minute. Maybe thats why you aren't seeing the box if you are exiting the script forcefully.

By the way, there's a way to allow users to read from a file while you have exclusive write access - that'd be the 'Ex' version (LockFileEx)

Hey Ascend4nt, I do see the messagebox after a minute but it's not showing anything read from the text file. If I change the the CreateFile to read only mode then the messagebox shows the data read from the file. But if I change it to write mode then message box comes back empty. I will need to open that in write mode so I can delete a empty line. I have tested it on XP SP2 aswell now with same results.

$hFile = _WinAPI_CreateFile($File1, 2, 2, 2)  ;Read only mode

$hFile = _WinAPI_CreateFile($File1, 2, 4, 4)  ;Write Mode

It just looks like that when CreateFile open the file in write mode the FileReadLine & FileWriteLine don't have access to the file.

Thanks!

Edited by Jat421
Link to comment
Share on other sites

After looking into this and experimenting, it appears you can't open more than one handle to a file, which is what FileOpen/Read/Line functions do. You're going to have to do everything with _WinAPI_ReadFile() and _WinAPI_WriteFile() functions.

And by the way - all you need to do to stop others from writing to the file is alter the access mode on _WinAPI_CreateFile.

For example, this will let you read & write to a file but only allow others to read from the file:

$hFile=_WinAPI_CreateFile($File1, 2, 6, 2)

To read individual lines, you'll have to rely on searching for @LF, or @CRLF in the data you read. Look at the examples in Help to see how to use the Read/WriteFile operations.

Lastly, don't forget to call _WinAPI_CloseHandle to close the handle and restore access.Function _WinAPI_CloseHandle

Link to comment
Share on other sites

After looking into this and experimenting, it appears you can't open more than one handle to a file, which is what FileOpen/Read/Line functions do. You're going to have to do everything with _WinAPI_ReadFile() and _WinAPI_WriteFile() functions.

And by the way - all you need to do to stop others from writing to the file is alter the access mode on _WinAPI_CreateFile.

For example, this will let you read & write to a file but only allow others to read from the file:

$hFile=_WinAPI_CreateFile($File1, 2, 6, 2)

To read individual lines, you'll have to rely on searching for @LF, or @CRLF in the data you read. Look at the examples in Help to see how to use the Read/WriteFile operations.

Lastly, don't forget to call _WinAPI_CloseHandle to close the handle and restore access.Function _WinAPI_CloseHandle

Thanks bunch for your help!!...k so I will give this a try. Also the user should not have access to the file for reading only because once they read a line that line needs to be deleted so no one else can read that line.
Link to comment
Share on other sites

Also the user should not have access to the file for reading only because once they read a line that line needs to be deleted so no one else can read that line.

Set the 4th parameter to 0 (default) instead of 2 then, and you'll be set.
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...