Windows API: Open Dialog to Browse for a File

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Windows API: Open Dialog to Browse for a File

Postby KristopherWindsor » Mar 20, 2008 9:12

I didn't write this, but I figured it should be in the Tips and Tricks section. ;-)

See also:
-> Run Open File Dialog Box on Load

Code: Select all

#define WIN_INCLUDEALL
#include once "windows.bi"

Function filebrowser (Byref ititle As String, Byref idir As String = Curdir) As String
  Dim ofn As OPENFILENAME
  Dim filename As Zstring * (MAX_PATH + 1)
  Dim title As Zstring * 32 => ititle
  Dim initialdir As Zstring * 256 => idir
 
  With ofn
    .lStructSize       = Sizeof(OPENFILENAME)
    .hwndOwner         = NULL
    .hInstance         = GetModuleHandle(NULL)
                        '"All Files, (*.*)"
                        '"*.*"
                        '"Bas Files, (*.BAS)"
                        '"*.bas"
    .lpstrFilter       = Strptr(!"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0\0")
    .lpstrCustomFilter = NULL
    .nMaxCustFilter    = 0
    .nFilterIndex      = 1
    .lpstrFile         = @filename
    .nMaxFile          = Sizeof(filename)
    .lpstrFileTitle    = NULL
    .nMaxFileTitle     = 0
    .lpstrInitialDir   = @initialdir
    .lpstrTitle        = @title
    .Flags             = OFN_EXPLORER Or OFN_FILEMUSTEXIST Or OFN_PATHMUSTEXIST
    .nFileOffset       = 0
    .nFileExtension    = 0
    .lpstrDefExt       = NULL
    .lCustData         = 0
    .lpfnHook          = NULL
    .lpTemplateName    = NULL
  End With

  If (GetOpenFileName(@ofn) = FALSE) Then Return ""
  Return filename
End Function

Print filebrowser("Find a source code file...", "C:\Program Files")
Sleep


Tags: kristopherwindsor_program_trick
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Apr 19, 2008 18:10

Thanks for the Open File Dialog Box tip. I'm quite experienced with QB45, new to Freebasic, and a total newbie for Win API calls. I tried to modify your code to pass the argument for

.lpstrFilter = Strptr(!"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0Dat Files, (*.DAT)\0*.dat\0\0")

as a string passed to Function Filebrowser, so the calling program could specify which type of files to list. No problem passing the string, but I couldn't get it to work. Can you help?

