Select folder dialog

Share your advanced PureBasic knowledge/code with the community.
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Select folder dialog

Post by tatanas »

Hi !

I was looking for a OpenFolderRequester function (same style as OpenFileRequester) because the PathRequester interface is not user friendly to deal with network share.
I found IFileOpenDialog interface (WinApi) then my search led me to a Russian Purebasic forum.

Here is the result : http://purebasic.info/phpBB3ex/viewtopi ... 242#p49242 --> Link is DEAD

Here is the code :

Code: Select all

IncludeFile "IFileDialogDef.pbi"

; Procedure.s OpenFolderRequester(Title.s, DefaultFolder.s, Array AddPlace.s(1), hWndWindow = #Null) ; le tableau AddPlace sert à ajouter des emplacements dans la partie Favoris de la boite de dialogue
Procedure.s OpenFolderRequester(Title.s = "", DefaultFolder.s = "", hWndWindow = #Null)
	Define.s FolderName
	
	PathRemoveBackslash_(DefaultFolder)
	hResult = CoInitializeEx_(#Null, #COINIT_APARTMENTTHREADED | #COINIT_DISABLE_OLE1DDE)
	
	If hResult = #S_OK Or hResult = #S_FALSE
		If CoCreateInstance_(?CLSID_IFileOpenDialog, #Null, #CLSCTX_ALL, ?IID_IFileOpenDialog, @FileOpenDialog.IFileOpenDialog) = #S_OK
			ShellItem.IShellItem = CreateItemFromParsingName(DefaultFolder)
			FileOpenDialog\SetTitle(@Title)
			FileOpenDialog\SetDefaultFolder(ShellItem)
			
			; permet d'ajouter des emplacements dans la partie "Favoris" en haut à gauche de la boite de dialogue
; 			For rtnCount = 0 To ArraySize(AddPlace()) - 1
; 				ShellItem = CreateItemFromParsingName(AddPlace(rtnCount))
; 				FileOpenDialog\AddPlace(ShellItem, #FDAP_BOTTOM)
; 			Next
			
			FileOpenDialog\SetFileNameLabel(@"Nom du dossier :")
; 			FileOpenDialog\SetFileName(@DefaultFolder)
			FileOpenDialog\SetOkButtonLabel(@"Sélectionner")
			FileOpenDialog\GetOptions(@pfos)
			FileOpenDialog\SetOptions(pfos | #FOS_PICKFOLDERS | #FOS_FORCEFILESYSTEM | #FOS_PATHMUSTEXIST | #FOS_DONTADDTORECENT)
			FileOpenDialog\SetClientGuid(CreateGUID())
			
			If FileOpenDialog\Show(hWndWindow) = #S_OK
				FileOpenDialog\GetResult(@ShellItem)
				ShellItem\GetDisplayName(#SIGDN_FILESYSPATH, @ppszName)
				FolderName = PeekS(ppszName)
				CoTaskMemFree_(ppszName)
			EndIf
			FileOpenDialog\ClearClientData()
			FileOpenDialog\Release()
		EndIf
		CoUninitialize_()
	EndIf
	PathAddBackslash_(FolderName)
	ProcedureReturn FolderName
EndProcedure

;----example
;Define.s Dim AddPlace(2), FolderName
;AddPlace(0) = GetHomeDirectory()
;AddPlace(1) = GetTemporaryDirectory()
;FolderName = OpenFolderRequester("Open Folder Requester", GetHomeDirectory(), AddPlace())
;If FolderName : MessageRequester("Open Folder Requester", FolderName, #PB_MessageRequester_Info) : EndIf
The IFileDialogDef.pbi file :

Code: Select all

#CLSCTX_INPROC_SERVER = $1
#CLSCTX_INPROC_HANDLER = $2
#CLSCTX_LOCAL_SERVER = $4
#CLSCTX_INPROC_SERVER16 = $8
#CLSCTX_REMOTE_SERVER = $10
#CLSCTX_ALL = #CLSCTX_INPROC_SERVER | #CLSCTX_LOCAL_SERVER | #CLSCTX_REMOTE_SERVER
#CLSCTX_INPROC_HANDLER16 = $20
#CLSCTX_RESERVED1 = $40
#CLSCTX_RESERVED2 = $80
#CLSCTX_RESERVED3 = $100
#CLSCTX_RESERVED4 = $200
#CLSCTX_NO_CODE_DOWNLOAD = $400
#CLSCTX_RESERVED5 = $800
#CLSCTX_NO_CUSTOM_MARSHAL = $1000
#CLSCTX_ENABLE_CODE_DOWNLOAD = $2000
#CLSCTX_NO_FAILURE_LOG = $4000
#CLSCTX_DISABLE_AAA = $8000
#CLSCTX_ENABLE_AAA = $10000
#CLSCTX_FROM_DEFAULT_CONTEXT = $20000
#CLSCTX_ACTIVATE_X86_SERVER = $40000
#CLSCTX_ACTIVATE_32_BIT_SERVER = #CLSCTX_ACTIVATE_X86_SERVER
#CLSCTX_ACTIVATE_64_BIT_SERVER = $80000
#CLSCTX_ENABLE_CLOAKING = $100000
#CLSCTX_APPCONTAINER = $400000
#CLSCTX_ACTIVATE_AAA_AS_IU = $800000
#CLSCTX_RESERVED6 = $1000000
#CLSCTX_ACTIVATE_ARM32_SERVER = $2000000
#CLSCTX_PS_DLL = $80000000

#FOS_OVERWRITEPROMPT = $2
#FOS_STRICTFILETYPES = $4
#FOS_NOCHANGEDIR = $8
#FOS_PICKFOLDERS = $20
#FOS_FORCEFILESYSTEM = $40
#FOS_ALLNONSTORAGEITEMS = $80
#FOS_NOVALIDATE = $100
#FOS_ALLOWMULTISELECT = $200
#FOS_PATHMUSTEXIST = $800
#FOS_FILEMUSTEXIST = $1000
#FOS_CREATEPROMPT = $2000
#FOS_SHAREAWARE = $4000
#FOS_NOREADONLYRETURN = $8000
#FOS_NOTESTFILECREATE = $10000
#FOS_HIDEMRUPLACES = $20000
#FOS_HIDEPINNEDPLACES = $40000
#FOS_NODEREFERENCELINKS = $100000
#FOS_OKBUTTONNEEDSINTERACTION = $200000
#FOS_DONTADDTORECENT = $2000000
#FOS_FORCESHOWHIDDEN = $10000000
#FOS_DEFAULTNOMINIMODE = $20000000
#FOS_FORCEPREVIEWPANEON = $40000000
#FOS_SUPPORTSTREAMABLEITEMS = $FFFFFFFF80000000

#FDAP_BOTTOM = $0
#FDAP_TOP = $1

#SIGDN_NORMALDISPLAY = $0
#SIGDN_PARENTRELATIVEPARSING = $80018001
#SIGDN_DESKTOPABSOLUTEPARSING = $80028000
#SIGDN_PARENTRELATIVEEDITING = $80031001
#SIGDN_DESKTOPABSOLUTEEDITING = $8004c000
#SIGDN_FILESYSPATH = $80058000
#SIGDN_URL = $80068000
#SIGDN_PARENTRELATIVEFORADDRESSBAR = $8007c001
#SIGDN_PARENTRELATIVE = $80080001
#SIGDN_PARENTRELATIVEFORUI = $80094001

Interface IFileDialog Extends IModalWindow
  SetFileTypes(cFileTypes, *rgFilterSpec)
  SetFileTypeIndex(iFileType)
  GetFileTypeIndex(*piFileType)
  Advise(*pfde, *pdwCookie)
  Unadvise(dwCookie)
  SetOptions(fos)
  GetOptions(*pfos)
  SetDefaultFolder(*psi)
  SetFolder(*psi)
  GetFolder(*ppsi)
  GetCurrentSelection(*ppsi)
  SetFileName(*pszName)
  GetFileName(*pszName)
  SetTitle(*pszTitle)
  SetOkButtonLabel(*pszText)
  SetFileNameLabel(*pszLabel)
  GetResult(*ppsi)
  AddPlace(*psi, fdap)
  SetDefaultExtension(*pszDefaultExtension)
  Close(hr)
  SetClientGuid(guid)
  ClearClientData()
  SetFilter(*pFilter)
EndInterface

Interface IFileDialog2 Extends IFileDialog
  SetCancelButtonLabel(*pszLabel)
  SetNavigationRoot(*psi)
EndInterface

Interface IFileOpenDialog Extends IFileDialog
  GetResults(*ppenum)
  GetSelectedItems(*ppsai)
EndInterface

Interface IFileSaveDialog Extends IFileDialog
  ApplyProperties(*psi, *pStore, hwnd, *pSink)
  GetProperties(*ppStore)
  SetCollectedProperties(*pList, fAppendDefault)
  SetProperties(*pStore)
  SetSaveAsItem(*psi)
EndInterface

Interface IFileDialogCustomize Extends IUnknown
  EnableOpenDropDown(dwIDCtl)
  AddMenu(dwIDCtl, *pszLabel)
  AddPushButton(dwIDCtl, *pszLabel)
  AddComboBox(dwIDCtl)
  AddRadioButtonList(dwIDCtl)
  AddCheckButton(dwIDCtl, *pszLabel, bChecked)
  AddEditBox(dwIDCtl, *pszText)
  AddSeparator(dwIDCtl)
  AddText(dwIDCtl, *pszText)
  SetControlLabel(dwIDCtl, *pszLabel)
  GetControlState(dwIDCtl, *pdwState)
  SetControlState(dwIDCtl, dwState)
  GetEditBoxText(dwIDCtl, *ppszText)
  SetEditBoxText(dwIDCtl, *pszText)
  GetCheckButtonState(dwIDCtl, *pbChecked)
  SetCheckButtonState(dwIDCtl, bChecked)
  AddControlItem(dwIDCtl, dwIDItem, *pszLabel)
  RemoveControlItem(dwIDCtl, dwIDItem)
  RemoveAllControlItems(dwIDCtl)
  GetControlItemState(dwIDCtl, dwIDItem, *pdwState)
  SetControlItemState(dwIDCtl, dwIDItem, dwState)
  GetSelectedControlItem(dwIDCtl, *pdwIDItem)
  SetSelectedControlItem(dwIDCtl, dwIDItem)
  StartVisualGroup(dwIDCtl, *pszLabel)
  EndVisualGroup()
  MakeProminent(dwIDCtl)
  SetControlItemText(dwIDCtl, dwIDItem, *pszLabel)
EndInterface

Interface IFileDialogControlEvents Extends IUnknown
  OnItemSelected(*pfdc, dwIDCtl, dwIDItem)
  OnButtonClicked(*pfdc, dwIDCtl)
  OnCheckButtonToggled(*pfdc, dwIDCtl, bChecked)
  OnControlActivating(*pfdc, dwIDCtl)
EndInterface

Interface IFileDialogEvents Extends IUnknown
  OnFileOk(*pfd)
  OnFolderChanging(*pfd, *psiFolder)
  OnFolderChange(*pfd)
  OnSelectionChange(*pfd)
  OnShareViolation(*pfd, *psi, *pResponse)
  OnTypeChange(*pfd)
  OnOverwrite(*pfd, *psi, *pResponse)
EndInterface

Prototype protoSHCreateItemFromParsingName(*pszPath, *pbc, riid, *ppv)

Procedure CreateItemFromParsingName(FolderName.s)
  Protected SHCreateItemFromParsingName.protoSHCreateItemFromParsingName

  hResult = OleInitialize_(#Null)

  If hResult = #S_OK Or hResult = #S_FALSE
    shell32 = OpenLibrary(#PB_Any, "shell32.dll")

    If IsLibrary(shell32)
      SHCreateItemFromParsingName = GetFunction(shell32, "SHCreateItemFromParsingName")

      If SHCreateItemFromParsingName : SHCreateItemFromParsingName(@FolderName, #Null, ?IID_IShellItem, @ShellItem.IShellItem) : EndIf

      CloseLibrary(shell32)
    EndIf
    OleUninitialize_()
  EndIf
  ProcedureReturn ShellItem
EndProcedure

Procedure CreateGUID()
  guid.GUID : CoCreateGuid_(@guid) : ProcedureReturn guid
EndProcedure

DataSection
  CLSID_IFileOpenDialog:
    Data.l $DC1C5A9C
    Data.w $E88A, $4DDE
    Data.b $A5, $A1, $60, $F8, $2A, $20, $AE, $F7
  CLSID_FileSaveDialog:
    Data.l $C0B4E2F3
    Data.w $BA21, $4773
    Data.b $8D, $BA, $33, $5E, $C9, $46, $EB, $8B
  IID_IFileDialog:
    Data.l $42F85136
    Data.w $DB7E, $439C
    Data.b $85, $F1, $E4, $07, $5D, $13, $5F, $C8
  IID_IFileDialog2:
    Data.l $61744FC7
    Data.w $85B5, $4791
    Data.b $A9, $B0, $27, $22, $76, $30, $9B, $13
  IID_IFileOpenDialog:
    Data.l $D57C7288
    Data.w $D4AD, $4768
    Data.b $BE, $02, $9D, $96, $95, $32, $D9, $60
  IID_IFileSaveDialog:
    Data.l $84bCCD23
    Data.w $5FDE, $4CDB
    Data.b $AE, $A4, $AF, $64, $B8, $3D, $78, $AB
  IID_IFileDialogCustomize:
    Data.l $E6FDD21A
    Data.w $163F, $4975
    Data.b $9C, $8C, $A6, $9F, $1B, $A3, $70, $34
  IID_IFileDialogControlEvents:
    Data.l $36116642
    Data.w $D713, $4B97
    Data.b $9B, $83, $74, $84, $A9, $D0, $04, $33
  IID_IFileDialogEvents:
    Data.l $973510DB
    Data.w $7D7F, $452B
    Data.b $89, $75, $74, $A8, $58, $28, $D3, $54
  IID_IShellItem:
    Data.l $43826D1E
    Data.w $E718, $42EE
    Data.b $BC, $55, $A1, $E2, $61, $C3, $7B, $FE
EndDataSection
Last edited by tatanas on Fri Jun 03, 2022 12:49 pm, edited 2 times in total.
Windows 10 Pro x64
PureBasic 6.04 x64
Denis
Enthusiast
Enthusiast
Posts: 704
Joined: Fri Apr 25, 2003 5:10 pm
Location: Doubs - France

Re: Select folder dialog

Post by Denis »

Hi tatanas

Thanks for the link, the code runs well under Win 10 x64.
Corresponds to my need :D
A+
Denis
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: Select folder dialog

Post by tatanas »

You're welcome :)
I knew this code would interest someone.
Windows 10 Pro x64
PureBasic 6.04 x64
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5357
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Select folder dialog

Post by Kwai chang caine »

Very usefull code, a selecter like in the majority of others big softwares :D
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5357
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Select folder dialog

Post by Kwai chang caine »

I knew a day, i need this splendid code 8)
After 3 years, someone know if it's possible to ask to PathRequester to expand the tree in the left side until the defauult path for example "C:\Users\Public\" ?
For the moment the explorer at right go to the folder "C:\Users\Public\"
But the tree at left is collapsed :|
ImageThe happiness is a road...
Not a destination
Quin
Enthusiast
Enthusiast
Posts: 332
Joined: Thu Mar 31, 2022 7:03 pm
Location: United States
Contact:

Re: Select folder dialog

Post by Quin »

When trying to use this code on Windows 11 ARM (21H2), the dialog doesn't show at all, and always returns 0. Has anyone else seen this?
PB v5.40/6.10, Windows 10 64-bit.
16-core AMD Ryzen 9 5950X, 128 GB DDR5.
Post Reply