Page 1 of 1

Select folder dialog

Posted: Thu Jan 09, 2020 4:18 pm
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

Re: Select folder dialog

Posted: Fri Jan 10, 2020 10:08 am
by Denis
Hi tatanas

Thanks for the link, the code runs well under Win 10 x64.
Corresponds to my need :D

Re: Select folder dialog

Posted: Fri Jan 10, 2020 12:43 pm
by tatanas
You're welcome :)
I knew this code would interest someone.

Re: Select folder dialog

Posted: Fri Jan 10, 2020 3:07 pm
by Kwai chang caine
Very usefull code, a selecter like in the majority of others big softwares :D
Thanks for sharing 8)

Re: Select folder dialog

Posted: Fri Aug 18, 2023 7:22 pm
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 :|

Re: Select folder dialog

Posted: Wed Mar 13, 2024 2:02 pm
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?

Re: Select folder dialog

Posted: Tue May 14, 2024 1:45 pm
by tatanas
Quin,
Try using this call (without the array variable):

Code: Select all

OpenFolderRequester("Open Folder Requester", GetHomeDirectory())
Kwain chang caine,
It seems we have to use the NameSpaceTreeControl interface for interacting with the tree control.
Unfortunatly for now it doesnt work. Here is the interface declaration :

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


#NSTCIS_NONE = $0
#NSTCIS_SELECTED = $1
#NSTCIS_EXPANDED = $2
#NSTCIS_BOLD = $4
#NSTCIS_DISABLED = $8
#NSTCIS_SELECTEDNOEXPAND = $10

#NSTCS_HASEXPANDOS = $1
#NSTCS_HASLINES = $2
#NSTCS_SINGLECLICKEXPAND = $4
#NSTCS_FULLROWSELECT = $8
#NSTCS_SPRINGEXPAND = $10
#NSTCS_HORIZONTALSCROLL = $20
#NSTCS_ROOTHASEXPANDO = $40
#NSTCS_SHOWSELECTIONALWAYS = $80
#NSTCS_NOINFOTIP = $200
#NSTCS_EVENHEIGHT = $400
#NSTCS_NOREPLACEOPEN = $800
#NSTCS_DISABLEDRAGDROP = $1000
#NSTCS_NOORDERSTREAM = $2000
#NSTCS_RICHTOOLTIP = $4000
#NSTCS_BORDER = $8000
#NSTCS_NOEDITLABELS = $10000
#NSTCS_TABSTOP = $20000
#NSTCS_FAVORITESMODE = $80000
#NSTCS_AUTOHSCROLL = $100000
#NSTCS_FADEINOUTEXPANDOS = $200000
#NSTCS_EMPTYTEXT = $400000
#NSTCS_CHECKBOXES = $800000
#NSTCS_PARTIALCHECKBOXES = $1000000
#NSTCS_EXCLUSIONCHECKBOXES = $2000000
#NSTCS_DIMMEDCHECKBOXES = $4000000
#NSTCS_NOINDENTCHECKS = $8000000
#NSTCS_ALLOWJUNCTIONS = $10000000
#NSTCS_SHOWTABSBUTTON = $20000000
#NSTCS_SHOWDELETEBUTTON = $40000000
#NSTCS_SHOWREFRESHBUTTON = $80000000

#NSTCS2_DEFAULT = $0
#NSTCS2_INTERRUPTNOTIFICATIONS = $1
#NSTCS2_SHOWNULLSPACEMENU = $2
#NSTCS2_DISPLAYPADDING = $4
#NSTCS2_DISPLAYPINNEDONLY = $8
#NTSCS2_NOSINGLETONAUTOEXPAND = $10
#NTSCS2_NEVERINSERTNONENUMERATED = $20


Interface INameSpaceTreeControl Extends IUnknown
	AppendRoot(*psiRoot, grfEnumFlags, grfRootStyle, *pif)
	CollapseAll()
	EnsureItemVisible(*psi)
	GetItemCustomState(*psi, *piStateNumber)
	GetItemRect(*psi, *prect)
	GetItemState(*psi, nstcisMask, *pnstcisFlags)
	GetNextItem(*psi, nstcgi, *ppsiNext)
	GetRootItems(*ppsiaRootItems)
	GetSelectedItems(*psiaItems)
	HitTest(*ppt, *ppsiOut)
	Initialize(hwndParent, *prc, nsctsFlags)
	InsertRoot(iIndex, *psiRoot, grfEnumFlags, grfRootStyle, *pif)
	RemoveAllRoots()
	RemoveRoot(*psiRoot)
	SetItemCustomState(*psi, iStateNumber)
	SetItemState(*psi, nstcisMask, nstcisFlags)
	SetTheme(*pszTheme)
	TreeAdvise(*punk, *pdwCookie)
	TreeUnadvise(dwCookie)
EndInterface

Interface INameSpaceTreeControl2 Extends INameSpaceTreeControl
	GetControlStyle(nstcsMask, *pnstcsStyle)
	SetControlStyle(nstcsMask, nstcsStyle)
	GetControlStyle2(nstcsMask, *pnstcsStyle)
	SetControlStyle2(nstcsMask, nstcsStyle)