Second, it would be great if there were a way to force the Open File Dialog Box to be on top of all other open windows (especially the working screen page for FB.

Thanks.
calstover
Posts: 68
Joined: Aug 21, 2006 16:51

Postby calstover » Apr 19, 2008 18:57

Code: Select all

sTF = !"Text Files (*.txt)\0*.txt\0" _
    + !"Data Files (*.mdb)\0*.mdb\0"


using StrPtr(sTF) will append another chr(0)
Mysoft
Posts: 779
Joined: Jul 28, 2005 13:56
Location: Brazil, Santa Catarina, Indaial (ouch!)
Contact:

Postby Mysoft » Apr 19, 2008 19:38

hum... i have a example for each of the "common" windows dialog... may i need to post them to add more to this?
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Postby Zippy » Apr 19, 2008 20:01

BasicScience wrote:<snip>
Second, it would be great if there were a way to force the Open File Dialog Box to be on top of all other open windows (especially the working screen page for FB.



Try:

Code: Select all

'FileDialog TOPMOST, Windows only
' alternately may hide gfx window
' compile -s gui
'
#include once "windows.bi"
#include once "win\commdlg.bi"
#include once "fbgfx.bi"
    using fb
'
'pass (1) to hide the gfx window while file dialog is open
declare Function file_getname(hide_hwnd as integer=0) As String
'
dim ret as string

'
screen 18 'MUST have gfx window for this to work
print "Press a key to open file dialog"
sleep
'
'passing (1) to hide gfx window..
ret=file_getname(1)
'
print
print "FileDialog returned: ";ret
print
print "Sleeping to Exit.."
sleep
end

Function file_getname(hide_hwnd as integer) As String
'
    Dim ofn As OPENFILENAME
    Dim filename As Zstring * MAX_PATH+1
    dim as HWND hwnd
    '
    ScreenControl GET_WINDOW_HANDLE,cast(integer,hwnd)
    SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE)
    '
    if hide_hwnd=1 then ShowWindow(hwnd,SW_HIDE)
    '       
    With ofn
            .lStructSize       = sizeof( OPENFILENAME )
            .hwndOwner         = hwnd
            .hInstance         = GetModuleHandle( NULL )
            .lpstrFilter       = Strptr( !"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0\0" )
            .lpstrCustomFilter = NULL
            .nMaxCustFilter    = 0
            .nFilterIndex      = 1
            .lpstrFile         = @filename
            .nMaxFile          = sizeof( filename )
            .lpstrFileTitle    = NULL
            .nMaxFileTitle     = 0
            .lpstrInitialDir   = NULL
            .lpstrTitle        = @"File Open Test"
            .Flags             = OFN_EXPLORER Or OFN_FILEMUSTEXIST Or OFN_PATHMUSTEXIST
            .nFileOffset       = 0
            .nFileExtension    = 0
            .lpstrDefExt       = NULL
            .lCustData         = 0
            .lpfnHook          = NULL
            .lpTemplateName    = NULL
    End With
    '       
    If( GetOpenFileName( @ofn ) = FALSE ) Then filename=""
    '   
    SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE)
    if hide_hwnd=1 then ShowWindow(hwnd,SW_SHOW)
    '
    return filename
'
End Function

I posted, somewhere around here, a UNICODE-friendly file dialog.

@MySoft

It wouldn't hurt to post them in one place. I believe a print dialog example is about. MichaelW has posted one or more. Many things buried in the Windows forum, which I expect is why Kris decided to dig up the file dialog.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Apr 19, 2008 20:21

Zippy wrote:Many things buried in the Windows forum, which I expect is why Kris decided to dig up the file dialog.


Yes.
Several codes have been posted to answer questions, instead of being put in the Tips & Tricks section, and it is hard to find these with the forum search.
Also, sometimes the code is not put in a function with example usage, so it is harder to use.
;-) :-P

BTW, my tagging system doesn't work because of limits to the forum search feature. -(o.O);
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Apr 19, 2008 20:55

Thanks Zippy. Your code did the trick with TopMost.
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Apr 19, 2008 21:21

Calstover.....

Tried your suggestion, but the Open File Dialog Box only listed the first file_type option in the drop down menu (i.e only *.TXT), and even worse, the folder listing was for all file types (*.*), not just *.TXT.

Here's a partial listing of the modifications I tried.

(PARTIAL CODE)


dim sTF as string
sTF = !"Text Files (*.txt)\0*.txt\0" + !"Data Files (*.dat)\0*.dat\0"

With ofn
.lStructSize = Sizeof(OPENFILENAME)
.hwndOwner = NULL
.hInstance = GetModuleHandle(NULL)
'.lpstrFilter = Strptr(!"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0Dat Files, (*.DAT)\0*.dat\0\0")
.lpstrFilter = Strptr(sTF)
.lpstrCustomFilter = NULL

MORE STUFF HERE TO FOLLOW...
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Apr 19, 2008 21:39

I'm going to guess something is wrong...

Code: Select all

Dim As String * 32 s = !"123\0456\0789"
For i As Integer = 0 To 30
  Print Chr(s[i]);
Next i
Sleep
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Apr 19, 2008 21:43

Yup. Output is

123-N

then a bunch of spaces and an extended character (a with diacritical mark).

So... the null character termination is working ???
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Postby Zippy » Apr 19, 2008 22:07

Rather than fuss with trying to pass strings containing nulls (a contradiction), I would instead pass a parameter to spec which filter I wanted to use, and hardcode the filterZ in the dialog function.

