Author Topic: GetOpenFileName  (Read 9050 times)

cman

  • Member
  • **
  • Posts: 223
GetOpenFileName
« 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.

jj2007

  • Member
  • *****
  • Posts: 13002
  • Assembler is fun ;-)
    • MasmBasic
Re: GetOpenFileName
« Reply #1 on: December 28, 2012, 10:58:18 AM »
You can use the OFN_NOVALIDATE flag, and type * instead of a file name. Then look for the rightmost backslash.

Otherwise, use ShBrowseForFolder.

Magnum

  • Member
  • *****
  • Posts: 2367
Re: GetOpenFileName
« Reply #2 on: December 28, 2012, 11:12:53 AM »
Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

jj2007

  • Member
  • *****
  • Posts: 13002
  • Assembler is fun ;-)
    • MasmBasic
Re: GetOpenFileName
« Reply #3 on: December 28, 2012, 09:37:17 PM »
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.
« Last Edit: December 29, 2012, 01:51:23 AM by jj2007 »

Tedd

  • Member
  • ***
  • Posts: 377
  • Procrastinor Extraordinaire
Re: GetOpenFileName
« Reply #4 on: December 29, 2012, 03:22:50 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

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: GetOpenFileName
« Reply #5 on: December 29, 2012, 04:15:48 AM »
i am a little bit confused (again)

in the documentation for SHBrowseForFolder...
Quote
You 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

  • Member
  • ***
  • Posts: 377
  • Procrastinor Extraordinaire
Re: GetOpenFileName
« Reply #6 on: December 29, 2012, 04:53:19 AM »
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

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: GetOpenFileName
« Reply #7 on: December 29, 2012, 04:55:48 AM »
Quote
It'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

  • Member
  • *****
  • Posts: 13002
  • Assembler is fun ;-)
    • MasmBasic
Re: GetOpenFileName
« Reply #8 on: December 29, 2012, 04:56:40 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

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: GetOpenFileName
« Reply #9 on: December 29, 2012, 05:00:09 AM »
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