Code Red > VB(A)
'Browse for folder' system dialog box in 64-Bit VBA 7.1
Patch61:
This module will allow you to use the Windows system SHBrowseForFolder dialog in 64-bit VBA 7.1.
--- Code: ---
'##########################################################################################
'# #
'# modFolderBrowse #
'# code compiled by #
'# Steven Elliott #
'# from many sources on the net #
'# Released to Public Domain #
'# #
'##########################################################################################
Option Explicit
Private Declare PtrSafe Function SHBrowseForFolder Lib "shell32.dll" _
Alias "SHBrowseForFolderA" (lpBrowseInfo As BrowseInfo) As Long
Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
(ByVal pidList As Long, ByVal lpBuffer As String) As Long
Public Declare PtrSafe Function SendMessageA Lib "user32" _
(ByVal hWnd As LongPtr, ByVal wMsg As Long, _
ByVal wParam As LongPtr, lParam As Any) As LongPtr
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal hMem As Long)
Private Const BIF_RETURNONLYFSDIRS As Long = 1
Private Const CSIDL_DRIVES As Long = &H11
Private Const WM_USER As Long = &H400
Private Const MAX_PATH As Long = 260 ' Is it a bad thing that I memorized this value?
'// message from browser
Private Const BFFM_INITIALIZED As Long = 1
Private Const BFFM_SELCHANGED As Long = 2
Private Const BFFM_VALIDATEFAILEDA As Long = 3 '// lParam:szPath ret:1(cont),0(EndDialog)
Private Const BFFM_VALIDATEFAILEDW As Long = 4 '// lParam:wzPath ret:1(cont),0(EndDialog)
Private Const BFFM_IUNKNOWN As Long = 5 '// provides IUnknown to client. lParam: IUnknown*
'// messages to browser
Private Const BFFM_SETSTATUSTEXTA As Long = WM_USER + 100
Private Const BFFM_ENABLEOK As Long = WM_USER + 101
Private Const BFFM_SETSELECTIONA As Long = WM_USER + 102
Private Const BFFM_SETSELECTIONW As Long = WM_USER + 103
Private Const BFFM_SETSTATUSTEXTW As Long = WM_USER + 104
Private Const BFFM_SETOKTEXT As Long = WM_USER + 105 '// Unicode only
Private Const BFFM_SETEXPANDED As Long = WM_USER + 106 '// Unicode only
Public Type BrowseInfo
hWndOwner As LongPtr
pIDLRoot As Long
pszDisplayName As String
lpszTitle As String
ulFlags As Long
lpfnCallback As LongPtr
lParam As LongPtr
iImage As Long
End Type
Private Function PtrToFunction(ByVal lFcnPtr As LongPtr) As LongPtr
PtrToFunction = lFcnPtr
End Function
Private Function CorrectPath(ByVal sPath As String) As String
If Right$(sPath, 1) = "\" Then
If Len(sPath) > 3 Then sPath = Left$(sPath, Len(sPath) - 1) ' Strip backslash from non-root
Else
If Len(sPath) = 2 Then sPath = sPath & "\" ' Append backslash to root
End If
CorrectPath = sPath
End Function
Public Function FolderBrowse(ByVal sDialogTitle As String, ByVal sPath As String) As String
Dim ReturnPath As String
Dim b(MAX_PATH) As Byte
Dim pItem As Long
Dim sFullPath As String
Dim bi As BrowseInfo
Dim ppidl As Long
sPath = CorrectPath(sPath)
bi.hWndOwner = 0 'Screen.ActiveForm.hwnd
'SHGetSpecialFolderLocation bi.hWndOwner, CSIDL_DRIVES, ppidl
bi.pIDLRoot = 0 'ppidl
bi.pszDisplayName = VarPtr(b(0))
bi.lpszTitle = sDialogTitle
bi.ulFlags = BIF_RETURNONLYFSDIRS
If FolderExists(sPath) Then bi.lpfnCallback = PtrToFunction(AddressOf BFFCallback)
bi.lParam = StrPtr(sPath)
pItem = SHBrowseForFolder(bi)
If pItem Then ' Succeeded
sFullPath = Space$(MAX_PATH)
If SHGetPathFromIDList(pItem, sFullPath) Then
ReturnPath = Left$(sFullPath, InStr(sFullPath, vbNullChar) - 1) ' Strip nulls
CoTaskMemFree pItem
End If
End If
If Right$(ReturnPath, 1) <> "\" And ReturnPath <> "" Then 'Could be "C:"
FolderBrowse = ReturnPath & "\"
End If
End Function
Public Function BFFCallback(ByVal hWnd As Long, ByVal uMsg As Long, ByVal lParam As Long, ByVal sData As String) As Long
If uMsg = BFFM_INITIALIZED Then
SendMessageA hWnd, BFFM_SETSELECTIONA, True, ByVal sData
End If
End Function
Public Function FolderExists(ByVal sFolderName As String) As Boolean
Dim att As Long
On Error Resume Next
att = GetAttr(sFolderName)
If Err.Number = 0 Then
FolderExists = True
Else
Err.Clear
FolderExists = False
End If
On Error GoTo 0
End Function
--- End code ---
Use it with the simple calls below:
--- Code: ---
Private Sub cmdGetLibraryPath_Click()
Dim sPath As String
' FolderBrowse(DialogBoxTitle, StartingPath)
sPath = modFolderBrowse.FolderBrowse("Select Folder Containing Block Library", txtLibraryPath.Text)
If sPath <> "" Then
If modFolderBrowse.FolderExists(sPath) Then
txtLibraryPath.Text = sPath
End If
End If
End Sub
--- End code ---
zzyong00:
It's great!
Can you achieve "opendialog" and "savedialog" in 64-Bit VBA7.1?
57gmc:
The code crashes AutoCAD on this line:
If SHGetPathFromIDList(pItem, sFullPath) Then
Alexander Rivilis:
Change
--- Code - vb.net: ---Dim pItem As Longwith
--- Code - vb.net: ---Dim pItem As LongPtr
--- Code - vb.net: --- Option Explicit '---------------------------------------------------------------------- ' 64 bit VBA 7 version of File and Folder Browswers ' FileBrowseOpen() ' FileBrowseSave() ' FolderBrowse() '---------------------------------------------------------------------- Public Declare PtrSafe Function SendMessageA Lib "user32" _ (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr Private Declare PtrSafe Function SHBrowseForFolder Lib "shell32.dll" _ Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As LongPtr Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _ Alias "SHGetPathFromIDListA" (ByVal pidList As LongPtr, ByVal lpBuffer As String) As Boolean Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal hMem As LongPtr) Private Declare PtrSafe Function GetOpenFileName Lib "comdlg32.dll" Alias _ "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long Private Declare PtrSafe Function GetSaveFileName Lib "comdlg32.dll" Alias _ "GetSaveFileNameA" (pOpenfilename As OPENFILENAME) As Long Private Const BIF_RETURNONLYFSDIRS As Long = 1 Private Const CSIDL_DRIVES As Long = &H11 Private Const WM_USER As Long = &H400 Private Const MAX_PATH As Long = 260 '// message from browser Private Const BFFM_INITIALIZED As Long = 1 Private Const BFFM_SELCHANGED As Long = 2 Private Const BFFM_VALIDATEFAILEDA As Long = 3 '// lParam:szPath ret:1(cont),0(EndDialog) Private Const BFFM_VALIDATEFAILEDW As Long = 4 '// lParam:wzPath ret:1(cont),0(EndDialog) Private Const BFFM_IUNKNOWN As Long = 5 '// provides IUnknown to client. lParam: IUnknown* '// messages to browser Private Const BFFM_SETSTATUSTEXTA As Long = WM_USER + 100 Private Const BFFM_ENABLEOK As Long = WM_USER + 101 Private Const BFFM_SETSELECTIONA As Long = WM_USER + 102 Private Const BFFM_SETSELECTIONW As Long = WM_USER + 103 Private Const BFFM_SETSTATUSTEXTW As Long = WM_USER + 104 Private Const BFFM_SETOKTEXT As Long = WM_USER + 105 '// Unicode only Private Const BFFM_SETEXPANDED As Long = WM_USER + 106 '// Unicode only Public Const OFN_ALLOWMULTISELECT As Long = &H200 Public Const OFN_CREATEPROMPT As Long = &H2000 Public Const OFN_ENABLEHOOK As Long = &H20 Public Const OFN_ENABLETEMPLATE As Long = &H40 Public Const OFN_ENABLETEMPLATEHANDLE As Long = &H80 Public Const OFN_EXPLORER As Long = &H80000 Public Const OFN_EXTENSIONDIFFERENT As Long = &H400 Public Const OFN_FILEMUSTEXIST As Long = &H1000 Public Const OFN_HIDEREADONLY As Long = &H4 Public Const OFN_LONGNAMES As Long = &H200000 Public Const OFN_NOCHANGEDIR As Long = &H8 Public Const OFN_NODEREFERENCELINKS As Long = &H100000 Public Const OFN_NOLONGNAMES As Long = &H40000 Public Const OFN_NONETWORKBUTTON As Long = &H20000 Public Const OFN_NOREADONLYRETURN As Long = &H8000& '*see comments Public Const OFN_NOTESTFILECREATE As Long = &H10000 Public Const OFN_NOVALIDATE As Long = &H100 Public Const OFN_OVERWRITEPROMPT As Long = &H2 Public Const OFN_PATHMUSTEXIST As Long = &H800 Public Const OFN_READONLY As Long = &H1 Public Const OFN_SHAREAWARE As Long = &H4000 Public Const OFN_SHAREFALLTHROUGH As Long = 2 Public Const OFN_SHAREWARN As Long = 0 Public Const OFN_SHARENOWARN As Long = 1 Public Const OFN_SHOWHELP As Long = &H10 Public Const OFN_ENABLESIZING As Long = &H800000 Public Const OFS_MAXPATHNAME As Long = 260 Private Type OPENFILENAME lStructSize As Long hWndOwner As LongPtr hInstance As LongPtr lpstrFilter As String lpstrCustomFilter As String nMaxCustFilter As Long nFilterIndex As Long lpstrFile As String nMaxFile As Long lpstrFileTitle As String nMaxFileTitle As Long lpstrInitialDir As String lpstrTitle As String flags As Long nFileOffset As Integer nFileExtension As Integer lpstrDefExt As String lCustData As Long lpfnHook As LongPtr lpTemplateName As String End Type Public Type BROWSEINFO hWndOwner As LongPtr pidlRoot As LongPtr pszDisplayName As String lpszTitle As String ulFlags As Long lpfnCallback As LongPtr lParam As LongPtr iImage As Long End Type '====== Folder Browser for 64 bit VBA 7 ======== Public Function FolderBrowse(ByVal sDialogTitle As String, ByVal sInitFolder As String) As String Dim ReturnPath As String Dim b(MAX_PATH) As Byte Dim pItem As LongPtr Dim sFullPath As String Dim bi As BROWSEINFO Dim ppidl As Long sInitFolder = CorrectPath(sInitFolder) ' Note VBA windows and dialogs do not have an hWnd property. bi.hWndOwner = 0 'Windows Main Screen handle. bi.pidlRoot = 0 'ppidl bi.pszDisplayName = VarPtr(b(0)) bi.lpszTitle = sDialogTitle bi.ulFlags = BIF_RETURNONLYFSDIRS If FolderExists(sInitFolder) Then bi.lpfnCallback = PtrToFunction(AddressOf BFFCallback) bi.lParam = StrPtr(sInitFolder) pItem = SHBrowseForFolder(bi) If pItem Then ' Succeeded sFullPath = Space$(MAX_PATH) If SHGetPathFromIDList(pItem, sFullPath) Then ReturnPath = Left$(sFullPath, InStr(sFullPath, vbNullChar) - 1) ' Strip nulls CoTaskMemFree pItem End If End If If ReturnPath <> "" Then If Right$(ReturnPath, 1) <> "\" Then ReturnPath = ReturnPath & "\" End If End If FolderBrowse = ReturnPath End Function ' typedef int (CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); Private Function BFFCallback(ByVal hWnd As LongPtr, ByVal uMsg As LongPtr, ByVal lParam As LongPtr, ByVal sData As String) As LongPtr If uMsg = BFFM_INITIALIZED Then SendMessageA hWnd, BFFM_SETSELECTIONA, True, ByVal sData End If End Function Private Function PtrToFunction(ByVal lFcnPtr As LongPtr) As LongPtr PtrToFunction = lFcnPtr End Function Private Function CorrectPath(ByVal sPath As String) As String If Right$(sPath, 1) = "\" Then If Len(sPath) > 3 Then sPath = Left$(sPath, Len(sPath) - 1) ' Strip backslash from non-root Else If Len(sPath) = 2 Then sPath = sPath & "\" ' Append backslash to root End If CorrectPath = sPath End Function Public Function FolderExists(ByVal sFolderName As String) As Boolean Dim att As Long On Error Resume Next att = GetAttr(sFolderName) If Err.Number = 0 Then FolderExists = True Else Err.Clear FolderExists = False End If On Error GoTo 0 End Function
Keith™:
I have a very similar function
Navigation
[0] Message Index
[#] Next page
Go to full version