ReactOS 0.4.15-dev-8116-gf69e256
filedlg.c
Go to the documentation of this file.
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"
84#endif
85
87
88#define UNIMPLEMENTED_FLAGS \
89(OFN_DONTADDTORECENT |\
90OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
91OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
92
93/***********************************************************************
94 * Data structure and global variables
95 */
96typedef struct SFolder
97{
98 int m_iImageIndex; /* Index of picture in image list */
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102
104
105typedef struct tagLookInInfo
106{
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. */
114static HHOOK s_hFileDialogHook = NULL;
115static LONG s_nFileDialogHookCount = 0;
116
117#define MAX_TRANSLATE 8
118static HWND s_ahwndTranslate[MAX_TRANSLATE] = { NULL };
119
120static 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
133static __inline BOOL
134FILEDLG95_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 */
156static LRESULT CALLBACK
157FILEDLG95_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
217static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
218static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
219
220static 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};
225static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
226
227static const WCHAR filedlg_info_propnameW[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
228
230{
232}
233
235{
236 return (info->ofnInfos->Flags & OFN_ENABLEHOOK) && info->ofnInfos->lpfnHook;
237}
238
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 */
255static void FILEDLG95_Clean(HWND hwnd);
256
257/* Functions used by the shell navigation */
261static void FILEDLG95_SHELL_Clean(HWND hwnd);
262
263/* Functions used by the EDIT box */
264static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
265
266/* Functions used by the filetype combo box */
268static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
269static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
271
272/* Functions used by the Look In combo box */
273static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
275static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
276static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
277static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
281static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
282
283/* Functions for dealing with the most-recently-used registry keys */
284static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
285static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
287#ifdef __REACTOS__
288static void FILEDLG95_MRU_load_ext(LPWSTR stored_path, size_t cchMax, LPCWSTR defext);
289static void FILEDLG95_MRU_save_ext(LPCWSTR filename);
290#endif
291
292/* Miscellaneous tool functions */
293static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
296static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
297static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
298static UINT GetNumSelected( IDataObject *doSelected );
299static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
300
303static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
305
307{
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
321{
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
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
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
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
379{
380 static const int default_places[] =
381 {
382#ifdef __REACTOS__
388#else
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 {
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 */
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
467 {
469 return FALSE;
470 }
471 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
472 !(template = LockResource( hDlgTmpl )))
473 {
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) &&
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)
502 template,
503 fodInfos->ofnInfos->hwndOwner,
505 (LPARAM) fodInfos);
506 else
508 template,
509 fodInfos->ofnInfos->hwndOwner,
511 (LPARAM) fodInfos);
512 if (fodInfos->ole_initialized)
514
515 /* Unable to create the dialog */
516 if( lRes == -1)
517 return FALSE;
518
519 return lRes;
520}
521
522static 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));
533
534 return ret;
535}
536
538{
540
541 /* Initialize ComboBoxEx32 */
542 icc.dwSize = sizeof(icc);
545
546 /* Initialize CommDlgExtendedError() */
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 {
578 if (len)
579 {
580 info->initdir = heap_alloc(len * sizeof(WCHAR));
582 }
583 }
584
585 info->unicode = TRUE;
586}
587
589{
590 OPENFILENAMEW ofnW;
591 int len;
592
593 ofnW = *(OPENFILENAMEW *)ofn;
594
598
599 if (ofn->lpstrFile)
600 {
602 ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR));
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;
618 ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR));
620 }
621
622 /* convert lpstrCustomFilter */
624 {
625 int n, len;
626 LPCSTR s;
627
628 /* customfilter contains a pair of strings... title\0ext\0 */
630 if (*s) s = s+strlen(s)+1;
631 if (*s) s = s+strlen(s)+1;
634 ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR));
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 */
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:
671 break;
672 case SAVE_DIALOG:
673 info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
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);
688 }
689 else
690 {
692 char *file_title = PathFindFileNameA(ofn->lpstrFile);
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 */
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 */
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 */
792int 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 */
840static 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,
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,
983}
984
986{
987 switch(uMsg) {
988 case WM_INITDIALOG:
989 return TRUE;
990 }
991 return FALSE;
992}
993
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 */
1009 {
1011 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
1012 {
1014 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
1015 {
1017 return NULL;
1018 }
1019 }
1020 else
1021 {
1022 hinst = fodInfos->ofnInfos->hInstance;
1023 if(fodInfos->unicode)
1024 {
1025 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1027 }
1028 else
1029 {
1032 }
1033 if (!hRes)
1034 {
1036 return NULL;
1037 }
1038 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
1039 !(template = LockResource( hDlgTmpl )))
1040 {
1042 return NULL;
1043 }
1044 }
1045 if (fodInfos->unicode)
1046 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
1048 (LPARAM)fodInfos->ofnInfos);
1049 else
1050 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
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);
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
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
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
1116{
1117 UINT len, total;
1118 WCHAR *p, *buffer;
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 );
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*/
1158{
1160 WCHAR lpstrPath[MAX_PATH];
1161 INT_PTR retval;
1162
1163 if(!fodInfos) return FALSE;
1164
1165 switch(uMsg)
1166 {
1167 case CDM_GETFILEPATH:
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
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 )
1209 else
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 }
1260 return TRUE;
1261}
1262
1263/***********************************************************************
1264 * FILEDLG95_OnWMGetMMI
1265 *
1266 * WM_GETMINMAXINFO message handler for resizable dialogs
1267 */
1269{
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 */
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,
1321 /* change position and sizes of the controls */
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,
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,
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,
1354 break;
1355 default:
1356 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1357 0, 0,
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,
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,
1379 break;
1380 case IDC_TOOLBARSTATIC:
1381 case IDC_TOOLBAR:
1382 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1383 0, 0,
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,
1394 break;
1395 case IDC_TOOLBARPLACES:
1396 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1398 break;
1399 }
1400 }
1401 }
1402 if(fodInfos->DlgInfos.hwndCustomDlg &&
1404 {
1405 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
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,
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,
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,
1432 }
1433 EndDeferWindowPos( hdwp);
1434 /* should not be needed */
1436 return TRUE;
1437}
1438
1439/***********************************************************************
1440 * FileOpenDlgProc95
1441 *
1442 * File open dialog procedure
1443 */
1445{
1446#if 0
1447 TRACE("%p 0x%04x\n", hwnd, uMsg);
1448#endif
1449
1450 switch(uMsg)
1451 {
1452 case WM_INITDIALOG:
1453 {
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. */
1461 fodInfos->ole_initialized = TRUE;
1462
1464
1466
1467 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1468 {
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;
1481 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1482
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 |
1492
1493 GetWindowRect( hwnd, &rc );
1494 fodInfos->DlgInfos.hwndGrip =
1495 CreateWindowExA( 0, "SCROLLBAR", NULL,
1498 rc.right - gripx, rc.bottom - gripy,
1499 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1500 }
1501
1502 fodInfos->DlgInfos.hwndCustomDlg =
1504
1507
1508 if( fodInfos->DlgInfos.hwndCustomDlg)
1509 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1510
1511 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
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);
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,
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,
1539 /* resize the dialog to the previous invocation */
1544 }
1545
1546 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
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:
1564 case WM_GETMINMAXINFO:
1566 case WM_COMMAND:
1568 case WM_DRAWITEM:
1569 {
1570 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1571 {
1572 case IDC_LOOKIN:
1574 return TRUE;
1575 }
1576 }
1577 return FALSE;
1578
1581
1582 case WM_DESTROY:
1583 {
1585 HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1587
1588 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1589 MemDialogSize = fodInfos->sizedlg;
1590
1591 if (places_bar)
1592 {
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);
1608#endif
1609 return FALSE;
1610 }
1611
1612 case WM_NCDESTROY:
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 {
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 */
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)
1658 return FALSE;
1659 }
1660}
1661
1663{
1664 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1666}
1667
1668/***********************************************************************
1669 * FILEDLG95_InitControls
1670 *
1671 * WM_INITDIALOG message handler (before hook notification)
1672 */
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 },
1686 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1688 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1690 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {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;
1702
1704
1705 TRACE("%p\n", fodInfos);
1706
1707 /* Get windows version emulating */
1708 osVi.dwOSVersionInfoSize = sizeof(osVi);
1709 GetVersionExW(&osVi);
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 {
1723 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1724 }
1725 else
1726 {
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 */
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,
1750 rectTB.left, rectTB.top,
1751 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1753 else
1754 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1756 rectTB.left, rectTB.top,
1757 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
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);
1770 SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
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 };
1785 RECT rect;
1786 int i, cx;
1787
1790 cx = rect.right - rect.left;
1791
1794
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),
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;
1813
1814 DestroyIcon(fileinfo.hIcon);
1815 }
1816
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];
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
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
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));
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 {
2022 {
2023 /* last fallback */
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));
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 {
2048 }
2049
2050 /* Must the open as read only check box be hidden? */
2051 if (filedialog_is_readonly_hidden(fodInfos))
2052 {
2055 }
2056
2057 /* Must the help button be hidden? */
2058 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
2059 {
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
2076 }
2077
2078 /* Initialize the filter combo box */
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 */
2093{
2095
2096 if (fodInfos->DlgInfos.hwndCustomDlg)
2097 {
2098 RECT rc;
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 */
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 &
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),
2137 }
2138 }
2139 return TRUE;
2140}
2141
2142/***********************************************************************
2143 * FILEDLG95_FillControls
2144 *
2145 * WM_INITDIALOG message handler (after hook notification)
2146 */
2148{
2149 LPITEMIDLIST pidlItemId = NULL;
2150
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 {
2161
2163 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
2164 }
2165
2166 /* Initialise shell objects */
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 */
2185{
2189}
2190
2191
2192/***********************************************************************
2193 * Browse to arbitrary pidl
2194 */
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)
2202}
2203
2204/***********************************************************************
2205 * FILEDLG95_OnWMCommand
2206 *
2207 * WM_COMMAND message handler
2208 */
2210{
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:
2220 break;
2221 /* Cancel button */
2222 case IDCANCEL:
2225 break;
2226 /* Filetype combo box */
2227 case IDC_FILETYPE:
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:
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 */
2250 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2251 break;
2252
2253 case FCIDM_TB_DESKTOP:
2254 {
2255 LPITEMIDLIST pidl;
2256
2258 filedlg_browse_to_pidl(fodInfos, pidl);
2259 ILFree(pidl);
2260 break;
2261 }
2262
2263 /* Places bar */
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 */
2288{
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 */
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)
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 */
2345BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2346{
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 {
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);
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 {
2420
2421 if (ofn->lpstrFile != NULL)
2422 {
2423 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
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 */
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 */
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
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){
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 */
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
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){
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 */
2620static 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
2637 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2638}
2639#ifdef __REACTOS__
2640
2641static 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};
2648static const WCHAR s_szAst[] = { '*', 0 };
2649
2650typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
2651typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
2652
2653/* https://docs.microsoft.com/en-us/windows/desktop/shell/mruinfo */
2654typedef struct tagMRUINFOW
2655{
2656 DWORD cbSize;
2657 UINT uMax;
2658 UINT fFlags;
2659 HKEY hKey;
2661 union
2662 {
2665 } u;
2667
2668/* flags for MRUINFOW.fFlags */
2669#define MRU_STRING 0x0000
2670#define MRU_BINARY 0x0001
2671#define MRU_CACHEWRITE 0x0002
2672
2673static HINSTANCE s_hComCtl32 = NULL;
2674
2675/* comctl32.400: CreateMRUListW */
2676typedef HANDLE (WINAPI *CREATEMRULISTW)(const MRUINFOW *);
2677static CREATEMRULISTW s_pCreateMRUListW = NULL;
2678
2679/* comctl32.401: AddMRUStringW */
2680typedef INT (WINAPI *ADDMRUSTRINGW)(HANDLE, LPCWSTR);
2681static ADDMRUSTRINGW s_pAddMRUStringW = NULL;
2682
2683/* comctl32.402: FindMRUStringW */
2684typedef INT (WINAPI *FINDMRUSTRINGW)(HANDLE, LPCWSTR, LPINT);
2685static FINDMRUSTRINGW s_pFindMRUStringW = NULL;
2686
2687/* comctl32.403: EnumMRUListW */
2688typedef INT (WINAPI *ENUMMRULISTW)(HANDLE, INT, LPVOID, DWORD);
2689static ENUMMRULISTW s_pEnumMRUListW = NULL;
2690
2691/* comctl32.152: FreeMRUList */
2692typedef void (WINAPI *FREEMRULIST)(HANDLE);
2693static FREEMRULIST s_pFreeMRUList = NULL;
2694
2695static 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
2722static 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
2749static 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 {
2799 }
2800 else
2801 {
2803 }
2804 SHGetPathFromIDListW(pidl, stored_path);
2805 ILFree(pidl);
2806 }
2807}
2808
2809static void FILEDLG95_MRU_save_ext(LPCWSTR filename)
2810{
2811 HKEY hOpenSaveMRT = NULL;
2812 LONG result;
2813 MRUINFOW mi;
2814 HANDLE hList;
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
2861void 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 */
2875static 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
2911static BOOL
2912FILEDLG95_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
2952
2953 return ret;
2954}
2955#endif
2956
2957#ifdef __REACTOS__
2958int FILEDLG95_ValidatePathAction(struct FileOpenDlgInfos *fodInfos, LPWSTR lpstrPathAndFile,
2959 IShellFolder **ppsf, HWND hwnd, DWORD flags, BOOL isSaveDlg,
2960 int defAction)
2961#else
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 {
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 {
3052 {
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 {
3066 break;
3067 }
3068#else
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 */
3097{
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 */
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 {
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 */
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
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,
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,
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);
3382 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
3383 }
3384 else
3385 {
3387
3388 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
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 {
3429 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
3430 NULL, 0, NULL, NULL);
3432 {
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");
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;
3464 ret = EndDialog(hwnd, FALSE);
3466 }
3467 }
3468 break;
3469 }
3470
3471ret:
3472 if(lpsf) IShellFolder_Release(lpsf);
3473 return ret;
3474}
3475
3476/***********************************************************************
3477 * FILEDLG95_SHELL_Init
3478 *
3479 * Initialisation of the shell objects
3480 */
3482{
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 */
3517{
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 */
3548{
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)
3559 return TRUE;
3560 }
3561 return FALSE;
3562}
3563/***********************************************************************
3564 * FILEDLG95_SHELL_Clean
3565 *
3566 * Cleans the memory used by shell objects
3567 */
3569{
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 */
3595{
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 */
3711{
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)
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 */
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 */
3780{
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 */
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
3825 return TRUE;
3826}
3827
3828static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3829{
3830 IShellFolder *psfRoot, *psfDrives;
3831 IEnumIDList *lpeRoot, *lpeDrives;
3832 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3833 HDC hdc;
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 */
3857 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3858 ILFree(pidlTmp);
3859
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 */
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 */
3914{
3916 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3918 RECT rectText;
3919 RECT rectIcon;
3920 SHFILEINFOW sfi;
3921 HIMAGELIST ilItemImage;
3922 int iIndentation;
3924 LPSFOLDER tmpFolder;
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,
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 */
4007{
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)
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 */
4049static 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),
4085
4086 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.