Try:

Code: Select all

'FileDialog TOPMOST, Windows only
' alternately may hide gfx window
' compile -s gui
'
#include once "windows.bi"
#include once "win\commdlg.bi"
#include once "fbgfx.bi"
    using fb
'
'pass (1) to hide the gfx window while file dialog is open
declare Function file_getname(hide_hwnd as integer=0,MyFilter as integer=0) As String
'
dim ret as string

'
screen 18 'MUST have gfx window for this to work
print "Press a key to open file dialog"
sleep
'
'passing (1) to hide gfx window..
ret=file_getname(1,1)
'
print
print "FileDialog returned: ";ret
print
print "Sleeping to Exit.."
sleep
end

Function file_getname(hide_hwnd as integer,MyFilter as integer=0) As String
'
    Dim ofn As OPENFILENAME
    Dim filename As Zstring * MAX_PATH+1
    dim as HWND hwnd
    '
    ScreenControl GET_WINDOW_HANDLE,cast(integer,hwnd)
    SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE)
    '
    if hide_hwnd=1 then ShowWindow(hwnd,SW_HIDE)
    '
    select case MyFilter
        case 0 'default
            ofn.lpstrFilter=Strptr( !"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0\0" )
        case 1
            ofn.lpstrFilter=strptr(!"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0Dat Files, (*.DAT)\0*.dat\0\0")
        case else 'default again..
            ofn.lpstrFilter=Strptr( !"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0\0" )
    end select
    '       
    With ofn
            .lStructSize       = sizeof( OPENFILENAME )
            .hwndOwner         = hwnd
            .hInstance         = GetModuleHandle( NULL )
'            .lpstrFilter       = Strptr( !"All Files, (*.*)\0*.*\0Bas Files, (*.BAS)\0*.bas\0\0" )
            .lpstrCustomFilter = NULL
            .nMaxCustFilter    = 0
            .nFilterIndex      = 1
            .lpstrFile         = @filename
            .nMaxFile          = sizeof( filename )
            .lpstrFileTitle    = NULL
            .nMaxFileTitle     = 0
            .lpstrInitialDir   = NULL
            .lpstrTitle        = @"File Open Test"
            .Flags             = OFN_EXPLORER Or OFN_FILEMUSTEXIST Or OFN_PATHMUSTEXIST
            .nFileOffset       = 0
            .nFileExtension    = 0
            .lpstrDefExt       = NULL
            .lCustData         = 0
            .lpfnHook          = NULL
            .lpTemplateName    = NULL
    End With
    '       
    If( GetOpenFileName( @ofn ) = FALSE ) Then filename=""
    '   
    SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE)
    if hide_hwnd=1 then ShowWindow(hwnd,SW_SHOW)
    '
    return filename
'
End Function
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Postby Zippy » Apr 19, 2008 23:38

KristopherWindsor wrote:<snip>
BTW, my tagging system doesn't work because of limits to the forum search feature. -(o.O);

I cringe every time someone "suggests" that the forum search function be used to answer a question. Let them use Google, I say.

Searching for Tags: with your author name works.

You can't use underscores in your keywords/keyphrases. Use a sacrificial char, say, "Z", instead. Let's try

KristopherwindsorZprogramZtrick

but wait 24 hours until the indices are updated?
spodhaje
Posts: 38
Joined: Oct 25, 2007 14:05

Postby spodhaje » Apr 21, 2008 22:00

Try this, it's a mashup of a bunch of different code

Code: Select all

#Include Once "crt.bi"
#Include Once "windows.bi"
#Include Once "win/commdlg.bi"
#include Once "win/shlobj.bi"
#Ifndef _FILE_HELPERS_WIN32
#Define _FILE_HELPERS_WIN32

#Define FileOpenDialog(a,b,c,d,e) FileOpenSaveDialog(0,(a),(b),(c),(d),(e))
#Define FileSaveDialog(a,b,c,d,e) FileOpenSaveDialog(1,(a),(b),(c),(d),(e))

