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