EndInterface

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_NameSpaceTreeControl: ; "{AE054212-3535-4430-83ED-D501AA6680E6}"
    Data.l $AE054212
    Data.w $3535, $4430
    Data.b $83, $ED, $D5, $01, $AA, $66, $80, $E6
  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_INameSpaceTreeControl: ; "{028212A3-B627-47e9-8856-C14265554E4F}"
    Data.l $028212A3
    Data.w $B627, $47e9
    Data.b $88, $56, $C1, $42, $65, $55, $4E, $4F
  IID_INameSpaceTreeControl2: ; "7cc7aed8-290e-49bc-8945-c1401cc9306c"
    Data.l $7CC7AED8
    Data.w $290E, $49BC
    Data.b $89, $45, $C1, $40, $1C, $C9, $30, $6C
  IID_IFileDialog: ; "{42f85136-db7e-439c-85f1-e4075d135fc8}"
    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
And an example from Microsoft : https://github.com/microsoft/Windows-cl ... Sample.cpp

Re: Select folder dialog

Posted: Wed May 15, 2024 3:35 pm
by tatanas
Actually, we don't need the NameSpaceTreeControl interface to interact with the treeview.

Not very clean but it works :

Code: Select all

IncludeFile "IFileDialogDef.pbi"



; https://www.purebasic.fr/english/viewtopic.php?t=20397
; https://www.autohotkey.com/boards/viewtopic.php?t=108274

Global hTreeView, ProcID
Global path.s = "C:\Windows"
Global title.s = "Open Folder Requester"

Procedure EnumCallback(hWnd, Value)
	ClassName$ = Space(64)
	GetClassName_(hWnd, @ClassName$, 64)
	If ClassName$ = "SysTreeView32"
		hTreeView = hWnd
		ProcedureReturn #False
	EndIf
	ProcedureReturn #True
EndProcedure

Procedure GetItemID(Gadget, Item)
	Protected hItem, hItem2
	hItem = SendMessage_(Gadget, #TVM_GETNEXTITEM, #TVGN_ROOT, 0)
	For i = 0 To Item - 1
		hItem2 = SendMessage_(Gadget, #TVM_GETNEXTITEM, #TVGN_CHILD, hItem)
		Repeat
			If hItem2 = #Null : hItem2 = SendMessage_(Gadget, #TVM_GETNEXTITEM, #TVGN_NEXT, hItem) : EndIf
			If hItem2 = #Null : hItem = SendMessage_(Gadget, #TVM_GETNEXTITEM, #TVGN_PARENT, hItem) : EndIf
		Until hItem2 <> #Null
		hItem = hItem2
	Next
	ProcedureReturn hItem
EndProcedure

Procedure ExpandTreeView(*value)

	count = CountString(path, "\") + 1
	NewList pathpart.s()
	For i = 1 To count
		AddElement(pathpart())
		pathpart() = StringField(path, i, "\")
	Next
	
	Repeat
		hWin = FindWindow_(0, title)
		Delay(500)
	Until hWin

	GetWindowThreadProcessId_(hWin, @ProcID)
	EnumChildWindows_(hWin, @EnumCallback(), 0)
	
	Buffer = AllocateMemory(100)
	hProc = OpenProcess_(#PROCESS_VM_OPERATION | #PROCESS_VM_READ | #PROCESS_VM_WRITE, 0, ProcID)
	Result = VirtualAllocEx_(hProc, 0, SizeOf(TV_ITEM), #MEM_RESERVE | #MEM_COMMIT, #PAGE_READWRITE)
	
	Define TVItem.TV_ITEM
	TVItem\mask = #TVIF_TEXT | #TVIF_HANDLE
	TVItem\pszText = Result + 400
	TVItem\cchTextMax = 100
	
	If hTreeView
		For i = 0 To SendMessage_(hTreeView, #TVM_GETCOUNT, 0, 0) - 1
	
			TVItem\hItem = GetItemID(hTreeView, i)
			
			WriteProcessMemory_(hProc, Result, @TVItem, SizeOf(TV_ITEM), 0)
			SendMessage_(hTreeView, #TVM_GETITEM, 0, Result)
			ReadProcessMemory_(hProc, Result + 400, Buffer, MemorySize(Buffer), 0)
	; 		Debug PeekS(Buffer)
	
			ForEach pathpart()
				If FindString(PeekS(Buffer), pathpart())
					SendMessage_(hTreeView, #TVM_EXPAND, #TVE_EXPAND, TVItem\hItem)
					DeleteElement(pathpart(), 1)
					Break
				EndIf
			Next
		Next
	EndIf
	
	VirtualFreeEx_(hProc, Result, 0, #MEM_RELEASE)
	CloseHandle_(hProc)

EndProcedure


; 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)
	Protected FolderName.s
	
	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

CreateThread(@ExpandTreeView(), 0)

Define FolderName.s
FolderName = OpenFolderRequester(title, path)

If FolderName
	MessageRequester("Open Folder Requester", FolderName, #PB_MessageRequester_Info)
EndIf

Re: Select folder dialog

Posted: Thu May 01, 2025 9:31 am
by Wolfram
How can I use the SetCancelButtonLabel() Methode?

Re: Select folder dialog

Posted: Fri May 16, 2025 9:10 am
by tatanas
Sorry it seems there is no SetCancelButtonLabel() Method, or I can't find it.
https://learn.microsoft.com/en-us/windo ... uttonlabel