Dim Shared as Integer OFS_FILE_OPEN_FLAGS = OFN_EXPLORER _
Or OFN_LONGNAMES _
Or OFN_CREATEPROMPT _
Or OFN_NODEREFERENCELINKS

Dim Shared As Integer OFS_FILE_SAVE_FLAGS = OFN_EXPLORER _
Or OFN_LONGNAMES _
Or OFN_OVERWRITEPROMPT _
Or OFN_HIDEREADONLY

Declare Function FileOpenSaveDialog(iMode As Integer,ByVal szTitle As ZString Ptr , ByVal szInitialDir As ZString Ptr, ByVal _szFilter As ZString Ptr, ByVal iFlags As Dword, ByVal szName As ZString Ptr) as String
Declare Function FileSelectFolder_callback (Byval hwndbrowse As HWND, Byval uMsg As UINT, Byval lp As LPARAM, Byval lpData As LPARAM) As Integer
Declare Function FileSelectFolder (Byref title As String = "Choose A Folder",ByVal nCSIDL As Integer, ulFlags As ULong =BIF_NEWDIALOGSTYLE, ByRef sz_InitialDir As String) As String

Type FOLDER_PROPS
   Dim lpszTitle As ZString Ptr
   Dim lpszInitialFolder As ZString Ptr
   Dim As UInteger ulFlags
End Type
Function FileOpenSaveDialog(iMode as Integer, ByVal szTitle As ZString Ptr , ByVal szInitialDir As ZString Ptr, ByVal _szFilter As ZString Ptr, ByVal iFlags As Dword, ByVal szName As ZString Ptr) as String
   Dim ofn As OPENFILENAME
   Dim buff As ZString*260
   Dim sz_Filter as ZString Ptr
   Dim iIndex As UInteger
   ofn.lStructSize=SizeOf(OPENFILENAME)
   ofn.hwndOwner=NULL
   ofn.hInstance=GetModuleHandle(NULL)
   ofn.lpstrInitialDir= szInitialDir
   buff=String(260,0)
   If szName Then
       StrCpy(buff,szName)
   EndIf
   ofn.lpstrFile=@buff
   ofn.nMaxFile=260
    sz_Filter = malloc(StrLen(_szFilter)+2)
    StrCpy(sz_Filter,_szFilter)
    sz_Filter[StrLen(sz_Filter)+1] = 0
    For iIndex = 0 To StrLen(sz_Filter) - 1
      If sz_Filter[iIndex] = Asc("|") Then sz_Filter[iIndex] = 0
    Next iIndex
      ofn.lpstrFilter = sz_Filter
   ofn.lpstrTitle = szTitle
   If iFlags = 0 Then
       ofn.Flags = iFlags
   EndIf
   If iMode = 0 Then
       If GetOpenFileName(@ofn) Then Function =  buff
   Else
       If GetSaveFileName(@ofn) Then Function =  buff
   EndIf
   free(sz_Filter)
End Function

Function FileSelectFolder_callback (Byval hwndbrowse As HWND, Byval uMsg As UINT, _
  Byval lp As LPARAM, Byval lpData As LPARAM) As Integer
    If uMsg = BFFM_INITIALIZED Then
            Dim fp As FOLDER_PROPS Ptr
            fp = Cast(FOLDER_PROPS Ptr, lpData)
         if fp Then
             if (*fp).lpszInitialFolder Then
                 If (*fp).lpszInitialFolder[0] <> 0   Then
                ' set initial directory
                   SendMessage(hwndbrowse, BFFM_SETSELECTION, TRUE, Cast(LPARAM,fp->lpszInitialFolder))
                endif
             EndIf
             if fp->lpszTitle Then
                 If (fp->lpszTitle[0] <>0) Then
                '   // set window caption
                   SetWindowText(hwndbrowse, fp->lpszTitle)
                endif
             EndIf
            EndIf
   
        EndIf
    Return 0
End Function

