Author Topic: Open, Save, and Folder dialogs (ANSI and Unicode, 32 and 64 bit)  (Read 3449 times)

0 Members and 1 Guest are viewing this topic.

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
I've made a demo program here for 32 and 64 bit Open and Save dialogs for ANSI and Unicode. The Unicode usage will not return characters beyond the ASCII range because this code converts it to an ANSI string first. The Open and Save dialogs can be performed with the ComDlgFileName function. If you specify the SAVE_DIALOG flag then it will show a save dialog. The OPEN_DIALOG flag is not necessary to show an open dialog as it is the default for the wrapper function.

Code: QB64: [Select]
  1.  
  2. '$Let UNICODE = TRUE
  3. $If UNICODE = DEFINED Then
  4.     Const MAX_PATH = 65534 'Since the MAX_PATH for unicode is 32767 and it is a wide string, two bytes are needed per character. So, double the length
  5.     Const MODE = "Unicode"
  6.     Const MAX_PATH = 260
  7.     Const MODE = "ANSI"
  8.  
  9. $ExeIcon:'.\internal\source\qb64.ico'
  10.  
  11. _ConsoleTitle "Comdlg32 Open/Save Dialog (32/64) Test - " + MODE
  12.  
  13. Const OFN_ALLOWMULTISELECT = &H00000200
  14. Const OFN_CREATEPROMPT = &H00002000
  15. Const OFN_DONTADDTORECENT = &H02000000
  16. Const OFN_EXPLORER = &H00080000
  17. Const OFN_EXTENSIONDIFFERENT = &H00000400
  18. Const OFN_FILEMUSTEXIST = &H00001000
  19. Const OFN_FORCESHOWHIDDEN = &H10000000
  20. Const OFN_HIDEREADONLY = &H00000004
  21. Const OFN_NOCHANGEDIR = &H00000008
  22. Const OFN_NODEREFERENCELINKS = &H00100000
  23. Const OFN_NONETWORKBUTTON = &H00020000
  24. Const OFN_NOREADONLYRETURN = &H00008000
  25. Const OFN_NOTESTFILECREATE = &H00010000
  26. Const OFN_NOVALIDATE = &H00000100
  27. Const OFN_OVERWRITEPROMPT = &H00000002
  28. Const OFN_PATHMUSTEXIST = &H00000800
  29. Const OFN_READONLY = &H00000001
  30. Const OFN_SHAREAWARE = &H00004000
  31. Const OFN_SHOWHELP = &H00000010
  32. Const SAVE_DIALOG = &H01000000
  33. Const OPEN_DIALOG = &H02000000
  34.  
  35.  
  36. file = ComDlgFileName("Open Source File", _CWD$, "QB64 Files (*.BAS, *.BI, *.BM, *.FRM)|*.BAS;*.BI;*.BM;*.FRM|C/C++ Files (*.CPP, *.HPP, *.H, *.C)|*.CPP;*.HPP;*.H;*.C|All Files|*.*", OFN_FORCESHOWHIDDEN)
  37. If file <> "" Then
  38.     Print file
  39.     Open file For Binary Access Read As #1
  40.     Dim As String content: content = Space$(LOF(1))
  41.     Get #1, , content
  42.     Close
  43.     Print content
  44.     Dim As String filename: filename = Mid$(file, _InStrRev(file, "\") + 1)
  45.     _ConsoleTitle "Viewing - " + filename
  46.  
  47. 'Print SelectFolder("Pick a folder")
  48.  
  49. Function ComDlgFileName$ (Title As String, InitialDir As String, Filter As String, Flags As _Unsigned Long)
  50.     Type OPENFILENAME
  51.         As _Unsigned Long lStructSize
  52.         $If 64BIT Then
  53.             As String * 4 padding
  54.         $End If
  55.         As _Offset hwndOwner, hInstance, lpstrFilter, lpstrCustomFilter
  56.         As _Unsigned Long nMaxCustFilter, nFilterIndex
  57.         As _Offset lpstrFile
  58.         As _Unsigned Long nMaxFile
  59.         $If 64BIT Then
  60.             As String * 4 padding2
  61.         $End If
  62.         As _Offset lpstrFileTitle
  63.         As _Unsigned Long nMaxFileTitle
  64.         $If 64BIT Then
  65.             As String * 4 padding3
  66.         $End If
  67.         As _Offset lpstrInitialDir, lpstrTitle
  68.         As _Unsigned Long Flags
  69.         As Integer nFileOffset, nFileExtension
  70.         As _Offset lpstrDefExt, lCustData, lpfnHook, lpTemplateName, pvReserved
  71.         As _Unsigned Long dwReserved, FlagsEx
  72.     End Type
  73.  
  74.     Declare Dynamic Library "Comdlg32"
  75.         $If UNICODE = DEFINED Then
  76.         Sub GetSaveFileName Alias "GetSaveFileNameW" (ByVal ofn As _Offset)
  77.         Function GetOpenFileName& Alias "GetOpenFileNameW" (ByVal ofn As _Offset)
  78.         $Else
  79.             Sub GetSaveFileName Alias "GetSaveFileNameA" (ByVal ofn As _Offset)
  80.             Function GetOpenFileName& Alias "GetOpenFileNameA" (ByVal ofn As _Offset)
  81.         $End If
  82.     End Declare
  83.  
  84.     $If UNICODE = DEFINED Then
  85.         Function wcslen%& (ByVal str As _Offset)
  86.         End Declare
  87.     $Else
  88.         $If 64BIT Then
  89.             Declare CustomType Library ".\internal\c\c_compiler\x86_64-w64-mingw32\include\tchar"
  90.                 Function tcslen%& Alias "_tcslen" (ByVal str As _Offset)
  91.             End Declare
  92.         $Else
  93.             Declare CustomType Library ".\internal\c\c_compiler\i686-w64-mingw32\include\tchar"
  94.             Function tcslen%& Alias "_tcslen" (ByVal str As _Offset)
  95.             End Declare
  96.         $End If
  97.     $End If
  98.  
  99.     Dim As OPENFILENAME ofn
  100.     Do
  101.         Mid$(Filter, InStr(Filter, "|")) = Chr$(0)
  102.     Loop While InStr(Filter, "|")
  103.  
  104.     $If UNICODE = DEFINED Then
  105.         Title = ANSIToUnicode(Title + Chr$(0))
  106.         InitialDir = ANSIToUnicode(InitialDir + Chr$(0))
  107.         Filter = ANSIToUnicode(Filter + Chr$(0) + Chr$(0))
  108.     $Else
  109.         Title = Title + Chr$(0)
  110.         InitialDir = InitialDir + Chr$(0)
  111.         Filter = Filter + Chr$(0) + Chr$(0)
  112.     $End If
  113.     Dim As String * MAX_PATH oFile
  114.     ofn.lStructSize = Len(ofn)
  115.     ofn.hwndOwner = _WindowHandle
  116.     ofn.lpstrFilter = _Offset(Filter)
  117.     ofn.nFilterIndex = 1
  118.     ofn.nMaxFile = Len(oFile)
  119.     ofn.lpstrFileTitle = ofn.lpstrFile
  120.     ofn.nMaxFileTitle = ofn.nMaxFile
  121.     ofn.lpstrInitialDir = _Offset(InitialDir)
  122.     ofn.lpstrTitle = _Offset(Title)
  123.     ofn.lpstrFile = _Offset(oFile)
  124.     If OPEN_DIALOG And Flags Or (SAVE_DIALOG And Flags) = 0 Then
  125.         If OFN_ALLOWMULTISELECT And Flags Then Flags = Flags Or OFN_EXPLORER
  126.         ofn.Flags = Flags
  127.         If GetOpenFileName(_Offset(ofn)) <> 0 Then
  128.             If OFN_ALLOWMULTISELECT And Flags Then
  129.                 Dim As String file, outfiles, directory
  130.                 $If UNICODE = DEFINED Then
  131.                     Dim As _Offset tmp: tmp = ofn.lpstrFile + (ofn.nFileOffset * 2)
  132.                     Dim As _MEM pFiles: pFiles = _Mem(tmp, wcslen(tmp) * 2)
  133.                     Dim As _MEM dir: dir = _Mem(ofn.lpstrFile, wcslen(ofn.lpstrFile) * 2)
  134.                     directory = Space$(wcslen(ofn.lpstrFile) * 2)
  135.                 $Else
  136.                     Dim As _Offset tmp: tmp = ofn.lpstrFile + ofn.nFileOffset
  137.                     Dim As _MEM pFiles: pFiles = _Mem(tmp, tcslen(tmp))
  138.                     Dim As _MEM dir: dir = _Mem(ofn.lpstrFile, tcslen(ofn.lpstrFile))
  139.                     directory = Space$(tcslen(ofn.lpstrFile))
  140.                 $End If
  141.                 _MemGet dir, dir.OFFSET, directory
  142.                 _MemFree dir
  143.                 Dim As Long i
  144.                 $If UNICODE = DEFINED Then
  145.                     While wcslen(tmp)
  146.                     file = Space$(wcslen(tmp) * 2)
  147.                     _MemGet pFiles, pFiles.OFFSET, file
  148.                     Select Case i
  149.                     Case 0
  150.                     outfiles = directory + ANSIToUnicode("\") + file
  151.                     Case Else
  152.                     outfiles = outfiles + ANSIToUnicode("|") + directory + ANSIToUnicode("\") + file
  153.                     End Select
  154.                     i = i + 1
  155.                     tmp = tmp + Len(file) + 2
  156.                     pFiles = _Mem(tmp, wcslen(tmp) * 2)
  157.                     Wend
  158.                 $Else
  159.                     While tcslen(tmp)
  160.                         file = Space$(tcslen(tmp))
  161.                         _MemGet pFiles, pFiles.OFFSET, file
  162.                         Select Case i
  163.                             Case 0
  164.                                 outfiles = directory + "\" + file
  165.                             Case Else
  166.                                 outfiles = outfiles + "|" + directory + "\" + file
  167.                         End Select
  168.                         i = i + 1
  169.                         tmp = tmp + (tcslen(tmp) + 1)
  170.                         pFiles = _Mem(tmp, tcslen(tmp))
  171.                     Wend
  172.                 $End If
  173.                 _MemFree pFiles
  174.                 If i = 1 Then
  175.                     $If UNICODE = DEFINED Then
  176.                         file = wCharPtrToString(_Offset(directory))
  177.                     $Else
  178.                         file = directory
  179.                     $End If
  180.                     ComDlgFileName = file
  181.                 Else
  182.                     $If UNICODE = DEFINED Then
  183.                         outfiles = wCharPtrToString(_Offset(outfiles))
  184.                     $End If
  185.                     ComDlgFileName = outfiles
  186.                 End If
  187.             Else
  188.                 $If UNICODE = DEFINED Then
  189.                     Dim As String selectedfile: selectedfile = wCharPtrToString(_Offset(oFile))
  190.                     ComDlgFileName = selectedfile
  191.                 $Else
  192.                     ComDlgFileName = Mid$(oFile, 1, InStr(oFile, Chr$(0)) - 1)
  193.                 $End If
  194.             End If
  195.         End If
  196.     ElseIf SAVE_DIALOG And Flags Then
  197.         ofn.Flags = Flags
  198.         GetSaveFileName _Offset(ofn)
  199.         $If UNICODE = DEFINED Then
  200.             selectedfile = wCharPtrToString(_Offset(oFile))
  201.             ComDlgFileName = selectedfile
  202.         $Else
  203.             ComDlgFileName = Mid$(oFile, 1, InStr(oFile, Chr$(0)) - 1)
  204.         $End If
  205.     End If
  206.  
  207. Function SelectFolder$ (title As String)
  208.     Type BROWSEINFO
  209.         As _Offset hwndOwner, pidlRoot, pszDisplayName, lpszTitle
  210.         As _Unsigned Long ulFlags
  211.         As _Offset lpfn, lParam
  212.         As Long iImage
  213.     End Type
  214.     Declare Dynamic Library "Shell32"
  215.         $If UNICODE = DEFINED Then
  216.         Function SHBrowseForFolder%& Alias "SHBrowseForFolderW" (ByVal lpbi As _Offset)
  217.         Function SHGetPathFromIDList%% Alias "SHGetPathFromIDListW" (ByVal lpItem As _Offset, Byval szDir As _Offset)
  218.         $Else
  219.             Function SHBrowseForFolder%& (ByVal lpbi As _Offset)
  220.             Function SHGetPathFromIDList%% (ByVal lpItem As _Offset, Byval szDir As _Offset)
  221.         $End If
  222.     End Declare
  223.     Dim As BROWSEINFO browse
  224.     Dim As String * MAX_PATH folder
  225.     $If UNICODE = DEFINED Then
  226.         title = ANSIToUnicode(title + Chr$(0))
  227.     $Else
  228.         title = title + Chr$(0)
  229.     $End If
  230.     browse.hwndOwner = _WindowHandle
  231.     browse.pszDisplayName = _Offset(folder)
  232.     browse.lpszTitle = _Offset(title)
  233.     Dim As _Offset pfolder
  234.     pfolder = SHBrowseForFolder(_Offset(browse))
  235.     If pfolder Then
  236.         Dim As String * MAX_PATH resolvedPath
  237.         If SHGetPathFromIDList(pfolder, _Offset(resolvedPath)) Then
  238.             $If UNICODE = DEFINED Then
  239.                 SelectFolder = wCharPtrToString(_Offset(resolvedPath))
  240.             $Else
  241.                 SelectFolder = Mid$(resolvedPath, 1, InStr(resolvedPath, Chr$(0)) - 1)
  242.             $End If
  243.         End If
  244.     End If
  245.  
  246. $If UNICODE = DEFINED Then
  247.     Function wCharPtrToString$ (wchar As _Offset)
  248.     Dim As _Offset wlen: wlen = wcslen(wchar) * 2 'The length does not account for the 2-byte nature of Unicode so we multiply by 2
  249.     Dim As _MEM pChar: pChar = _Mem(wchar, wlen) 'Declaring a new _MEM block and setting it to grab the number of bytes referenced by wlen at pointer wchar
  250.     Dim As String char: char = Space$(wlen) 'Declaring a new string large enough to hold the unicode string
  251.     _MemGet pChar, pChar.OFFSET, char 'Storing the data in the string
  252.     _MemFree pChar 'Freeing the _MEM block
  253.     wCharPtrToString = UnicodeToANSI(char) 'Returning the converted Unicode string
  254.  
  255.     '$INCLUDE:'unicodetoansi.bas'
* unicodetoansi.bas (Filesize: 1.74 KB, Downloads: 211)
Shuwatch!

Offline loudar

  • Newbie
  • Posts: 73
  • improve it bit by bit.
    • View Profile
Re: Open, Save, and Folder dialogs (ANSI and Unicode, 32 and 64 bit)
« Reply #1 on: August 02, 2021, 12:24:25 pm »
Works super well in the image editor! Great work again.
Check out what I do besides coding: http://loudar.myportfolio.com/