26e183efa471a35770baafebebdd17b4b746840b
[reactos.git] / reactos / dll / win32 / comdlg32 / filedlg.c
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
3 *
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
28 *
29 * FIXME: any hook gets a OPENFILENAMEA structure
30 *
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
32 *
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
34 *
35 * FIXME: algorithm for selecting the initial directory is too simple
36 *
37 * FIXME: add to recent docs
38 *
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
42 *
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
44 *
45 *
46 */
47
48 #include "cdlg.h"
49
50 #include <shellapi.h>
51
52 #define UNIMPLEMENTED_FLAGS \
53 (OFN_DONTADDTORECENT |\
54 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
55 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
56
57 #define IsHooked(fodInfos) \
58 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
59 /***********************************************************************
60 * Data structure and global variables
61 */
62 typedef struct SFolder
63 {
64 int m_iImageIndex; /* Index of picture in image list */
65 HIMAGELIST hImgList;
66 int m_iIndent; /* Indentation index */
67 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
68
69 } SFOLDER,*LPSFOLDER;
70
71 typedef struct tagLookInInfo
72 {
73 int iMaxIndentation;
74 UINT uSelectedItem;
75 } LookInInfos;
76
77
78 /***********************************************************************
79 * Defines and global variables
80 */
81
82 /* Draw item constant */
83 #define XTEXTOFFSET 3
84
85 /* AddItem flags*/
86 #define LISTEND -1
87
88 /* SearchItem methods */
89 #define SEARCH_PIDL 1
90 #define SEARCH_EXP 2
91 #define ITEM_NOTFOUND -1
92
93 /* Undefined windows message sent by CreateViewObject*/
94 #define WM_GETISHELLBROWSER WM_USER+7
95
96 /* NOTE
97 * Those macros exist in windowsx.h. However, you can't really use them since
98 * they rely on the UNICODE defines and can't be used inside Wine itself.
99 */
100
101 /* Combo box macros */
102 #define CBAddString(hwnd,str) \
103 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
104
105 #define CBInsertString(hwnd,str,pos) \
106 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
107
108 #define CBDeleteString(hwnd,pos) \
109 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
110
111 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
112 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
113
114 #define CBGetItemDataPtr(hwnd,iItemId) \
115 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
116
117 #define CBGetLBText(hwnd,iItemId,str) \
118 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
119
120 #define CBGetCurSel(hwnd) \
121 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
122
123 #define CBSetCurSel(hwnd,pos) \
124 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
125
126 #define CBGetCount(hwnd) \
127 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
128 #define CBShowDropDown(hwnd,show) \
129 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
130 #define CBSetItemHeight(hwnd,index,height) \
131 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
132
133 #define CBSetExtendedUI(hwnd,flag) \
134 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
135
136 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
137 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
138 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
139
140 static const WCHAR LastVisitedMRUW[] =
141 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
142 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
143 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
144 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
145 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
146
147 /***********************************************************************
148 * Prototypes
149 */
150
151 /* Internal functions used by the dialog */
152 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
153 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
154 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
155 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
156 static BOOL FILEDLG95_OnOpen(HWND hwnd);
157 static LRESULT FILEDLG95_InitControls(HWND hwnd);
158 static void FILEDLG95_Clean(HWND hwnd);
159
160 /* Functions used by the shell navigation */
161 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
162 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
163 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
164 static void FILEDLG95_SHELL_Clean(HWND hwnd);
165 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
166
167 /* Functions used by the EDIT box */
168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
169
170 /* Functions used by the filetype combo box */
171 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
172 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
173 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
174 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
175
176 /* Functions used by the Look In combo box */
177 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
178 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
179 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
180 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
181 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
182 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
183 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
184 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
185 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
186
187 /* Functions for dealing with the most-recently-used registry keys */
188 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
189 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
190 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
191
192 /* Miscellaneous tool functions */
193 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
194 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
195 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
196 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
197 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
198 static UINT GetNumSelected( IDataObject *doSelected );
199 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
200
201 /* Shell memory allocation */
202 static void *MemAlloc(UINT size);
203 static void MemFree(void *mem);
204
205 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
206 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
207 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
208 static BOOL BrowseSelectedFolder(HWND hwnd);
209
210 /***********************************************************************
211 * GetFileName95
212 *
213 * Creates an Open common dialog box that lets the user select
214 * the drive, directory, and the name of a file or set of files to open.
215 *
216 * IN : The FileOpenDlgInfos structure associated with the dialog
217 * OUT : TRUE on success
218 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
219 */
220 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
221 {
222
223 LRESULT lRes;
224 LPCVOID origTemplate;
225 DWORD dwSize;
226 LPDLGTEMPLATEW template;
227 HRSRC hRes;
228 HANDLE hDlgTmpl = 0;
229 HRESULT hr;
230
231 /* test for missing functionality */
232 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
233 {
234 FIXME("Flags 0x%08x not yet implemented\n",
235 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
236 }
237
238 /* Create the dialog from a template */
239
240 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
241 {
242 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
243 return FALSE;
244 }
245 if (!(dwSize = SizeofResource(COMDLG32_hInstance, hRes)) ||
246 !(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes)) ||
247 !(origTemplate = LockResource(hDlgTmpl)))
248 {
249 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
250 return FALSE;
251 }
252 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize)))
253 {
254 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
255 return FALSE;
256 }
257 memcpy(template, origTemplate, dwSize);
258
259 /* msdn: explorer style dialogs permit sizing by default.
260 * The OFN_ENABLESIZING flag is only needed when a hook or
261 * custom tmeplate is provided */
262 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
263 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
264 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
265
266 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
267 {
268 template->style |= WS_SIZEBOX;
269 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
270 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
271 }
272 else
273 template->style &= ~WS_SIZEBOX;
274
275
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
278 {
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
283 }
284
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
287
288 if (fodInfos->unicode)
289 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
290 template,
291 fodInfos->ofnInfos->hwndOwner,
292 FileOpenDlgProc95,
293 (LPARAM) fodInfos);
294 else
295 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
296 template,
297 fodInfos->ofnInfos->hwndOwner,
298 FileOpenDlgProc95,
299 (LPARAM) fodInfos);
300 if (SUCCEEDED(hr))
301 OleUninitialize();
302
303 HeapFree(GetProcessHeap(), 0, template);
304
305 /* Unable to create the dialog */
306 if( lRes == -1)
307 return FALSE;
308
309 return lRes;
310 }
311
312 /***********************************************************************
313 * GetFileDialog95A
314 *
315 * Call GetFileName95 with this structure and clean the memory.
316 *
317 * IN : The OPENFILENAMEA initialisation structure passed to
318 * GetOpenFileNameA win api function (see filedlg.c)
319 */
320 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
321 {
322 BOOL ret;
323 FileOpenDlgInfos fodInfos;
324 LPSTR lpstrSavDir = NULL;
325 LPWSTR title = NULL;
326 LPWSTR defext = NULL;
327 LPWSTR filter = NULL;
328 LPWSTR customfilter = NULL;
329 INITCOMMONCONTROLSEX icc;
330
331 /* Initialize ComboBoxEx32 */
332 icc.dwSize = sizeof(icc);
333 icc.dwICC = ICC_USEREX_CLASSES;
334 InitCommonControlsEx(&icc);
335
336 /* Initialize CommDlgExtendedError() */
337 COMDLG32_SetCommDlgExtendedError(0);
338
339 /* Initialize FileOpenDlgInfos structure */
340 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
341
342 /* Pass in the original ofn */
343 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
344
345 /* save current directory */
346 if (ofn->Flags & OFN_NOCHANGEDIR)
347 {
348 lpstrSavDir = MemAlloc(MAX_PATH);
349 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
350 }
351
352 fodInfos.unicode = FALSE;
353
354 /* convert all the input strings to unicode */
355 if(ofn->lpstrInitialDir)
356 {
357 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
358 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
359 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
360 }
361 else
362 fodInfos.initdir = NULL;
363
364 if(ofn->lpstrFile)
365 {
366 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
367 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
368 }
369 else
370 fodInfos.filename = NULL;
371
372 if(ofn->lpstrDefExt)
373 {
374 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
375 defext = MemAlloc((len+1)*sizeof(WCHAR));
376 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
377 }
378 fodInfos.defext = defext;
379
380 if(ofn->lpstrTitle)
381 {
382 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
383 title = MemAlloc((len+1)*sizeof(WCHAR));
384 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
385 }
386 fodInfos.title = title;
387
388 if (ofn->lpstrFilter)
389 {
390 LPCSTR s;
391 int n, len;
392
393 /* filter is a list... title\0ext\0......\0\0 */
394 s = ofn->lpstrFilter;
395 while (*s) s = s+strlen(s)+1;
396 s++;
397 n = s - ofn->lpstrFilter;
398 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
399 filter = MemAlloc(len*sizeof(WCHAR));
400 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
401 }
402 fodInfos.filter = filter;
403
404 /* convert lpstrCustomFilter */
405 if (ofn->lpstrCustomFilter)
406 {
407 LPCSTR s;
408 int n, len;
409
410 /* customfilter contains a pair of strings... title\0ext\0 */
411 s = ofn->lpstrCustomFilter;
412 if (*s) s = s+strlen(s)+1;
413 if (*s) s = s+strlen(s)+1;
414 n = s - ofn->lpstrCustomFilter;
415 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
416 customfilter = MemAlloc(len*sizeof(WCHAR));
417 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
418 }
419 fodInfos.customfilter = customfilter;
420
421 /* Initialize the dialog property */
422 fodInfos.DlgInfos.dwDlgProp = 0;
423 fodInfos.DlgInfos.hwndCustomDlg = NULL;
424
425 switch(iDlgType)
426 {
427 case OPEN_DIALOG :
428 ret = GetFileName95(&fodInfos);
429 break;
430 case SAVE_DIALOG :
431 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
432 ret = GetFileName95(&fodInfos);
433 break;
434 default :
435 ret = FALSE;
436 }
437
438 /* set the lpstrFileTitle */
439 if (ret && ofn->lpstrFile && ofn->lpstrFileTitle)
440 {
441 LPSTR lpstrFileTitle = PathFindFileNameA(ofn->lpstrFile);
442 lstrcpynA(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
443 }
444
445 if (lpstrSavDir)
446 {
447 SetCurrentDirectoryA(lpstrSavDir);
448 MemFree(lpstrSavDir);
449 }
450
451 MemFree(title);
452 MemFree(defext);
453 MemFree(filter);
454 MemFree(customfilter);
455 MemFree(fodInfos.initdir);
456 MemFree(fodInfos.filename);
457
458 TRACE("selected file: %s\n",ofn->lpstrFile);
459
460 return ret;
461 }
462
463 /***********************************************************************
464 * GetFileDialog95W
465 *
466 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
467 * Call GetFileName95 with this structure and clean the memory.
468 *
469 */
470 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
471 {
472 BOOL ret;
473 FileOpenDlgInfos fodInfos;
474 LPWSTR lpstrSavDir = NULL;
475 INITCOMMONCONTROLSEX icc;
476
477 /* Initialize ComboBoxEx32 */
478 icc.dwSize = sizeof(icc);
479 icc.dwICC = ICC_USEREX_CLASSES;
480 InitCommonControlsEx(&icc);
481
482 /* Initialize CommDlgExtendedError() */
483 COMDLG32_SetCommDlgExtendedError(0);
484
485 /* Initialize FileOpenDlgInfos structure */
486 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
487
488 /* Pass in the original ofn */
489 fodInfos.ofnInfos = ofn;
490
491 fodInfos.title = ofn->lpstrTitle;
492 fodInfos.defext = ofn->lpstrDefExt;
493 fodInfos.filter = ofn->lpstrFilter;
494 fodInfos.customfilter = ofn->lpstrCustomFilter;
495
496 /* convert string arguments, save others */
497 if(ofn->lpstrFile)
498 {
499 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
500 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
501 }
502 else
503 fodInfos.filename = NULL;
504
505 if(ofn->lpstrInitialDir)
506 {
507 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
508 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
509 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
510 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
511 }
512 else
513 fodInfos.initdir = NULL;
514
515 /* save current directory */
516 if (ofn->Flags & OFN_NOCHANGEDIR)
517 {
518 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
519 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
520 }
521
522 fodInfos.unicode = TRUE;
523
524 switch(iDlgType)
525 {
526 case OPEN_DIALOG :
527 ret = GetFileName95(&fodInfos);
528 break;
529 case SAVE_DIALOG :
530 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
531 ret = GetFileName95(&fodInfos);
532 break;
533 default :
534 ret = FALSE;
535 }
536
537 /* set the lpstrFileTitle */
538 if (ret && ofn->lpstrFile && ofn->lpstrFileTitle)
539 {
540 LPWSTR lpstrFileTitle = PathFindFileNameW(ofn->lpstrFile);
541 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
542 }
543
544 if (lpstrSavDir)
545 {
546 SetCurrentDirectoryW(lpstrSavDir);
547 MemFree(lpstrSavDir);
548 }
549
550 /* restore saved IN arguments and convert OUT arguments back */
551 MemFree(fodInfos.filename);
552 MemFree(fodInfos.initdir);
553 return ret;
554 }
555
556 /******************************************************************************
557 * COMDLG32_GetDisplayNameOf [internal]
558 *
559 * Helper function to get the display name for a pidl.
560 */
561 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
562 LPSHELLFOLDER psfDesktop;
563 STRRET strret;
564
565 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
566 return FALSE;
567
568 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
569 IShellFolder_Release(psfDesktop);
570 return FALSE;
571 }
572
573 IShellFolder_Release(psfDesktop);
574 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
575 }
576
577 /******************************************************************************
578 * COMDLG32_GetCanonicalPath [internal]
579 *
580 * Helper function to get the canonical path.
581 */
582 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
583 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
584 {
585 WCHAR lpstrTemp[MAX_PATH];
586
587 /* Get the current directory name */
588 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
589 {
590 /* last fallback */
591 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
592 }
593 PathAddBackslashW(lpstrPathAndFile);
594
595 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
596
597 /* if the user specified a fully qualified path use it */
598 if(PathIsRelativeW(lpstrFile))
599 {
600 lstrcatW(lpstrPathAndFile, lpstrFile);
601 }
602 else
603 {
604 /* does the path have a drive letter? */
605 if (PathGetDriveNumberW(lpstrFile) == -1)
606 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
607 else
608 lstrcpyW(lpstrPathAndFile, lpstrFile);
609 }
610
611 /* resolve "." and ".." */
612 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
613 lstrcpyW(lpstrPathAndFile, lpstrTemp);
614 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
615 }
616
617 /***********************************************************************
618 * COMDLG32_SplitFileNames [internal]
619 *
620 * Creates a delimited list of filenames.
621 */
622 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
623 {
624 UINT nStrCharCount = 0; /* index in src buffer */
625 UINT nFileIndex = 0; /* index in dest buffer */
626 UINT nFileCount = 0; /* number of files */
627
628 /* we might get single filename without any '"',
629 * so we need nStrLen + terminating \0 + end-of-list \0 */
630 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
631 *sizeUsed = 0;
632
633 /* build delimited file list from filenames */
634 while ( nStrCharCount <= nStrLen )
635 {
636 if ( lpstrEdit[nStrCharCount]=='"' )
637 {
638 nStrCharCount++;
639 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
640 {
641 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
642 nStrCharCount++;
643 }
644 (*lpstrFileList)[nFileIndex++] = 0;
645 nFileCount++;
646 }
647 nStrCharCount++;
648 }
649
650 /* single, unquoted string */
651 if ((nStrLen > 0) && (nFileIndex == 0) )
652 {
653 lstrcpyW(*lpstrFileList, lpstrEdit);
654 nFileIndex = lstrlenW(lpstrEdit) + 1;
655 nFileCount = 1;
656 }
657
658 /* trailing \0 */
659 (*lpstrFileList)[nFileIndex++] = '\0';
660
661 *sizeUsed = nFileIndex;
662 return nFileCount;
663 }
664
665 /***********************************************************************
666 * ArrangeCtrlPositions [internal]
667 *
668 * NOTE: Make sure to add testcases for any changes made here.
669 */
670 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
671 {
672 HWND hwndChild, hwndStc32;
673 RECT rectParent, rectChild, rectStc32;
674 INT help_fixup = 0;
675 int chgx, chgy;
676
677 /* Take into account if open as read only checkbox and help button
678 * are hidden
679 */
680 if (hide_help)
681 {
682 RECT rectHelp, rectCancel;
683 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
684 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
685 /* subtract the height of the help button plus the space between
686 * the help button and the cancel button to the height of the dialog
687 */
688 help_fixup = rectHelp.bottom - rectCancel.bottom;
689 }
690
691 /*
692 There are two possibilities to add components to the default file dialog box.
693
694 By default, all the new components are added below the standard dialog box (the else case).
695
696 However, if there is a static text component with the stc32 id, a special case happens.
697 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
698 in the window and the cx and cy indicate how to size the window.
699 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
700 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
701
702 */
703
704 GetClientRect(hwndParentDlg, &rectParent);
705
706 /* when arranging controls we have to use fixed parent size */
707 rectParent.bottom -= help_fixup;
708
709 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
710 if (hwndStc32)
711 {
712 GetWindowRect(hwndStc32, &rectStc32);
713 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
714
715 /* set the size of the stc32 control according to the size of
716 * client area of the parent dialog
717 */
718 SetWindowPos(hwndStc32, 0,
719 0, 0,
720 rectParent.right, rectParent.bottom,
721 SWP_NOMOVE | SWP_NOZORDER);
722 }
723 else
724 SetRectEmpty(&rectStc32);
725
726 /* this part moves controls of the child dialog */
727 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
728 while (hwndChild)
729 {
730 if (hwndChild != hwndStc32)
731 {
732 GetWindowRect(hwndChild, &rectChild);
733 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
734
735 /* move only if stc32 exist */
736 if (hwndStc32 && rectChild.left > rectStc32.right)
737 {
738 /* move to the right of visible controls of the parent dialog */
739 rectChild.left += rectParent.right;
740 rectChild.left -= rectStc32.right;
741 }
742 /* move even if stc32 doesn't exist */
743 if (rectChild.top >= rectStc32.bottom)
744 {
745 /* move below visible controls of the parent dialog */
746 rectChild.top += rectParent.bottom;
747 rectChild.top -= rectStc32.bottom - rectStc32.top;
748 }
749
750 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
751 0, 0, SWP_NOSIZE | SWP_NOZORDER);
752 }
753 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
754 }
755
756 /* this part moves controls of the parent dialog */
757 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
758 while (hwndChild)
759 {
760 if (hwndChild != hwndChildDlg)
761 {
762 GetWindowRect(hwndChild, &rectChild);
763 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
764
765 /* left,top of stc32 marks the position of controls
766 * from the parent dialog
767 */
768 rectChild.left += rectStc32.left;
769 rectChild.top += rectStc32.top;
770
771 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
772 0, 0, SWP_NOSIZE | SWP_NOZORDER);
773 }
774 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
775 }
776
777 /* calculate the size of the resulting dialog */
778
779 /* here we have to use original parent size */
780 GetClientRect(hwndParentDlg, &rectParent);
781 GetClientRect(hwndChildDlg, &rectChild);
782 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
783 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
784
785 if (hwndStc32)
786 {
787 /* width */
788 if (rectParent.right > rectStc32.right - rectStc32.left)
789 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
790 else
791 chgx = rectChild.right - rectParent.right;
792 /* height */
793 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
794 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
795 else
796 /* Unconditionally set new dialog
797 * height to that of the child
798 */
799 chgy = rectChild.bottom - rectParent.bottom;
800 }
801 else
802 {
803 chgx = 0;
804 chgy = rectChild.bottom - help_fixup;
805 }
806 /* set the size of the parent dialog */
807 GetWindowRect(hwndParentDlg, &rectParent);
808 SetWindowPos(hwndParentDlg, 0,
809 0, 0,
810 rectParent.right - rectParent.left + chgx,
811 rectParent.bottom - rectParent.top + chgy,
812 SWP_NOMOVE | SWP_NOZORDER);
813 }
814
815 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
816 {
817 switch(uMsg) {
818 case WM_INITDIALOG:
819 return TRUE;
820 }
821 return FALSE;
822 }
823
824 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
825 {
826 LPCVOID template;
827 HRSRC hRes;
828 HANDLE hDlgTmpl = 0;
829 HWND hChildDlg = 0;
830
831 TRACE("\n");
832
833 /*
834 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
835 * structure's hInstance parameter is not a HINSTANCE, but
836 * instead a pointer to a template resource to use.
837 */
838 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
839 {
840 HINSTANCE hinst;
841 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
842 {
843 hinst = COMDLG32_hInstance;
844 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
845 {
846 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
847 return NULL;
848 }
849 }
850 else
851 {
852 hinst = fodInfos->ofnInfos->hInstance;
853 if(fodInfos->unicode)
854 {
855 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
856 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
857 }
858 else
859 {
860 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
861 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
862 }
863 if (!hRes)
864 {
865 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
866 return NULL;
867 }
868 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
869 !(template = LockResource( hDlgTmpl )))
870 {
871 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
872 return NULL;
873 }
874 }
875 if (fodInfos->unicode)
876 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
877 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
878 (LPARAM)fodInfos->ofnInfos);
879 else
880 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
881 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
882 (LPARAM)fodInfos->ofnInfos);
883 return hChildDlg;
884 }
885 else if( IsHooked(fodInfos))
886 {
887 RECT rectHwnd;
888 struct {
889 DLGTEMPLATE tmplate;
890 WORD menu,class,title;
891 } temp;
892 GetClientRect(hwnd,&rectHwnd);
893 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
894 temp.tmplate.dwExtendedStyle = 0;
895 temp.tmplate.cdit = 0;
896 temp.tmplate.x = 0;
897 temp.tmplate.y = 0;
898 temp.tmplate.cx = 0;
899 temp.tmplate.cy = 0;
900 temp.menu = temp.class = temp.title = 0;
901
902 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
903 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
904
905 return hChildDlg;
906 }
907 return NULL;
908 }
909
910 /***********************************************************************
911 * SendCustomDlgNotificationMessage
912 *
913 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
914 */
915
916 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
917 {
918 LRESULT hook_result = 0;
919 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
920
921 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
922
923 if(!fodInfos) return 0;
924
925 if(fodInfos->DlgInfos.hwndCustomDlg)
926 {
927 TRACE("CALL NOTIFY for %x\n", uCode);
928 if(fodInfos->unicode)
929 {
930 OFNOTIFYW ofnNotify;
931 ofnNotify.hdr.hwndFrom=hwndParentDlg;
932 ofnNotify.hdr.idFrom=0;
933 ofnNotify.hdr.code = uCode;
934 ofnNotify.lpOFN = fodInfos->ofnInfos;
935 ofnNotify.pszFile = NULL;
936 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
937 }
938 else
939 {
940 OFNOTIFYA ofnNotify;
941 ofnNotify.hdr.hwndFrom=hwndParentDlg;
942 ofnNotify.hdr.idFrom=0;
943 ofnNotify.hdr.code = uCode;
944 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
945 ofnNotify.pszFile = NULL;
946 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
947 }
948 TRACE("RET NOTIFY\n");
949 }
950 TRACE("Retval: 0x%08lx\n", hook_result);
951 return hook_result;
952 }
953
954 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
955 {
956 UINT len, total;
957 WCHAR *p, *buffer;
958 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
959
960 TRACE("CDM_GETFILEPATH:\n");
961
962 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
963 return -1;
964
965 /* get path and filenames */
966 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
967 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
968 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
969 if (len)
970 {
971 p = buffer + strlenW(buffer);
972 *p++ = '\\';
973 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
974 }
975 if (fodInfos->unicode)
976 {
977 total = strlenW( buffer) + 1;
978 if (result) lstrcpynW( result, buffer, size );
979 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
980 }
981 else
982 {
983 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
984 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
985 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
986 }
987 HeapFree( GetProcessHeap(), 0, buffer );
988 return total;
989 }
990
991 /***********************************************************************
992 * FILEDLG95_HandleCustomDialogMessages
993 *
994 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
995 */
996 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
997 {
998 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
999 WCHAR lpstrPath[MAX_PATH];
1000 INT_PTR retval;
1001
1002 if(!fodInfos) return FALSE;
1003
1004 switch(uMsg)
1005 {
1006 case CDM_GETFILEPATH:
1007 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1008 break;
1009
1010 case CDM_GETFOLDERPATH:
1011 TRACE("CDM_GETFOLDERPATH:\n");
1012 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1013 if (lParam)
1014 {
1015 if (fodInfos->unicode)
1016 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1017 else
1018 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1019 (LPSTR)lParam, (int)wParam, NULL, NULL);
1020 }
1021 retval = lstrlenW(lpstrPath) + 1;
1022 break;
1023
1024 case CDM_GETFOLDERIDLIST:
1025 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1026 if (retval <= wParam)
1027 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1028 break;
1029
1030 case CDM_GETSPEC:
1031 TRACE("CDM_GETSPEC:\n");
1032 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1033 if (lParam)
1034 {
1035 if (fodInfos->unicode)
1036 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1037 else
1038 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1039 }
1040 break;
1041
1042 case CDM_SETCONTROLTEXT:
1043 TRACE("CDM_SETCONTROLTEXT:\n");
1044 if ( lParam )
1045 {
1046 if( fodInfos->unicode )
1047 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1048 else
1049 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1050 }
1051 retval = TRUE;
1052 break;
1053
1054 case CDM_HIDECONTROL:
1055 /* MSDN states that it should fail for not OFN_EXPLORER case */
1056 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1057 {
1058 HWND control = GetDlgItem( hwnd, wParam );
1059 if (control) ShowWindow( control, SW_HIDE );
1060 retval = TRUE;
1061 }
1062 else retval = FALSE;
1063 break;
1064
1065 default:
1066 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1067 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1068 return FALSE;
1069 }
1070 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1071 return TRUE;
1072 }
1073
1074 /***********************************************************************
1075 * FILEDLG95_OnWMGetMMI
1076 *
1077 * WM_GETMINMAXINFO message handler for resizable dialogs
1078 */
1079 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1080 {
1081 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1082 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1083 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1084 {
1085 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1086 }
1087 return TRUE;
1088 }
1089
1090 /***********************************************************************
1091 * FILEDLG95_OnWMSize
1092 *
1093 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1094 *
1095 * FIXME: this could be made more elaborate. Now use a simple scheme
1096 * where the file view is enlarged and the controls are either moved
1097 * vertically or horizontally to get out of the way. Only the "grip"
1098 * is moved in both directions to stay in the corner.
1099 */
1100 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1101 {
1102 RECT rc, rcview;
1103 int chgx, chgy;
1104 HWND ctrl;
1105 HDWP hdwp;
1106 FileOpenDlgInfos *fodInfos;
1107
1108 if( wParam != SIZE_RESTORED) return FALSE;
1109 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1110 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1111 /* get the new dialog rectangle */
1112 GetWindowRect( hwnd, &rc);
1113 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1114 rc.right -rc.left, rc.bottom -rc.top);
1115 /* not initialized yet */
1116 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1117 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1118 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1119 return FALSE;
1120 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1121 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1122 fodInfos->sizedlg.cx = rc.right - rc.left;
1123 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1124 /* change the size of the view window */
1125 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1126 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1127 hdwp = BeginDeferWindowPos( 10);
1128 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1129 rcview.right - rcview.left + chgx,
1130 rcview.bottom - rcview.top + chgy,
1131 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1132 /* change position and sizes of the controls */
1133 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1134 {
1135 int ctrlid = GetDlgCtrlID( ctrl);
1136 GetWindowRect( ctrl, &rc);
1137 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1138 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1139 {
1140 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1141 0, 0,
1142 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1143 }
1144 else if( rc.top > rcview.bottom)
1145 {
1146 /* if it was below the shell view
1147 * move to bottom */
1148 switch( ctrlid)
1149 {
1150 /* file name (edit or comboboxex) and file types combo change also width */
1151 case edt1:
1152 case cmb13:
1153 case cmb1:
1154 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1155 rc.right - rc.left + chgx, rc.bottom - rc.top,
1156 SWP_NOACTIVATE | SWP_NOZORDER);
1157 break;
1158 /* then these buttons must move out of the way */
1159 case IDOK:
1160 case IDCANCEL:
1161 case pshHelp:
1162 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1163 0, 0,
1164 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1165 break;
1166 default:
1167 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1168 0, 0,
1169 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1170 }
1171 }
1172 else if( rc.left > rcview.right)
1173 {
1174 /* if it was to the right of the shell view
1175 * move to right */
1176 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1177 0, 0,
1178 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1179 }
1180 else
1181 /* special cases */
1182 {
1183 switch( ctrlid)
1184 {
1185 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1186 case IDC_LOOKIN:
1187 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1188 rc.right - rc.left + chgx, rc.bottom - rc.top,
1189 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1190 break;
1191 case IDC_TOOLBARSTATIC:
1192 case IDC_TOOLBAR:
1193 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1194 0, 0,
1195 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1196 break;
1197 #endif
1198 /* not resized in windows. Since wine uses this invisible control
1199 * to size the browser view it needs to be resized */
1200 case IDC_SHELLSTATIC:
1201 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1202 rc.right - rc.left + chgx,
1203 rc.bottom - rc.top + chgy,
1204 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1205 break;
1206 }
1207 }
1208 }
1209 if(fodInfos->DlgInfos.hwndCustomDlg &&
1210 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1211 {
1212 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1213 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1214 {
1215 GetWindowRect( ctrl, &rc);
1216 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1217 if( rc.top > rcview.bottom)
1218 {
1219 /* if it was below the shell view
1220 * move to bottom */
1221 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1222 rc.right - rc.left, rc.bottom - rc.top,
1223 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1224 }
1225 else if( rc.left > rcview.right)
1226 {
1227 /* if it was to the right of the shell view
1228 * move to right */
1229 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1230 rc.right - rc.left, rc.bottom - rc.top,
1231 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1232 }
1233 }
1234 /* size the custom dialog at the end: some applications do some
1235 * control re-arranging at this point */
1236 GetClientRect(hwnd, &rc);
1237 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1238 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1239 }
1240 EndDeferWindowPos( hdwp);
1241 /* should not be needed */
1242 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1243 return TRUE;
1244 }
1245
1246 /***********************************************************************
1247 * FileOpenDlgProc95
1248 *
1249 * File open dialog procedure
1250 */
1251 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1252 {
1253 #if 0
1254 TRACE("%p 0x%04x\n", hwnd, uMsg);
1255 #endif
1256
1257 switch(uMsg)
1258 {
1259 case WM_INITDIALOG:
1260 {
1261 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1262 RECT rc, rcstc;
1263 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1264 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1265
1266 /* Adds the FileOpenDlgInfos in the property list of the dialog
1267 so it will be easily accessible through a GetPropA(...) */
1268 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1269
1270 FILEDLG95_InitControls(hwnd);
1271
1272 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1273 {
1274 GetWindowRect( hwnd, &rc);
1275 fodInfos->DlgInfos.hwndGrip =
1276 CreateWindowExA( 0, "SCROLLBAR", NULL,
1277 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1278 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1279 rc.right - gripx, rc.bottom - gripy,
1280 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1281 }
1282
1283 fodInfos->DlgInfos.hwndCustomDlg =
1284 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1285
1286 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1287 FILEDLG95_FillControls(hwnd, wParam, lParam);
1288
1289 if( fodInfos->DlgInfos.hwndCustomDlg)
1290 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1291
1292 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1293 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1294 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1295 }
1296
1297 /* if the app has changed the position of the invisible listbox,
1298 * change that of the listview (browser) as well */
1299 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1300 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1301 if( !EqualRect( &rc, &rcstc))
1302 {
1303 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1304 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1305 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1306 SWP_NOACTIVATE | SWP_NOZORDER);
1307 }
1308
1309 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1310 {
1311 GetWindowRect( hwnd, &rc);
1312 fodInfos->sizedlg.cx = rc.right - rc.left;
1313 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1314 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1315 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1316 GetClientRect( hwnd, &rc);
1317 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1318 rc.right - gripx, rc.bottom - gripy,
1319 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1320 /* resize the dialog to the previous invocation */
1321 if( MemDialogSize.cx && MemDialogSize.cy)
1322 SetWindowPos( hwnd, NULL,
1323 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1324 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1325 }
1326
1327 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1328 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1329
1330 return 0;
1331 }
1332 case WM_SIZE:
1333 return FILEDLG95_OnWMSize(hwnd, wParam);
1334 case WM_GETMINMAXINFO:
1335 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1336 case WM_COMMAND:
1337 return FILEDLG95_OnWMCommand(hwnd, wParam);
1338 case WM_DRAWITEM:
1339 {
1340 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1341 {
1342 case IDC_LOOKIN:
1343 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1344 return TRUE;
1345 }
1346 }
1347 return FALSE;
1348
1349 case WM_GETISHELLBROWSER:
1350 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1351
1352 case WM_DESTROY:
1353 {
1354 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1355 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1356 MemDialogSize = fodInfos->sizedlg;
1357 RemovePropA(hwnd, FileOpenDlgInfosStr);
1358 return FALSE;
1359 }
1360 case WM_NOTIFY:
1361 {
1362 LPNMHDR lpnmh = (LPNMHDR)lParam;
1363 UINT stringId = -1;
1364
1365 /* set up the button tooltips strings */
1366 if(TTN_GETDISPINFOA == lpnmh->code )
1367 {
1368 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1369 switch(lpnmh->idFrom )
1370 {
1371 /* Up folder button */
1372 case FCIDM_TB_UPFOLDER:
1373 stringId = IDS_UPFOLDER;
1374 break;
1375 /* New folder button */
1376 case FCIDM_TB_NEWFOLDER:
1377 stringId = IDS_NEWFOLDER;
1378 break;
1379 /* List option button */
1380 case FCIDM_TB_SMALLICON:
1381 stringId = IDS_LISTVIEW;
1382 break;
1383 /* Details option button */
1384 case FCIDM_TB_REPORTVIEW:
1385 stringId = IDS_REPORTVIEW;
1386 break;
1387 /* Desktop button */
1388 case FCIDM_TB_DESKTOP:
1389 stringId = IDS_TODESKTOP;
1390 break;
1391 default:
1392 stringId = 0;
1393 }
1394 lpdi->hinst = COMDLG32_hInstance;
1395 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1396 }
1397 return FALSE;
1398 }
1399 default :
1400 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1401 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1402 return FALSE;
1403 }
1404 }
1405
1406 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1407 {
1408 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1409 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1410 }
1411
1412 /***********************************************************************
1413 * FILEDLG95_InitControls
1414 *
1415 * WM_INITDIALOG message handler (before hook notification)
1416 */
1417 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1418 {
1419 BOOL win2000plus = FALSE;
1420 BOOL win98plus = FALSE;
1421 BOOL handledPath = FALSE;
1422 OSVERSIONINFOW osVi;
1423 static const WCHAR szwSlash[] = { '\\', 0 };
1424 static const WCHAR szwStar[] = { '*',0 };
1425
1426 static const TBBUTTON tbb[] =
1427 {
1428 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1429 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1430 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1431 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1432 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1433 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1434 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1435 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1436 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1437 };
1438 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1439
1440 RECT rectTB;
1441 RECT rectlook;
1442
1443 HIMAGELIST toolbarImageList;
1444 SHFILEINFOA shFileInfo;
1445 ITEMIDLIST *desktopPidl;
1446
1447 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1448
1449 TRACE("%p\n", fodInfos);
1450
1451 /* Get windows version emulating */
1452 osVi.dwOSVersionInfoSize = sizeof(osVi);
1453 GetVersionExW(&osVi);
1454 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1455 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1456 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1457 win2000plus = (osVi.dwMajorVersion > 4);
1458 if (win2000plus) win98plus = TRUE;
1459 }
1460 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1461
1462
1463 /* Use either the edit or the comboboxex for the filename control */
1464 if (filename_is_edit( fodInfos ))
1465 {
1466 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1467 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1468 }
1469 else
1470 {
1471 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1472 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1473 }
1474
1475 /* Get the hwnd of the controls */
1476 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1477 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1478
1479 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1480 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1481
1482 /* construct the toolbar */
1483 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1484 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1485
1486 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1487 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1488 rectTB.left = rectlook.right;
1489 rectTB.top = rectlook.top-1;
1490
1491 if (fodInfos->unicode)
1492 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1493 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1494 rectTB.left, rectTB.top,
1495 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1496 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1497 else
1498 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1499 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1500 rectTB.left, rectTB.top,
1501 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1502 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1503
1504 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1505
1506 /* FIXME: use TB_LOADIMAGES when implemented */
1507 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1508 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1509 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1510
1511 /* Retrieve and add desktop icon to the toolbar */
1512 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1513 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1514 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1515 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1516 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1517
1518 DestroyIcon(shFileInfo.hIcon);
1519 CoTaskMemFree(desktopPidl);
1520
1521 /* Finish Toolbar Construction */
1522 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1523 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1524
1525 /* Set the window text with the text specified in the OPENFILENAME structure */
1526 if(fodInfos->title)
1527 {
1528 SetWindowTextW(hwnd,fodInfos->title);
1529 }
1530 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1531 {
1532 WCHAR buf[64];
1533 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1534 SetWindowTextW(hwnd, buf);
1535 }
1536
1537 /* Initialise the file name edit control */
1538 handledPath = FALSE;
1539 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1540
1541 if(fodInfos->filename)
1542 {
1543 /* 1. If win2000 or higher and filename contains a path, use it
1544 in preference over the lpstrInitialDir */
1545 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1546 WCHAR tmpBuf[MAX_PATH];
1547 WCHAR *nameBit;
1548 DWORD result;
1549
1550 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1551 if (result) {
1552
1553 /* nameBit is always shorter than the original filename. It may be NULL
1554 * when the filename contains only a drive name instead of file name */
1555 if (nameBit)
1556 {
1557 lstrcpyW(fodInfos->filename,nameBit);
1558 *nameBit = 0x00;
1559 }
1560 else
1561 *fodInfos->filename = '\0';
1562
1563 MemFree(fodInfos->initdir);
1564 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1565 lstrcpyW(fodInfos->initdir, tmpBuf);
1566 handledPath = TRUE;
1567 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1568 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1569 }
1570 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1571
1572 } else {
1573 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1574 }
1575 }
1576
1577 /* 2. (All platforms) If initdir is not null, then use it */
1578 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1579 {
1580 /* Work out the proper path as supplied one might be relative */
1581 /* (Here because supplying '.' as dir browses to My Computer) */
1582 WCHAR tmpBuf[MAX_PATH];
1583 WCHAR tmpBuf2[MAX_PATH];
1584 WCHAR *nameBit;
1585 DWORD result;
1586
1587 lstrcpyW(tmpBuf, fodInfos->initdir);
1588 if (PathFileExistsW(tmpBuf)) {
1589 /* initdir does not have to be a directory. If a file is
1590 * specified, the dir part is taken */
1591 if (PathIsDirectoryW(tmpBuf)) {
1592 PathAddBackslashW(tmpBuf);
1593 lstrcatW(tmpBuf, szwStar);
1594 }
1595 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1596 if (result) {
1597 *nameBit = 0x00;
1598 MemFree(fodInfos->initdir);
1599 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1600 lstrcpyW(fodInfos->initdir, tmpBuf2);
1601 handledPath = TRUE;
1602 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1603 }
1604 }
1605 else if (fodInfos->initdir)
1606 {
1607 MemFree(fodInfos->initdir);
1608 fodInfos->initdir = NULL;
1609 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1610 }
1611 }
1612
1613 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1614 {
1615 /* 3. All except w2k+: if filename contains a path use it */
1616 if (!win2000plus && fodInfos->filename &&
1617 *fodInfos->filename &&
1618 strpbrkW(fodInfos->filename, szwSlash)) {
1619 WCHAR tmpBuf[MAX_PATH];
1620 WCHAR *nameBit;
1621 DWORD result;
1622
1623 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1624 tmpBuf, &nameBit);
1625 if (result) {
1626 int len;
1627
1628 /* nameBit is always shorter than the original filename */
1629 lstrcpyW(fodInfos->filename, nameBit);
1630 *nameBit = 0x00;
1631
1632 len = lstrlenW(tmpBuf);
1633 MemFree(fodInfos->initdir);
1634 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1635 lstrcpyW(fodInfos->initdir, tmpBuf);
1636
1637 handledPath = TRUE;
1638 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1639 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1640 }
1641 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1642 }
1643
1644 /* 4. Win2000+: Recently used */
1645 if (!handledPath && win2000plus) {
1646 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1647 fodInfos->initdir[0] = '\0';
1648
1649 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1650
1651 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1652 handledPath = TRUE;
1653 }else{
1654 MemFree(fodInfos->initdir);
1655 fodInfos->initdir = NULL;
1656 }
1657 }
1658
1659 /* 5. win98+ and win2000+ if any files of specified filter types in
1660 current directory, use it */
1661 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1662
1663 LPCWSTR lpstrPos = fodInfos->filter;
1664 WIN32_FIND_DATAW FindFileData;
1665 HANDLE hFind;
1666
1667 while (1)
1668 {
1669 /* filter is a list... title\0ext\0......\0\0 */
1670
1671 /* Skip the title */
1672 if(! *lpstrPos) break; /* end */
1673 lpstrPos += lstrlenW(lpstrPos) + 1;
1674
1675 /* See if any files exist in the current dir with this extension */
1676 if(! *lpstrPos) break; /* end */
1677
1678 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1679
1680 if (hFind == INVALID_HANDLE_VALUE) {
1681 /* None found - continue search */
1682 lpstrPos += lstrlenW(lpstrPos) + 1;
1683
1684 } else {
1685
1686 MemFree(fodInfos->initdir);
1687 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1688 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1689
1690 handledPath = TRUE;
1691 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1692 debugstr_w(lpstrPos));
1693 FindClose(hFind);
1694 break;
1695 }
1696 }
1697 }
1698
1699 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1700 if (!handledPath && (win2000plus || win98plus)) {
1701 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1702
1703 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1704 {
1705 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1706 {
1707 /* last fallback */
1708 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1709 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1710 } else {
1711 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1712 }
1713 } else {
1714 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1715 }
1716 handledPath = TRUE;
1717 } else if (!handledPath) {
1718 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1719 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1720 handledPath = TRUE;
1721 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1722 }
1723 }
1724 SetFocus( fodInfos->DlgInfos.hwndFileName );
1725 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1726
1727 /* Must the open as read only check box be checked ?*/
1728 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1729 {
1730 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1731 }
1732
1733 /* Must the open as read only check box be hidden? */
1734 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1735 {
1736 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1737 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1738 }
1739
1740 /* Must the help button be hidden? */
1741 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1742 {
1743 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1744 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1745 }
1746
1747 /* change Open to Save */
1748 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1749 {
1750 WCHAR buf[16];
1751 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1752 SetDlgItemTextW(hwnd, IDOK, buf);
1753 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1754 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1755 }
1756
1757 /* Initialize the filter combo box */
1758 FILEDLG95_FILETYPE_Init(hwnd);
1759
1760 return 0;
1761 }
1762
1763 /***********************************************************************
1764 * FILEDLG95_ResizeControls
1765 *
1766 * WM_INITDIALOG message handler (after hook notification)
1767 */
1768 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1769 {
1770 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1771
1772 if (fodInfos->DlgInfos.hwndCustomDlg)
1773 {
1774 RECT rc;
1775 UINT flags = SWP_NOACTIVATE;
1776
1777 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1778 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1779
1780 /* resize the custom dialog to the parent size */
1781 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1782 GetClientRect(hwnd, &rc);
1783 else
1784 {
1785 /* our own fake template is zero sized and doesn't have children, so
1786 * there is no need to resize it. Picasa depends on it.
1787 */
1788 flags |= SWP_NOSIZE;
1789 SetRectEmpty(&rc);
1790 }
1791 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1792 0, 0, rc.right, rc.bottom, flags);
1793 }
1794 else
1795 {
1796 /* Resize the height; if opened as read-only, checkbox and help button are
1797 * hidden and we are not using a custom template nor a customDialog
1798 */
1799 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1800 (!(fodInfos->ofnInfos->Flags &
1801 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1802 {
1803 RECT rectDlg, rectHelp, rectCancel;
1804 GetWindowRect(hwnd, &rectDlg);
1805 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1806 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1807 /* subtract the height of the help button plus the space between the help
1808 * button and the cancel button to the height of the dialog
1809 */
1810 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1811 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1812 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1813 }
1814 }
1815 return TRUE;
1816 }
1817
1818 /***********************************************************************
1819 * FILEDLG95_FillControls
1820 *
1821 * WM_INITDIALOG message handler (after hook notification)
1822 */
1823 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1824 {
1825 LPITEMIDLIST pidlItemId = NULL;
1826
1827 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1828
1829 TRACE("dir=%s file=%s\n",
1830 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1831
1832 /* Get the initial directory pidl */
1833
1834 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1835 {
1836 WCHAR path[MAX_PATH];
1837
1838 GetCurrentDirectoryW(MAX_PATH,path);
1839 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1840 }
1841
1842 /* Initialise shell objects */
1843 FILEDLG95_SHELL_Init(hwnd);
1844
1845 /* Initialize the Look In combo box */
1846 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1847
1848 /* Browse to the initial directory */
1849 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1850
1851 /* Free pidlItem memory */
1852 COMDLG32_SHFree(pidlItemId);
1853
1854 return TRUE;
1855 }
1856 /***********************************************************************
1857 * FILEDLG95_Clean
1858 *
1859 * Regroups all the cleaning functions of the filedlg
1860 */
1861 void FILEDLG95_Clean(HWND hwnd)
1862 {
1863 FILEDLG95_FILETYPE_Clean(hwnd);
1864 FILEDLG95_LOOKIN_Clean(hwnd);
1865 FILEDLG95_SHELL_Clean(hwnd);
1866 }
1867 /***********************************************************************
1868 * FILEDLG95_OnWMCommand
1869 *
1870 * WM_COMMAND message handler
1871 */
1872 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1873 {
1874 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1875 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1876 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1877
1878 switch(wID)
1879 {
1880 /* OK button */
1881 case IDOK:
1882 FILEDLG95_OnOpen(hwnd);
1883 break;
1884 /* Cancel button */
1885 case IDCANCEL:
1886 FILEDLG95_Clean(hwnd);
1887 EndDialog(hwnd, FALSE);
1888 break;
1889 /* Filetype combo box */
1890 case IDC_FILETYPE:
1891 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1892 break;
1893 /* LookIn combo box */
1894 case IDC_LOOKIN:
1895 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1896 break;
1897
1898 /* --- toolbar --- */
1899 /* Up folder button */
1900 case FCIDM_TB_UPFOLDER:
1901 FILEDLG95_SHELL_UpFolder(hwnd);
1902 break;
1903 /* New folder button */
1904 case FCIDM_TB_NEWFOLDER:
1905 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1906 break;
1907 /* List option button */
1908 case FCIDM_TB_SMALLICON:
1909 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1910 break;
1911 /* Details option button */
1912 case FCIDM_TB_REPORTVIEW:
1913 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1914 break;
1915 /* Details option button */
1916 case FCIDM_TB_DESKTOP:
1917 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1918 break;
1919
1920 case edt1:
1921 case cmb13:
1922 break;
1923
1924 }
1925 /* Do not use the listview selection anymore */
1926 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1927 return 0;
1928 }
1929
1930 /***********************************************************************
1931 * FILEDLG95_OnWMGetIShellBrowser
1932 *
1933 * WM_GETISHELLBROWSER message handler
1934 */
1935 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1936 {
1937 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1938
1939 TRACE("\n");
1940
1941 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1942
1943 return TRUE;
1944 }
1945
1946
1947 /***********************************************************************
1948 * FILEDLG95_SendFileOK
1949 *
1950 * Sends the CDN_FILEOK notification if required
1951 *
1952 * RETURNS
1953 * TRUE if the dialog should close
1954 * FALSE if the dialog should not be closed
1955 */
1956 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1957 {
1958 /* ask the hook if we can close */
1959 if(IsHooked(fodInfos))
1960 {
1961 LRESULT retval = 0;
1962
1963 TRACE("---\n");
1964 /* First send CDN_FILEOK as MSDN doc says */
1965 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1966 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1967 if( retval)
1968 {
1969 TRACE("canceled\n");
1970 return FALSE;
1971 }
1972
1973 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1974 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1975 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1976 if( retval)
1977 {
1978 TRACE("canceled\n");
1979 return FALSE;
1980 }
1981 }
1982 return TRUE;
1983 }
1984
1985 /***********************************************************************
1986 * FILEDLG95_OnOpenMultipleFiles
1987 *
1988 * Handles the opening of multiple files.
1989 *
1990 * FIXME
1991 * check destination buffer size
1992 */
1993 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1994 {
1995 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1996 UINT nCount, nSizePath;
1997 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1998
1999 TRACE("\n");
2000
2001 if(fodInfos->unicode)
2002 {
2003 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2004 ofn->lpstrFile[0] = '\0';
2005 }
2006 else
2007 {
2008 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2009 ofn->lpstrFile[0] = '\0';
2010 }
2011
2012 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2013
2014 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2015 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2016 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2017 {
2018 LPWSTR lpstrTemp = lpstrFileList;
2019
2020 for ( nCount = 0; nCount < nFileCount; nCount++ )
2021 {
2022 LPITEMIDLIST pidl;
2023
2024 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2025 if (!pidl)
2026 {
2027 WCHAR lpstrNotFound[100];
2028 WCHAR lpstrMsg[100];
2029 WCHAR tmp[400];
2030 static const WCHAR nl[] = {'\n',0};
2031
2032 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2033 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2034
2035 lstrcpyW(tmp, lpstrTemp);
2036 lstrcatW(tmp, nl);
2037 lstrcatW(tmp, lpstrNotFound);
2038 lstrcatW(tmp, nl);
2039 lstrcatW(tmp, lpstrMsg);
2040
2041 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2042 return FALSE;
2043 }
2044
2045 /* move to the next file in the list of files */
2046 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2047 COMDLG32_SHFree(pidl);
2048 }
2049 }
2050
2051 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2052 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2053 {
2054 /* For "oldstyle" dialog the components have to
2055 be separated by blanks (not '\0'!) and short
2056 filenames have to be used! */
2057 FIXME("Components have to be separated by blanks\n");
2058 }
2059 if(fodInfos->unicode)
2060 {
2061 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2062 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2063 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2064 }
2065 else
2066 {
2067 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2068
2069 if (ofn->lpstrFile != NULL)
2070 {
2071 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2072 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2073 if (ofn->nMaxFile > nSizePath)
2074 {
2075 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2076 ofn->lpstrFile + nSizePath,
2077 ofn->nMaxFile - nSizePath, NULL, NULL);
2078 }
2079 }
2080 }
2081
2082 fodInfos->ofnInfos->nFileOffset = nSizePath;
2083 fodInfos->ofnInfos->nFileExtension = 0;
2084
2085 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2086 return FALSE;
2087
2088 /* clean and exit */
2089 FILEDLG95_Clean(hwnd);
2090 return EndDialog(hwnd,TRUE);
2091 }
2092
2093 /* Returns the 'slot name' of the given module_name in the registry's
2094 * most-recently-used list. This will be an ASCII value in the
2095 * range ['a','z'). Returns zero on error.
2096 *
2097 * The slot's value in the registry has the form:
2098 * module_name\0mru_path\0
2099 *
2100 * If stored_path is given, then stored_path will contain the path name
2101 * stored in the registry's MRU list for the given module_name.
2102 *
2103 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2104 * MRU list key for the given module_name.
2105 */
2106 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2107 {
2108 WCHAR mru_list[32], *cur_mru_slot;
2109 BOOL taken[25] = {0};
2110 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2111 HKEY hkey_tmp, *hkey;
2112 LONG ret;
2113
2114 if(hkey_ret)
2115 hkey = hkey_ret;
2116 else
2117 hkey = &hkey_tmp;
2118
2119 if(stored_path)
2120 *stored_path = '\0';
2121
2122 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2123 if(ret){
2124 WARN("Unable to create MRU key: %d\n", ret);
2125 return 0;
2126 }
2127
2128 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2129 (LPBYTE)mru_list, &mru_list_size);
2130 if(ret || key_type != REG_SZ){
2131 if(ret == ERROR_FILE_NOT_FOUND)
2132 return 'a';
2133
2134 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2135 RegCloseKey(*hkey);
2136 return 0;
2137 }
2138
2139 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2140 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2141 DWORD value_data_size = sizeof(value_data);
2142
2143 *value_name = *cur_mru_slot;
2144
2145 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2146 &key_type, (LPBYTE)value_data, &value_data_size);
2147 if(ret || key_type != REG_BINARY){
2148 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2149 continue;
2150 }
2151
2152 if(!strcmpiW(module_name, value_data)){
2153 if(!hkey_ret)
2154 RegCloseKey(*hkey);
2155 if(stored_path)
2156 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2157 return *value_name;
2158 }
2159 }
2160
2161 if(!hkey_ret)
2162 RegCloseKey(*hkey);
2163
2164 /* the module name isn't in the registry, so find the next open slot */
2165 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2166 taken[*cur_mru_slot - 'a'] = TRUE;
2167 for(i = 0; i < 25; ++i){
2168 if(!taken[i])
2169 return i + 'a';
2170 }
2171
2172 /* all slots are taken, so return the last one in MRUList */
2173 --cur_mru_slot;
2174 return *cur_mru_slot;
2175 }
2176
2177 /* save the given filename as most-recently-used path for this module */
2178 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2179 {
2180 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2181 LONG ret;
2182 HKEY hkey;
2183
2184 /* get the current executable's name */
2185 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2186 WARN("GotModuleFileName failed: %d\n", GetLastError());
2187 return;
2188 }
2189 module_name = strrchrW(module_path, '\\');
2190 if(!module_name)
2191 module_name = module_path;
2192 else
2193 module_name += 1;
2194
2195 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2196 if(!slot)
2197 return;
2198 *slot_name = slot;
2199
2200 { /* update the slot's info */
2201 WCHAR *path_ends, *final;
2202 DWORD path_len, final_len;
2203
2204 /* use only the path segment of `filename' */
2205 path_ends = strrchrW(filename, '\\');
2206 path_len = path_ends - filename;
2207
2208 final_len = path_len + lstrlenW(module_name) + 2;
2209
2210 final = MemAlloc(final_len * sizeof(WCHAR));
2211 if(!final)
2212 return;
2213 lstrcpyW(final, module_name);
2214 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2215 final[final_len-1] = '\0';
2216
2217 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2218 final_len * sizeof(WCHAR));
2219 if(ret){
2220 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2221 MemFree(final);
2222 RegCloseKey(hkey);
2223 return;
2224 }
2225
2226 MemFree(final);
2227 }
2228
2229 { /* update MRUList value */
2230 WCHAR old_mru_list[32], new_mru_list[32];
2231 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2232 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2233
2234 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2235 (LPBYTE)old_mru_list, &mru_list_size);
2236 if(ret || key_type != REG_SZ){
2237 if(ret == ERROR_FILE_NOT_FOUND){
2238 new_mru_list[0] = slot;
2239 new_mru_list[1] = '\0';
2240 }else{
2241 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2242 RegCloseKey(hkey);
2243 return;
2244 }
2245 }else{
2246 /* copy old list data over so that the new slot is at the start
2247 * of the list */
2248 *new_mru_slot++ = slot;
2249 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2250 if(*old_mru_slot != slot)
2251 *new_mru_slot++ = *old_mru_slot;
2252 }
2253 *new_mru_slot = '\0';
2254 }
2255
2256 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2257 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2258 if(ret){
2259 WARN("Error saving MRUList data: %d\n", ret);
2260 RegCloseKey(hkey);
2261 return;
2262 }
2263 }
2264 }
2265
2266 /* load the most-recently-used path for this module */
2267 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2268 {
2269 WCHAR module_path[MAX_PATH], *module_name;
2270
2271 /* get the current executable's name */
2272 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2273 WARN("GotModuleFileName failed: %d\n", GetLastError());
2274 return;
2275 }
2276 module_name = strrchrW(module_path, '\\');
2277 if(!module_name)
2278 module_name = module_path;
2279 else
2280 module_name += 1;
2281
2282 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2283 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2284 }
2285
2286 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2287 {
2288 WCHAR strMsgTitle[MAX_PATH];
2289 WCHAR strMsgText [MAX_PATH];
2290 if (idCaption)
2291 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2292 else
2293 strMsgTitle[0] = '\0';
2294 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2295 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2296 }
2297
2298 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2299 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2300 {
2301 int nOpenAction = defAction;
2302 LPWSTR lpszTemp, lpszTemp1;
2303 LPITEMIDLIST pidl = NULL;
2304 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2305
2306 /* check for invalid chars */
2307 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2308 {
2309 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2310 return FALSE;
2311 }
2312
2313 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2314
2315 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2316 while (lpszTemp1)
2317 {
2318 LPSHELLFOLDER lpsfChild;
2319 WCHAR lpwstrTemp[MAX_PATH];
2320 DWORD dwEaten, dwAttributes;
2321 LPWSTR p;
2322
2323 lstrcpyW(lpwstrTemp, lpszTemp);
2324 p = PathFindNextComponentW(lpwstrTemp);
2325
2326 if (!p) break; /* end of path */
2327
2328 *p = 0;
2329 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2330
2331 /* There are no wildcards when OFN_NOVALIDATE is set */
2332 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2333 {
2334 static const WCHAR wszWild[] = { '*', '?', 0 };
2335 /* if the last element is a wildcard do a search */
2336 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2337 {
2338 nOpenAction = ONOPEN_SEARCH;
2339 break;
2340 }
2341 }
2342 lpszTemp1 = lpszTemp;
2343
2344 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2345
2346 /* append a backslash to drive letters */
2347 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2348 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2349 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2350 {
2351 PathAddBackslashW(lpwstrTemp);
2352 }
2353
2354 dwAttributes = SFGAO_FOLDER;
2355 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2356 {
2357 /* the path component is valid, we have a pidl of the next path component */
2358 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2359 if(dwAttributes & SFGAO_FOLDER)
2360 {
2361 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2362 {
2363 ERR("bind to failed\n"); /* should not fail */
2364 break;
2365 }
2366 IShellFolder_Release(*ppsf);
2367 *ppsf = lpsfChild;
2368 lpsfChild = NULL;
2369 }
2370 else
2371 {
2372 TRACE("value\n");
2373
2374 /* end dialog, return value */
2375 nOpenAction = ONOPEN_OPEN;
2376 break;
2377 }
2378 COMDLG32_SHFree(pidl);
2379 pidl = NULL;
2380 }
2381 else if (!(flags & OFN_NOVALIDATE))
2382 {
2383 if(*lpszTemp || /* points to trailing null for last path element */
2384 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2385 {
2386 if(flags & OFN_PATHMUSTEXIST)
2387 {
2388 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2389 break;
2390 }
2391 }
2392 else
2393 {
2394 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2395 {
2396 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2397 break;
2398 }
2399 }
2400 /* change to the current folder */
2401 nOpenAction = ONOPEN_OPEN;
2402 break;
2403 }
2404 else
2405 {
2406 nOpenAction = ONOPEN_OPEN;
2407 break;
2408 }
2409 }
2410 if(pidl) COMDLG32_SHFree(pidl);
2411
2412 return nOpenAction;
2413 }
2414
2415 /***********************************************************************
2416 * FILEDLG95_OnOpen
2417 *
2418 * Ok button WM_COMMAND message handler
2419 *
2420 * If the function succeeds, the return value is nonzero.
2421 */
2422 BOOL FILEDLG95_OnOpen(HWND hwnd)
2423 {
2424 LPWSTR lpstrFileList;
2425 UINT nFileCount = 0;
2426 UINT sizeUsed = 0;
2427 BOOL ret = TRUE;
2428 WCHAR lpstrPathAndFile[MAX_PATH];
2429 LPSHELLFOLDER lpsf = NULL;
2430 int nOpenAction;
2431 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2432
2433 TRACE("hwnd=%p\n", hwnd);
2434
2435 /* try to browse the selected item */
2436 if(BrowseSelectedFolder(hwnd))
2437 return FALSE;
2438
2439 /* get the files from the edit control */
2440 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2441
2442 if(nFileCount == 0)
2443 return FALSE;
2444
2445 if(nFileCount > 1)
2446 {
2447 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2448 goto ret;
2449 }
2450
2451 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2452
2453 /*
2454 Step 1: Build a complete path name from the current folder and
2455 the filename or path in the edit box.
2456 Special cases:
2457 - the path in the edit box is a root path
2458 (with or without drive letter)
2459 - the edit box contains ".." (or a path with ".." in it)
2460 */
2461
2462 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2463 MemFree(lpstrFileList);
2464
2465 /*
2466 Step 2: here we have a cleaned up path
2467
2468 We have to parse the path step by step to see if we have to browse
2469 to a folder if the path points to a directory or the last
2470 valid element is a directory.
2471
2472 valid variables:
2473 lpstrPathAndFile: cleaned up path
2474 */
2475
2476 if (nFileCount &&
2477 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2478 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2479 nOpenAction = ONOPEN_OPEN;
2480 else
2481 nOpenAction = ONOPEN_BROWSE;
2482
2483 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2484 fodInfos->ofnInfos->Flags,
2485 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2486 nOpenAction);
2487 if(!nOpenAction)
2488 goto ret;
2489
2490 /*
2491 Step 3: here we have a cleaned up and validated path
2492
2493 valid variables:
2494 lpsf: ShellFolder bound to the rightmost valid path component
2495 lpstrPathAndFile: cleaned up path
2496 nOpenAction: action to do
2497 */
2498 TRACE("end validate sf=%p\n", lpsf);
2499
2500 switch(nOpenAction)
2501 {
2502 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2503 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2504 {
2505 int iPos;
2506 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2507 DWORD len;
2508
2509 /* replace the current filter */
2510 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2511 len = lstrlenW(lpszTemp)+1;
2512 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2513 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2514
2515 /* set the filter cb to the extension when possible */
2516 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2517 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2518 }
2519 /* fall through */
2520 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2521 TRACE("ONOPEN_BROWSE\n");
2522 {
2523 IPersistFolder2 * ppf2;
2524 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2525 {
2526 LPITEMIDLIST pidlCurrent;
2527 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2528 IPersistFolder2_Release(ppf2);
2529 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2530 {
2531 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2532 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2533 {
2534 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2535 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2536 }
2537 }
2538 else if( nOpenAction == ONOPEN_SEARCH )
2539 {
2540 if (fodInfos->Shell.FOIShellView)
2541 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2542 }
2543 COMDLG32_SHFree(pidlCurrent);
2544 if (filename_is_edit( fodInfos ))
2545 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2546 else
2547 {
2548 HWND hwnd;
2549
2550 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2551 SendMessageW(hwnd, EM_SETSEL, 0, -1);
2552 }
2553 }
2554 }
2555 ret = FALSE;
2556 break;
2557 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2558 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2559 {
2560 WCHAR *ext = NULL;
2561
2562 /* update READONLY check box flag */
2563 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2564 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2565 else
2566 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2567
2568 /* Attach the file extension with file name*/
2569 ext = PathFindExtensionW(lpstrPathAndFile);
2570 if (! *ext && fodInfos->defext)
2571 {
2572 /* if no extension is specified with file name, then */
2573 /* attach the extension from file filter or default one */
2574
2575 WCHAR *filterExt = NULL;
2576 LPWSTR lpstrFilter = NULL;
2577 static const WCHAR szwDot[] = {'.',0};
2578 int PathLength = lstrlenW(lpstrPathAndFile);
2579
2580 /*Get the file extension from file type filter*/
2581 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2582 fodInfos->ofnInfos->nFilterIndex-1);
2583
2584 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2585 {
2586 WCHAR* filterSearchIndex;
2587 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2588 strcpyW(filterExt, lpstrFilter);
2589
2590 /* if a semicolon-separated list of file extensions was given, do not include the
2591 semicolon or anything after it in the extension.
2592 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2593 filterSearchIndex = strchrW(filterExt, ';');
2594 if (filterSearchIndex)
2595 {
2596 filterSearchIndex[0] = '\0';
2597 }
2598
2599 /* find the file extension by searching for the first dot in filterExt */
2600 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2601 /* if the extension is invalid or contains a glob, ignore it */
2602 filterSearchIndex = strchrW(filterExt, '.');
2603 if (filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2604 {
2605 strcpyW(filterExt, filterSearchIndex);
2606 }
2607 else
2608 {
2609 HeapFree(GetProcessHeap(), 0, filterExt);
2610 filterExt = NULL;
2611 }
2612 }
2613
2614 if (!filterExt)
2615 {
2616 /* use the default file extension */
2617 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2618 strcpyW(filterExt, fodInfos->defext);
2619 }
2620
2621 if (*filterExt) /* ignore filterExt="" */
2622 {
2623 /* Attach the dot*/
2624 lstrcatW(lpstrPathAndFile, szwDot);
2625 /* Attach the extension */
2626 lstrcatW(lpstrPathAndFile, filterExt);
2627 }
2628
2629 HeapFree(GetProcessHeap(), 0, filterExt);
2630
2631 /* In Open dialog: if file does not exist try without extension */
2632 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2633 lpstrPathAndFile[PathLength] = '\0';
2634
2635 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2636 if (*ext)
2637 ext++;
2638 if (!lstrcmpiW(fodInfos->defext, ext))
2639 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2640 else
2641 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2642 }
2643
2644 /* In Save dialog: check if the file already exists */
2645 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2646 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2647 && PathFileExistsW(lpstrPathAndFile))
2648 {
2649 WCHAR lpstrOverwrite[100];
2650 int answer;
2651
2652 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2653 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2654 MB_YESNO | MB_ICONEXCLAMATION);
2655 if (answer == IDNO || answer == IDCANCEL)
2656 {
2657 ret = FALSE;
2658 goto ret;
2659 }
2660 }
2661
2662 /* In Open dialog: check if it should be created if it doesn't exist */
2663 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2664 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2665 && !PathFileExistsW(lpstrPathAndFile))
2666 {
2667 WCHAR lpstrCreate[100];
2668 int answer;
2669
2670 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2671 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2672 MB_YESNO | MB_ICONEXCLAMATION);
2673 if (answer == IDNO || answer == IDCANCEL)
2674 {
2675 ret = FALSE;
2676 goto ret;
2677 }
2678 }
2679
2680 /* Check that the size of the file does not exceed buffer size.
2681 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2682 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2683 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2684 {
2685
2686 /* fill destination buffer */
2687 if (fodInfos->ofnInfos->lpstrFile)
2688 {
2689 if(fodInfos->unicode)
2690 {
2691 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2692
2693 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2694 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2695 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2696 }
2697 else
2698 {
2699 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2700
2701 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2702 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2703 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2704 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2705 }
2706 }
2707
2708 if(fodInfos->unicode)
2709 {
2710 LPWSTR lpszTemp;
2711
2712 /* set filename offset */
2713 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2714 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2715
2716 /* set extension offset */
2717 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2718 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2719 }
2720 else
2721 {
2722 LPSTR lpszTemp;
2723 CHAR tempFileA[MAX_PATH];
2724
2725 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2726 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2727 tempFileA, sizeof(tempFileA), NULL, NULL);
2728
2729 /* set filename offset */
2730 lpszTemp = PathFindFileNameA(tempFileA);
2731 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2732
2733 /* set extension offset */
2734 lpszTemp = PathFindExtensionA(tempFileA);
2735 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2736 }
2737
2738 /* copy currently selected filter to lpstrCustomFilter */
2739 if (fodInfos->ofnInfos->lpstrCustomFilter)
2740 {
2741 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2742 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2743 NULL, 0, NULL, NULL);
2744 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2745 {
2746 LPSTR s = ofn->lpstrCustomFilter;
2747 s += strlen(ofn->lpstrCustomFilter)+1;
2748 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2749 s, len, NULL, NULL);
2750 }
2751 }
2752
2753
2754 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2755 goto ret;
2756
2757 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2758
2759 TRACE("close\n");
2760 FILEDLG95_Clean(hwnd);
2761 ret = EndDialog(hwnd, TRUE);
2762 }
2763 else
2764 {
2765 WORD size;
2766
2767 size = lstrlenW(lpstrPathAndFile) + 1;
2768 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2769 size += 1;
2770 /* return needed size in first two bytes of lpstrFile */
2771 if(fodInfos->ofnInfos->lpstrFile)
2772 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2773 FILEDLG95_Clean(hwnd);
2774 ret = EndDialog(hwnd, FALSE);
2775 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2776 }
2777 }
2778 break;
2779 }
2780
2781 ret:
2782 if(lpsf) IShellFolder_Release(lpsf);
2783 return ret;
2784 }
2785
2786 /***********************************************************************
2787 * FILEDLG95_SHELL_Init
2788 *
2789 * Initialisation of the shell objects
2790 */
2791 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2792 {
2793 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2794
2795 TRACE("\n");
2796
2797 /*
2798 * Initialisation of the FileOpenDialogInfos structure
2799 */
2800
2801 /* Shell */
2802
2803 /*ShellInfos */
2804 fodInfos->ShellInfos.hwndOwner = hwnd;
2805
2806 /* Disable multi-select if flag not set */
2807 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2808 {
2809 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2810 }
2811 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2812 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2813
2814 /* Construct the IShellBrowser interface */
2815 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2816
2817 return NOERROR;
2818 }
2819
2820 /***********************************************************************
2821 * FILEDLG95_SHELL_ExecuteCommand
2822 *
2823 * Change the folder option and refresh the view
2824 * If the function succeeds, the return value is nonzero.
2825 */
2826 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2827 {
2828 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2829 IContextMenu * pcm;
2830
2831 TRACE("(%p,%p)\n", hwnd, lpVerb);
2832
2833 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2834 SVGIO_BACKGROUND,
2835 &IID_IContextMenu,
2836 (LPVOID*)&pcm)))
2837 {
2838 CMINVOKECOMMANDINFO ci;
2839 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2840 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2841 ci.lpVerb = lpVerb;
2842 ci.hwnd = hwnd;
2843
2844 IContextMenu_InvokeCommand(pcm, &ci);
2845 IContextMenu_Release(pcm);
2846 }
2847
2848 return FALSE;
2849 }
2850
2851 /***********************************************************************
2852 * FILEDLG95_SHELL_UpFolder
2853 *
2854 * Browse to the specified object
2855 * If the function succeeds, the return value is nonzero.
2856 */
2857 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2858 {
2859 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2860
2861 TRACE("\n");
2862
2863 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2864 NULL,
2865 SBSP_PARENT)))
2866 {
2867 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2868 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2869 return TRUE;
2870 }
2871 return FALSE;
2872 }
2873
2874 /***********************************************************************
2875 * FILEDLG95_SHELL_BrowseToDesktop
2876 *
2877 * Browse to the Desktop
2878 * If the function succeeds, the return value is nonzero.
2879 */
2880 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2881 {
2882 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2883 LPITEMIDLIST pidl;
2884 HRESULT hres;
2885
2886 TRACE("\n");
2887
2888 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2889 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2890 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2891 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2892 COMDLG32_SHFree(pidl);
2893 return SUCCEEDED(hres);
2894 }
2895 /***********************************************************************
2896 * FILEDLG95_SHELL_Clean
2897 *
2898 * Cleans the memory used by shell objects
2899 */
2900 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2901 {
2902 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2903
2904 TRACE("\n");
2905
2906 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2907
2908 /* clean Shell interfaces */
2909 if (fodInfos->Shell.FOIShellView)
2910 {
2911 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2912 IShellView_Release(fodInfos->Shell.FOIShellView);
2913 }
2914 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2915 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2916 if (fodInfos->Shell.FOIDataObject)
2917 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2918 }
2919
2920 /***********************************************************************
2921 * FILEDLG95_FILETYPE_Init
2922 *
2923 * Initialisation of the file type combo box
2924 */
2925 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2926 {
2927 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2928 int nFilters = 0; /* number of filters */
2929 int nFilterIndexCB;
2930
2931 TRACE("\n");
2932
2933 if(fodInfos->customfilter)
2934 {
2935 /* customfilter has one entry... title\0ext\0
2936 * Set first entry of combo box item with customfilter
2937 */
2938 LPWSTR lpstrExt;
2939 LPCWSTR lpstrPos = fodInfos->customfilter;
2940
2941 /* Get the title */
2942 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2943
2944 /* Copy the extensions */
2945 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2946 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2947 lstrcpyW(lpstrExt,lpstrPos);
2948
2949 /* Add the item at the end of the combo */
2950 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2951 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2952 nFilters++;
2953 }
2954 if(fodInfos->filter)
2955 {
2956 LPCWSTR lpstrPos = fodInfos->filter;
2957
2958 for(;;)
2959 {
2960 /* filter is a list... title\0ext\0......\0\0
2961 * Set the combo item text to the title and the item data
2962 * to the ext
2963 */
2964 LPCWSTR lpstrDisplay;
2965 LPWSTR lpstrExt;
2966
2967 /* Get the title */
2968 if(! *lpstrPos) break; /* end */
2969 lpstrDisplay = lpstrPos;
2970 lpstrPos += lstrlenW(lpstrPos) + 1;
2971
2972 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2973
2974 nFilters++;
2975
2976 /* Copy the extensions */
2977 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2978 lstrcpyW(lpstrExt,lpstrPos);
2979 lpstrPos += lstrlenW(lpstrPos) + 1;
2980
2981 /* Add the item at the end of the combo */
2982 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2983
2984 /* malformed filters are added anyway... */
2985 if (!*lpstrExt) break;
2986 }
2987 }
2988
2989 /*
2990 * Set the current filter to the one specified
2991 * in the initialisation structure
2992 */
2993 if (fodInfos->filter || fodInfos->customfilter)
2994 {
2995 LPWSTR lpstrFilter;
2996
2997 /* Check to make sure our index isn't out of bounds. */
2998 if ( fodInfos->ofnInfos->nFilterIndex >
2999 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3000 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3001
3002 /* set default filter index */
3003 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3004 fodInfos->ofnInfos->nFilterIndex = 1;
3005
3006 /* calculate index of Combo Box item */
3007 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3008 if (fodInfos->customfilter == NULL)
3009 nFilterIndexCB--;
3010
3011 /* Set the current index selection. */
3012 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3013
3014 /* Get the corresponding text string from the combo box. */
3015 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3016 nFilterIndexCB);
3017
3018 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3019 lpstrFilter = NULL;
3020
3021 if(lpstrFilter)
3022 {
3023 DWORD len;
3024 CharLowerW(lpstrFilter); /* lowercase */
3025 len = lstrlenW(lpstrFilter)+1;
3026 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3027 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3028 }
3029 } else
3030 fodInfos->ofnInfos->nFilterIndex = 0;
3031 return S_OK;
3032 }
3033
3034 /***********************************************************************
3035 * FILEDLG95_FILETYPE_OnCommand
3036 *
3037 * WM_COMMAND of the file type combo box
3038 * If the function succeeds, the return value is nonzero.
3039 */
3040 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3041 {
3042 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3043
3044 switch(wNotifyCode)
3045 {
3046 case CBN_SELENDOK:
3047 {
3048 LPWSTR lpstrFilter;
3049
3050 /* Get the current item of the filetype combo box */
3051 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3052
3053 /* set the current filter index */
3054 fodInfos->ofnInfos->nFilterIndex = iItem +
3055 (fodInfos->customfilter == NULL ? 1 : 0);
3056
3057 /* Set the current filter with the current selection */
3058 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3059
3060 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3061 iItem);
3062 if((INT_PTR)lpstrFilter != CB_ERR)
3063 {
3064 DWORD len;
3065 CharLowerW(lpstrFilter); /* lowercase */
3066 len = lstrlenW(lpstrFilter)+1;
3067 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3068 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3069 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3070 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3071 }
3072
3073 /* Refresh the actual view to display the included items*/
3074 if (fodInfos->Shell.FOIShellView)
3075 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3076 }
3077 }
3078 return FALSE;
3079 }
3080 /***********************************************************************
3081 * FILEDLG95_FILETYPE_SearchExt
3082 *
3083 * searches for an extension in the filetype box
3084 */
3085 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3086 {
3087 int i, iCount = CBGetCount(hwnd);
3088
3089 TRACE("%s\n", debugstr_w(lpstrExt));
3090
3091 if(iCount != CB_ERR)
3092 {
3093 for(i=0;i<iCount;i++)
3094 {
3095 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3096 return i;
3097 }
3098 }
3099 return -1;
3100 }
3101
3102 /***********************************************************************
3103 * FILEDLG95_FILETYPE_Clean
3104 *
3105 * Clean the memory used by the filetype combo box
3106 */
3107 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3108 {
3109 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3110 int iPos;
3111 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3112
3113 TRACE("\n");
3114
3115 /* Delete each string of the combo and their associated data */
3116 if(iCount != CB_ERR)
3117 {
3118 for(iPos = iCount-1;iPos>=0;iPos--)
3119 {
3120 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3121 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3122 }
3123 }
3124 /* Current filter */
3125 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3126
3127 }
3128
3129 /***********************************************************************
3130 * FILEDLG95_LOOKIN_Init
3131 *
3132 * Initialisation of the look in combo box
3133 */
3134
3135 /* Small helper function, to determine if the unixfs shell extension is rooted
3136 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3137 */
3138 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3139 HKEY hKey;
3140 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3141 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3142 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3143 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3144 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3145 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3146 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3147
3148 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3149 return FALSE;
3150
3151 RegCloseKey(hKey);
3152 return TRUE;
3153 }
3154
3155 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3156 {
3157 IShellFolder *psfRoot, *psfDrives;
3158 IEnumIDList *lpeRoot, *lpeDrives;
3159 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3160 HDC hdc;
3161 TEXTMETRICW tm;
3162 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3163
3164 TRACE("\n");
3165
3166 liInfos->iMaxIndentation = 0;
3167
3168 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3169
3170 hdc = GetDC( hwndCombo );
3171 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3172 GetTextMetricsW( hdc, &tm );
3173 ReleaseDC( hwndCombo, hdc );
3174
3175 /* set item height for both text field and listbox */
3176 CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3177 CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3178
3179 /* Turn on the extended UI for the combo box like Windows does */
3180 CBSetExtendedUI(hwndCombo, TRUE);
3181
3182 /* Initialise data of Desktop folder */
3183 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3184 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3185 COMDLG32_SHFree(pidlTmp);
3186
3187 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3188
3189 SHGetDesktopFolder(&psfRoot);
3190
3191 if (psfRoot)
3192 {
3193 /* enumerate the contents of the desktop */
3194 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3195 {
3196 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3197 {
3198 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3199
3200 /* If the unixfs extension is rooted, we don't expand the drives by default */
3201 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3202 {
3203 /* special handling for CSIDL_DRIVES */
3204 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3205 {
3206 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3207 {
3208 /* enumerate the drives */
3209 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3210 {
3211 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3212 {
3213 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3214 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3215 COMDLG32_SHFree(pidlAbsTmp);
3216 COMDLG32_SHFree(pidlTmp1);
3217 }
3218 IEnumIDList_Release(lpeDrives);
3219 }
3220 IShellFolder_Release(psfDrives);
3221 }
3222 }
3223 }
3224
3225 COMDLG32_SHFree(pidlTmp);
3226 }
3227 IEnumIDList_Release(lpeRoot);
3228 }
3229 IShellFolder_Release(psfRoot);
3230 }
3231
3232 COMDLG32_SHFree(pidlDrives);
3233 }
3234
3235 /***********************************************************************
3236 * FILEDLG95_LOOKIN_DrawItem
3237 *
3238 * WM_DRAWITEM message handler
3239 */
3240 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3241 {
3242 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3243 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3244 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3245 RECT rectText;
3246 RECT rectIcon;
3247 SHFILEINFOW sfi;
3248 HIMAGELIST ilItemImage;
3249 int iIndentation;
3250 TEXTMETRICW tm;
3251 LPSFOLDER tmpFolder;
3252 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3253 UINT icon_width, icon_height;
3254
3255 TRACE("\n");
3256
3257 if(pDIStruct->itemID == -1)
3258 return 0;
3259
3260 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3261 pDIStruct->itemID)))
3262 return 0;
3263
3264
3265 icon_width = GetSystemMetrics(SM_CXICON);
3266 icon_height = GetSystemMetrics(SM_CYICON);
3267 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3268 {
3269 icon_width = GetSystemMetrics(SM_CXSMICON);
3270 icon_height = GetSystemMetrics(SM_CYSMICON);
3271 shgfi_flags |= SHGFI_SMALLICON;
3272 }
3273
3274 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3275 0, &sfi, sizeof (sfi), shgfi_flags );
3276
3277 /* Is this item selected ? */
3278 if(pDIStruct->itemState & ODS_SELECTED)
3279 {
3280 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3281 SetBkColor(pDIStruct->hDC,crHighLight);
3282 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3283 }
3284 else
3285 {
3286 SetTextColor(pDIStruct->hDC,crText);
3287 SetBkColor(pDIStruct->hDC,crWin);
3288 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3289 }
3290
3291 /* Do not indent item if drawing in the edit of the combo */
3292 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3293 iIndentation = 0;
3294 else
3295 iIndentation = tmpFolder->m_iIndent;
3296
3297 /* Draw text and icon */
3298
3299 /* Initialise the icon display area */
3300 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3301 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3302 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3303 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3304
3305 /* Initialise the text display area */
3306 GetTextMetricsW(pDIStruct->hDC, &tm);
3307 rectText.left = rectIcon.right;
3308 rectText.top =
3309 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3310 rectText.right = pDIStruct->rcItem.right;
3311 rectText.bottom =
3312 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3313
3314 /* Draw the icon from the image list */
3315 ImageList_Draw(ilItemImage,
3316 sfi.iIcon,
3317 pDIStruct->hDC,
3318 rectIcon.left,
3319 rectIcon.top,
3320 ILD_TRANSPARENT );
3321
3322 /* Draw the associated text */
3323 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3324 return NOERROR;
3325 }
3326
3327 /***********************************************************************
3328 * FILEDLG95_LOOKIN_OnCommand
3329 *
3330 * LookIn combo box WM_COMMAND message handler
3331 * If the function succeeds, the return value is nonzero.
3332 */
3333 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3334 {
3335 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3336
3337 TRACE("%p\n", fodInfos);
3338
3339 switch(wNotifyCode)
3340 {
3341 case CBN_SELENDOK:
3342 {
3343 LPSFOLDER tmpFolder;
3344 int iItem;
3345
3346 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3347
3348 if( iItem == CB_ERR) return FALSE;
3349
3350 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3351 iItem)))
3352 return FALSE;
3353
3354
3355 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3356 tmpFolder->pidlItem,
3357 SBSP_ABSOLUTE)))
3358 {
3359 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3360 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3361 return TRUE;
3362 }
3363 break;
3364 }
3365
3366 }
3367 return FALSE;
3368 }
3369
3370 /***********************************************************************
3371 * FILEDLG95_LOOKIN_AddItem
3372 *
3373 * Adds an absolute pidl item to the lookin combo box
3374 * returns the index of the inserted item
3375 */
3376 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3377 {
3378 LPITEMIDLIST pidlNext;
3379 SHFILEINFOW sfi;
3380 SFOLDER *tmpFolder;
3381 LookInInfos *liInfos;
3382
3383 TRACE("%08x\n", iInsertId);
3384
3385 if(!pidl)
3386 return -1;
3387
3388 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3389 return -1;
3390
3391 tmpFolder = MemAlloc(sizeof(SFOLDER));
3392 tmpFolder->m_iIndent = 0;
3393
3394 /* Calculate the indentation of the item in the lookin*/
3395 pidlNext = pidl;
3396 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3397 {
3398 tmpFolder->m_iIndent++;
3399 }
3400
3401 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3402
3403 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3404 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3405
3406 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3407 SHGetFileInfoW((LPCWSTR)pidl,
3408 0,
3409 &sfi,
3410 sizeof(sfi),
3411 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3412 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3413
3414 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3415
3416 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3417 {
3418 int iItemID;
3419
3420 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3421
3422 /* Add the item at the end of the list */
3423 if(iInsertId < 0)
3424 {
3425 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3426 }
3427 /* Insert the item at the iInsertId position*/
3428 else
3429 {
3430 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3431 }
3432
3433 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3434 return iItemID;
3435 }
3436
3437 COMDLG32_SHFree( tmpFolder->pidlItem );
3438 MemFree( tmpFolder );
3439 return -1;
3440
3441 }
3442
3443 /***********************************************************************
3444 * FILEDLG95_LOOKIN_InsertItemAfterParent
3445 *
3446 * Insert an item below its parent
3447 */
3448 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3449 {
3450
3451 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3452 int iParentPos;
3453
3454 TRACE("\n");
3455
3456 if (pidl == pidlParent)
3457 return -1;
3458
3459 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3460
3461 if(iParentPos < 0)
3462 {
3463 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3464 }
3465
3466 /* Free pidlParent memory */
3467 COMDLG32_SHFree(pidlParent);
3468
3469 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3470 }
3471
3472 /***********************************************************************
3473 * FILEDLG95_LOOKIN_SelectItem
3474 *
3475 * Adds an absolute pidl item to the lookin combo box
3476 * returns the index of the inserted item
3477 */
3478 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3479 {
3480 int iItemPos;
3481 LookInInfos *liInfos;
3482
3483 TRACE("\n");
3484
3485 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3486
3487 liInfos = GetPropA(hwnd,LookInInfosStr);
3488
3489 if(iItemPos < 0)
3490 {
3491 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3492 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3493 }
3494
3495 else
3496 {
3497 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3498 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3499 {
3500 int iRemovedItem;
3501
3502 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3503 break;
3504 if(iRemovedItem < iItemPos)
3505 iItemPos--;
3506 }
3507 }
3508
3509 CBSetCurSel(hwnd,iItemPos);
3510 liInfos->uSelectedItem = iItemPos;
3511
3512 return 0;
3513
3514 }
3515
3516 /***********************************************************************
3517 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3518 *
3519 * Remove the item with an expansion level over iExpansionLevel
3520 */
3521 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3522 {
3523 int iItemPos;
3524 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3525
3526 TRACE("\n");
3527
3528 if(liInfos->iMaxIndentation <= 2)
3529 return -1;
3530
3531 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3532 {
3533 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3534 COMDLG32_SHFree(tmpFolder->pidlItem);
3535 MemFree(tmpFolder);
3536 CBDeleteString(hwnd,iItemPos);
3537 liInfos->iMaxIndentation--;
3538
3539 return iItemPos;
3540 }
3541
3542 return -1;
3543 }
3544
3545 /***********************************************************************
3546 * FILEDLG95_LOOKIN_SearchItem
3547 *
3548 * Search for pidl in the lookin combo box
3549 * returns the index of the found item
3550 */
3551 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3552 {
3553 int i = 0;
3554 int iCount = CBGetCount(hwnd);
3555
3556 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3557
3558 if (iCount != CB_ERR)
3559 {
3560 for(;i<iCount;i++)
3561 {
3562 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3563
3564 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3565 return i;
3566 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3567 return i;
3568 }
3569 }
3570
3571 return -1;
3572 }
3573
3574 /***********************************************************************
3575 * FILEDLG95_LOOKIN_Clean
3576 *
3577 * Clean the memory used by the lookin combo box
3578 */
3579 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3580 {
3581 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3582 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3583 int iPos;
3584 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3585
3586 TRACE("\n");
3587
3588 /* Delete each string of the combo and their associated data */
3589 if (iCount != CB_ERR)
3590 {
3591 for(iPos = iCount-1;iPos>=0;iPos--)
3592 {
3593 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3594 COMDLG32_SHFree(tmpFolder->pidlItem);
3595 MemFree(tmpFolder);
3596 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3597 }
3598 }
3599
3600 /* LookInInfos structure */
3601 MemFree(liInfos);
3602 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3603 }
3604
3605 /***********************************************************************
3606 * get_def_format
3607 *
3608 * Fill the FORMATETC used in the shell id list
3609 */
3610 static FORMATETC get_def_format(void)
3611 {
3612 static CLIPFORMAT cfFormat;
3613 FORMATETC formatetc;
3614
3615 if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3616 formatetc.cfFormat = cfFormat;
3617 formatetc.ptd = 0;
3618 formatetc.dwAspect = DVASPECT_CONTENT;
3619 formatetc.lindex = -1;
3620 formatetc.tymed = TYMED_HGLOBAL;
3621 return formatetc;
3622 }
3623
3624 /***********************************************************************
3625 * FILEDLG95_FILENAME_FillFromSelection
3626 *
3627 * fills the edit box from the cached DataObject
3628 */
3629 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3630 {
3631 FileOpenDlgInfos *fodInfos;
3632 LPITEMIDLIST pidl;
3633 LPWSTR lpstrAllFiles, lpstrTmp;
3634 UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3635 STGMEDIUM medium;
3636 LPIDA cida;
3637 FORMATETC formatetc = get_def_format();
3638
3639 TRACE("\n");
3640 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3641
3642 if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3643 return;
3644
3645 cida = GlobalLock(medium.u.hGlobal);
3646 nFileSelected = cida->cidl;
3647
3648 /* Allocate a buffer */
3649 nAllFilesMaxLength = MAX_PATH + 3;
3650 lpstrAllFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nAllFilesMaxLength * sizeof(WCHAR));
3651 if (!lpstrAllFiles)
3652 goto ret;
3653
3654 /* Loop through the selection, handle only files (not folders) */
3655 for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3656 {
3657 pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3658 if (pidl)
3659 {
3660 if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3661 {
3662 if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3663 {
3664 nAllFilesMaxLength *= 2;
3665 lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3666 if (!lpstrTmp)
3667 goto ret;
3668 lpstrAllFiles = lpstrTmp;
3669 }
3670 nFiles += 1;
3671 lpstrAllFiles[nAllFilesLength++] = '"';
3672 GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3673 nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3674 nAllFilesLength += nThisFileLength;
3675 lpstrAllFiles[nAllFilesLength++] = '"';
3676 lpstrAllFiles[nAllFilesLength++] = ' ';
3677 }
3678 }
3679 }
3680
3681 if (nFiles != 0)
3682 {
3683 /* If there's only one file, use the name as-is without quotes */
3684 lpstrTmp = lpstrAllFiles;
3685 if (nFiles == 1)
3686 {
3687 lpstrTmp += 1;
3688 lpstrTmp[nThisFileLength] = 0;
3689 }
3690 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3691 /* Select the file name like Windows does */
3692 if (filename_is_edit(fodInfos))
3693 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3694 }
3695
3696 ret:
3697 HeapFree(GetProcessHeap(), 0, lpstrAllFiles);
3698 COMCTL32_ReleaseStgMedium(medium);
3699 }
3700
3701
3702 /* copied from shell32 to avoid linking to it
3703 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3704 * is dependent on whether emulated OS is unicode or not.
3705 */
3706 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3707 {
3708 switch (src->uType)
3709 {
3710 case STRRET_WSTR:
3711 lstrcpynW(dest, src->u.pOleStr, len);
3712 COMDLG32_SHFree(src->u.pOleStr);
3713 break;
3714
3715 case STRRET_CSTR:
3716 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3717 dest[len-1] = 0;
3718 break;
3719
3720 case STRRET_OFFSET:
3721 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3722 dest[len-1] = 0;
3723 break;
3724
3725 default:
3726 FIXME("unknown type %x!\n", src->uType);
3727 if (len) *dest = '\0';
3728 return E_FAIL;
3729 }
3730 return S_OK;
3731 }
3732
3733 /***********************************************************************
3734 * FILEDLG95_FILENAME_GetFileNames
3735 *
3736 * Copies the filenames to a delimited string list.
3737 */
3738 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3739 {
3740 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3741 UINT nFileCount = 0; /* number of files */
3742 UINT nStrLen = 0; /* length of string in edit control */
3743 LPWSTR lpstrEdit; /* buffer for string from edit control */
3744
3745 TRACE("\n");
3746
3747 /* get the filenames from the filename control */
3748 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3749 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3750 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3751
3752 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3753
3754 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3755 MemFree(lpstrEdit);
3756 return nFileCount;
3757 }
3758
3759 /*
3760 * DATAOBJECT Helper functions
3761 */
3762
3763 /***********************************************************************
3764 * COMCTL32_ReleaseStgMedium
3765 *
3766 * like ReleaseStgMedium from ole32
3767 */
3768 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3769 {
3770 if(medium.pUnkForRelease)
3771 {
3772 IUnknown_Release(medium.pUnkForRelease);
3773 }
3774 else
3775 {
3776 GlobalUnlock(medium.u.hGlobal);
3777 GlobalFree(medium.u.hGlobal);
3778 }
3779 }
3780
3781 /***********************************************************************
3782 * GetPidlFromDataObject
3783 *
3784 * Return pidl(s) by number from the cached DataObject
3785 *
3786 * nPidlIndex=0 gets the fully qualified root path
3787 */
3788 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3789 {
3790
3791 STGMEDIUM medium;
3792 FORMATETC formatetc = get_def_format();
3793 LPITEMIDLIST pidl = NULL;
3794
3795 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3796
3797 if (!doSelected)
3798 return NULL;
3799
3800 /* Get the pidls from IDataObject */
3801 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3802 {
3803 LPIDA cida = GlobalLock(medium.u.hGlobal);
3804 if(nPidlIndex <= cida->cidl)
3805 {
3806 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3807 }
3808 COMCTL32_ReleaseStgMedium(medium);
3809 }
3810 return pidl;
3811 }
3812
3813 /***********************************************************************
3814 * GetNumSelected
3815 *
3816 * Return the number of selected items in the DataObject.
3817 *
3818 */
3819 static UINT GetNumSelected( IDataObject *doSelected )
3820 {
3821 UINT retVal = 0;
3822 STGMEDIUM medium;
3823 FORMATETC formatetc = get_def_format();
3824
3825 TRACE("sv=%p\n", doSelected);
3826
3827 if (!doSelected) return 0;
3828
3829 /* Get the pidls from IDataObject */
3830 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3831 {
3832 LPIDA cida = GlobalLock(medium.u.hGlobal);
3833 retVal = cida->cidl;
3834 COMCTL32_ReleaseStgMedium(medium);
3835 return retVal;
3836 }
3837 return 0;
3838 }
3839
3840 /*
3841 * TOOLS
3842 */
3843
3844 /***********************************************************************
3845 * GetName
3846 *
3847 * Get the pidl's display name (relative to folder) and
3848 * put it in lpstrFileName.
3849 *
3850 * Return NOERROR on success,
3851 * E_FAIL otherwise
3852 */
3853
3854 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3855 {
3856 STRRET str;
3857 HRESULT hRes;
3858
3859 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3860
3861 if(!lpsf)
3862 {
3863 SHGetDesktopFolder(&lpsf);
3864 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3865 IShellFolder_Release(lpsf);
3866 return hRes;
3867 }
3868
3869 /* Get the display name of the pidl relative to the folder */
3870 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3871 {
3872 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3873 }
3874 return E_FAIL;
3875 }
3876
3877 /***********************************************************************
3878 * GetShellFolderFromPidl
3879 *
3880 * pidlRel is the item pidl relative
3881 * Return the IShellFolder of the absolute pidl
3882 */
3883 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3884 {
3885 IShellFolder *psf = NULL,*psfParent;
3886
3887 TRACE("%p\n", pidlAbs);
3888
3889 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3890 {
3891 psf = psfParent;
3892 if(pidlAbs && pidlAbs->mkid.cb)
3893 {
3894 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3895 {
3896 IShellFolder_Release(psfParent);
3897 return psf;
3898 }
3899 }
3900 /* return the desktop */
3901 return psfParent;
3902 }
3903 return NULL;
3904 }
3905
3906 /***********************************************************************
3907 * GetParentPidl
3908 *
3909 * Return the LPITEMIDLIST to the parent of the pidl in the list
3910 */
3911 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3912 {
3913 LPITEMIDLIST pidlParent;
3914
3915 TRACE("%p\n", pidl);
3916
3917 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3918 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3919
3920 return pidlParent;
3921 }
3922
3923 /***********************************************************************
3924 * GetPidlFromName
3925 *
3926 * returns the pidl of the file name relative to folder
3927 * NULL if an error occurred
3928 */
3929 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3930 {
3931 LPITEMIDLIST pidl = NULL;
3932 ULONG ulEaten;
3933
3934 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3935
3936 if(!lpcstrFileName) return NULL;
3937 if(!*lpcstrFileName) return NULL;
3938
3939 if(!lpsf)
3940 {
3941 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3942 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3943 IShellFolder_Release(lpsf);
3944 }
3945 }
3946 else
3947 {
3948 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3949 }
3950 return pidl;
3951 }
3952
3953 /*
3954 */
3955 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3956 {
3957 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3958 HRESULT ret;
3959
3960 TRACE("%p, %p\n", psf, pidl);
3961
3962 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3963
3964 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3965 /* see documentation shell 4.1*/
3966 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3967 }
3968
3969 /***********************************************************************
3970 * BrowseSelectedFolder
3971 */
3972 static BOOL BrowseSelectedFolder(HWND hwnd)
3973 {
3974 BOOL bBrowseSelFolder = FALSE;
3975 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3976
3977 TRACE("\n");
3978
3979 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3980 {
3981 LPITEMIDLIST pidlSelection;
3982
3983 /* get the file selected */
3984 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3985 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3986 {
3987 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3988 pidlSelection, SBSP_RELATIVE ) ) )
3989 {
3990 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3991 ' ','n','o','t',' ','e','x','i','s','t',0};
3992 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3993 }
3994 bBrowseSelFolder = TRUE;
3995 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3996 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3997 }
3998 COMDLG32_SHFree( pidlSelection );
3999 }
4000
4001 return bBrowseSelFolder;
4002 }
4003
4004 /*
4005 * Memory allocation methods */
4006 static void *MemAlloc(UINT size)
4007 {
4008 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4009 }
4010
4011 static void MemFree(void *mem)
4012 {
4013 HeapFree(GetProcessHeap(),0,mem);
4014 }
4015
4016 static inline BOOL valid_struct_size( DWORD size )
4017 {
4018 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4019 (size == sizeof( OPENFILENAMEW ));
4020 }
4021
4022 static inline BOOL is_win16_looks(DWORD flags)
4023 {
4024 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4025 !(flags & OFN_EXPLORER));
4026 }
4027
4028 /* ------------------ APIs ---------------------- */
4029
4030 /***********************************************************************
4031 * GetOpenFileNameA (COMDLG32.@)
4032 *
4033 * Creates a dialog box for the user to select a file to open.
4034 *
4035 * RETURNS
4036 * TRUE on success: user enters a valid file
4037 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4038 *
4039 */
4040 BOOL WINAPI GetOpenFileNameA(
4041 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4042 {
4043 TRACE("flags %08x\n", ofn->Flags);
4044
4045 if (!valid_struct_size( ofn->lStructSize ))
4046 {
4047 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4048 return FALSE;
4049 }
4050
4051 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4052 if (ofn->Flags & OFN_FILEMUSTEXIST)
4053 ofn->Flags |= OFN_PATHMUSTEXIST;
4054
4055 if (is_win16_looks(ofn->Flags))
4056 return GetFileName31A(ofn, OPEN_DIALOG);
4057 else
4058 return GetFileDialog95A(ofn, OPEN_DIALOG);
4059 }
4060
4061 /***********************************************************************
4062 * GetOpenFileNameW (COMDLG32.@)
4063 *
4064 * Creates a dialog box for the user to select a file to open.
4065 *
4066 * RETURNS
4067 * TRUE on success: user enters a valid file
4068 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4069 *
4070 */
4071 BOOL WINAPI GetOpenFileNameW(
4072 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4073 {
4074 TRACE("flags %08x\n", ofn->Flags);
4075
4076 if (!valid_struct_size( ofn->lStructSize ))
4077 {
4078 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4079 return FALSE;
4080 }
4081
4082 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4083 if (ofn->Flags & OFN_FILEMUSTEXIST)
4084 ofn->Flags |= OFN_PATHMUSTEXIST;
4085
4086 if (is_win16_looks(ofn->Flags))
4087 return GetFileName31W(ofn, OPEN_DIALOG);
4088 else
4089 return GetFileDialog95W(ofn, OPEN_DIALOG);
4090 }
4091
4092
4093 /***********************************************************************
4094 * GetSaveFileNameA (COMDLG32.@)
4095 *
4096 * Creates a dialog box for the user to select a file to save.
4097 *
4098 * RETURNS
4099 * TRUE on success: user enters a valid file
4100 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4101 *
4102 */
4103 BOOL WINAPI GetSaveFileNameA(
4104 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4105 {
4106 if (!valid_struct_size( ofn->lStructSize ))
4107 {
4108 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4109 return FALSE;
4110 }
4111
4112 if (is_win16_looks(ofn->Flags))
4113 return GetFileName31A(ofn, SAVE_DIALOG);
4114 else
4115 return GetFileDialog95A(ofn, SAVE_DIALOG);
4116 }
4117
4118 /***********************************************************************
4119 * GetSaveFileNameW (COMDLG32.@)
4120 *
4121 * Creates a dialog box for the user to select a file to save.
4122 *
4123 * RETURNS
4124 * TRUE on success: user enters a valid file
4125 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4126 *
4127 */
4128 BOOL WINAPI GetSaveFileNameW(
4129 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4130 {
4131 if (!valid_struct_size( ofn->lStructSize ))
4132 {
4133 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4134 return FALSE;
4135 }
4136
4137 if (is_win16_looks(ofn->Flags))
4138 return GetFileName31W(ofn, SAVE_DIALOG);
4139 else
4140 return GetFileDialog95W(ofn, SAVE_DIALOG);
4141 }
4142
4143 /***********************************************************************
4144 * GetFileTitleA (COMDLG32.@)
4145 *
4146 * See GetFileTitleW.
4147 */
4148 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4149 {
4150 int ret;
4151 UNICODE_STRING strWFile;
4152 LPWSTR lpWTitle;
4153
4154 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4155 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4156 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4157 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4158 RtlFreeUnicodeString( &strWFile );
4159 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4160 return ret;
4161 }
4162
4163
4164 /***********************************************************************
4165 * GetFileTitleW (COMDLG32.@)
4166 *
4167 * Get the name of a file.
4168 *
4169 * PARAMS
4170 * lpFile [I] name and location of file
4171 * lpTitle [O] returned file name
4172 * cbBuf [I] buffer size of lpTitle
4173 *
4174 * RETURNS
4175 * Success: zero
4176 * Failure: negative number.
4177 */
4178 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4179 {
4180 int i, len;
4181 static const WCHAR brkpoint[] = {'*','[',']',0};
4182 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4183
4184 if(lpFile == NULL || lpTitle == NULL)
4185 return -1;
4186
4187 len = lstrlenW(lpFile);
4188
4189 if (len == 0)
4190 return -1;
4191
4192 if(strpbrkW(lpFile, brkpoint))
4193 return -1;
4194
4195 len--;
4196
4197 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4198 return -1;
4199
4200 for(i = len; i >= 0; i--)
4201 {
4202 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4203 {
4204 i++;
4205 break;
4206 }
4207 }
4208
4209 if(i == -1)
4210 i++;
4211
4212 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4213
4214 len = lstrlenW(lpFile+i)+1;
4215 if(cbBuf < len)
4216 return len;
4217
4218 lstrcpyW(lpTitle, &lpFile[i]);
4219 return 0;
4220 }