#include "win7filedialog.h" #include "ptrlist.h" #include "win32_utf8.h" Win7FileDialog::Win7FileDialog(const char *name, int issave) { m_dlgid = 0; m_inst = 0; m_proc = NULL; if(!issave) CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, reinterpret_cast(&m_fod)); else CoCreateInstance(__uuidof(FileSaveDialog), NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, reinterpret_cast(&m_fod)); if(m_fod != NULL) { m_fdc = m_fod; #if defined(WDL_NO_SUPPORT_UTF8) WCHAR tmp[1024]; mbstowcs(tmp, name, 1023); tmp[1023]=0; m_fod->SetTitle(tmp); #else WCHAR *tmp = WDL_UTF8ToWC(name, false, 0, NULL); m_fod->SetTitle(tmp); free(tmp); #endif } } Win7FileDialog::~Win7FileDialog() { } void Win7FileDialog::setFilterList(const char *list) { //generate wchar filter list WDL_PtrList wlist; { const char *p = list; while(*p) { #if defined(WDL_NO_SUPPORT_UTF8) int l = strlen(p); WCHAR *n = (WCHAR*)malloc(sizeof(WCHAR)*(l+1)); mbstowcs(n, p, l+1); wlist.Add(n); #else wlist.Add(WDL_UTF8ToWC(p, false, 0, NULL)); #endif p+=strlen(p)+1; } } m_fod->SetFileTypes(wlist.GetSize()/2, (_COMDLG_FILTERSPEC *)wlist.GetList()); wlist.Empty(true,free); } void Win7FileDialog::addOptions(DWORD o) { DWORD fileOpenDialogOptions; m_fod->GetOptions(&fileOpenDialogOptions); fileOpenDialogOptions |= o; m_fod->SetOptions(fileOpenDialogOptions); } void Win7FileDialog::setDefaultExtension(const char *ext) { #if defined(WDL_NO_SUPPORT_UTF8) WCHAR tmp[1024]; mbstowcs(tmp, ext, 1023); tmp[1023]=0; m_fod->SetDefaultExtension(tmp); #else WCHAR *tmp = WDL_UTF8ToWC(ext, false, 0, NULL); m_fod->SetDefaultExtension(tmp); free(tmp); #endif } void Win7FileDialog::setFileTypeIndex(int i) { m_fod->SetFileTypeIndex(i); } void Win7FileDialog::setFolder(const char *folder, int def) { static HRESULT (WINAPI *my_SHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv) = NULL; if(!my_SHCreateItemFromParsingName) { HMODULE dll = LoadLibrary("shell32.dll"); if(dll) { *((void **)(&my_SHCreateItemFromParsingName)) = (void *)GetProcAddress(dll, "SHCreateItemFromParsingName"); } } if(!my_SHCreateItemFromParsingName) return; #if defined(WDL_NO_SUPPORT_UTF8) WCHAR tmp[4096]; mbstowcs(tmp, folder, 4095); tmp[4095]=0; #else WCHAR *tmp = WDL_UTF8ToWC(folder, false, 0, NULL); #endif IShellItemPtr si; my_SHCreateItemFromParsingName(tmp, NULL, __uuidof(IShellItem), (void **)&si); #if !defined(WDL_NO_SUPPORT_UTF8) free(tmp); #endif if(si == NULL) return; if(def) m_fod->SetDefaultFolder(si); else m_fod->SetFolder(si); } void Win7FileDialog::addText(DWORD id, char *txt) { if(m_fdc == NULL) return; #if defined(WDL_NO_SUPPORT_UTF8) WCHAR tmp[1024]; mbstowcs(tmp, txt, 1023); tmp[1023]=0; m_fdc->AddText(id, tmp); #else WCHAR *tmp = WDL_UTF8ToWC(txt, false, 0, NULL); m_fdc->AddText(id, tmp); free(tmp); #endif } void Win7FileDialog::addCheckbox(char *name, DWORD id, int defval) { if(m_fdc == NULL) return; #if defined(WDL_NO_SUPPORT_UTF8) WCHAR tmp[1024]; mbstowcs(tmp, name, 1023); tmp[1023]=0; m_fdc->AddCheckButton(id, tmp, defval); #else WCHAR *tmp = WDL_UTF8ToWC(name, false, 0, NULL); m_fdc->AddCheckButton(id, tmp, defval); free(tmp); #endif } void Win7FileDialog::startGroup(DWORD id, char *label) { if(m_fdc == NULL) return; #if defined(WDL_NO_SUPPORT_UTF8) WCHAR tmp[1024]; mbstowcs(tmp, label, 1023); tmp[1023]=0; m_fdc->StartVisualGroup(id, tmp); #else WCHAR *tmp = WDL_UTF8ToWC(label, false, 0, NULL); m_fdc->StartVisualGroup(id, tmp); free(tmp); #endif } void Win7FileDialog::endGroup() { if(m_fdc == NULL) return; m_fdc->EndVisualGroup(); } void Win7FileDialog::getResult(char *fn, int maxlen) { IShellItemPtr si; m_fod->GetResult(&si); if(si == NULL) { fn[0] = 0; return; } WCHAR *res = NULL; si->GetDisplayName(SIGDN_FILESYSPATH, &res); if(!res) { fn[0] = 0; return; } #if defined(WDL_NO_SUPPORT_UTF8) if (wcstombs(fn,res,maxlen) == (size_t)-1) fn[0]=0; #else int len = WideCharToMultiByte(CP_UTF8,0,res,-1,fn,maxlen-1,NULL,NULL); fn[len] = 0; #endif CoTaskMemFree(res); } int Win7FileDialog::getResult(int i, char *fn, int maxlen) { IShellItemArrayPtr sia; ((IFileOpenDialogPtr)m_fod)->GetResults(&sia); // good enough: only makes sense with IFileOpenDialog if (sia == NULL) { fn[0] = 0; return 0; } IShellItemPtr item; if (SUCCEEDED(sia->GetItemAt(i, &item))) { WCHAR *res = NULL; item->GetDisplayName(SIGDN_FILESYSPATH, &res); if(!res) { fn[0] = 0; return 0; } int len=0; #if defined(WDL_NO_SUPPORT_UTF8) size_t l = wcstombs(fn, res, maxlen); if (l==(size_t)-1) fn[0]=0; else len=l+1; #else len = WideCharToMultiByte(CP_UTF8,0,res,-1,fn,maxlen-1,NULL,NULL); #endif CoTaskMemFree(res); return len; } return 0; } int Win7FileDialog::getResultCount() { IShellItemArrayPtr sia; ((IFileOpenDialogPtr)m_fod)->GetResults(&sia); // good enough: only makes sense with IFileOpenDialog if (sia == NULL) return 0; DWORD cnt; return SUCCEEDED(sia->GetCount(&cnt)) ? cnt : 0; } int Win7FileDialog::getState(DWORD id) { BOOL c = FALSE; m_fdc->GetCheckButtonState(id, &c); return c; } static WNDPROC m_oldproc, m_oldproc2; static LRESULT CALLBACK newWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if(msg == WM_SIZE) { //disable the win7 dialog to resize our custom dialog static int reent = 0; if(!reent) { reent = 1; RECT r2; GetWindowRect(hwnd, &r2); SetWindowPos(hwnd, NULL, r2.left, r2.top, 1000, r2.bottom-r2.top, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); reent = 0; } return 0; } if(msg == WM_GETDLGCODE) { int a=1; } return CallWindowProc(m_oldproc, hwnd, msg, wparam, lparam); } class myEvent : public IFileDialogEvents { public: myEvent(HINSTANCE inst, char *dlgid, LPOFNHOOKPROC proc, char *statictxt) { m_didhook = 0; m_didhook2 = 0; m_inst = inst; m_dlgid = dlgid; m_proc = proc; m_crwnd = NULL; m_statictxt.Set(statictxt); } STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return E_NOINTERFACE; } STDMETHODIMP_(ULONG) AddRef() { return 1; } STDMETHODIMP_(ULONG) Release() { if(m_crwnd) DestroyWindow(m_crwnd); return 0; } virtual HRESULT STDMETHODCALLTYPE OnFileOk( /* [in] */ __RPC__in_opt IFileDialog *pfd) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnFolderChanging( /* [in] */ __RPC__in_opt IFileDialog *pfd, /* [in] */ __RPC__in_opt IShellItem *psiFolder) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnFolderChange( /* [in] */ __RPC__in_opt IFileDialog *pfd) { doHook2(pfd); //post a msg for the actual hook return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnSelectionChange( /* [in] */ __RPC__in_opt IFileDialog *pfd) { doHook2(pfd); //post a msg for the actual hook return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnShareViolation( /* [in] */ __RPC__in_opt IFileDialog *pfd, /* [in] */ __RPC__in_opt IShellItem *psi, /* [out] */ __RPC__out FDE_SHAREVIOLATION_RESPONSE *pResponse) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnTypeChange( /* [in] */ __RPC__in_opt IFileDialog *pfd) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnOverwrite( /* [in] */ __RPC__in_opt IFileDialog *pfd, /* [in] */ __RPC__in_opt IShellItem *psi, /* [out] */ __RPC__out FDE_OVERWRITE_RESPONSE *pResponse) { return E_NOTIMPL; } static BOOL CALLBACK enumProc(HWND hwnd, LPARAM lParam) { char tmp[1024]={0,}; GetClassName(hwnd, tmp, 1023); if(!stricmp(tmp,"FloatNotifySink")) { myEvent *me = (myEvent *)lParam; if(!FindWindowEx(hwnd, NULL, NULL, me->m_statictxt.Get())) return TRUE; me->m_findwnd = hwnd; return FALSE; } return TRUE; } void doHook() { if(m_dlgid && !m_didhook) { IOleWindowPtr ow = m_lastpfd; if(ow!=NULL) { HWND filehwnd = NULL; ow->GetWindow(&filehwnd); if(filehwnd) { m_findwnd = NULL; EnumChildWindows(filehwnd, enumProc, (LPARAM)this); if(m_findwnd) { //hide other button HWND h3 = m_findwnd; HWND h5 = FindWindowEx(h3, NULL, NULL, NULL); ShowWindow(h5, SW_HIDE); //resize the sink RECT r,r2; GetWindowRect(h3, &r2); SetWindowPos(h3, NULL, r2.left, r2.top, 1000, r2.bottom-r2.top, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); //put our own dialog instead HWND h4 = CreateDialog(m_inst, m_dlgid, h3, (DLGPROC)m_proc); //SetWindowLong(h4, GWL_ID, 1001); //SetWindowLong(h4, GWL_STYLE, GetWindowLong(h4, GWL_STYLE)&~(DS_CONTROL|DS_3DLOOK|DS_SETFONT)); //SetWindowLong(h4, GWL_STYLE, GetWindowLong(h4, GWL_STYLE)|WS_GROUP); SetWindowLong(h3, GWL_STYLE, GetWindowLong(h3, GWL_STYLE)|WS_TABSTOP); m_crwnd = h4; ShowWindow(h4, SW_SHOW); GetClientRect(h3, &r); SetWindowPos(h4, NULL, 0, 0, r.right, r.bottom, 0); //disable the win7 dialog to resize our custom dialog sink m_oldproc = (WNDPROC)SetWindowLongPtr(h3, GWLP_WNDPROC, (LPARAM)&newWndProc); m_didhook = 1; } } } } } static LRESULT CALLBACK newWndProc2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if(msg == WM_USER+666) { myEvent *me = (myEvent*)lparam; me->doHook(); } return CallWindowProc(m_oldproc2, hwnd, msg, wparam, lparam); } void doHook2(IFileDialog *pfd) { if(m_dlgid && !m_didhook2) { IOleWindowPtr ow = pfd; HWND filehwnd = NULL; ow->GetWindow(&filehwnd); if(filehwnd) { m_lastpfd = pfd; m_oldproc2 = (WNDPROC)SetWindowLongPtr(filehwnd, GWLP_WNDPROC, (LPARAM)&newWndProc2); PostMessage(filehwnd, WM_USER+666,0,(LPARAM)this); m_didhook2 = 1; } } } int m_didhook, m_didhook2; HINSTANCE m_inst; char *m_dlgid; LPOFNHOOKPROC m_proc; HWND m_findwnd; HWND m_crwnd; WDL_String m_statictxt; IFileDialog *m_lastpfd; }; int Win7FileDialog::show(HWND parent) { DWORD c; myEvent *ev = new myEvent(m_inst, (char*)m_dlgid, m_proc, m_statictxt.Get()); m_fod->Advise(ev, &c); int res = SUCCEEDED(m_fod->Show(parent)); m_fod->Unadvise(c); delete ev; return res; } #ifndef DLGTEMPLATEEX #pragma pack(push, 1) typedef struct { WORD dlgVer; WORD signature; DWORD helpID; DWORD exStyle; DWORD style; WORD cDlgItems; short x; short y; short cx; short cy; } DLGTEMPLATEEX; #pragma pack(pop) #endif void Win7FileDialog::setTemplate(HINSTANCE inst, const char *dlgid, LPOFNHOOKPROC proc) { //get the dialog height size HRSRC r = FindResource(inst, dlgid, RT_DIALOG); if(!r) return; HGLOBAL hTemplate = LoadResource(inst, r); if(!hTemplate) return; int ysizedlg = 0; DLGTEMPLATEEX* pTemplate = (DLGTEMPLATEEX*)LockResource(hTemplate); if(pTemplate->signature == 0xffff) ysizedlg = pTemplate->cy; else { DLGTEMPLATE *p2 = (DLGTEMPLATE*)pTemplate; ysizedlg = p2->cy; } UnlockResource(hTemplate); FreeResource(hTemplate); int ysize = ysizedlg/8; //make room for our custom template dialog WDL_String txt("."); if(ysize) { while(--ysize) { txt.Append("\n."); } } addText(1, txt.Get()); m_statictxt.Set(txt.Get()); addText(2, ""); m_inst = inst; m_dlgid = dlgid; m_proc = proc; } void Win7FileDialog::setFilename(const char *fn) { if(m_fod == NULL) return; #if defined(WDL_NO_SUPPORT_UTF8) WCHAR tmp[4096]; mbstowcs(tmp, fn, 4095); tmp[4095]=0; m_fod->SetFileName(tmp); #else WCHAR *tmp = WDL_UTF8ToWC(fn, false, 0, NULL); m_fod->SetFileName(tmp); free(tmp); #endif }