问题
If an input html element of type=file is used to select a file then that file cannot be deleted by the hta program.
This MVCE works but doesn't use the file dialog - you have to type the filename in manually:
<html>
<HEAD>
<SCRIPT Language="VBScript">
Sub Process
Set x = CreateObject("Scripting.FileSystemObject")
MsgBox "this will actually delete "& INIFile.Value
x.DeleteFile INIFile.Value
MsgBox "see? "& INIFile.Value &" is gone"
Set x = Nothing
End Sub
</SCRIPT>
</HEAD>
<body id='body'>
<input type="text" name="INIFile" >
<input type="button" value="Go!" onClick="Process" >
</body>
</html>
But this MVCE doesn't work - the file is not deleted; just deferred until the program exits:
<html>
<HEAD>
<SCRIPT Language="VBScript">
Sub Process
Set x = CreateObject("Scripting.FileSystemObject")
MsgBox "try to manually delete "& INIFile.Value &" (and then undo it)"
x.DeleteFile INIFile.Value
MsgBox "now try to delete file "& INIFile.Value &" (now it can't be deleted until the app is closed)"
Set x = Nothing
End Sub
</SCRIPT>
</HEAD>
<body id='body'>
<input type="file" name="INIFile" >
<input type="button" value="Go!" onClick="Process" >
</body>
</html>
Somehow using a file type input html element makes it so that the file CAN be manually deleted from outside the program UNTIL the DeleteFile function is called. The DeleteFile function doesn't actually delete the file - it just deferrs the deletion until the hta program exits - at which point the file finally deletes itself.
I need to delete the file while the program is still running. Is there any way to use a file type input html element in an hta file and still delete the file while the hta program is running?
EDIT
My actual use case! In an attempt to produce a usable MVCE I didn't realize a solution would be found that doesn't work with my particular requirements.
The reason I am deleting the file is so that I can replace it with something else, so I need the file to disappear before the end of the function. Call window.location.reload()
absolutely works but the file disappears at the end of the function.
What I am actually trying to do is something like this:
<HTML>
<HEAD>
<SCRIPT Language="VBScript">
Sub Process
Dim file: file = INIFile.Value
Call window.location.reload()
'backup the file to tempfile.tmp
'Now edit tempfile.tmp with all the changes and preview it
'then ask the user whether they are happy with the changes
'delete the original file
'and put the tempfile.tmp in its place
Dim x: Set x = CreateObject("Scripting.FileSystemObject")
x.CopyFile file,"tempfile.tmp"
x.DeleteFile file
MsgBox "why is "& file &" still there?"
x.MoveFile "tempfile.tmp",file ' this produces "file already exists"
Set x = Nothing
End Sub
</SCRIPT>
</HEAD>
<BODY id='body'>
<INPUT type="file" name="INIFile" onChange="Process">
</BODY>
</HTML>
回答1:
Use a regular text input box
<input type="text" name="FileName" size="30">
Add a button to click to open the file
<input type="button" onClick="SelectFile" value="Browse...">
Add a file dialog object
<OBJECT id=Dlg classid="CLSID:3050F4E1-98B5-11CF-BB82-00AA00BDCE0B" width=0 height=0>
Add a sub to take the return value of this object and put it in your text box.
Sub SelectFile
FileName.value = ""
strStartPath = "C:\Test"
strFilter = "Text (*.txt;*.csv)| *.txt;*.csv|VBScript (*.vbs;*.vbc)|*.vbs;*.vbc|HTML (*.htm;*.html;*.hta)|*.htm;*.html;*.hta|All Files (*.*)|*.*|"
strCaption = "Select a File"
FileName.value = Dlg.openfiledlg(CStr(strStartPath), , CStr(strFilter), CStr(strCaption))
End Sub
The strStartPath, strFilter, and strCaption variables can be excluded or customized as needed.
FileName.value will contain the path to the file and it will not be locked.
Edit:
Here's the entire HTA, excluding code to delete the file (I have tested this with the delete code):
<html>
<HEAD>
<HTA:APPLICATION
APPLICATIONNAME="Select File"
ID="SelectFileApplication"
VERSION="1.0"/>
<SCRIPT Language="VBScript">
Sub SelectFile
FileName.value = ""
strStartPath = "C:\Test"
strFilter = "Text (*.txt;*.csv)| *.txt;*.csv|VBScript (*.vbs;*.vbc)|*.vbs;*.vbc|HTML (*.htm;*.html;*.hta)|*.htm;*.html;*.hta|All Files (*.*)|*.*|"
strCaption = "Select a File"
FileName.value = Dlg.openfiledlg(CStr(strStartPath), , CStr(strFilter), CStr(strCaption))
'The file at FileName.value can be deleted at this point.
End Sub
</SCRIPT>
</HEAD>
<body id="body">
<input type="text" name="FileName" size="30">
<input type="button" onClick="SelectFile" value="Browse...">
<OBJECT id=Dlg classid="CLSID:3050F4E1-98B5-11CF-BB82-00AA00BDCE0B" width=0 height=0>
</body>
</html>
回答2:
Update: Based on feedback from OP
Well have now tested this approach myself with similar results to the OP so thought I'd investigate further.
The File Handle appears to be held for the life of the page, tried the following
- Encapsulating in a
<form>
then callingReset()
method - Clearing the
<input>
value
attribute and using a variable to hold the file path.
Neither work but while tested realised that if you refresh the page inside the HTA the file deletion occurs, this means that forcing the page to reload should work, so ended up doing just that.
<html>
<HEAD>
<HTA:APPLICATION ID="oHTA"
APPLICATIONNAME="myApp"
BORDER="thin"
BORDERSTYLE="normal"
CAPTION="yes"
ICON=""
MAXIMIZEBUTTON="yes"
MINIMIZEBUTTON="yes"
SHOWINTASKBAR="no"
SINGLEINSTANCE="no"
SYSMENU="yes"
VERSION="1.0"
WINDOWSTATE="normal"/>
<SCRIPT Language="VBScript">
Sub Process
Set x = CreateObject("Scripting.FileSystemObject")
MsgBox "try to manually delete "& INIFile.Value &" (and then undo it)"
x.DeleteFile INIFile.Value
'Reload page
Call window.location.reload()
End Sub
</SCRIPT>
</HEAD>
<body id='body'>
<input type="file" name="INIFile" >
<input type="button" value="Go!" onClick="Process" >
</body>
</html>
which works, obviously this isn't ideal for capturing the fact the file has been deleted as the page is reloaded but the OP hasn't gone into detail as to their requirement.
You could also make the the Go
button a <input type="submit">
and use the OnSubmit
event to call Process()
which might be cleaner approach then calling window.location.reload()
.
Further Update:
From testing with multiple files have noticed that once another file is selected using the <input type="file">
the previous file is deleted as the handle is released and given to the newly selected file.
I wonder if cloning the <input type="file">
element and removing the previous one will have the same effect and avoid needing to reload the page?
Update: Have since tested and does still hold on to the File Handle
The <input type="file">
is designed for uploading files so it makes sense that once you have selected a file the HTA holds a handle open to it. That being said, there is no reason why you have to call the value of INIFile
directly instead store it in a variable (after all it's just a string) and then clear the Value
attribute of the <input>
.
Sub Process
Dim x: Set x = CreateObject("Scripting.FileSystemObject")
'Get file path from INPUT
Dim file: file = INIFile.Value
'Reset file INPUT
INIFile.Value = ""
MsgBox "this will actually delete "& file
x.DeleteFile file
MsgBox "see? "& file &" is gone"
Set x = Nothing
End Sub
Useful Links
- How do you set file input to nothing with JavaScript or HTML?
来源:https://stackoverflow.com/questions/37583532/using-file-input-element-in-hta-file-prevents-deleting-selected-file