Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / win7filedialog.cpp
blob9d505325e99b9dba500337dd6936f3ce8040967c
1 #include "win7filedialog.h"
3 #include "ptrlist.h"
4 #include "win32_utf8.h"
7 Win7FileDialog::Win7FileDialog(const char *name, int issave)
9 m_dlgid = 0;
10 m_inst = 0;
11 m_proc = NULL;
13 if(!issave)
14 CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, reinterpret_cast<void**>(&m_fod));
15 else
16 CoCreateInstance(__uuidof(FileSaveDialog), NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, reinterpret_cast<void**>(&m_fod));
18 if(m_fod != NULL)
20 m_fdc = m_fod;
22 #if defined(WDL_NO_SUPPORT_UTF8)
23 WCHAR tmp[1024];
24 mbstowcs(tmp, name, 1023);
25 tmp[1023]=0;
26 m_fod->SetTitle(tmp);
27 #else
28 WCHAR *tmp = WDL_UTF8ToWC(name, false, 0, NULL);
29 m_fod->SetTitle(tmp);
30 free(tmp);
31 #endif
35 Win7FileDialog::~Win7FileDialog()
39 void Win7FileDialog::setFilterList(const char *list)
41 //generate wchar filter list
42 WDL_PtrList<WCHAR> wlist;
44 const char *p = list;
45 while(*p)
47 #if defined(WDL_NO_SUPPORT_UTF8)
48 int l = strlen(p);
49 WCHAR *n = (WCHAR*)malloc(sizeof(WCHAR)*(l+1));
50 mbstowcs(n, p, l+1);
51 wlist.Add(n);
52 #else
53 wlist.Add(WDL_UTF8ToWC(p, false, 0, NULL));
54 #endif
55 p+=strlen(p)+1;
58 m_fod->SetFileTypes(wlist.GetSize()/2, (_COMDLG_FILTERSPEC *)wlist.GetList());
59 wlist.Empty(true,free);
62 void Win7FileDialog::addOptions(DWORD o)
64 DWORD fileOpenDialogOptions;
65 m_fod->GetOptions(&fileOpenDialogOptions);
66 fileOpenDialogOptions |= o;
67 m_fod->SetOptions(fileOpenDialogOptions);
70 void Win7FileDialog::setDefaultExtension(const char *ext)
72 #if defined(WDL_NO_SUPPORT_UTF8)
73 WCHAR tmp[1024];
74 mbstowcs(tmp, ext, 1023);
75 tmp[1023]=0;
76 m_fod->SetDefaultExtension(tmp);
77 #else
78 WCHAR *tmp = WDL_UTF8ToWC(ext, false, 0, NULL);
79 m_fod->SetDefaultExtension(tmp);
80 free(tmp);
81 #endif
84 void Win7FileDialog::setFileTypeIndex(int i)
86 m_fod->SetFileTypeIndex(i);
89 void Win7FileDialog::setFolder(const char *folder, int def)
91 static HRESULT (WINAPI *my_SHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv) = NULL;
92 if(!my_SHCreateItemFromParsingName)
94 HMODULE dll = LoadLibrary("shell32.dll");
95 if(dll)
97 *((void **)(&my_SHCreateItemFromParsingName)) = (void *)GetProcAddress(dll, "SHCreateItemFromParsingName");
100 if(!my_SHCreateItemFromParsingName) return;
102 #if defined(WDL_NO_SUPPORT_UTF8)
103 WCHAR tmp[4096];
104 mbstowcs(tmp, folder, 4095);
105 tmp[4095]=0;
106 #else
107 WCHAR *tmp = WDL_UTF8ToWC(folder, false, 0, NULL);
108 #endif
110 IShellItemPtr si;
111 my_SHCreateItemFromParsingName(tmp, NULL, __uuidof(IShellItem), (void **)&si);
113 #if !defined(WDL_NO_SUPPORT_UTF8)
114 free(tmp);
115 #endif
117 if(si == NULL) return;
119 if(def)
120 m_fod->SetDefaultFolder(si);
121 else
122 m_fod->SetFolder(si);
125 void Win7FileDialog::addText(DWORD id, char *txt)
127 if(m_fdc == NULL) return;
128 #if defined(WDL_NO_SUPPORT_UTF8)
129 WCHAR tmp[1024];
130 mbstowcs(tmp, txt, 1023);
131 tmp[1023]=0;
132 m_fdc->AddText(id, tmp);
133 #else
134 WCHAR *tmp = WDL_UTF8ToWC(txt, false, 0, NULL);
135 m_fdc->AddText(id, tmp);
136 free(tmp);
137 #endif
140 void Win7FileDialog::addCheckbox(char *name, DWORD id, int defval)
142 if(m_fdc == NULL) return;
144 #if defined(WDL_NO_SUPPORT_UTF8)
145 WCHAR tmp[1024];
146 mbstowcs(tmp, name, 1023);
147 tmp[1023]=0;
148 m_fdc->AddCheckButton(id, tmp, defval);
149 #else
150 WCHAR *tmp = WDL_UTF8ToWC(name, false, 0, NULL);
151 m_fdc->AddCheckButton(id, tmp, defval);
152 free(tmp);
153 #endif
156 void Win7FileDialog::startGroup(DWORD id, char *label)
158 if(m_fdc == NULL) return;
159 #if defined(WDL_NO_SUPPORT_UTF8)
160 WCHAR tmp[1024];
161 mbstowcs(tmp, label, 1023);
162 tmp[1023]=0;
163 m_fdc->StartVisualGroup(id, tmp);
164 #else
165 WCHAR *tmp = WDL_UTF8ToWC(label, false, 0, NULL);
166 m_fdc->StartVisualGroup(id, tmp);
167 free(tmp);
168 #endif
171 void Win7FileDialog::endGroup()
173 if(m_fdc == NULL) return;
174 m_fdc->EndVisualGroup();
177 void Win7FileDialog::getResult(char *fn, int maxlen)
179 IShellItemPtr si;
180 m_fod->GetResult(&si);
181 if(si == NULL)
183 fn[0] = 0;
184 return;
186 WCHAR *res = NULL;
187 si->GetDisplayName(SIGDN_FILESYSPATH, &res);
188 if(!res)
190 fn[0] = 0;
191 return;
194 #if defined(WDL_NO_SUPPORT_UTF8)
195 if (wcstombs(fn,res,maxlen) == (size_t)-1) fn[0]=0;
196 #else
197 int len = WideCharToMultiByte(CP_UTF8,0,res,-1,fn,maxlen-1,NULL,NULL);
198 fn[len] = 0;
199 #endif
201 CoTaskMemFree(res);
204 int Win7FileDialog::getResult(int i, char *fn, int maxlen)
206 IShellItemArrayPtr sia;
207 ((IFileOpenDialogPtr)m_fod)->GetResults(&sia); // good enough: only makes sense with IFileOpenDialog
208 if (sia == NULL)
210 fn[0] = 0;
211 return 0;
214 IShellItemPtr item;
215 if (SUCCEEDED(sia->GetItemAt(i, &item)))
217 WCHAR *res = NULL;
218 item->GetDisplayName(SIGDN_FILESYSPATH, &res);
219 if(!res)
221 fn[0] = 0;
222 return 0;
225 int len=0;
226 #if defined(WDL_NO_SUPPORT_UTF8)
227 size_t l = wcstombs(fn, res, maxlen);
228 if (l==(size_t)-1) fn[0]=0;
229 else len=l+1;
230 #else
231 len = WideCharToMultiByte(CP_UTF8,0,res,-1,fn,maxlen-1,NULL,NULL);
232 #endif
234 CoTaskMemFree(res);
235 return len;
237 return 0;
240 int Win7FileDialog::getResultCount()
242 IShellItemArrayPtr sia;
243 ((IFileOpenDialogPtr)m_fod)->GetResults(&sia); // good enough: only makes sense with IFileOpenDialog
244 if (sia == NULL) return 0;
246 DWORD cnt;
247 return SUCCEEDED(sia->GetCount(&cnt)) ? cnt : 0;
250 int Win7FileDialog::getState(DWORD id)
252 BOOL c = FALSE;
253 m_fdc->GetCheckButtonState(id, &c);
254 return c;
257 static WNDPROC m_oldproc, m_oldproc2;
258 static LRESULT CALLBACK newWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
260 if(msg == WM_SIZE)
262 //disable the win7 dialog to resize our custom dialog
263 static int reent = 0;
264 if(!reent)
266 reent = 1;
267 RECT r2;
268 GetWindowRect(hwnd, &r2);
269 SetWindowPos(hwnd, NULL, r2.left, r2.top, 1000, r2.bottom-r2.top, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
270 reent = 0;
272 return 0;
274 if(msg == WM_GETDLGCODE)
276 int a=1;
278 return CallWindowProc(m_oldproc, hwnd, msg, wparam, lparam);
281 class myEvent : public IFileDialogEvents
283 public:
284 myEvent(HINSTANCE inst, char *dlgid, LPOFNHOOKPROC proc, char *statictxt)
286 m_didhook = 0;
287 m_didhook2 = 0;
288 m_inst = inst;
289 m_dlgid = dlgid;
290 m_proc = proc;
291 m_crwnd = NULL;
292 m_statictxt.Set(statictxt);
295 STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
297 return E_NOINTERFACE;
299 STDMETHODIMP_(ULONG) AddRef()
301 return 1;
303 STDMETHODIMP_(ULONG) Release()
305 if(m_crwnd) DestroyWindow(m_crwnd);
306 return 0;
309 virtual HRESULT STDMETHODCALLTYPE OnFileOk(
310 /* [in] */ __RPC__in_opt IFileDialog *pfd)
312 return E_NOTIMPL;
315 virtual HRESULT STDMETHODCALLTYPE OnFolderChanging(
316 /* [in] */ __RPC__in_opt IFileDialog *pfd,
317 /* [in] */ __RPC__in_opt IShellItem *psiFolder)
319 return E_NOTIMPL;
322 virtual HRESULT STDMETHODCALLTYPE OnFolderChange(
323 /* [in] */ __RPC__in_opt IFileDialog *pfd)
325 doHook2(pfd); //post a msg for the actual hook
326 return E_NOTIMPL;
329 virtual HRESULT STDMETHODCALLTYPE OnSelectionChange(
330 /* [in] */ __RPC__in_opt IFileDialog *pfd)
332 doHook2(pfd); //post a msg for the actual hook
333 return E_NOTIMPL;
336 virtual HRESULT STDMETHODCALLTYPE OnShareViolation(
337 /* [in] */ __RPC__in_opt IFileDialog *pfd,
338 /* [in] */ __RPC__in_opt IShellItem *psi,
339 /* [out] */ __RPC__out FDE_SHAREVIOLATION_RESPONSE *pResponse)
341 return E_NOTIMPL;
344 virtual HRESULT STDMETHODCALLTYPE OnTypeChange(
345 /* [in] */ __RPC__in_opt IFileDialog *pfd)
347 return E_NOTIMPL;
350 virtual HRESULT STDMETHODCALLTYPE OnOverwrite(
351 /* [in] */ __RPC__in_opt IFileDialog *pfd,
352 /* [in] */ __RPC__in_opt IShellItem *psi,
353 /* [out] */ __RPC__out FDE_OVERWRITE_RESPONSE *pResponse)
355 return E_NOTIMPL;
358 static BOOL CALLBACK enumProc(HWND hwnd, LPARAM lParam)
360 char tmp[1024]={0,};
361 GetClassName(hwnd, tmp, 1023);
362 if(!stricmp(tmp,"FloatNotifySink"))
364 myEvent *me = (myEvent *)lParam;
365 if(!FindWindowEx(hwnd, NULL, NULL, me->m_statictxt.Get()))
366 return TRUE;
367 me->m_findwnd = hwnd;
368 return FALSE;
370 return TRUE;
373 void doHook()
375 if(m_dlgid && !m_didhook)
377 IOleWindowPtr ow = m_lastpfd;
378 if(ow!=NULL)
380 HWND filehwnd = NULL;
381 ow->GetWindow(&filehwnd);
382 if(filehwnd)
384 m_findwnd = NULL;
385 EnumChildWindows(filehwnd, enumProc, (LPARAM)this);
386 if(m_findwnd)
388 //hide other button
389 HWND h3 = m_findwnd;
390 HWND h5 = FindWindowEx(h3, NULL, NULL, NULL);
391 ShowWindow(h5, SW_HIDE);
393 //resize the sink
394 RECT r,r2;
395 GetWindowRect(h3, &r2);
396 SetWindowPos(h3, NULL, r2.left, r2.top, 1000, r2.bottom-r2.top, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
398 //put our own dialog instead
399 HWND h4 = CreateDialog(m_inst, m_dlgid, h3, (DLGPROC)m_proc);
401 //SetWindowLong(h4, GWL_ID, 1001);
402 //SetWindowLong(h4, GWL_STYLE, GetWindowLong(h4, GWL_STYLE)&~(DS_CONTROL|DS_3DLOOK|DS_SETFONT));
403 //SetWindowLong(h4, GWL_STYLE, GetWindowLong(h4, GWL_STYLE)|WS_GROUP);
404 SetWindowLong(h3, GWL_STYLE, GetWindowLong(h3, GWL_STYLE)|WS_TABSTOP);
406 m_crwnd = h4;
407 ShowWindow(h4, SW_SHOW);
409 GetClientRect(h3, &r);
410 SetWindowPos(h4, NULL, 0, 0, r.right, r.bottom, 0);
412 //disable the win7 dialog to resize our custom dialog sink
413 m_oldproc = (WNDPROC)SetWindowLongPtr(h3, GWLP_WNDPROC, (LPARAM)&newWndProc);
414 m_didhook = 1;
421 static LRESULT CALLBACK newWndProc2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
423 if(msg == WM_USER+666)
425 myEvent *me = (myEvent*)lparam;
426 me->doHook();
428 return CallWindowProc(m_oldproc2, hwnd, msg, wparam, lparam);
431 void doHook2(IFileDialog *pfd)
433 if(m_dlgid && !m_didhook2)
435 IOleWindowPtr ow = pfd;
436 HWND filehwnd = NULL;
437 ow->GetWindow(&filehwnd);
438 if(filehwnd)
440 m_lastpfd = pfd;
441 m_oldproc2 = (WNDPROC)SetWindowLongPtr(filehwnd, GWLP_WNDPROC, (LPARAM)&newWndProc2);
442 PostMessage(filehwnd, WM_USER+666,0,(LPARAM)this);
443 m_didhook2 = 1;
448 int m_didhook, m_didhook2;
449 HINSTANCE m_inst;
450 char *m_dlgid;
451 LPOFNHOOKPROC m_proc;
452 HWND m_findwnd;
453 HWND m_crwnd;
454 WDL_String m_statictxt;
455 IFileDialog *m_lastpfd;
458 int Win7FileDialog::show(HWND parent)
460 DWORD c;
461 myEvent *ev = new myEvent(m_inst, (char*)m_dlgid, m_proc, m_statictxt.Get());
462 m_fod->Advise(ev, &c);
464 int res = SUCCEEDED(m_fod->Show(parent));
466 m_fod->Unadvise(c);
467 delete ev;
468 return res;
471 #ifndef DLGTEMPLATEEX
472 #pragma pack(push, 1)
473 typedef struct
475 WORD dlgVer;
476 WORD signature;
477 DWORD helpID;
478 DWORD exStyle;
479 DWORD style;
480 WORD cDlgItems;
481 short x;
482 short y;
483 short cx;
484 short cy;
485 } DLGTEMPLATEEX;
486 #pragma pack(pop)
487 #endif
489 void Win7FileDialog::setTemplate(HINSTANCE inst, const char *dlgid, LPOFNHOOKPROC proc)
491 //get the dialog height size
492 HRSRC r = FindResource(inst, dlgid, RT_DIALOG);
493 if(!r) return;
494 HGLOBAL hTemplate = LoadResource(inst, r);
495 if(!hTemplate) return;
496 int ysizedlg = 0;
497 DLGTEMPLATEEX* pTemplate = (DLGTEMPLATEEX*)LockResource(hTemplate);
498 if(pTemplate->signature == 0xffff)
499 ysizedlg = pTemplate->cy;
500 else
502 DLGTEMPLATE *p2 = (DLGTEMPLATE*)pTemplate;
503 ysizedlg = p2->cy;
505 UnlockResource(hTemplate);
506 FreeResource(hTemplate);
508 int ysize = ysizedlg/8;
510 //make room for our custom template dialog
511 WDL_String txt(".");
512 if(ysize)
514 while(--ysize)
516 txt.Append("\n.");
519 addText(1, txt.Get());
520 m_statictxt.Set(txt.Get());
521 addText(2, "");
523 m_inst = inst;
524 m_dlgid = dlgid;
525 m_proc = proc;
528 void Win7FileDialog::setFilename(const char *fn)
530 if(m_fod == NULL) return;
532 #if defined(WDL_NO_SUPPORT_UTF8)
533 WCHAR tmp[4096];
534 mbstowcs(tmp, fn, 4095);
535 tmp[4095]=0;
536 m_fod->SetFileName(tmp);
537 #else
538 WCHAR *tmp = WDL_UTF8ToWC(fn, false, 0, NULL);
539 m_fod->SetFileName(tmp);
540 free(tmp);
541 #endif