How can the GetOpenFileName API be used to select a folder? I can only seem to get the function to select a file. Thank for any information.
You can use the OFN_NOVALIDATE flag, and type * instead of a file name. Then look for the rightmost backslash.
Otherwise, use ShBrowseForFolder.
I found this that might be helpful.
http://www.codeproject.com/Articles/5063/XBrowseForFolder-Wrapper-for-SHBrowseForFolder
Here is a full example in plain Masm32.
include \masm32\include\masm32rt.inc
.data?
buffer db MAX_PATH dup(?)
.code
Browse4Folder proc pCaption
LOCAL bInfo:BROWSEINFO, initialPath[MAX_PATH]:BYTE
mov eax, ebp
.Repeat
sub eax, 4
and dword ptr [eax], 0 ; clear the locals
.Until eax<=esp
push esi
push edi
mov edi, offset buffer
mov bInfo.pszDisplayName, edi
m2m bInfo.lpszTitle, pCaption
mov bInfo.lpfn, cbSHB ; callback, credits to Tedd (http://masm32.com/board/index.php?topic=623.msg5112#msg5112)
lea esi, initialPath
mov bInfo.lParam, esi
invoke GetCurrentDirectory, MAX_PATH, esi
invoke SHBrowseForFolder, addr bInfo
.if eax
invoke SHGetPathFromIDList, eax, edi
xchg eax, edi
.endif
pop edi
pop esi
ret
Browse4Folder endp
cbSHB proc hwnd:HWND, uMsg:UINT, lParam:LPARAM, lpData:LPARAM
.if uMsg==BFFM_INITIALIZED
invoke SendMessage, hwnd, BFFM_SETSELECTION, TRUE, lpData
.endif
ret
cbSHB endp
start:
invoke Browse4Folder, chr$("Select a folder")
.if eax
MsgBox 0, eax, "Selected folder:", MB_OK
.else
MsgBox 0, "You cancelled", "Selected folder:", MB_OK
.endif
exit
end start
EDIT: Version 2 attached - the clear locals loop was one off.
Quote from: cman on December 28, 2012, 10:33:12 AM
How can the GetOpenFileName API be used to select a folder? I can only seem to get the function to select a file. Thank for any information.
It's only meant for selection files (the hint is in the name :P).
ShBrowseForFolder is for selecting folders (see JJ's example.)
i am a little bit confused (again)
in the documentation for SHBrowseForFolder...
QuoteYou must initialize Component Object Model (COM) before you call SHBrowseForFolder. If you initialize COM using CoInitializeEx, you must set the COINIT_APARTMENTTHREADED flag in its dwCoInit parameter. You can also use CoInitialize or OleInitialize, which always use apartment threading. If you require drag-and-drop functionality, OleInitialize is recommended because it initializes the required OLE as well as COM.
Note If COM is initialized using CoInitializeEx with the COINIT_MULTITHREADED flag, SHBrowseForFolder fails if the calling application uses the BIF_USENEWUI or BIF_NEWDIALOGSTYLE flag in the BROWSEINFO structure.
yet, neither Jochen's nor Tedd's example initialize COM - and they work :redface:
Tedd's original example from the other thread does use CoTaskMemFree
after the SHGetPathFromIDList call, provided SHBrowseForFolder was successful
Jochen's example does not do this
http://masm32.com/board/index.php?topic=623.msg5112#msg5112 (http://masm32.com/board/index.php?topic=623.msg5112#msg5112)
It's only necessary to call CoInitialize when you call COM methods from your code. The SHBrowseForFolder function does, but it calls CoInitialize itself, regardless of whether you have previously.
And yes, you should do CoTaskMemFree afterward.
But isn't that a COM function and would then require CoInitialize?
Good question! Yes... but not really :biggrin:
CoInitialize actually only needs to be called once within a thread, any further calls effectively do nothing (though CoInitializeEx does, if you change the concurrency mode.) It's also not necessary if you're only using the memory allocation functions - which we are in this case.
QuoteIt's also not necessary if you're only using the memory allocation functions - which we are in this case.
thanks Tedd - that explains a lot :t
i may play with the OleInitialize and see if drag and drop is worthwhile :P
Quote from: dedndave on December 29, 2012, 04:15:48 AM
yet, neither Jochen's nor Tedd's example initialize COM - and they work :redface:
Mysteries of Windows :P
Wine: (http://wine.1045685.n5.nabble.com/Ok-to-call-CoInitialize-in-the-file-dialogs-td1794274.html)... browse into shell instance objects on winxp, but the call to GetDisplayNameOf fails with CO_E_NOTINITIALIZED. This means COM is initialized inside SHBrowseForFolder, but un-initialized after the call returns.
not a mystery of windows as much as a mystery in the documentation
i am not complaining, really - lol
with thousands of functions, structures, and constants to document, it's a pretty big job
almost as big as writing the OS