News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

GetOpenFileName

Started by cman, December 28, 2012, 10:33:12 AM

Previous topic - Next topic

cman

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.

jj2007

You can use the OFN_NOVALIDATE flag, and type * instead of a file name. Then look for the rightmost backslash.

Otherwise, use ShBrowseForFolder.

Magnum

I found this that might be helpful.

http://www.codeproject.com/Articles/5063/XBrowseForFolder-Wrapper-for-SHBrowseForFolder
Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

jj2007

#3
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
  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.

Tedd

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.)
Potato2

dedndave

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

Tedd

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.
Potato2

dedndave

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

jj2007

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:... 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.

dedndave

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