bat-tomr / dialog-node

x-platform simple GUI dialogs for node js. Inspired by dialog from Tomás Pollak
MIT License
13 stars 11 forks source link

On Linux, `dialog-node.fileselect` browses for a file. On Windows, it browses for a directory. #12

Open apboon opened 5 years ago

apboon commented 5 years ago

On Linux, dialog-node.fileselect browses for a file. On Windows, it browses for a directory. Which is differs from what it claims it would do. This is because on Windows, shell.BrowseForFolder is called, which indeed shows a directory selection dialog instead of a file selection dialog (common file dialog).

apboon commented 5 years ago

I saw the following on https://gist.github.com/mlhaufe/1034241

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

Looking at the above code it seems that calling shell.BrowseForFolder is the way to go, but the difference is in the third argument. dialog-node uses 0 in shell.BrowseForFolder(0, dialogTitle, 0), and the example code I found uses &H4000..

Needs more investigation..

apboon commented 5 years ago

Nope.. shell.BrowseForFolder isn't the right call for the job of selecting a file. At most, shell.BrowseForFolder (in combination with &H4000) can select directories and files, but never just files (source: https://docs.microsoft.com/en-us/windows/win32/shell/shell-browseforfolder).

This example will do the trick (source: https://stackoverflow.com/questions/38643487/vbscript-browseforfile-function-how-to-specify-file-types)

Function GetFileDlgEx(sIniDir,sFilter,sTitle) 
Set oDlg = CreateObject("WScript.Shell").Exec("mshta.exe ""about:<object id=d classid=clsid:3050f4e1-98b5-11cf-bb82-00aa00bdce0b></object><script>moveTo(0,-9999);eval(new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(0).Read("&Len(sIniDir)+Len(sFilter)+Len(sTitle)+41&"));function window.onload(){var p=/[^\0]*/;new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).Write(p.exec(d.object.openfiledlg(iniDir,null,filter,title)));close();}</script><hta:application showintaskbar=no />""") 
oDlg.StdIn.Write "var iniDir='" & sIniDir & "';var filter='" & sFilter & "';var title='" & sTitle & "';" 
GetFileDlgEx = oDlg.StdOut.ReadAll 
End Function
set fso = CreateObject("Scripting.FileSystemObject")
CurrentDirectory = fso.GetAbsolutePathName(".")
sIniDir = CurrentDirectory &"\Myfile.csv" 
sFilter = "csv files (*.csv)|*.csv|txt files (*.txt)|*.txt|log files (*.log)|*.log|" 
sTitle = "Put a title of your program here :) (-_°)" 
MyFile = GetFileDlgEx(Replace(sIniDir,"\","\\"),sFilter,sTitle) 
wscript.echo MyFile

(painfully not indented.. -__-)

leefsmp commented 10 months ago

this is a VB sample ... :(

apboon commented 10 months ago

You are correct.

I found no other way to call native Win32 shell APIs from Node.js.

Maybe there's another bright mind out there that knows how to do this?

justind000 commented 2 months ago

Ran into this as well. I was able to cobble this together from here. It works well enough for me.

---msgbox.vbs---

Function GetFileDlgEx() 
  Set oDlg = CreateObject("WScript.Shell").Exec("mshta.exe ""about:<input type=file id=FILE><script>FILE.click();new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).WriteLine(FILE.value);close();resizeTo(0,0);</script>""") 
  GetFileDlgEx = oDlg.StdOut.ReadAll 
End Function

Set objArgs = WScript.Arguments
dialogType = objArgs(0)
dialogTitle = objArgs(1)
dialogText = objArgs(2)

If dialogType = "notification" Then
  MsgBox dialogText, 0, dialogTitle
ElseIf dialogType = "question" Then
  answer = MsgBox( dialogText, vbOKCancel, dialogTitle )
  Wscript.Stdout.Write answer
ElseIf dialogType = "entry" Then
  entryText = InputBox( dialogText, dialogTitle )
  Wscript.Stdout.Write entryText
ElseIf dialogType = "fileselect" Then
  fileName =  GetFileDlgEx()
  WScript.echo fileName
Else
  WScript.Echo "unknown dialog type"
End If

I couldn't figure out how to change the title or add a filter, however. Discussion surrounding the source of the code hints it isn't possible with this particular method.