Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Get file handle # from filename?

Nov
76
1
Hi.

I have the following problem :

I have a BTM that opens a file for WRITE with %@FILEOPEN and somehting crashes in my program (not through debugging). Which means the file handle remains assigned and the file open.

It's therefore not possible to reopen the file with %@FILEOPEN until the handle on the file is released.

I can get the filename associated with a handle with %@FILEHANDLE, and even the program maintaining the lock with %@FILELOCK, but the reverse is not possible apparently. And there is no UNLOCK command, sadly.

(I have a program called 'Unlocker' that does this very thing, but I'd like to handle that specific condition from within my BTM)

So I need a trick to find out the handle number of the open file, and then close it so I can reopen it.
Perhaps some obscure attribute query, or even a WMIC query if all else fails...


PS:
==
I love TC, but I often find that variable functions only work one-way.
It would be nice if everything could be queried back and forth, as above.

Thanks.
M.
 
Don't think that's possible with internal TCC commands.

You could always use SyInternals' Handle.exe

Here's my CMD version. You have to do your own BTM-magic to integrate it in your script : -)

Code:
for /f "tokens=3,6 usebackq delims=: " %%x in (`handle.exe -nobanner Yourfilename.txt `) do handle.exe -c %%y -p %%x

- Yourfilename.txt can include path, but don't use ""
- remove prompt on removing filehandle with command handle.exe with extra "-y" parameter.

EDIT: Here is the link to Handle : [title]
 
Am I missing something? Just save the handle ...
Code:
set h=%@fileopen[...]
... and use it later if necessary.
 
Oh sure, I thought of using external commands if TC has no such ability...

But it just seems strange that TC can get the filename for handle, but not the opposite.
The file handles must be stored somewhere in RAM.


@vince: You make a good point. ;)

Thanks anyway.
M.
 
The return value from %@FILEOPEN is the file handle. Save it somewhere, and pass it to %@FILECLOSE later -- in another instance of TCC, if need be.
 
Suppose you have a test.btm running with contents like:

Code:
setlocal
set h=%@fileopen[c:\Temp\testfile.txt,R]
pause
Press Ctrl-C when script is pausing (to simulate x13's crash).

After that, the %h variable is gone, but the filehandle still exists.

I guess that is the problem where @x13 wants a solution for.

(Another way to solve this, is to close TCC.exe itself. That will close the handle,too)
 
Oh sure, I thought of using external commands if TC has no such ability...

But it just seems strange that TC can get the filename for handle, but not the opposite.
The file handles must be stored somewhere in RAM.


@vince: You make a good point. ;)

Thanks anyway.
M.
Apps like HANDLE.EXE are rather heavy-handed ... designed to get handles of other apps. And even they (internally) get the handle first, and the file name from the handle (and not the handle from the file name).
 
Suppose you have a test.btm running with contents like:

Code:
setlocal
set h=%@fileopen[c:\Temp\testfile.txt,R]
pause
Press Ctrl-C when script is pausing (to simulate x13's crash).

After that, the %h variable is gone, but the filehandle still exists.

I guess that is the problem where @x13 wants a solution for.
The simple answer ... don't do that. The user keeping that handle is (as I see it) the perfect solution.
 
Yes, @MaartenG is exactly right.

Though it should be obvious, when a BTM crashes, all local variables vanish.
And short of using a program like Handle.exe, TC forgets its file handle allocation table (shame).
Hence my original question.

Yes, I can save the file handle in a text file for example, and use it to close the file before I reopen again, but it's a bit laboured, when TC has so many wonderful variable functions...

It's not a huge deal of course, but it seems to me that if %@FILEHANDLE[handle] exists, the reverse should also be there.

Case in point : %@IPADDRESS[hostname] vs %@IPNAME[numeric_IP]

x13/Mark
 
Assuming you have handle.exe, you could create a wrapper using a BTM and/or Function.

If tcc itself crashed, you may have more than one mapping. So you really can't do the reverse operation. There's a one to one mapping from handle to file name. But one to many from file name to handle.
 
Apps like HANDLE.EXE are rather heavy-handed ... designed to get handles of other apps. And even they (internally) get the handle first, and the file name from the handle (and not the handle from the file name).

All true. Do you have a better suggestion?
 
All true. Do you have a better suggestion?
No. As far as I know, it must be done that way. In addition, you'd have to test each handle to determine which process it belongs to, and test it even further to determine which type of object it's a handle to (file, process, reg key, synchronization object, ...). My point was that is seems a bit much to expect of TCC.
 
This is how Sysinternals does it:
[title]
(didn't check the code, btw; if it empties your bank account, don't blame me! ;-)

Just FYI. In my opinion it doesn't "deserve" a seperate function in TCMD. Just close TCC and start fresh :-)
 
The return value from %@FILEOPEN is the file handle. Save it somewhere, and pass it to %@FILECLOSE later -- in another instance of TCC, if need be.
Not in my experience (regarding the "another instance" part).

If you try to @FILECLOSE a handle from another TCC process as a regular user. It returns a "1".
If run as administrator it returns "0", so it seems the file is closed, but in fact it isn't.
Handles are unique *per process*. It is very well possible that the same handle(number) is used in TCC 1 as well as TCC 2. So there is some logic behind it all.


Found out when I wanted to write a "one-liner" to list all the open files and @SELECT the file to close:
Code:
handle.exe -p %_pid | ffind /R /km /v /T": File" | echo %_pid %@fileclose[%@convert[16,10,%@word[" :",0,%@select[con:,1,1,20,100,Close filehandle]]]]

The %@FILECLOSE[] part is started as a new process (as expected) and wasn't able to close the file.



EDIT: Apparently I forgot to post the code that is actualy working:
In short: ( part a | part b ) |! part c
Code:
( handle.exe -p %_pid | ffind /R /km /v /T": File" ) |! echo %@fileclose[%@convert[16,10,%@word[" :",0,%@select[con:,1,1,20,100,Close  filehandle]]]]
 
Last edited:
Back
Top