Skip to content

Instantly share code, notes, and snippets.

@mlhaufe
Last active August 19, 2023 19:28
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mlhaufe/1034241 to your computer and use it in GitHub Desktop.
Save mlhaufe/1034241 to your computer and use it in GitHub Desktop.
VBScript File Browser
'Bypasses IE7+ c:\fakepath\file.txt problem
Function BrowseForFile()
With CreateObject("WScript.Shell")
Dim fso : Set fso = CreateObject("Scripting.FileSystemObject")
Dim tempFolder : Set tempFolder = fso.GetSpecialFolder(2)
Dim tempName : tempName = fso.GetTempName() & ".hta"
Dim path : path = "HKCU\Volatile Environment\MsgResp"
With tempFolder.CreateTextFile(tempName)
.Write "<input type=file name=f>" & _
"<script>f.click();(new ActiveXObject('WScript.Shell'))" & _
".RegWrite('HKCU\\Volatile Environment\\MsgResp', f.value);" & _
"close();</script>"
.Close
End With
.Run tempFolder & "\" & tempName, 1, True
BrowseForFile = .RegRead(path)
.RegDelete path
fso.DeleteFile tempFolder & "\" & tempName
End With
End Function
MsgBox BrowseForFile
Function BrowseForFile()
Dim shell : Set shell = CreateObject("Shell.Application")
Dim file : Set file = shell.BrowseForFolder(0, "Choose a file:", &H4000, "C:\")
BrowseForFile = file.self.Path
End Function
MsgBox BrowseForFile
Option Explicit
' Flags for the options parameter
Const BIF_returnonlyfsdirs = &H0001
Const BIF_dontgobelowdomain = &H0002
Const BIF_statustext = &H0004
Const BIF_returnfsancestors = &H0008
Const BIF_editbox = &H0010
Const BIF_validate = &H0020
Const BIF_browseforcomputer = &H1000
Const BIF_browseforprinter = &H2000
Const BIF_browseincludefiles = &H4000
Dim file
file = BrowseForFolder( _
"Select a file or folder to copy", _
BIF_returnonlyfsdirs + BIF_browseincludefiles, _
"")
If file = "-5" Then
WScript.Echo "Not possible to select files in root folder"
Else
If file = "-1" Then
WScript.Echo "No object selected; Cancel clicked"
Else
WScript.Echo "Object: ", file
End If
End If
' Using the shell's BrowseForFolder method to
' return the full path to the selected object
' title = Text shown in the dialog box
' flag = One of the values for controlling the
' BrowseForFolder behavior
' dir = Preselected directory (can be "")
Function BrowseForFolder(title, flag, dir)
On Error Resume Next
Dim oShell, oItem, tmp
' Create WshShell object.
Set oShell = WScript.CreateObject("Shell.Application")
' Invoke Browse For Folder dialog box.
Set oItem = oShell.BrowseForFolder(&H0, title, flag, dir)
If Err.Number <> 0 Then
If Err.Number = 5 Then
BrowseForFolder= "-5"
Err.Clear
Set oShell = Nothing
Set oItem = Nothing
Exit Function
End If
End If
' Now we try to retrieve the full path.
BrowseForFolder = oItem.ParentFolder.ParseName(oItem.Title).Path
' Handling: Cancel button and selecting a drive
If Err<> 0 Then
If Err.Number = 424 Then ' Handle Cancel button.
BrowseForFolder = "-1"
Else
Err.Clear
' Handle situation in which user selects a drive.
' Extract drive letter from the title--first search
' for a colon (:).
tmp = InStr(1, oItem.Title, ":")
If tmp > 0 Then ' A : is found; use two
' characters and add \.
BrowseForFolder = _
Mid(oItem.Title, (tmp - 1), 2) & "\"
End If
End If
End If
Set oShell = Nothing
Set oItem = Nothing
On Error GoTo 0
End Function
@akatukiyo
Copy link

browser2.vbs The 2nd vbs does not work, Error when run for picking up files. How can you make it start up from a fixed location? I like the 2nd dialog window only with a OK button to select file or folder. Can you fix the file selection in 2nd vbs? Thanks

@mlhaufe
Copy link
Author

mlhaufe commented Jul 12, 2015

browser2.vbs has been updated to specify an explicit starting path. This should solve the problem of mystery errors happening for some people.

@zwfl
Copy link

zwfl commented May 19, 2016

The Dialog works fine but I only get "No object selected; Cancel clicked" (BrowseForFolder = -1) in Shellbrowse.vbs when I try to choose a file. If I choose a folder i get the path as return value.

@manuganu9
Copy link

The dialog works fine in browse.vbs. But it's showing all files of folder.

I want to add filter for (*.jpg) files..Is it possible?

@mlhaufe
Copy link
Author

mlhaufe commented Aug 4, 2019

@manuganu9

browse.vbs relies on generating a *.hta file to trigger the browse dialog. HTA files use Internet Explorer 5 - 9 (depending on what is installed on your machine). If a newer version of Internet Explorer is installed, the HTA will still use IE9.

With that said, the feature you want is the 'accept' attribute of the element:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept

The problem though is that IE9 does not support this attribute:

https://www.caniuse.com/#search=accept

So no, it's not possible through the approach used in browse.vbs

@mlhaufe
Copy link
Author

mlhaufe commented Aug 5, 2019

@wonkawilly
Copy link

wonkawilly commented Aug 12, 2023

Although you can display files with .BrowseForFolder, the method will only return a folder: unfortunately, selecting a file and hitting the confirm button to open it or at least to get its complete path name, will generate an un-handled error.

@mlhaufe
Copy link
Author

mlhaufe commented Aug 12, 2023

@wonkawilly which version of Windows are you using?

@mlhaufe
Copy link
Author

mlhaufe commented Aug 13, 2023

@wonkawilly So, it looks like at some point Windows has changed how this works. After some testing with browse2.vbs it still works if the file is a *.zip file or a zip file in disguise like Microsoft office files *.xlsx or *.pptx

According to the following:

https://stackoverflow.com/a/41029833/153209

The registry can be modified to enable the other file types. I don't think it's worth the effort though.

The first approach which utilizes an *.hta behind-the-scenes still works in Windows 11

@wonkawilly
Copy link

wonkawilly commented Aug 15, 2023

@mlhaufe

I have on my Win7 32bit system,
IE11 installed
and
mshta.exe 8.~
and even
mshta.exe 11.~

I am trying to deal with html (-> hta + vbs, more precisely) for learning purposes and:
<input type="file" accept="my file extension filters list" multiple >
and
<object id="FilePickerDialog" classid="CLSID:3050F4E1-98B5-11CF-BB82-00AA00BDCE0B"></object>
and
BrowseForFolder(0, "Choose a file:", &H4000, "C:\")

and more...

So into the hta head I've set the doctype as
<!DOCTYPE html>

and the meta tag to
<meta charset="UTF-8" http-equiv="x-ua-compatible" content="IE=9"/>
or
<meta charset="UTF-8" http-equiv="x-ua-compatible" content="IE=10"/>
or
<meta charset="UTF-8" http-equiv="x-ua-compatible" content="IE=11"/>
or
<meta charset="UTF-8" http-equiv="x-ua-compatible" content="IE=edge"/>

I've also tried
.BrowseForFolder(0, "Choose a file:", &H4000, "C:\") as I said

What seems to a better job in .hta and vbs is the combination of the following code:

<meta charset="UTF-8" http-equiv="x-ua-compatible" content="IE=9"/>
<object id="FilePickerDialog" classid="CLSID:3050F4E1-98B5-11CF-BB82-00AA00BDCE0B"></object>

or

<meta charset="UTF-8" http-equiv="x-ua-compatible" content="IE=9"/>
<input type="file" accept="my file extension filters list" multiple >

with some limits tho:

  • In both cases I cannot select multiple files
  • In the last case I cannot even set file type (extensions) as filters

Among other things I have also tried to change the meta tag content attribute by vbs at runtime hopping this change will allow the input type=file to support accept and multiple attributes as in more recent IE versions, but unfortunately it did not work as I hopped: I suppose it is because the meta tag and its content is processed by the engine once at loading time and so even modifying its attribute at run time by vbs doesn't really updates the input type file behavior because the meta tag is not processed anymore once the page has finished loading the meta tag itself the first time to load correctly the HTA:APPLICATION... tag.

Of course I've tried even
<meta charset="UTF-8" http-equiv="x-ua-compatible" content="IE=10"/> (and even IE=11 and IE=edge)
<input type="file" accept="myfilters" multiple>

This combination works as expected for accept and multiple attributes, but at the cost of loosing some other .hta features as the app icon and the maximize attribute and more.

In other words, to get the main and unique hta file working correctly for some features seems to be necessary having IE=9 set into meta tag, no more recent version so the IE11 version I have in my system uses a compatible mode engine and supports all hta features correctly (the <HTA:APPLICATION tag and its attributes). But IE9 compatibility mode doesn't support accept and multiple attributes.
Viceversa, to get the file selector () working at its best, with the support for multiple files selection and filters for file types, seems necessary having a more recent version of IE (IE=10 or IE=11 or IE=edge) set into the meta tag (the IE=edge does not mean MS Edge, but such a setting just tells to mshta.exe just to use the most recent IE engine available (IE11 in my case) instead going into compatibility med with old IE9 or IE10 browser to render hta file content) at the price of losing some other features of hta. Also as if all the previous was not enough, setting the content attribute to IE=11 seems that also makes hta not able to handle and work with vbs anymore, or at least some of it must be edited and adapted... I don't know it for sure. Maybe its about time to abandon vbs and pass to js...

So i agree with you and also add that unfortunately setting IE at version > 9 solves some problems and causes others and viceversa: so it seems it is not possible to make them work together, not as a single .hta file at least.

I really have to add that these incoherences of Microsoft developing its products make a lot of people cranky from the early morning...
like having a fountain pen with a dull nib or a pencil with blunt tip after accidental falls. That is... brrrr...

@mlhaufe
Copy link
Author

mlhaufe commented Aug 15, 2023

@wonkawilly okay, you might be lucky and have MsComDlg.CommonDialog available. You'll have to do some research on how to use it as I haven't touched this in ~10 years maybe and it won't work on my machines:

Function BrowseForFile(pstrPath, pstrFilter)
    Set objDialog = CreateObject("MSComDlg.CommonDialog")

    objDialog.Filter = pstrFilter
    objDialog.InitDir = pstrPath
    objDialog.MaxFileSize = 256 
    objDialog.Flags = &H80000 + &H4 + &H8
    intResult = objDialog.ShowOpen()
    BrowseForFile = objDialog.FileName
End Function

BrowseForFile "c:","*.vbs"

If that ends up working, let me know and we can add it to the list above.

Another option might be CreateObject("UserAccounts.CommonDialog"). This was available in Windows XP, and I think later versions up to win 7 if Microsoft Office was installed. It might have been killed though based on a security patch.

@wonkawilly
Copy link

wonkawilly commented Aug 17, 2023

To integrate the information I shared before, in my little experience on Win7 32bit, IE11 installed, set meta tag for compatibility mode with IE9 into the in HTML (hta+vbs to be precise ), I have also tried these that also are NOT working:

  • Set objDialog = CreateObject("MSComDlg.CommonDialog")
  • Set objDialog = CreateObject("UserAccounts.CommonDialog")

Probably their support was removed with upgrades

The reported error is usually "The activex component cannot create the object "the object quoted into the CreateObject"

I would used the html standard approach
<input type="file" id="SelectScriptFile" accept=".ext1, .ext2, .extn" multiple />

but accept and multiple do not work on IE9 engine

I also tried to use into the main hta file even an iframe , pointing to the same folder where is saved the hta it self setting src attribute as:
src="c.\path...\MyfilehtafileFolder"
With this approach I can select multiple files and I have amazing filters functionality built-in into the columns headers as in Windows Explorer, but I can't have directory tree, at all, at the side: to navigate i can just go deep down into sub dirs and I cannot even go up to the parent dir. Also I am not able to get the selected objects into the hta vbscript from the iframe itself: this is comprehensible for security reasons.

The following is partially working
<object id="FilePickerDialog" classid="CLSID:3050F4E1-98B5-11CF-BB82-00AA00BDCE0B"></object>

I can set filters and few other parameters like this in vbs
Dim strFileToOpenPath : strFileToOpenPath = FilePickerDialog.openFileDlg(CStr(fpdStartFilePath), CStr(fpdStartDirPath), CStr(fpdFilter), CStr(fpdOpenFileDlgTitle))

but multi file selection doesn't work, but at least I have filters. For multiple file select I will use a button to append new opened files with the user intervention, one by one, it will do the trick.

I would use IE11 mode into the meta tag but I loose other HTA functionalities in that mode so I implemented a compromise:

IE9 compatibility mode
the above object that supports filters
but not multiple file selection
implementing by vbs the possibility to append files one by one: it will not be to ugly for few files to be selected and appended.

@mlhaufe
Copy link
Author

mlhaufe commented Aug 17, 2023

@wonkawilly

I just stumbled upon the following which still works when dropped in an HTA:

https://learn.microsoft.com/en-us/windows/win32/shell/shellfolderview-focuseditem?redirectedfrom=MSDN
https://learn.microsoft.com/en-us/windows/win32/shell/shellfolderview-selecteditems

It would need some design work to make it look pretty but there is a ViewOptions property available that might be partly useful.

There may even be a CLSID that represents the explorer url box, but I can't find my old forum posts on the internet archive at the moment.

At this point you'd be trying to create your own fully custom file browser that may not be worth the effort.

@wonkawilly
Copy link

wonkawilly commented Aug 19, 2023

For the moment I am using the following code:
The script part:

Dim fpdStartFilePath : fpdStartFilePath = "the string path"
Dim fpdStartDirPath : fpdStartDirPath = "" 'This does not seems to work at all
Dim fpdFilter : fpdFilter = "My custom filters for example (" & FileExtDlgFilter & ")|" & FileExtDlgFilter & "|"
Dim fpdOpenFileDlgTitle : fpdOpenFileDlgTitle = "Open a file of type " & FileExtDlgFilter ' This is the title of the dialog
Dim strFileToOpenPath : strFileToOpenPath = FilePickerDialog.openFileDlg(CStr(fpdStartFilePath), CStr(fpdStartDirPath), CStr(fpdFilter), CStr(fpdOpenFileDlgTitle))
If Not strFileToOpenPath = "" Then
	Dim strFileContent : strFileContent = FileReadContent(strFileToOpenPath)
	OrganizeContent(strFileContent)
End If

The html part:

<object id="FilePickerDialog" classid="CLSID:3050F4E1-98B5-11CF-BB82-00AA00BDCE0B"></object>

With such combination of VBScript and html (into a hta file) I get a full navigable Open File Dialog that allows me to:

  • navigate throughout the integrated folder tree view and chose a folder to pick a file from (a single one);
  • further filter the content of the folder by using the filters integrated into the columns headers;
  • search for items with the Search function by typing a string into the relative Search text box
  • pick a file;
  • read that selected file content;
  • elaborate the file content as I need to.

So it is an almost complete GUI: the limit is that I can't select more than one file at once: I haven't discovered yet if it is even possible to set a multi selection property to true for the dialog with such GUI object I don't know yet if it supports such selection mode. For the rest it works as expected opening the dialog and showing only the files that mach the extensions I need to be shown. Follows an example on how to set multiple file filters for the dialog:

Dim fpdFilter : fpdFilter = "HTML Files(*.html;*.htm)|*.html;*.htm|Text Files(*.txt;*.log)|*.txt;*.log|Image Files(*.jpg;*.gif)|*.jpg;*.gif|"

The syntax is a bit redundant but it allows to set a description that is shown for each option of the drop down file type selector and what is the relative value of each option that is the filter itself.
Notice that in order to work the string has to be converted by CStr as indicated into the following row of vbs code:

Dim strFileToOpenPath : strFileToOpenPath = FilePickerDialog.openFileDlg(CStr(fpdStartFilePath), CStr(fpdStartDirPath), CStr(fpdFilter), CStr(fpdOpenFileDlgTitle))

Of course it is possible to do the same in with JavaScript, by converting the given code accordingly with this language rules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment