Author Topic: Open, Save, and Folder dialogs using Pipecom  (Read 3159 times)

0 Members and 1 Guest are viewing this topic.

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
Open, Save, and Folder dialogs using Pipecom
« on: June 12, 2021, 12:02:09 am »
No longer needing to use script files or turning off execution policies. Now you can use pipecom to call up common dialogs! Each function uses one string call to PowerShell to generate the dialog. Very efficient. The GetOpenFileNames sub can be used to return an array of files selected. The other three are self-explanatory.

Code: QB64: [Select]
  1.  
  2. Print GetOpenFileName("This is a test", _Dir$("desktop"), "txt files (*.txt)|*.txt|All files (*.*)|*.*", 2)
  3. 'Dim As String savefile
  4. 'savefile = GetSaveFileName("Save test", _CWD$, "txt files (*.txt)|*.txt|All files (*.*)|*.*", 1)
  5. 'If savefile <> "" Then
  6. '    Open savefile For Output As #1
  7. '    Print #1, Chr$(34) + "Success! Success! We've done it! We've done it!" + Chr$(34)
  8. '    Print #1, Chr$(9) + Chr$(9) + Chr$(9) + "-Every diplomatic leader in The Batman Movie";
  9. '    Close
  10. 'End If
  11.  
  12. 'Print GetFolderName("Pick a folder")
  13.  
  14. 'ReDim As String filelist(1 To 1)
  15. 'GetOpenFileNames "Pick multiple files", _Dir$("desktop"), "txt files (*.txt)|*.txt|All files (*.*)|*.*", 1, filelist()
  16.  
  17. 'Dim x
  18. 'For x = LBound(filelist) To UBound(filelist)
  19. '    Print filelist(x)
  20. 'Next
  21.  
  22. Function GetOpenFileName$ (Title As String, InitialDir As String, Filter As String, FilterIndex As Long)
  23.     Dim As String cmd, stdout, stderr
  24.     Dim As Long exit_code
  25.     If Mid$(InitialDir, Len(InitialDir) - 1) <> "\" Then InitialDir = InitialDir + "\"
  26.     cmd = "PowerShell Add-Type -AssemblyName System.Windows.Forms;$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ Title = '" + Chr$(34) + Title + Chr$(34) + "'; InitialDirectory = '" + Chr$(34) + InitialDir + Chr$(34) + "'; Filter = '" + Chr$(34) + Filter + Chr$(34) + "'; FilterIndex = '" + Chr$(34) + LTrim$(Str$(FilterIndex)) + Chr$(34) + "'; };$null = $FileBrowser.ShowDialog();$FileBrowser.FileName;exit $LASTEXITCODE"
  27.     exit_code = pipecom(cmd, stdout, stderr)
  28.     If stdout <> "" Then GetOpenFileName = Mid$(stdout, 1, Len(stdout) - 1)
  29.  
  30. Sub GetOpenFileNames (Title As String, InitialDir As String, Filter As String, FilterIndex As Long, filenames() As String)
  31.     Dim As String cmd, stdout, stderr
  32.     Dim As Long exit_code
  33.     If Mid$(InitialDir, Len(InitialDir) - 1) <> "\" Then InitialDir = InitialDir + "\"
  34.     cmd = "PowerShell Add-Type -AssemblyName System.Windows.Forms;$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ Title = '" + Chr$(34) + Title + Chr$(34) + "'; InitialDirectory = '" + Chr$(34) + InitialDir + Chr$(34) + "'; Filter = '" + Chr$(34) + Filter + Chr$(34) + "'; FilterIndex = '" + Chr$(34) + LTrim$(Str$(FilterIndex)) + Chr$(34) + "'; Multiselect = 'true'; };$null = $FileBrowser.ShowDialog();$FileBrowser.FileNames;exit $LASTEXITCODE"
  35.     exit_code = pipecom(cmd, stdout, stderr)
  36.     If stdout <> "" Then
  37.         stdout = Mid$(stdout, 1, Len(stdout) - 1)
  38.         If InStr(stdout, Chr$(10)) = 0 Then
  39.             filenames(1) = stdout
  40.         Else
  41.             String.Split stdout, Chr$(10), filenames()
  42.         End If
  43.     End If
  44.  
  45. Function GetSaveFileName$ (Title As String, InitialDir As String, Filter As String, FilterIndex As Long)
  46.     Dim As String cmd, stdout, stderr
  47.     Dim As Long exit_code
  48.     If Mid$(InitialDir, Len(InitialDir) - 1) <> "\" Then InitialDir = InitialDir + "\"
  49.     cmd = "PowerShell Add-Type -AssemblyName System.Windows.Forms;$FileBrowser = New-Object System.Windows.Forms.SaveFileDialog -Property @{ Title = '" + Chr$(34) + Title + Chr$(34) + "'; InitialDirectory = '" + Chr$(34) + InitialDir + Chr$(34) + "'; Filter = '" + Chr$(34) + Filter + Chr$(34) + "'; FilterIndex = '" + Chr$(34) + LTrim$(Str$(FilterIndex)) + Chr$(34) + "'; };$null = $FileBrowser.ShowDialog();$FileBrowser.FileName;exit $LASTEXITCODE"
  50.     exit_code = pipecom(cmd, stdout, stderr)
  51.     If stdout <> "" Then GetSaveFileName = Mid$(stdout, 1, Len(stdout) - 1)
  52.  
  53. Function GetFolderName$ (Title As String)
  54.     Dim As String cmd, stdout, stderr
  55.     Dim As Long exit_code
  56.     cmd = "PowerShell Add-Type -AssemblyName System.Windows.Forms;$FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog -Property @{ Description = '" + Chr$(34) + Title + Chr$(34) + "'; ShowNewFolderButton = 'true'; };$null = $FolderBrowser.ShowDialog();$FolderBrowser.SelectedPath;exit $LASTEXITCODE"
  57.     exit_code = pipecom(cmd, stdout, stderr)
  58.     If stdout <> "" Then GetFolderName = Mid$(stdout, 1, Len(stdout) - 1)
  59.  
  60. Sub String.Split (Expression As String, delimiter As String, StorageArray() As String)
  61.     Dim copy As String, p As Long, curpos As Long, arrpos As Long, dpos As Long
  62.     copy = Expression
  63.     If delimiter = " " Then
  64.         copy = RTrim$(LTrim$(copy))
  65.         p = InStr(copy, "  ")
  66.         While p > 0
  67.             copy = Mid$(copy, 1, p - 1) + Mid$(copy, p + 1)
  68.             p = InStr(copy, "  ")
  69.         Wend
  70.     End If
  71.     curpos = 1
  72.     arrpos = UBound(StorageArray)
  73.     dpos = InStr(curpos, copy, delimiter)
  74.     Do Until dpos = 0
  75.         StorageArray(UBound(StorageArray)) = Mid$(copy, curpos, dpos - curpos)
  76.         ReDim _Preserve StorageArray(UBound(StorageArray) + 1) As String
  77.         curpos = dpos + Len(delimiter)
  78.         dpos = InStr(curpos, copy, delimiter)
  79.     Loop
  80.     StorageArray(UBound(StorageArray)) = Mid$(copy, curpos)
  81.     ReDim _Preserve StorageArray(UBound(StorageArray)) As String
  82.  
  83. '$INCLUDE:'pipecomqb64.bas'

pipecomqb64.bas:
Code: QB64: [Select]
  1. Function pipecom& (cmd As String, stdout As String, stderr As String)
  2.     $If WIN Then
  3.         Type SECURITY_ATTRIBUTES
  4.             As Long nLength
  5.             $If 64BIT Then
  6.                 As Long padding
  7.             $End If
  8.             As _Offset lpSecurityDescriptor
  9.             As Long bInheritHandle
  10.             $If 64BIT Then
  11.                 As Long padding2
  12.             $End If
  13.         End Type
  14.  
  15.         Type STARTUPINFO
  16.             As Long cb
  17.             $If 64BIT Then
  18.                 As Long padding
  19.             $End If
  20.             As _Offset lpReserved, lpDesktop, lpTitle
  21.             As Long dwX, dwY, dwXSize, dwYSize, dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags
  22.             As Integer wShowWindow, cbReserved2
  23.             $If 64BIT Then
  24.                 As Long padding2
  25.             $End If
  26.             As _Offset lpReserved2, hStdInput, hStdOutput, hStdError
  27.         End Type
  28.  
  29.         Type PROCESS_INFORMATION
  30.             As _Offset hProcess, hThread
  31.             As Long dwProcessId
  32.             $If 64BIT Then
  33.                 As Long padding
  34.             $End If
  35.         End Type
  36.  
  37.         Const STARTF_USESTDHANDLES = &H00000100
  38.         Const CREATE_NO_WINDOW = &H8000000
  39.  
  40.         Const INFINITE = 4294967295
  41.         Const WAIT_FAILED = &HFFFFFFFF
  42.  
  43.             Function CreatePipe%% (ByVal hReadPipe As _Offset, Byval hWritePipe As _Offset, Byval lpPipeAttributes As _Offset, Byval nSize As Long)
  44.             Function CreateProcess%% Alias CreateProcessA (ByVal lpApplicationName As _Offset, Byval lpCommandLine As _Offset, Byval lpProcessAttributes As _Offset, Byval lpThreadAttributes As _Offset, Byval bInheritHandles As Integer, Byval dwCreationFlags As Long, Byval lpEnvironment As _Offset, Byval lpCurrentDirectory As _Offset, Byval lpStartupInfor As _Offset, Byval lpProcessInformation As _Offset)
  45.             Function GetExitCodeProcess%% (ByVal hProcess As _Offset, Byval lpExitCode As _Offset)
  46.             Function HandleClose%% Alias CloseHandle (ByVal hObject As _Offset)
  47.             Function ReadFile%% (ByVal hFile As _Offset, Byval lpBuffer As _Offset, Byval nNumberOfBytesToRead As Long, Byval lpNumberOfBytesRead As _Offset, Byval lpOverlapped As _Offset)
  48.             Function WaitForSingleObject& (ByVal hHandle As _Offset, Byval dwMilliseconds As Long)
  49.         End Declare
  50.  
  51.         Dim As _Byte ok: ok = 1
  52.         Dim As _Offset hStdOutPipeRead, hStdOutPipeWrite, hStdReadPipeError, hStdOutPipeError
  53.         Dim As SECURITY_ATTRIBUTES sa: sa.nLength = Len(sa): sa.lpSecurityDescriptor = 0: sa.bInheritHandle = 1
  54.  
  55.         If CreatePipe(_Offset(hStdOutPipeRead), _Offset(hStdOutPipeWrite), _Offset(sa), 0) = 0 Then
  56.             pipecom = -1
  57.             Exit Function
  58.         End If
  59.  
  60.         If CreatePipe(_Offset(hStdReadPipeError), _Offset(hStdOutPipeError), _Offset(sa), 0) = 0 Then
  61.             pipecom = -1
  62.             Exit Function
  63.         End If
  64.  
  65.         Dim As STARTUPINFO si
  66.         si.cb = Len(si)
  67.         si.dwFlags = STARTF_USESTDHANDLES
  68.         si.hStdError = hStdOutPipeError
  69.         si.hStdOutput = hStdOutPipeWrite
  70.         si.hStdInput = 0
  71.         Dim As PROCESS_INFORMATION pi
  72.         Dim As _Offset lpApplicationName
  73.         Dim As String fullcmd: fullcmd = "cmd /c " + cmd + Chr$(0)
  74.         Dim As String lpCommandLine: lpCommandLine = fullcmd
  75.         Dim As _Offset lpProcessAttributes, lpThreadAttributes
  76.         Dim As Integer bInheritHandles: bInheritHandles = 1
  77.         Dim As Long dwCreationFlags: dwCreationFlags = CREATE_NO_WINDOW
  78.         Dim As _Offset lpEnvironment, lpCurrentDirectory
  79.         ok = CreateProcess(lpApplicationName,_
  80.         _Offset(lpCommandLine),_
  81.         lpProcessAttributes,_
  82.         lpThreadAttributes,_
  83.         bInheritHandles,_
  84.         dwCreationFlags,_
  85.         lpEnvironment,_
  86.         lpCurrentDirectory,_
  87.         _Offset(si),_
  88.         _Offset(pi))
  89.         If ok = 0 Then
  90.             pipecom = -1
  91.             Exit Function
  92.         End If
  93.  
  94.         ok = HandleClose(hStdOutPipeWrite)
  95.         ok = HandleClose(hStdOutPipeError)
  96.  
  97.         Dim As String buf: buf = Space$(4096 + 1)
  98.         Dim As Long dwRead
  99.         While ReadFile(hStdOutPipeRead, _Offset(buf), 4096, _Offset(dwRead), 0) <> 0 And dwRead > 0
  100.             buf = Mid$(buf, 1, dwRead)
  101.             GoSub RemoveChr13
  102.             stdout = stdout + buf
  103.             buf = Space$(4096 + 1)
  104.         Wend
  105.  
  106.         While ReadFile(hStdReadPipeError, _Offset(buf), 4096, _Offset(dwRead), 0) <> 0 And dwRead > 0
  107.             buf = Mid$(buf, 1, dwRead)
  108.             GoSub RemoveChr13
  109.             stderr = stderr + buf
  110.             buf = Space$(4096 + 1)
  111.         Wend
  112.  
  113.         Dim As Long exit_code, ex_stat
  114.         If WaitForSingleObject(pi.hProcess, INFINITE) <> WAIT_FAILED Then
  115.             If GetExitCodeProcess(pi.hProcess, _Offset(exit_code)) Then
  116.                 ex_stat = 1
  117.             End If
  118.         End If
  119.  
  120.         ok = HandleClose(hStdOutPipeRead)
  121.         ok = HandleClose(hStdReadPipeError)
  122.         If ex_stat = 1 Then
  123.             pipecom = exit_code
  124.         Else
  125.             pipecom = -1
  126.         End If
  127.  
  128.         Exit Function
  129.  
  130.         RemoveChr13:
  131.         Dim As Long j
  132.         j = InStr(buf, Chr$(13))
  133.         Do While j
  134.             buf = Left$(buf, j - 1) + Mid$(buf, j + 1)
  135.             j = InStr(buf, Chr$(13))
  136.         Loop
  137.         Return
  138.     $Else
  139.         Function popen%& (cmd As String, readtype As String)
  140.         Function feof& (ByVal stream As _Offset)
  141.         Function fgets$ (str As String, Byval n As Long, Byval stream As _Offset)
  142.         Function pclose& (ByVal stream As _Offset)
  143.         End Declare
  144.  
  145.         Declare Library
  146.         Function WEXITSTATUS& (ByVal stat_val As Long)
  147.         End Declare
  148.  
  149.         Dim As String pipecom_buffer
  150.         Dim As _Offset stream
  151.  
  152.         Dim buffer As String * 4096
  153.         If _FileExists("pipestderr") Then
  154.         Kill "pipestderr"
  155.         End If
  156.         stream = popen(cmd + " 2>pipestderr", "r")
  157.         If stream Then
  158.         While feof(stream) = 0
  159.         If fgets(buffer, 4096, stream) <> "" And feof(stream) = 0 Then
  160.         stdout = stdout + Mid$(buffer, 1, InStr(buffer, Chr$(0)) - 1)
  161.         End If
  162.         Wend
  163.         Dim As Long status, exit_code
  164.         status = pclose(stream)
  165.         exit_code = WEXITSTATUS(status)
  166.         If _FileExists("pipestderr") Then
  167.         Dim As Integer errfile
  168.         errfile = FreeFile
  169.         Open "pipestderr" For Binary As #errfile
  170.         If LOF(errfile) > 0 Then
  171.         stderr = Space$(LOF(errfile))
  172.         Get #errfile, , stderr
  173.         End If
  174.         Close #errfile
  175.         Kill "pipestderr"
  176.         End If
  177.         pipecom = exit_code
  178.         Else
  179.         pipecom = -1
  180.         End If
  181.     $End If
  182.  
  183. Function pipecom_lite$ (cmd As String)
  184.     Dim As Long a
  185.     Dim As String stdout, stderr
  186.     a = pipecom(cmd, stdout, stderr)
  187.     If stderr <> "" Then
  188.         pipecom_lite = stderr
  189.     Else
  190.         pipecom_lite = stdout
  191.     End If
« Last Edit: June 12, 2021, 01:27:47 pm by SpriggsySpriggs »
Shuwatch!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Open, Save, and Folder dialogs using Pipecom
« Reply #1 on: June 12, 2021, 01:17:22 pm »
Oh where was this when I was putting together oh? :)

Definitely got to check this out, multi-select you say? That would be fabulous!

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
Re: Open, Save, and Folder dialogs using Pipecom
« Reply #2 on: June 12, 2021, 01:19:11 pm »
Definitely got to check this out, multi-select you say? That would be fabulous!

@bplus Just updated the original code. Had to change the logic for the multi-select. Now it works right. The array wasn't getting anything if only one file was selected. Now it works properly.

EDIT: Changed it again because InitialDir needs a backslash on the end in order to be valid and didn't want people to have to remember to put one.
« Last Edit: June 12, 2021, 01:25:04 pm by SpriggsySpriggs »
Shuwatch!