Quoted from wahorger
I have yet to figure out how to invoke the Windows open dialog directly, so if someone can help with that, I'll give it a go!
From Windows Vista and up, the new file dialogs are exposed through COM interface. If you know a little bit C++ and have an access to compiler with up to date header files, then it's not too difficult.
Take a look at the:
IFileDialog, IFileOpenDialog and IFileSaveDialog interfaces
I personally use MiniBASIC to write my DLL files, as I don't like C++ and curly braces. It supports 'C' style pointer operations and OOP, so most of the C code syntax is easy to translate.
Anyway, below are two examples. The First example lets you select a folder and second lets you select a file. Remember, the COM stuff uses wide character strings instead of character strings.
First example:
func GetFolder(string title, string buffer)
CoInitialize(NULL)
IFileOpenDIalog *pfd = NULL
HRESULT hr = CoCreateInstance(_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, _IID_IFileOpenDialog, &pfd)
if hr >= 0
FILEOPENDIALOGOPTIONS options
hr = pfd->GetOptions(&options)
hr = pfd->SetOptions(options|FOS_PICKFOLDERS)
hr = pfd->SetTitle(a2w(title))
hr = pfd->Show(0)
if hr >= 0
IShellItem *psi
wstring *pwszName
hr = pfd->GetResult(&psi)
if hr >= 0
hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pwszName)
buffer = w2a(#pwszName)
CoTaskMemFree(pwszName)
psi->Release()
endif
endif
hr = pfd->Release()
endif
CoUninitialize()
endf
Some declarations and helper functions for the second example:
type wstr
wstring str
endtype
type COMDLG_FILTERSPEC
wstring *name
wstring *spec
endtype
func count(string str), int
int pos = instrr(str,',')
int pos2 = len(str)
int count = 0
if len(str) > 0
count += 1
while pos
count += 1
pos2 = pos-1
pos = instrr(pos-1, str, ',')
endwhile
endif
return count
endf
Second example part 1:
func GetFile(string title, string buffer, string names, string specs)
CoInitialize(NULL)
int c = count(names)
if count(specs) <> c
buffer = ''
return
endif
COMDLG_FILTERSPEC *rgFileTypes = new(COMDLG_FILTERSPEC, c)
wstr *n = new(wstr, c)
wstr *s = new(wstr, c)
int pos = instrr(names,',')
int pos2 = len(names)
int i = 0
while pos
#n[i].str = a2w(ltrim$(mid$(names,pos+1,pos2-pos)))
i += 1
pos2 = pos-1
pos = instrr(pos-1,names,',')
endwhile
#n[i].str = a2w(ltrim$(mid$(names,pos+1,pos2-pos)))
for i = 0 to c-1
#rgFileTypes[c-1-i].name = #n[i].str
next i
pos = instrr(specs,',')
pos2 = len(specs)
i = 0
while pos
#s[i].str = a2w(ltrim$(mid$(specs,pos+1,pos2-pos)))
i += 1
pos2 = pos-1
pos = instrr(pos-1,specs,',')
endwhile
#s[i].str = a2w(ltrim$(mid$(specs,pos+1,pos2-pos)))
for i = 0 to c-1
#rgFileTypes[c-1-i].spec = #s[i].str
next i
Second example part2:
IFileOpenDIalog *pfd = NULL
HRESULT hr = CoCreateInstance(_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, _IID_IFileOpenDialog, &pfd)
if hr >= 0
hr = pfd->SetFileTypes(c,#rgFileTypes[0])
hr = pfd->SetTitle(a2w(title))
hr = pfd->Show(0)
if hr >= 0
IShellItem *psi
wstring *pwszName
hr = pfd->GetResult(&psi)
if hr >= 0
hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pwszName)
buffer = w2a(#pwszName)
CoTaskMemFree(pwszName)
psi->Release()
endif
endif
hr = pfd->Release()
endif
delete n
delete s
delete rgFileTypes
CoUninitialize()
endf