Function FileSelectFolder (Byref title As String = "Choose A Folder", ByVal nCSIDL As Integer, iFlags As ULong = BIF_EDITBOX, ByRef sz_InitialDir As String) As String
  Dim bi As BROWSEINFO
  Dim pidl As LPITEMIDLIST
  Dim ret As HRESULT
  Dim physpath As Zstring * MAX_PATH
  Dim dispname As Zstring * MAX_PATH
  Dim fp As FOLDER_PROPS
  bi.hwndOwner = HWND_DESKTOP
  If nCSIDL Then
    ret = SHGetSpecialFolderLocation(HWND_DESKTOP, nCSIDL, @bi.pidlRoot)
    'ret = SHGetFolderLocation(HWND_DESKTOP, nCSIDL, NULL, NULL, @bi.pidlRoot)
  Else
   'ret = SHGetSpecialFolderLocation(HWND_DESKTOP, CSIDL_DESKTOP, @bi.pidlRoot)
   ret = SHGetFolderLocation(HWND_DESKTOP, CSIDL_DESKTOP , NULL, NULL, @bi.pidlRoot)
  EndIf
 
  fp.lpszTitle = StrPtr(Title)
  fp.lpszInitialFolder = StrPtr(sz_InitialDir)
  fp.ulFlags = iFlags
 
  bi.pszDisplayName = @dispname
  bi.lpszTitle = Strptr(title)
  bi.ulFlags = iFlags
  bi.lpfn = @FileSelectFolder_callback
  bi.lParam = Cast(LPARAM,VarPtr(fp))
  bi.iImage = 0

  pidl = SHBrowseForFolder(@bi)
 
  If pidl <> 0 Then
    If SHGetPathFromIDList(pidl, physpath) = 0 Then
      Function = ""
    Else
      Function = physpath
    End If
    CoTaskMemFree pidl
   Else
    Function = ""
  End If
 
  CoTaskMemFree bi.pidlRoot
End Function
#EndIf


Usage:

Code: Select all

    Dim buff As ZString*260
    Dim ofnFlags As Integer

'FileOpen
    ofnFlags = OFN_LONGNAMES Or OFN_PATHMUSTEXIST Or OFN_FILEMUSTEXIST Or OFN_EXPLORER
    buff = FileOpenDialog("Open","C:\Program Files\FreeBasic\examples","FreeBasic(*.bas;*.bi)|*.bas;*.bi|All(*.*)|*.*",ofnFlags,"")

'FileSave
    ofnFlags = OFN_LONGNAMES Or OFN_PATHMUSTEXIST Or OFN_OVERWRITEPROMPT Or OFN_HIDEREADONLY
    buff = FileSaveDialog("Save","C:\Program Files\FreeBasic\examples","FreeBasic(*.bas;*.bi)|*.bas;*.bi|All(*.*)|*.*",ofnFlags,"untitled.bas")

'Select Folder
     ofnFlags = BIF_NEWDIALOGSTYLE Or BIF_RETURNONLYFSDIRS
     buff = FileSelectFolder("Select Folder",0,ofnFlags,"C:\Program Files")



provides File save, File Open and Folder Select dialogs.

edit: replaced ofn.hInstance = hInstance with ofn.hInstance = GetModuleHandle(NULL). Thx BasicScience.
The program I pulled it from had hInstance set shared.
Last edited by spodhaje on Apr 22, 2008 21:21, edited 1 time in total.
BasicScience
Posts: 489
Joined: Apr 18, 2008 4:09
Location: Los Angeles, CA
Contact:

Postby BasicScience » Apr 22, 2008 20:59

Thanks. Seems to work, after one line was changed (? typo)

ofn.hInstance=hInstance

Should be

ofn.hInstance=GetModuleHandle(NULL)
dpixel
Posts: 74
Joined: Aug 13, 2008 11:34
Location: US

Postby dpixel » Mar 10, 2009 17:19

This works perfectly!!

Return to “Tips and Tricks”

Who is online

Users browsing this forum: Bing [Bot] and 4 guests