ReactOS 0.4.15-dev-5666-gc548b97
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 info->defext = ofn->lpstrDefExt;
556 info->filter = ofn->lpstrFilter;
557 info->customfilter = ofn->lpstrCustomFilter;
558
559 if (ofn->lpstrFile)
560 {
561 info->filename = heap_alloc(ofn->nMaxFile * sizeof(WCHAR));
562 lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile);
563 }
564
565 if (ofn->lpstrInitialDir)
566 {
568 if (len)
569 {
570 info->initdir = heap_alloc(len * sizeof(WCHAR));
572 }
573 }
574
575 info->unicode = TRUE;
576}
577
579{
580 OPENFILENAMEW ofnW;
581 int len;
582
583 ofnW = *(OPENFILENAMEW *)ofn;
584
588
589 if (ofn->lpstrFile)
590 {
592 ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR));
594 ofnW.nMaxFile = len;
595 }
596
597 if (ofn->lpstrFilter)
598 {
599 LPCSTR s;
600 int n;
601
602 /* filter is a list... title\0ext\0......\0\0 */
603 s = ofn->lpstrFilter;
604 while (*s) s = s+strlen(s)+1;
605 s++;
606 n = s - ofn->lpstrFilter;
608 ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR));
610 }
611
612 /* convert lpstrCustomFilter */
614 {
615 int n, len;
616 LPCSTR s;
617
618 /* customfilter contains a pair of strings... title\0ext\0 */
620 if (*s) s = s+strlen(s)+1;
621 if (*s) s = s+strlen(s)+1;
624 ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR));
626 }
627
628 init_filedlg_infoW(&ofnW, info);
629
630 /* fixup A-specific fields */
631 info->ofnInfos = (OPENFILENAMEW *)ofn;
632 info->unicode = FALSE;
633
634 /* free what was duplicated */
635 heap_free((void *)ofnW.lpstrInitialDir);
636 heap_free(ofnW.lpstrFile);
637}
638
639/***********************************************************************
640 * GetFileDialog95
641 *
642 * Call GetFileName95 with this structure and clean the memory.
643 */
645{
646 WCHAR *current_dir = NULL;
647 unsigned int i;
648 BOOL ret;
649
650 /* save current directory */
651 if (info->ofnInfos->Flags & OFN_NOCHANGEDIR)
652 {
653 current_dir = heap_alloc(MAX_PATH * sizeof(WCHAR));
654 GetCurrentDirectoryW(MAX_PATH, current_dir);
655 }
656
657 switch (dlg_type)
658 {
659 case OPEN_DIALOG:
661 break;
662 case SAVE_DIALOG:
663 info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
665 break;
666 default:
667 ret = FALSE;
668 }
669
670 /* set the lpstrFileTitle */
671 if (ret && info->ofnInfos->lpstrFile && info->ofnInfos->lpstrFileTitle)
672 {
673 if (info->unicode)
674 {
675 LPOPENFILENAMEW ofn = info->ofnInfos;
676 WCHAR *file_title = PathFindFileNameW(ofn->lpstrFile);
678 }
679 else
680 {
682 char *file_title = PathFindFileNameA(ofn->lpstrFile);
684 }
685 }
686
687 if (current_dir)
688 {
689 SetCurrentDirectoryW(current_dir);
690 heap_free(current_dir);
691 }
692
693 if (!info->unicode)
694 {
695 heap_free((void *)info->defext);
696 heap_free((void *)info->title);
697 heap_free((void *)info->filter);
698 heap_free((void *)info->customfilter);
699 }
700
701 heap_free(info->filename);
702 heap_free(info->initdir);
703
704 for (i = 0; i < ARRAY_SIZE(info->places); i++)
705 ILFree(info->places[i]);
706
707 return ret;
708}
709
710/******************************************************************************
711 * COMDLG32_GetDisplayNameOf [internal]
712 *
713 * Helper function to get the display name for a pidl.
714 */
716 LPSHELLFOLDER psfDesktop;
717 STRRET strret;
718
719 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
720 return FALSE;
721
722 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
723 IShellFolder_Release(psfDesktop);
724 return FALSE;
725 }
726
727 IShellFolder_Release(psfDesktop);
728 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
729}
730
731/******************************************************************************
732 * COMDLG32_GetCanonicalPath [internal]
733 *
734 * Helper function to get the canonical path.
735 */
737 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
738{
739 WCHAR lpstrTemp[MAX_PATH];
740
741 /* Get the current directory name */
742 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
743 {
744 /* last fallback */
745 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
746 }
747 PathAddBackslashW(lpstrPathAndFile);
748
749 TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile));
750
751 /* if the user specified a fully qualified path use it */
752 if(PathIsRelativeW(lpstrFile))
753 {
754 lstrcatW(lpstrPathAndFile, lpstrFile);
755 }
756 else
757 {
758 /* does the path have a drive letter? */
759 if (PathGetDriveNumberW(lpstrFile) == -1)
760 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
761 else
762 lstrcpyW(lpstrPathAndFile, lpstrFile);
763 }
764
765 /* resolve "." and ".." */
766 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
767 lstrcpyW(lpstrPathAndFile, lpstrTemp);
768 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
769}
770
771/***********************************************************************
772 * COMDLG32_SplitFileNames [internal]
773 *
774 * Creates a delimited list of filenames.
775 */
776int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
777{
778 UINT nStrCharCount = 0; /* index in src buffer */
779 UINT nFileIndex = 0; /* index in dest buffer */
780 UINT nFileCount = 0; /* number of files */
781
782 /* we might get single filename without any '"',
783 * so we need nStrLen + terminating \0 + end-of-list \0 */
784 *lpstrFileList = heap_alloc((nStrLen + 2) * sizeof(WCHAR));
785 *sizeUsed = 0;
786
787 /* build delimited file list from filenames */
788 while ( nStrCharCount <= nStrLen )
789 {
790 if ( lpstrEdit[nStrCharCount]=='"' )
791 {
792 nStrCharCount++;
793 while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
794 {
795 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
796 nStrCharCount++;
797 }
798 (*lpstrFileList)[nFileIndex++] = 0;
799 nFileCount++;
800 }
801 nStrCharCount++;
802 }
803
804 /* single, unquoted string */
805 if ((nStrLen > 0) && (nFileIndex == 0) )
806 {
807 lstrcpyW(*lpstrFileList, lpstrEdit);
808 nFileIndex = lstrlenW(lpstrEdit) + 1;
809 nFileCount = 1;
810 }
811
812 /* trailing \0 */
813 (*lpstrFileList)[nFileIndex++] = '\0';
814
815 *sizeUsed = nFileIndex;
816 return nFileCount;
817}
818
819/***********************************************************************
820 * ArrangeCtrlPositions [internal]
821 *
822 * NOTE: Make sure to add testcases for any changes made here.
823 */
824static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
825{
826 HWND hwndChild, hwndStc32;
827 RECT rectParent, rectChild, rectStc32;
828 INT help_fixup = 0;
829 int chgx, chgy;
830
831 /* Take into account if open as read only checkbox and help button
832 * are hidden
833 */
834 if (hide_help)
835 {
836 RECT rectHelp, rectCancel;
837 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
838 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
839 /* subtract the height of the help button plus the space between
840 * the help button and the cancel button to the height of the dialog
841 */
842 help_fixup = rectHelp.bottom - rectCancel.bottom;
843 }
844
845 /*
846 There are two possibilities to add components to the default file dialog box.
847
848 By default, all the new components are added below the standard dialog box (the else case).
849
850 However, if there is a static text component with the stc32 id, a special case happens.
851 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
852 in the window and the cx and cy indicate how to size the window.
853 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
854 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
855
856 */
857
858 GetClientRect(hwndParentDlg, &rectParent);
859
860 /* when arranging controls we have to use fixed parent size */
861 rectParent.bottom -= help_fixup;
862
863 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
864 if (hwndStc32)
865 {
866 GetWindowRect(hwndStc32, &rectStc32);
867 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
868
869 /* set the size of the stc32 control according to the size of
870 * client area of the parent dialog
871 */
872 SetWindowPos(hwndStc32, 0,
873 0, 0,
874 rectParent.right, rectParent.bottom,
876 }
877 else
878 SetRectEmpty(&rectStc32);
879
880 /* this part moves controls of the child dialog */
881 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
882 while (hwndChild)
883 {
884 if (hwndChild != hwndStc32)
885 {
886 GetWindowRect(hwndChild, &rectChild);
887 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
888
889 /* move only if stc32 exist */
890 if (hwndStc32 && rectChild.left > rectStc32.right)
891 {
892 /* move to the right of visible controls of the parent dialog */
893 rectChild.left += rectParent.right;
894 rectChild.left -= rectStc32.right;
895 }
896 /* move even if stc32 doesn't exist */
897 if (rectChild.top >= rectStc32.bottom)
898 {
899 /* move below visible controls of the parent dialog */
900 rectChild.top += rectParent.bottom;
901 rectChild.top -= rectStc32.bottom - rectStc32.top;
902 }
903
904 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
905 0, 0, SWP_NOSIZE | SWP_NOZORDER);
906 }
907 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
908 }
909
910 /* this part moves controls of the parent dialog */
911 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
912 while (hwndChild)
913 {
914 if (hwndChild != hwndChildDlg)
915 {
916 GetWindowRect(hwndChild, &rectChild);
917 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
918
919 /* left,top of stc32 marks the position of controls
920 * from the parent dialog
921 */
922 rectChild.left += rectStc32.left;
923 rectChild.top += rectStc32.top;
924
925 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
926 0, 0, SWP_NOSIZE | SWP_NOZORDER);
927 }
928 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
929 }
930
931 /* calculate the size of the resulting dialog */
932
933 /* here we have to use original parent size */
934 GetClientRect(hwndParentDlg, &rectParent);
935 GetClientRect(hwndChildDlg, &rectChild);
936 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
937 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
938
939 if (hwndStc32)
940 {
941 /* width */
942 if (rectParent.right > rectStc32.right - rectStc32.left)
943 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
944 else
945 chgx = rectChild.right - rectParent.right;
946 /* height */
947 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
948 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
949 else
950 /* Unconditionally set new dialog
951 * height to that of the child
952 */
953 chgy = rectChild.bottom - rectParent.bottom;
954 }
955 else
956 {
957 chgx = 0;
958 chgy = rectChild.bottom - help_fixup;
959 }
960 /* set the size of the parent dialog */
961 GetWindowRect(hwndParentDlg, &rectParent);
962 SetWindowPos(hwndParentDlg, 0,
963 0, 0,
964 rectParent.right - rectParent.left + chgx,
965 rectParent.bottom - rectParent.top + chgy,
967}
968
970{
971 switch(uMsg) {
972 case WM_INITDIALOG:
973 return TRUE;
974 }
975 return FALSE;
976}
977
979{
980 LPCVOID template;
981 HRSRC hRes;
982 HANDLE hDlgTmpl = 0;
983 HWND hChildDlg = 0;
984
985 TRACE("%p, %p\n", fodInfos, hwnd);
986
987 /*
988 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
989 * structure's hInstance parameter is not a HINSTANCE, but
990 * instead a pointer to a template resource to use.
991 */
993 {
995 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
996 {
998 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
999 {
1001 return NULL;
1002 }
1003 }
1004 else
1005 {
1006 hinst = fodInfos->ofnInfos->hInstance;
1007 if(fodInfos->unicode)
1008 {
1009 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1011 }
1012 else
1013 {
1016 }
1017 if (!hRes)
1018 {
1020 return NULL;
1021 }
1022 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
1023 !(template = LockResource( hDlgTmpl )))
1024 {
1026 return NULL;
1027 }
1028 }
1029 if (fodInfos->unicode)
1030 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
1032 (LPARAM)fodInfos->ofnInfos);
1033 else
1034 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
1036 (LPARAM)fodInfos->ofnInfos);
1037 return hChildDlg;
1038 }
1039 else if (is_dialog_hooked(fodInfos))
1040 {
1041 RECT rectHwnd;
1042 struct {
1043 DLGTEMPLATE tmplate;
1044 WORD menu,class,title;
1045 } temp;
1046 GetClientRect(hwnd,&rectHwnd);
1048 temp.tmplate.dwExtendedStyle = 0;
1049 temp.tmplate.cdit = 0;
1050 temp.tmplate.x = 0;
1051 temp.tmplate.y = 0;
1052 temp.tmplate.cx = 0;
1053 temp.tmplate.cy = 0;
1054 temp.menu = temp.class = temp.title = 0;
1055
1057 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
1058
1059 return hChildDlg;
1060 }
1061 return NULL;
1062}
1063
1064/***********************************************************************
1065* SendCustomDlgNotificationMessage
1066*
1067* Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
1068*/
1069
1071{
1072 FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg);
1073 LRESULT hook_result;
1074 OFNOTIFYW ofnNotify;
1075
1076 TRACE("%p %d\n", hwndParentDlg, uCode);
1077
1078 if (!fodInfos || !fodInfos->DlgInfos.hwndCustomDlg)
1079 return 0;
1080
1081 TRACE("CALL NOTIFY for %d\n", uCode);
1082
1083 ofnNotify.hdr.hwndFrom = hwndParentDlg;
1084 ofnNotify.hdr.idFrom = 0;
1085 ofnNotify.hdr.code = uCode;
1086 ofnNotify.lpOFN = fodInfos->ofnInfos;
1087 ofnNotify.pszFile = NULL;
1088
1089 if (fodInfos->unicode)
1090 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
1091 else
1092 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
1093
1094 TRACE("RET NOTIFY retval %#lx\n", hook_result);
1095
1096 return hook_result;
1097}
1098
1100{
1101 UINT len, total;
1102 WCHAR *p, *buffer;
1104
1105 TRACE("CDM_GETFILEPATH:\n");
1106
1107 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
1108 return -1;
1109
1110 /* get path and filenames */
1111 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
1112 buffer = heap_alloc( (len + 2 + MAX_PATH) * sizeof(WCHAR) );
1113 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
1114 if (len)
1115 {
1116 p = buffer + lstrlenW(buffer);
1117 *p++ = '\\';
1118 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
1119 }
1120 if (fodInfos->unicode)
1121 {
1122 total = lstrlenW( buffer) + 1;
1123 if (result) lstrcpynW( result, buffer, size );
1124 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
1125 }
1126 else
1127 {
1128 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
1130 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1131 }
1132 heap_free( buffer );
1133 return total;
1134}
1135
1136/***********************************************************************
1137* FILEDLG95_HandleCustomDialogMessages
1138*
1139* Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1140*/
1142{
1144 WCHAR lpstrPath[MAX_PATH];
1145 INT_PTR retval;
1146
1147 if(!fodInfos) return FALSE;
1148
1149 switch(uMsg)
1150 {
1151 case CDM_GETFILEPATH:
1153 break;
1154
1155 case CDM_GETFOLDERPATH:
1156 TRACE("CDM_GETFOLDERPATH:\n");
1157 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1158 if (lParam)
1159 {
1160 if (fodInfos->unicode)
1161 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1162 else
1163 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1164 (LPSTR)lParam, (int)wParam, NULL, NULL);
1165 }
1166 retval = lstrlenW(lpstrPath) + 1;
1167 break;
1168
1170 retval = ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1171 if (retval <= wParam)
1172 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1173 break;
1174
1175 case CDM_GETSPEC:
1176 TRACE("CDM_GETSPEC:\n");
1177 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1178 if (lParam)
1179 {
1180 if (fodInfos->unicode)
1181 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1182 else
1183 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1184 }
1185 break;
1186
1187 case CDM_SETCONTROLTEXT:
1188 TRACE("CDM_SETCONTROLTEXT:\n");
1189 if ( lParam )
1190 {
1191 if( fodInfos->unicode )
1193 else
1195 }
1196 retval = TRUE;
1197 break;
1198
1199 case CDM_HIDECONTROL:
1200 /* MSDN states that it should fail for not OFN_EXPLORER case */
1201 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1202 {
1203 HWND control = GetDlgItem( hwnd, wParam );
1204 if (control) ShowWindow( control, SW_HIDE );
1205 retval = TRUE;
1206 }
1207 else retval = FALSE;
1208 break;
1209
1210 default:
1211 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1212 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1213 return FALSE;
1214 }
1216 return TRUE;
1217}
1218
1219/***********************************************************************
1220 * FILEDLG95_OnWMGetMMI
1221 *
1222 * WM_GETMINMAXINFO message handler for resizable dialogs
1223 */
1225{
1227 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1228 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1229 {
1230 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1231 }
1232 return TRUE;
1233}
1234
1235/***********************************************************************
1236 * FILEDLG95_OnWMSize
1237 *
1238 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1239 *
1240 * FIXME: this could be made more elaborate. Now use a simple scheme
1241 * where the file view is enlarged and the controls are either moved
1242 * vertically or horizontally to get out of the way. Only the "grip"
1243 * is moved in both directions to stay in the corner.
1244 */
1246{
1247 RECT rc, rcview;
1248 int chgx, chgy;
1249 HWND ctrl;
1250 HDWP hdwp;
1251 FileOpenDlgInfos *fodInfos;
1252
1253 if( wParam != SIZE_RESTORED) return FALSE;
1254 fodInfos = get_filedlg_infoptr(hwnd);
1255 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1256 /* get the new dialog rectangle */
1257 GetWindowRect( hwnd, &rc);
1258 TRACE("%p, size from %d,%d to %d,%d\n", hwnd, fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1259 rc.right -rc.left, rc.bottom -rc.top);
1260 /* not initialized yet */
1261 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1262 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1263 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1264 return FALSE;
1265 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1266 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1267 fodInfos->sizedlg.cx = rc.right - rc.left;
1268 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1269 /* change the size of the view window */
1270 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1271 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1272 hdwp = BeginDeferWindowPos( 10);
1273 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1274 rcview.right - rcview.left + chgx,
1275 rcview.bottom - rcview.top + chgy,
1277 /* change position and sizes of the controls */
1279 {
1280 int ctrlid = GetDlgCtrlID( ctrl);
1281 GetWindowRect( ctrl, &rc);
1282 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1283 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1284 {
1285 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1286 0, 0,
1288 }
1289 else if( rc.top > rcview.bottom)
1290 {
1291 /* if it was below the shell view
1292 * move to bottom */
1293 switch( ctrlid)
1294 {
1295 /* file name (edit or comboboxex) and file types combo change also width */
1296 case edt1:
1297 case cmb13:
1298 case cmb1:
1299 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1300 rc.right - rc.left + chgx, rc.bottom - rc.top,
1302 break;
1303 /* then these buttons must move out of the way */
1304 case IDOK:
1305 case IDCANCEL:
1306 case pshHelp:
1307 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1308 0, 0,
1310 break;
1311 default:
1312 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1313 0, 0,
1315 }
1316 }
1317 else if( rc.left > rcview.right)
1318 {
1319 /* if it was to the right of the shell view
1320 * move to right */
1321 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1322 0, 0,
1324 }
1325 else
1326 /* special cases */
1327 {
1328 switch( ctrlid)
1329 {
1330#if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1331 case IDC_LOOKIN:
1332 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1333 rc.right - rc.left + chgx, rc.bottom - rc.top,
1335 break;
1336 case IDC_TOOLBARSTATIC:
1337 case IDC_TOOLBAR:
1338 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1339 0, 0,
1341 break;
1342#endif
1343 /* not resized in windows. Since wine uses this invisible control
1344 * to size the browser view it needs to be resized */
1345 case IDC_SHELLSTATIC:
1346 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1347 rc.right - rc.left + chgx,
1348 rc.bottom - rc.top + chgy,
1350 break;
1351 case IDC_TOOLBARPLACES:
1352 DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1354 break;
1355 }
1356 }
1357 }
1358 if(fodInfos->DlgInfos.hwndCustomDlg &&
1360 {
1361 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1363 {
1364 GetWindowRect( ctrl, &rc);
1365 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1366 if( rc.top > rcview.bottom)
1367 {
1368 /* if it was below the shell view
1369 * move to bottom */
1370 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1371 rc.right - rc.left, rc.bottom - rc.top,
1373 }
1374 else if( rc.left > rcview.right)
1375 {
1376 /* if it was to the right of the shell view
1377 * move to right */
1378 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1379 rc.right - rc.left, rc.bottom - rc.top,
1381 }
1382 }
1383 /* size the custom dialog at the end: some applications do some
1384 * control re-arranging at this point */
1385 GetClientRect(hwnd, &rc);
1386 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1388 }
1389 EndDeferWindowPos( hdwp);
1390 /* should not be needed */
1392 return TRUE;
1393}
1394
1395/***********************************************************************
1396 * FileOpenDlgProc95
1397 *
1398 * File open dialog procedure
1399 */
1401{
1402#if 0
1403 TRACE("%p 0x%04x\n", hwnd, uMsg);
1404#endif
1405
1406 switch(uMsg)
1407 {
1408 case WM_INITDIALOG:
1409 {
1411 RECT rc, rcstc;
1412 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1413 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1414
1415 /* Some shell namespace extensions depend on COM being initialized. */
1417 fodInfos->ole_initialized = TRUE;
1418
1420
1422
1423 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1424 {
1426 DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1427 RECT client, client_adjusted;
1428
1429 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1430 {
1431 style |= WS_SIZEBOX;
1432 ex_style |= WS_EX_WINDOWEDGE;
1433 }
1434 else
1435 style &= ~WS_SIZEBOX;
1437 SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1438
1440 GetClientRect( hwnd, &client_adjusted );
1441 AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1442
1443 GetWindowRect( hwnd, &rc );
1444 rc.right += client_adjusted.right - client.right;
1445 rc.bottom += client_adjusted.bottom - client.bottom;
1446 SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1448
1449 GetWindowRect( hwnd, &rc );
1450 fodInfos->DlgInfos.hwndGrip =
1451 CreateWindowExA( 0, "SCROLLBAR", NULL,
1454 rc.right - gripx, rc.bottom - gripy,
1455 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1456 }
1457
1458 fodInfos->DlgInfos.hwndCustomDlg =
1460
1463
1464 if( fodInfos->DlgInfos.hwndCustomDlg)
1465 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1466
1467 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1470 }
1471
1472 /* if the app has changed the position of the invisible listbox,
1473 * change that of the listview (browser) as well */
1474 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1476 if( !EqualRect( &rc, &rcstc))
1477 {
1478 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1479 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1480 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1482 }
1483
1484 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1485 {
1486 GetWindowRect( hwnd, &rc);
1487 fodInfos->sizedlg.cx = rc.right - rc.left;
1488 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1489 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1490 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1491 GetClientRect( hwnd, &rc);
1492 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1493 rc.right - gripx, rc.bottom - gripy,
1495 /* resize the dialog to the previous invocation */
1500 }
1501
1502 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1504
1505#ifdef __REACTOS__
1506 /* Enable hook and translate */
1507 EnterCriticalSection(&COMDLG32_OpenFileLock);
1508 if (++s_nFileDialogHookCount == 1)
1509 {
1510 s_hFileDialogHook = SetWindowsHookEx(WH_MSGFILTER, FILEDLG95_TranslateMsgProc,
1511 0, GetCurrentThreadId());
1512 }
1513 FILEDLG95_AddRemoveTranslate(NULL, hwnd);
1514 LeaveCriticalSection(&COMDLG32_OpenFileLock);
1515#endif
1516 return 0;
1517 }
1518 case WM_SIZE:
1520 case WM_GETMINMAXINFO:
1522 case WM_COMMAND:
1524 case WM_DRAWITEM:
1525 {
1526 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1527 {
1528 case IDC_LOOKIN:
1530 return TRUE;
1531 }
1532 }
1533 return FALSE;
1534
1537
1538 case WM_DESTROY:
1539 {
1541 HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1543
1544 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1545 MemDialogSize = fodInfos->sizedlg;
1546
1547 if (places_bar)
1548 {
1552 }
1553#ifdef __REACTOS__
1554 /* Disable hook and translate */
1555 EnterCriticalSection(&COMDLG32_OpenFileLock);
1556 FILEDLG95_AddRemoveTranslate(hwnd, NULL);
1557 if (--s_nFileDialogHookCount == 0)
1558 {
1559 UnhookWindowsHookEx(s_hFileDialogHook);
1560 s_hFileDialogHook = NULL;
1561 }
1562 LeaveCriticalSection(&COMDLG32_OpenFileLock);
1564#endif
1565 return FALSE;
1566 }
1567
1568 case WM_NCDESTROY:
1570 return 0;
1571
1572 case WM_NOTIFY:
1573 {
1574 LPNMHDR lpnmh = (LPNMHDR)lParam;
1575 UINT stringId = -1;
1576
1577 /* set up the button tooltips strings */
1578 if(TTN_GETDISPINFOA == lpnmh->code )
1579 {
1581 switch(lpnmh->idFrom )
1582 {
1583 /* Up folder button */
1584 case FCIDM_TB_UPFOLDER:
1585 stringId = IDS_UPFOLDER;
1586 break;
1587 /* New folder button */
1588 case FCIDM_TB_NEWFOLDER:
1589 stringId = IDS_NEWFOLDER;
1590 break;
1591 /* List option button */
1592 case FCIDM_TB_SMALLICON:
1593 stringId = IDS_LISTVIEW;
1594 break;
1595 /* Details option button */
1597 stringId = IDS_REPORTVIEW;
1598 break;
1599 /* Desktop button */
1600 case FCIDM_TB_DESKTOP:
1601 stringId = IDS_TODESKTOP;
1602 break;
1603 default:
1604 stringId = 0;
1605 }
1606 lpdi->hinst = COMDLG32_hInstance;
1607 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1608 }
1609 return FALSE;
1610 }
1611 default :
1612 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1614 return FALSE;
1615 }
1616}
1617
1619{
1620 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1622}
1623
1624/***********************************************************************
1625 * FILEDLG95_InitControls
1626 *
1627 * WM_INITDIALOG message handler (before hook notification)
1628 */
1630{
1631 BOOL win2000plus = FALSE;
1632 BOOL win98plus = FALSE;
1633 BOOL handledPath = FALSE;
1634 OSVERSIONINFOW osVi;
1635 static const WCHAR szwSlash[] = { '\\', 0 };
1636 static const WCHAR szwStar[] = { '*',0 };
1637
1638 static const TBBUTTON tbb[] =
1639 {
1640 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1642 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1644 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1646 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1649 };
1650 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1651
1652 RECT rectTB;
1653 RECT rectlook;
1654
1655 HIMAGELIST toolbarImageList;
1656 ITEMIDLIST *desktopPidl;
1658
1660
1661 TRACE("%p\n", fodInfos);
1662
1663 /* Get windows version emulating */
1664 osVi.dwOSVersionInfoSize = sizeof(osVi);
1665 GetVersionExW(&osVi);
1667 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1668 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1669 win2000plus = (osVi.dwMajorVersion > 4);
1670 if (win2000plus) win98plus = TRUE;
1671 }
1672 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1673
1674
1675 /* Use either the edit or the comboboxex for the filename control */
1676 if (filename_is_edit( fodInfos ))
1677 {
1679 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1680 }
1681 else
1682 {
1684 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1685 }
1686
1687 /* Get the hwnd of the controls */
1688 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1689 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1690
1691 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1692 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1693
1694 /* construct the toolbar */
1696 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1697
1698 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1699 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1700 rectTB.left = rectlook.right;
1701 rectTB.top = rectlook.top-1;
1702
1703 if (fodInfos->unicode)
1704 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1706 rectTB.left, rectTB.top,
1707 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1709 else
1710 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1712 rectTB.left, rectTB.top,
1713 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1715
1716 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1717
1718/* FIXME: use TB_LOADIMAGES when implemented */
1719/* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1720 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1721 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1722
1723 /* Retrieve and add desktop icon to the toolbar */
1724 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1726 SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
1728 ImageList_AddIcon(toolbarImageList, fileinfo.hIcon);
1729
1730 DestroyIcon(fileinfo.hIcon);
1731 CoTaskMemFree(desktopPidl);
1732
1733 /* Finish Toolbar Construction */
1734 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1735 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1736
1737 if (is_places_bar_enabled(fodInfos))
1738 {
1739 TBBUTTON tb = { 0 };
1741 RECT rect;
1742 int i, cx;
1743
1746 cx = rect.right - rect.left;
1747
1750
1752 for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
1753 {
1754 int index;
1755
1756 if (!fodInfos->places[i])
1757 continue;
1758
1759 memset(&fileinfo, 0, sizeof(fileinfo));
1760 SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo),
1763
1764 tb.iBitmap = index;
1765 tb.iString = (INT_PTR)fileinfo.szDisplayName;
1766 tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
1767 tb.idCommand = TBPLACES_CMDID_PLACE0 + i;
1769
1770 DestroyIcon(fileinfo.hIcon);
1771 }
1772
1775 }
1776
1777 /* Set the window text with the text specified in the OPENFILENAME structure */
1778 if(fodInfos->title)
1779 {
1780 SetWindowTextW(hwnd,fodInfos->title);
1781 }
1782 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1783 {
1784 WCHAR buf[64];
1787 }
1788
1789 /* Initialise the file name edit control */
1790 handledPath = FALSE;
1791 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1792
1793 if(fodInfos->filename)
1794 {
1795 /* 1. If win2000 or higher and filename contains a path, use it
1796 in preference over the lpstrInitialDir */
1797 if (win2000plus && *fodInfos->filename && wcspbrk(fodInfos->filename, szwSlash)) {
1798 WCHAR tmpBuf[MAX_PATH];
1799 WCHAR *nameBit;
1800 DWORD result;
1801
1802 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1803 if (result) {
1804
1805 /* nameBit is always shorter than the original filename. It may be NULL
1806 * when the filename contains only a drive name instead of file name */
1807 if (nameBit)
1808 {
1809 lstrcpyW(fodInfos->filename,nameBit);
1810 *nameBit = 0x00;
1811 }
1812 else
1813 *fodInfos->filename = '\0';
1814
1815 heap_free(fodInfos->initdir);
1816 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1817 lstrcpyW(fodInfos->initdir, tmpBuf);
1818 handledPath = TRUE;
1819 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1820 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1821 }
1822 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1823
1824 } else {
1825 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1826 }
1827 }
1828
1829 /* 2. (All platforms) If initdir is not null, then use it */
1830 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1831 {
1832 /* Work out the proper path as supplied one might be relative */
1833 /* (Here because supplying '.' as dir browses to My Computer) */
1834 WCHAR tmpBuf[MAX_PATH];
1835 WCHAR tmpBuf2[MAX_PATH];
1836 WCHAR *nameBit;
1837 DWORD result;
1838
1839 lstrcpyW(tmpBuf, fodInfos->initdir);
1840 if (PathFileExistsW(tmpBuf)) {
1841 /* initdir does not have to be a directory. If a file is
1842 * specified, the dir part is taken */
1843 if (PathIsDirectoryW(tmpBuf)) {
1844 PathAddBackslashW(tmpBuf);
1845 lstrcatW(tmpBuf, szwStar);
1846 }
1847 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1848 if (result) {
1849 *nameBit = 0x00;
1850 heap_free(fodInfos->initdir);
1851 fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1852 lstrcpyW(fodInfos->initdir, tmpBuf2);
1853 handledPath = TRUE;
1854 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1855 }
1856 }
1857 else if (fodInfos->initdir)
1858 {
1859 heap_free(fodInfos->initdir);
1860 fodInfos->initdir = NULL;
1861 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1862 }
1863 }
1864
1865#ifdef __REACTOS__
1866 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1867 {
1868 /* 2.5. Win2000+: Recently used defext */
1869 if (win2000plus) {
1870 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1871 fodInfos->initdir[0] = '\0';
1872
1873 FILEDLG95_MRU_load_ext(fodInfos->initdir, MAX_PATH, fodInfos->defext);
1874
1875 if (fodInfos->initdir[0] && PathIsDirectoryW(fodInfos->initdir)) {
1876 handledPath = TRUE;
1877 } else {
1878 heap_free(fodInfos->initdir);
1879 fodInfos->initdir = NULL;
1880 }
1881 }
1882 }
1883#endif
1884
1885 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1886 {
1887 /* 3. All except w2k+: if filename contains a path use it */
1888 if (!win2000plus && fodInfos->filename &&
1889 *fodInfos->filename &&
1890 wcspbrk(fodInfos->filename, szwSlash)) {
1891 WCHAR tmpBuf[MAX_PATH];
1892 WCHAR *nameBit;
1893 DWORD result;
1894
1896 tmpBuf, &nameBit);
1897 if (result) {
1898 int len;
1899
1900 /* nameBit is always shorter than the original filename */
1901 lstrcpyW(fodInfos->filename, nameBit);
1902 *nameBit = 0x00;
1903
1904 len = lstrlenW(tmpBuf);
1905 heap_free(fodInfos->initdir);
1906 fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR));
1907 lstrcpyW(fodInfos->initdir, tmpBuf);
1908
1909 handledPath = TRUE;
1910 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1911 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1912 }
1913 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1914 }
1915
1916 /* 4. Win2000+: Recently used */
1917 if (!handledPath && win2000plus) {
1918 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1919 fodInfos->initdir[0] = '\0';
1920
1922
1923 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1924 handledPath = TRUE;
1925 }else{
1926 heap_free(fodInfos->initdir);
1927 fodInfos->initdir = NULL;
1928 }
1929 }
1930
1931 /* 5. win98+ and win2000+ if any files of specified filter types in
1932 current directory, use it */
1933 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1934
1935 LPCWSTR lpstrPos = fodInfos->filter;
1936 WIN32_FIND_DATAW FindFileData;
1937 HANDLE hFind;
1938
1939 while (1)
1940 {
1941 /* filter is a list... title\0ext\0......\0\0 */
1942
1943 /* Skip the title */
1944 if(! *lpstrPos) break; /* end */
1945 lpstrPos += lstrlenW(lpstrPos) + 1;
1946
1947 /* See if any files exist in the current dir with this extension */
1948 if(! *lpstrPos) break; /* end */
1949
1950 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1951
1952 if (hFind == INVALID_HANDLE_VALUE) {
1953 /* None found - continue search */
1954 lpstrPos += lstrlenW(lpstrPos) + 1;
1955
1956 } else {
1957
1958 heap_free(fodInfos->initdir);
1959 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1961
1962 handledPath = TRUE;
1963 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1964 debugstr_w(lpstrPos));
1965 FindClose(hFind);
1966 break;
1967 }
1968 }
1969 }
1970
1971 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1972 if (!handledPath && (win2000plus || win98plus)) {
1973 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1974
1975 if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK)
1976 {
1978 {
1979 /* last fallback */
1981 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1982 }
1983 else
1984 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1985 }
1986 else
1987 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1988
1989 handledPath = TRUE;
1990 } else if (!handledPath) {
1991 fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1993 handledPath = TRUE;
1994 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1995 }
1996 }
1997 SetFocus( fodInfos->DlgInfos.hwndFileName );
1998 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1999
2000 /* Must the open as read only check box be checked ?*/
2001 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
2002 {
2004 }
2005
2006 /* Must the open as read only check box be hidden? */
2007 if (filedialog_is_readonly_hidden(fodInfos))
2008 {
2011 }
2012
2013 /* Must the help button be hidden? */
2014 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
2015 {
2018 }
2019
2020 /* change Open to Save */
2021 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2022 {
2023#ifdef __REACTOS__
2024 WCHAR buf[24];
2025#else
2026 WCHAR buf[16];
2027#endif
2032 }
2033
2034 /* Initialize the filter combo box */
2036#ifdef __REACTOS__
2037 DoInitAutoCompleteWithCWD(fodInfos, fodInfos->DlgInfos.hwndFileName);
2038#endif
2039
2040 return 0;
2041}
2042
2043/***********************************************************************
2044 * FILEDLG95_ResizeControls
2045 *
2046 * WM_INITDIALOG message handler (after hook notification)
2047 */
2049{
2051
2052 if (fodInfos->DlgInfos.hwndCustomDlg)
2053 {
2054 RECT rc;
2056
2057 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
2058 filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP));
2059
2060 /* resize the custom dialog to the parent size */
2062 GetClientRect(hwnd, &rc);
2063 else
2064 {
2065 /* our own fake template is zero sized and doesn't have children, so
2066 * there is no need to resize it. Picasa depends on it.
2067 */
2068 flags |= SWP_NOSIZE;
2069 SetRectEmpty(&rc);
2070 }
2071 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
2072 0, 0, rc.right, rc.bottom, flags);
2073 }
2074 else
2075 {
2076 /* Resize the height; if opened as read-only, checkbox and help button are
2077 * hidden and we are not using a custom template nor a customDialog
2078 */
2079 if (filedialog_is_readonly_hidden(fodInfos) &&
2080 (!(fodInfos->ofnInfos->Flags &
2082 {
2083 RECT rectDlg, rectHelp, rectCancel;
2084 GetWindowRect(hwnd, &rectDlg);
2085 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
2086 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
2087 /* subtract the height of the help button plus the space between the help
2088 * button and the cancel button to the height of the dialog
2089 */
2090 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
2091 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
2093 }
2094 }
2095 return TRUE;
2096}
2097
2098/***********************************************************************
2099 * FILEDLG95_FillControls
2100 *
2101 * WM_INITDIALOG message handler (after hook notification)
2102 */
2104{
2105 LPITEMIDLIST pidlItemId = NULL;
2106
2108
2109 TRACE("dir=%s file=%s\n",
2110 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
2111
2112 /* Get the initial directory pidl */
2113
2114 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
2115 {
2117
2119 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
2120 }
2121
2122 /* Initialise shell objects */
2124
2125 /* Initialize the Look In combo box */
2126 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
2127
2128 /* Browse to the initial directory */
2129 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
2130
2131 ILFree(pidlItemId);
2132
2133 return TRUE;
2134}
2135/***********************************************************************
2136 * FILEDLG95_Clean
2137 *
2138 * Regroups all the cleaning functions of the filedlg
2139 */
2141{
2145}
2146
2147
2148/***********************************************************************
2149 * Browse to arbitrary pidl
2150 */
2152{
2153 TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl);
2154
2155 IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2156 if (info->ofnInfos->Flags & OFN_EXPLORER)
2158}
2159
2160/***********************************************************************
2161 * FILEDLG95_OnWMCommand
2162 *
2163 * WM_COMMAND message handler
2164 */
2166{
2168 WORD wNotifyCode = HIWORD(wParam); /* notification code */
2169 WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */
2170
2171 switch (id)
2172 {
2173 /* OK button */
2174 case IDOK:
2176 break;
2177 /* Cancel button */
2178 case IDCANCEL:
2181 break;
2182 /* Filetype combo box */
2183 case IDC_FILETYPE:
2185 break;
2186 /* LookIn combo box */
2187 case IDC_LOOKIN:
2188 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
2189 break;
2190
2191 /* --- toolbar --- */
2192 /* Up folder button */
2193 case FCIDM_TB_UPFOLDER:
2195 break;
2196 /* New folder button */
2197 case FCIDM_TB_NEWFOLDER:
2198 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
2199 break;
2200 /* List option button */
2201 case FCIDM_TB_SMALLICON:
2202 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
2203 break;
2204 /* Details option button */
2206 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2207 break;
2208
2209 case FCIDM_TB_DESKTOP:
2210 {
2211 LPITEMIDLIST pidl;
2212
2214 filedlg_browse_to_pidl(fodInfos, pidl);
2215 ILFree(pidl);
2216 break;
2217 }
2218
2219 /* Places bar */
2225 filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]);
2226 break;
2227
2228 case edt1:
2229 case cmb13:
2230 break;
2231
2232 }
2233 /* Do not use the listview selection anymore */
2234 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
2235 return 0;
2236}
2237
2238/***********************************************************************
2239 * FILEDLG95_OnWMGetIShellBrowser
2240 *
2241 * WM_GETISHELLBROWSER message handler
2242 */
2244{
2246
2247 TRACE("\n");
2248
2249 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
2250
2251 return TRUE;
2252}
2253
2254
2255/***********************************************************************
2256 * FILEDLG95_SendFileOK
2257 *
2258 * Sends the CDN_FILEOK notification if required
2259 *
2260 * RETURNS
2261 * TRUE if the dialog should close
2262 * FALSE if the dialog should not be closed
2263 */
2265{
2266 /* ask the hook if we can close */
2267 if (is_dialog_hooked(fodInfos))
2268 {
2269 LRESULT retval = 0;
2270
2271 TRACE("---\n");
2272 /* First send CDN_FILEOK as MSDN doc says */
2273 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2275 if( retval)
2276 {
2277 TRACE("canceled\n");
2278 return FALSE;
2279 }
2280
2281 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2282 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
2283 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
2284 if( retval)
2285 {
2286 TRACE("canceled\n");
2287 return FALSE;
2288 }
2289 }
2290 return TRUE;
2291}
2292
2293/***********************************************************************
2294 * FILEDLG95_OnOpenMultipleFiles
2295 *
2296 * Handles the opening of multiple files.
2297 *
2298 * FIXME
2299 * check destination buffer size
2300 */
2301BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2302{
2304 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2305 UINT nCount, nSizePath;
2306
2307 TRACE("\n");
2308
2309 if(fodInfos->unicode)
2310 {
2311 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2312 ofn->lpstrFile[0] = '\0';
2313 }
2314 else
2315 {
2317 ofn->lpstrFile[0] = '\0';
2318 }
2319
2320 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2321
2322 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2323 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2324 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2325 {
2326 LPWSTR lpstrTemp = lpstrFileList;
2327
2328 for ( nCount = 0; nCount < nFileCount; nCount++ )
2329 {
2330 LPITEMIDLIST pidl;
2331
2332 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2333 if (!pidl)
2334 {
2335 WCHAR lpstrNotFound[100];
2336 WCHAR lpstrMsg[100];
2337 WCHAR tmp[400];
2338 static const WCHAR nl[] = {'\n',0};
2339
2340 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2342
2343 lstrcpyW(tmp, lpstrTemp);
2344 lstrcatW(tmp, nl);
2345 lstrcatW(tmp, lpstrNotFound);
2346 lstrcatW(tmp, nl);
2347 lstrcatW(tmp, lpstrMsg);
2348
2349 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2350 return FALSE;
2351 }
2352
2353 /* move to the next file in the list of files */
2354 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2355 ILFree(pidl);
2356 }
2357 }
2358
2359 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2360 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2361 {
2362 /* For "oldstyle" dialog the components have to
2363 be separated by blanks (not '\0'!) and short
2364 filenames have to be used! */
2365 FIXME("Components have to be separated by blanks\n");
2366 }
2367 if(fodInfos->unicode)
2368 {
2369 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2370 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2371 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2372 }
2373 else
2374 {
2376
2377 if (ofn->lpstrFile != NULL)
2378 {
2379 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2381 if (ofn->nMaxFile > nSizePath)
2382 {
2383 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2384 ofn->lpstrFile + nSizePath,
2385 ofn->nMaxFile - nSizePath, NULL, NULL);
2386 }
2387 }
2388 }
2389
2390 fodInfos->ofnInfos->nFileOffset = nSizePath;
2391 fodInfos->ofnInfos->nFileExtension = 0;
2392
2393 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2394 return FALSE;
2395
2396 /* clean and exit */
2398 return EndDialog(hwnd,TRUE);
2399}
2400
2401/* Returns the 'slot name' of the given module_name in the registry's
2402 * most-recently-used list. This will be an ASCII value in the
2403 * range ['a','z'). Returns zero on error.
2404 *
2405 * The slot's value in the registry has the form:
2406 * module_name\0mru_path\0
2407 *
2408 * If stored_path is given, then stored_path will contain the path name
2409 * stored in the registry's MRU list for the given module_name.
2410 *
2411 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2412 * MRU list key for the given module_name.
2413 */
2415{
2416 WCHAR mru_list[32], *cur_mru_slot;
2417 BOOL taken[25] = {0};
2418 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2419 HKEY hkey_tmp, *hkey;
2420 LONG ret;
2421
2422 if(hkey_ret)
2423 hkey = hkey_ret;
2424 else
2425 hkey = &hkey_tmp;
2426
2427 if(stored_path)
2428 *stored_path = '\0';
2429
2431 if(ret){
2432 WARN("Unable to create MRU key: %d\n", ret);
2433 return 0;
2434 }
2435
2436 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2437 (LPBYTE)mru_list, &mru_list_size);
2438 if(ret || key_type != REG_SZ){
2440 return 'a';
2441
2442 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2443 RegCloseKey(*hkey);
2444 return 0;
2445 }
2446
2447 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2448 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2449 DWORD value_data_size = sizeof(value_data);
2450
2451 *value_name = *cur_mru_slot;
2452
2453 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2454 &key_type, (LPBYTE)value_data, &value_data_size);
2455 if(ret || key_type != REG_BINARY){
2456 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2457 continue;
2458 }
2459
2460 if(!wcsicmp(module_name, value_data)){
2461 if(!hkey_ret)
2462 RegCloseKey(*hkey);
2463 if(stored_path)
2464 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2465 return *value_name;
2466 }
2467 }
2468
2469 if(!hkey_ret)
2470 RegCloseKey(*hkey);
2471
2472 /* the module name isn't in the registry, so find the next open slot */
2473 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2474 taken[*cur_mru_slot - 'a'] = TRUE;
2475 for(i = 0; i < 25; ++i){
2476 if(!taken[i])
2477 return i + 'a';
2478 }
2479
2480 /* all slots are taken, so return the last one in MRUList */
2481 --cur_mru_slot;
2482 return *cur_mru_slot;
2483}
2484
2485/* save the given filename as most-recently-used path for this module */
2487{
2488 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2489 LONG ret;
2490 HKEY hkey;
2491
2492 /* get the current executable's name */
2493 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2494 {
2495 WARN("GotModuleFileName failed: %d\n", GetLastError());
2496 return;
2497 }
2498 module_name = wcsrchr(module_path, '\\');
2499 if(!module_name)
2500 module_name = module_path;
2501 else
2502 module_name += 1;
2503
2505 if(!slot)
2506 return;
2507 *slot_name = slot;
2508
2509 { /* update the slot's info */
2510 WCHAR *path_ends, *final;
2511 DWORD path_len, final_len;
2512
2513 /* use only the path segment of `filename' */
2514 path_ends = wcsrchr(filename, '\\');
2515 path_len = path_ends - filename;
2516
2517 final_len = path_len + lstrlenW(module_name) + 2;
2518
2519 final = heap_alloc(final_len * sizeof(WCHAR));
2520 if(!final)
2521 return;
2522 lstrcpyW(final, module_name);
2523 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2524 final[final_len-1] = '\0';
2525
2526 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2527 final_len * sizeof(WCHAR));
2528 if(ret){
2529 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2530 heap_free(final);
2531 RegCloseKey(hkey);
2532 return;
2533 }
2534
2535 heap_free(final);
2536 }
2537
2538 { /* update MRUList value */
2539 WCHAR old_mru_list[32], new_mru_list[32];
2540 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2541 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2542
2543 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2544 (LPBYTE)old_mru_list, &mru_list_size);
2545 if(ret || key_type != REG_SZ){
2547 new_mru_list[0] = slot;
2548 new_mru_list[1] = '\0';
2549 }else{
2550 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2551 RegCloseKey(hkey);
2552 return;
2553 }
2554 }else{
2555 /* copy old list data over so that the new slot is at the start
2556 * of the list */
2557 *new_mru_slot++ = slot;
2558 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2559 if(*old_mru_slot != slot)
2560 *new_mru_slot++ = *old_mru_slot;
2561 }
2562 *new_mru_slot = '\0';
2563 }
2564
2565 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2566 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2567 if(ret){
2568 WARN("Error saving MRUList data: %d\n", ret);
2569 RegCloseKey(hkey);
2570 return;
2571 }
2572 }
2573}
2574
2575/* load the most-recently-used path for this module */
2576static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2577{
2578 WCHAR module_path[MAX_PATH], *module_name;
2579
2580 /* get the current executable's name */
2581 if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2582 {
2583 WARN("GotModuleFileName failed: %d\n", GetLastError());
2584 return;
2585 }
2586 module_name = wcsrchr(module_path, '\\');
2587 if(!module_name)
2588 module_name = module_path;
2589 else
2590 module_name += 1;
2591
2593 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2594}
2595#ifdef __REACTOS__
2596
2597static const WCHAR s_subkey[] =
2598{
2599 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
2600 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s',
2601 'i','o','n','\\','E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g',
2602 '3','2','\\','O','p','e','n','S','a','v','e','M','R','U',0
2603};
2604static const WCHAR s_szAst[] = { '*', 0 };
2605
2606typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
2607typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
2608
2609/* https://docs.microsoft.com/en-us/windows/desktop/shell/mruinfo */
2610typedef struct tagMRUINFOW
2611{
2612 DWORD cbSize;
2613 UINT uMax;
2614 UINT fFlags;
2615 HKEY hKey;
2617 union
2618 {
2621 } u;
2623
2624/* flags for MRUINFOW.fFlags */
2625#define MRU_STRING 0x0000
2626#define MRU_BINARY 0x0001
2627#define MRU_CACHEWRITE 0x0002
2628
2629static HINSTANCE s_hComCtl32 = NULL;
2630
2631/* comctl32.400: CreateMRUListW */
2632typedef HANDLE (WINAPI *CREATEMRULISTW)(const MRUINFOW *);
2633static CREATEMRULISTW s_pCreateMRUListW = NULL;
2634
2635/* comctl32.401: AddMRUStringW */
2636typedef INT (WINAPI *ADDMRUSTRINGW)(HANDLE, LPCWSTR);
2637static ADDMRUSTRINGW s_pAddMRUStringW = NULL;
2638
2639/* comctl32.402: FindMRUStringW */
2640typedef INT (WINAPI *FINDMRUSTRINGW)(HANDLE, LPCWSTR, LPINT);
2641static FINDMRUSTRINGW s_pFindMRUStringW = NULL;
2642
2643/* comctl32.403: EnumMRUListW */
2644typedef INT (WINAPI *ENUMMRULISTW)(HANDLE, INT, LPVOID, DWORD);
2645static ENUMMRULISTW s_pEnumMRUListW = NULL;
2646
2647/* comctl32.152: FreeMRUList */
2648typedef void (WINAPI *FREEMRULIST)(HANDLE);
2649static FREEMRULIST s_pFreeMRUList = NULL;
2650
2651static BOOL FILEDLG_InitMRUList(void)
2652{
2653 if (s_hComCtl32)
2654 return TRUE;
2655
2656 s_hComCtl32 = GetModuleHandleA("comctl32");
2657 if (!s_hComCtl32)
2658 return FALSE;
2659
2660 s_pCreateMRUListW = (CREATEMRULISTW)GetProcAddress(s_hComCtl32, (LPCSTR)400);
2661 s_pAddMRUStringW = (ADDMRUSTRINGW)GetProcAddress(s_hComCtl32, (LPCSTR)401);
2662 s_pFindMRUStringW = (FINDMRUSTRINGW)GetProcAddress(s_hComCtl32, (LPCSTR)402);
2663 s_pEnumMRUListW = (ENUMMRULISTW)GetProcAddress(s_hComCtl32, (LPCSTR)403);
2664 s_pFreeMRUList = (FREEMRULIST)GetProcAddress(s_hComCtl32, (LPCSTR)152);
2665 if (!s_pCreateMRUListW ||
2666 !s_pAddMRUStringW ||
2667 !s_pFindMRUStringW ||
2668 !s_pEnumMRUListW ||
2669 !s_pFreeMRUList)
2670 {
2671 s_hComCtl32 = NULL;
2672 return FALSE;
2673 }
2674
2675 return TRUE;
2676}
2677
2678static BOOL ExtIsPicture(LPCWSTR ext)
2679{
2680 static const WCHAR s_image_exts[][6] =
2681 {
2682 { 'b','m','p',0 },
2683 { 'd','i','b',0 },
2684 { 'j','p','g',0 },
2685 { 'j','p','e','g',0 },
2686 { 'j','p','e',0 },
2687 { 'j','f','i','f',0 },
2688 { 'p','n','g',0 },
2689 { 'g','i','f',0 },
2690 { 't','i','f',0 },
2691 { 't','i','f','f',0 }
2692 };
2693 size_t i;
2694
2695 for (i = 0; i < ARRAY_SIZE(s_image_exts); ++i)
2696 {
2697 if (lstrcmpiW(ext, s_image_exts[i]) == 0)
2698 {
2699 return TRUE;
2700 }
2701 }
2702 return FALSE;
2703}
2704
2705static void FILEDLG95_MRU_load_ext(LPWSTR stored_path, size_t cchMax, LPCWSTR defext)
2706{
2707 HKEY hOpenSaveMRT = NULL;
2708 LONG result;
2709 MRUINFOW mi;
2710 HANDLE hList;
2711 WCHAR szText[MAX_PATH];
2712 INT ret = 0;
2713
2714 stored_path[0] = 0;
2715
2716 if (!defext || !*defext || !FILEDLG_InitMRUList())
2717 {
2718 return;
2719 }
2720
2721 if (*defext == '.')
2722 ++defext;
2723
2724 result = RegOpenKeyW(HKEY_CURRENT_USER, s_subkey, &hOpenSaveMRT);
2725 if (!result && hOpenSaveMRT)
2726 {
2727 ZeroMemory(&mi, sizeof(mi));
2728 mi.cbSize = sizeof(mi);
2729 mi.uMax = 26;
2730 mi.fFlags = MRU_STRING;
2731 mi.hKey = hOpenSaveMRT;
2732 mi.lpszSubKey = defext;
2733 mi.u.string_cmpfn = lstrcmpiW;
2734 hList = (*s_pCreateMRUListW)(&mi);
2735 if (hList)
2736 {
2737 ret = (*s_pEnumMRUListW)(hList, 0, szText, sizeof(szText));
2738 if (ret > 0)
2739 {
2740 lstrcpynW(stored_path, szText, cchMax);
2741 PathRemoveFileSpecW(stored_path);
2742 }
2743 (*s_pFreeMRUList)(hList);
2744 }
2745
2746 RegCloseKey(hOpenSaveMRT);
2747 }
2748
2749 if (stored_path[0] == 0)
2750 {
2751 LPITEMIDLIST pidl;
2752 if (ExtIsPicture(defext))
2753 {
2755 }
2756 else
2757 {
2759 }
2760 SHGetPathFromIDListW(pidl, stored_path);
2761 ILFree(pidl);
2762 }
2763}
2764
2765static void FILEDLG95_MRU_save_ext(LPCWSTR filename)
2766{
2767 HKEY hOpenSaveMRT = NULL;
2768 LONG result;
2769 MRUINFOW mi;
2770 HANDLE hList;
2772
2773 if (!defext || !*defext || !FILEDLG_InitMRUList())
2774 {
2775 return;
2776 }
2777
2778 if (*defext == '.')
2779 ++defext;
2780
2781 result = RegOpenKeyW(HKEY_CURRENT_USER, s_subkey, &hOpenSaveMRT);
2782 if (!result && hOpenSaveMRT)
2783 {
2784 ZeroMemory(&mi, sizeof(mi));
2785 mi.cbSize = sizeof(mi);
2786 mi.uMax = 26;
2787 mi.fFlags = MRU_STRING;
2788 mi.hKey = hOpenSaveMRT;
2789 mi.lpszSubKey = defext;
2790 mi.u.string_cmpfn = lstrcmpiW;
2791 hList = (*s_pCreateMRUListW)(&mi);
2792 if (hList)
2793 {
2794 (*s_pAddMRUStringW)(hList, filename);
2795 (*s_pFreeMRUList)(hList);
2796 }
2797
2798 mi.cbSize = sizeof(mi);
2799 mi.uMax = 26;
2800 mi.fFlags = MRU_STRING;
2801 mi.hKey = hOpenSaveMRT;
2802 mi.lpszSubKey = s_szAst;
2803 mi.u.string_cmpfn = lstrcmpiW;
2804 hList = (*s_pCreateMRUListW)(&mi);
2805 if (hList)
2806 {
2807 (*s_pAddMRUStringW)(hList, filename);
2808 (*s_pFreeMRUList)(hList);
2809 }
2810
2811 RegCloseKey(hOpenSaveMRT);
2812 }
2813}
2814
2815#endif /* __REACTOS__ */
2816
2817void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2818{
2819 WCHAR strMsgTitle[MAX_PATH];
2820 WCHAR strMsgText [MAX_PATH];
2821 if (idCaption)
2822 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle));
2823 else
2824 strMsgTitle[0] = '\0';
2825 LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText));
2826 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2827}
2828
2830 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2831{
2832 int nOpenAction = defAction;
2833 LPWSTR lpszTemp, lpszTemp1;
2834 LPITEMIDLIST pidl = NULL;
2835 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2836
2837 /* check for invalid chars */
2838 if((wcspbrk(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2839 {
2841 return FALSE;
2842 }
2843
2844 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2845
2846 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2847 while (lpszTemp1)
2848 {
2849 LPSHELLFOLDER lpsfChild;
2850 WCHAR lpwstrTemp[MAX_PATH];
2851 DWORD dwEaten, dwAttributes;
2852 LPWSTR p;
2853
2854 lstrcpyW(lpwstrTemp, lpszTemp);
2855 p = PathFindNextComponentW(lpwstrTemp);
2856
2857 if (!p) break; /* end of path */
2858
2859 *p = 0;
2860 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2861
2862 /* There are no wildcards when OFN_NOVALIDATE is set */
2863 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2864 {
2865 static const WCHAR wszWild[] = { '*', '?', 0 };
2866 /* if the last element is a wildcard do a search */
2867 if(wcspbrk(lpszTemp1, wszWild) != NULL)
2868 {
2869 nOpenAction = ONOPEN_SEARCH;
2870 break;
2871 }
2872 }
2873 lpszTemp1 = lpszTemp;
2874
2875 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2876
2877 /* append a backslash to drive letters */
2878 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2879 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2880 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2881 {
2882 PathAddBackslashW(lpwstrTemp);
2883 }
2884
2885 dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSANCESTOR;
2886 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2887 {
2888 /* the path component is valid, we have a pidl of the next path component */
2889 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2890 if((dwAttributes & (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR)) == (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR))
2891 {
2892 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2893 {
2894 ERR("bind to failed\n"); /* should not fail */
2895 break;
2896 }
2897 IShellFolder_Release(*ppsf);
2898 *ppsf = lpsfChild;
2899 lpsfChild = NULL;
2900 }
2901 else
2902 {
2903 TRACE("value\n");
2904
2905 /* end dialog, return value */
2906 nOpenAction = ONOPEN_OPEN;
2907 break;
2908 }
2909 ILFree(pidl);
2910 pidl = NULL;
2911 }
2912 else if (!(flags & OFN_NOVALIDATE))
2913 {
2914 if(*lpszTemp || /* points to trailing null for last path element */
2915 (lpwstrTemp[lstrlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2916 {
2918 {
2920 break;
2921 }
2922 }
2923 else
2924 {
2925 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2926 {
2928 break;
2929 }
2930 }
2931 /* change to the current folder */
2932 nOpenAction = ONOPEN_OPEN;
2933 break;
2934 }
2935 else
2936 {
2937 nOpenAction = ONOPEN_OPEN;
2938 break;
2939 }
2940 }
2941 ILFree(pidl);
2942
2943 return nOpenAction;
2944}
2945
2946/***********************************************************************
2947 * FILEDLG95_OnOpen
2948 *
2949 * Ok button WM_COMMAND message handler
2950 *
2951 * If the function succeeds, the return value is nonzero.
2952 */
2954{
2956 LPWSTR lpstrFileList;
2957 UINT nFileCount = 0;
2958 UINT sizeUsed = 0;
2959 BOOL ret = TRUE;
2960 WCHAR lpstrPathAndFile[MAX_PATH];
2961 LPSHELLFOLDER lpsf = NULL;
2962 int nOpenAction;
2963
2964 TRACE("hwnd=%p\n", hwnd);
2965
2966 /* try to browse the selected item */
2968 return FALSE;
2969
2970 /* get the files from the edit control */
2971 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2972
2973 if(nFileCount == 0)
2974 return FALSE;
2975
2976 if(nFileCount > 1)
2977 {
2978 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2979 goto ret;
2980 }
2981
2982 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2983
2984/*
2985 Step 1: Build a complete path name from the current folder and
2986 the filename or path in the edit box.
2987 Special cases:
2988 - the path in the edit box is a root path
2989 (with or without drive letter)
2990 - the edit box contains ".." (or a path with ".." in it)
2991*/
2992
2993 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2994 heap_free(lpstrFileList);
2995
2996/*
2997 Step 2: here we have a cleaned up path
2998
2999 We have to parse the path step by step to see if we have to browse
3000 to a folder if the path points to a directory or the last
3001 valid element is a directory.
3002
3003 valid variables:
3004 lpstrPathAndFile: cleaned up path
3005 */
3006
3007 if (nFileCount &&
3008 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
3009 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
3010 nOpenAction = ONOPEN_OPEN;
3011 else
3012 nOpenAction = ONOPEN_BROWSE;
3013
3014 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
3015 fodInfos->ofnInfos->Flags,
3016 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
3017 nOpenAction);
3018 if(!nOpenAction)
3019 goto ret;
3020
3021/*
3022 Step 3: here we have a cleaned up and validated path
3023
3024 valid variables:
3025 lpsf: ShellFolder bound to the rightmost valid path component
3026 lpstrPathAndFile: cleaned up path
3027 nOpenAction: action to do
3028*/
3029 TRACE("end validate sf=%p\n", lpsf);
3030
3031 switch(nOpenAction)
3032 {
3033 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
3034 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
3035 {
3036 int iPos;
3037 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
3038 DWORD len;
3039
3040 /* replace the current filter */
3041 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3042 len = lstrlenW(lpszTemp)+1;
3043 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR));
3044 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
3045
3046 /* set the filter cb to the extension when possible */
3047 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
3048 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0);
3049 }
3050 /* fall through */
3051 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
3052 TRACE("ONOPEN_BROWSE\n");
3053 {
3054 IPersistFolder2 * ppf2;
3055 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
3056 {
3057 LPITEMIDLIST pidlCurrent;
3058 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
3059 IPersistFolder2_Release(ppf2);
3060 if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
3061 {
3062 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
3063 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3064 {
3066 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
3067 }
3068 }
3069 else if( nOpenAction == ONOPEN_SEARCH )
3070 {
3071 if (fodInfos->Shell.FOIShellView)
3072 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3073 }
3074 ILFree(pidlCurrent);
3075 if (filename_is_edit( fodInfos ))
3076 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3077 else
3078 {
3079 HWND hwnd;
3080
3081 hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
3082 SendMessageW(hwnd, EM_SETSEL, 0, -1);
3083 }
3084 }
3085 }
3086 ret = FALSE;
3087 break;
3088 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
3089 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
3090 {
3091 WCHAR *ext = NULL;
3092
3093 /* update READONLY check box flag */
3095 fodInfos->ofnInfos->Flags |= OFN_READONLY;
3096 else
3097 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
3098
3099 /* Attach the file extension with file name*/
3100 ext = PathFindExtensionW(lpstrPathAndFile);
3101#ifdef __REACTOS__
3102 {
3103 LPWSTR filterExt = NULL, lpstrFilter = NULL, pch, pchNext;
3104 LPCWSTR the_ext = NULL;
3105 static const WCHAR szwDot[] = {'.',0};
3106 int PathLength = lstrlenW(lpstrPathAndFile);
3107
3108 /* get filter extensions */
3109 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3110 fodInfos->ofnInfos->nFilterIndex - 1);
3111 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
3112 {
3113 LPWSTR filterSearchIndex, pchFirst = NULL;
3114 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
3115 if (filterExt)
3116 {
3117 strcpyW(filterExt, lpstrFilter);
3118
3119 if (ext && *ext)
3120 {
3121 /* find ext in filter */
3122 for (pch = filterExt; pch && *pch; pch = pchNext)
3123 {
3124 filterSearchIndex = strchrW(pch, ';');
3125 if (filterSearchIndex)
3126 {
3127 filterSearchIndex[0] = 0;
3128 pchNext = filterSearchIndex + 1;
3129 }
3130 else
3131 {
3132 pchNext = NULL;
3133 }
3134
3135 while (*pch == '*' || *pch == '.' || *pch == '?')
3136 {
3137 ++pch;
3138 }
3139
3140 if (!pchFirst)
3141 pchFirst = pch;
3142
3143 if (lstrcmpiW(pch, &ext[1]) == 0)
3144 {
3145 the_ext = pch;
3146 break;
3147 }
3148 }
3149
3150 /* use first one if not found */
3151 if (!the_ext && pchFirst && *pchFirst)
3152 {
3153 the_ext = pchFirst;
3154 }
3155 }
3156 }
3157 }
3158
3159 if (!the_ext)
3160 {
3161 /* use default extension if no extension in filter */
3162 the_ext = fodInfos->defext;
3163 }
3164
3165 if (the_ext && *the_ext && lstrcmpiW(&ext[1], the_ext) != 0)
3166 {
3167 if (strlenW(lpstrPathAndFile) + 1 + strlenW(the_ext) + 1 <=
3168 fodInfos->ofnInfos->nMaxFile)
3169 {
3170 /* append the dot */
3171 lstrcatW(lpstrPathAndFile, szwDot);
3172 /* append the extension */
3173 lstrcatW(lpstrPathAndFile, the_ext);
3174 /* update ext */
3175 ext = PathFindExtensionW(lpstrPathAndFile);
3176 }
3177 }
3178
3179 heap_free(filterExt);
3180
3181 /* In Open dialog: if file does not exist try without extension */
3182 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
3183 lpstrPathAndFile[PathLength] = 0;
3184
3185 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
3186 if (*ext)
3187 ext++;
3188 if (!lstrcmpiW(fodInfos->defext, ext))
3189 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
3190 else
3192 }
3193
3194 /* update dialog data */
3195 SetWindowTextW(fodInfos->DlgInfos.hwndFileName, PathFindFileNameW(lpstrPathAndFile));
3196#else /* __REACTOS__ */
3197 if (! *ext && fodInfos->defext)
3198 {
3199 /* if no extension is specified with file name, then */
3200 /* attach the extension from file filter or default one */
3201
3202 WCHAR *filterExt = NULL;
3203 LPWSTR lpstrFilter = NULL;
3204 static const WCHAR szwDot[] = {'.',0};
3205 int PathLength = lstrlenW(lpstrPathAndFile);
3206
3207 /*Get the file extension from file type filter*/
3208 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3209 fodInfos->ofnInfos->nFilterIndex-1);
3210
3211 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
3212 {
3213 WCHAR* filterSearchIndex;
3214 filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
3215 lstrcpyW(filterExt, lpstrFilter);
3216
3217 /* if a semicolon-separated list of file extensions was given, do not include the
3218 semicolon or anything after it in the extension.
3219 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
3220 filterSearchIndex = wcschr(filterExt, ';');
3221 if (filterSearchIndex)
3222 {
3223 filterSearchIndex[0] = '\0';
3224 }
3225
3226 /* find the file extension by searching for the first dot in filterExt */
3227 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
3228 /* if the extension is invalid or contains a glob, ignore it */
3229 filterSearchIndex = wcschr(filterExt, '.');
3230 if (filterSearchIndex++ && !wcschr(filterSearchIndex, '*') && !wcschr(filterSearchIndex, '?'))
3231 {
3232 lstrcpyW(filterExt, filterSearchIndex);
3233 }
3234 else
3235 {
3236 heap_free(filterExt);
3237 filterExt = NULL;
3238 }
3239 }
3240
3241 if (!filterExt)
3242 {
3243 /* use the default file extension */
3244 filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
3245 lstrcpyW(filterExt, fodInfos->defext);
3246 }
3247
3248 if (*filterExt) /* ignore filterExt="" */
3249 {
3250 /* Attach the dot*/
3251 lstrcatW(lpstrPathAndFile, szwDot);
3252 /* Attach the extension */
3253 lstrcatW(lpstrPathAndFile, filterExt);
3254 }
3255
3256 heap_free(filterExt);
3257
3258 /* In Open dialog: if file does not exist try without extension */
3259 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
3260 lpstrPathAndFile[PathLength] = '\0';
3261
3262 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
3263 if (*ext)
3264 ext++;
3265 if (!lstrcmpiW(fodInfos->defext, ext))
3266 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
3267 else
3269 }
3270#endif /* __REACTOS__ */
3271
3272 /* In Save dialog: check if the file already exists */
3273 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
3274 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
3275 && PathFileExistsW(lpstrPathAndFile))
3276 {
3277 WCHAR lpstrOverwrite[100];
3278 int answer;
3279
3280 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
3281 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
3283 if (answer == IDNO || answer == IDCANCEL)
3284 {
3285 ret = FALSE;
3286 goto ret;
3287 }
3288 }
3289
3290 /* In Open dialog: check if it should be created if it doesn't exist */
3291 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
3292 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
3293 && !PathFileExistsW(lpstrPathAndFile))
3294 {
3295 WCHAR lpstrCreate[100];
3296 int answer;
3297
3298 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
3299 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
3301 if (answer == IDNO || answer == IDCANCEL)
3302 {
3303 ret = FALSE;
3304 goto ret;
3305 }
3306 }
3307
3308 /* Check that the size of the file does not exceed buffer size.
3309 (Allow for extra \0 if OFN_MULTISELECT is set.) */
3310 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
3311 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
3312 {
3313
3314 /* fill destination buffer */
3315 if (fodInfos->ofnInfos->lpstrFile)
3316 {
3317 if(fodInfos->unicode)
3318 {
3319 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
3320
3321 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
3323 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
3324 }
3325 else
3326 {
3328
3329 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
3332 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
3333 }
3334 }
3335
3336 if(fodInfos->unicode)
3337 {
3338 LPWSTR lpszTemp;
3339
3340 /* set filename offset */
3341 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
3342 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
3343
3344 /* set extension offset */
3345 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
3346 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
3347 }
3348 else
3349 {
3350 LPSTR lpszTemp;
3351 CHAR tempFileA[MAX_PATH];
3352
3353 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
3354 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
3355 tempFileA, sizeof(tempFileA), NULL, NULL);
3356
3357 /* set filename offset */
3358 lpszTemp = PathFindFileNameA(tempFileA);
3359 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
3360
3361 /* set extension offset */
3362 lpszTemp = PathFindExtensionA(tempFileA);
3363 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
3364 }
3365
3366 /* copy currently selected filter to lpstrCustomFilter */
3367 if (fodInfos->ofnInfos->lpstrCustomFilter)
3368 {
3370 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
3371 NULL, 0, NULL, NULL);
3373 {
3376 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
3377 s, len, NULL, NULL);
3378 }
3379 }
3380
3381
3382 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
3383 goto ret;
3384
3385 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
3386#ifdef __REACTOS__
3387 FILEDLG95_MRU_save_ext(lpstrPathAndFile);
3388#endif
3389
3390 TRACE("close\n");
3392 ret = EndDialog(hwnd, TRUE);
3393 }
3394 else
3395 {
3396 WORD size;
3397
3398 size = lstrlenW(lpstrPathAndFile) + 1;
3399 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
3400 size += 1;
3401 /* return needed size in first two bytes of lpstrFile */
3402 if(fodInfos->ofnInfos->lpstrFile)
3403 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
3405 ret = EndDialog(hwnd, FALSE);
3407 }
3408 }
3409 break;
3410 }
3411
3412ret:
3413 if(lpsf) IShellFolder_Release(lpsf);
3414 return ret;
3415}
3416
3417/***********************************************************************
3418 * FILEDLG95_SHELL_Init
3419 *
3420 * Initialisation of the shell objects
3421 */
3423{
3425
3426 TRACE("%p\n", hwnd);
3427
3428 /*
3429 * Initialisation of the FileOpenDialogInfos structure
3430 */
3431
3432 /* Shell */
3433
3434 /*ShellInfos */
3435 fodInfos->ShellInfos.hwndOwner = hwnd;
3436
3437 /* Disable multi-select if flag not set */
3438 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
3439 {
3440 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
3441 }
3442 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
3443 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
3444
3445 /* Construct the IShellBrowser interface */
3446 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
3447
3448 return NOERROR;
3449}
3450
3451/***********************************************************************
3452 * FILEDLG95_SHELL_ExecuteCommand
3453 *
3454 * Change the folder option and refresh the view
3455 * If the function succeeds, the return value is nonzero.
3456 */
3458{
3460 IContextMenu * pcm;
3461
3462 TRACE("(%p,%p)\n", hwnd, lpVerb);
3463
3464 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
3465 SVGIO_BACKGROUND,
3466 &IID_IContextMenu,
3467 (LPVOID*)&pcm)))
3468 {
3469 CMINVOKECOMMANDINFO ci;
3470 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
3471 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
3472 ci.lpVerb = lpVerb;
3473 ci.hwnd = hwnd;
3474
3475 IContextMenu_InvokeCommand(pcm, &ci);
3476 IContextMenu_Release(pcm);
3477 }
3478
3479 return FALSE;
3480}
3481
3482/***********************************************************************
3483 * FILEDLG95_SHELL_UpFolder
3484 *
3485 * Browse to the specified object
3486 * If the function succeeds, the return value is nonzero.
3487 */
3489{
3491
3492 TRACE("\n");
3493
3494 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3495 NULL,
3496 SBSP_PARENT)))
3497 {
3498 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3500 return TRUE;
3501 }
3502 return FALSE;
3503}
3504/***********************************************************************
3505 * FILEDLG95_SHELL_Clean
3506 *
3507 * Cleans the memory used by shell objects
3508 */
3510{
3512
3513 TRACE("\n");
3514
3515 ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3516
3517 /* clean Shell interfaces */
3518 if (fodInfos->Shell.FOIShellView)
3519 {
3520 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3521 IShellView_Release(fodInfos->Shell.FOIShellView);
3522 }
3523 if (fodInfos->Shell.FOIShellFolder)
3524 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3525 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3526 if (fodInfos->Shell.FOIDataObject)
3527 IDataObject_Release(fodInfos->Shell.FOIDataObject);
3528}
3529
3530/***********************************************************************
3531 * FILEDLG95_FILETYPE_Init
3532 *
3533 * Initialisation of the file type combo box
3534 */
3536{
3538 int nFilters = 0; /* number of filters */
3539 int nFilterIndexCB;
3540
3541 TRACE("%p\n", hwnd);
3542
3543 if(fodInfos->customfilter)
3544 {
3545 /* customfilter has one entry... title\0ext\0
3546 * Set first entry of combo box item with customfilter
3547 */
3548 LPWSTR lpstrExt;
3549 LPCWSTR lpstrPos = fodInfos->customfilter;
3550
3551 /* Get the title */
3552 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3553
3554 /* Copy the extensions */
3555 if (! *lpstrPos) return E_FAIL; /* malformed filter */
3556 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3557 lstrcpyW(lpstrExt,lpstrPos);
3558
3559 /* Add the item at the end of the combo */
3560 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3561 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3562
3563 nFilters++;
3564 }
3565 if(fodInfos->filter)
3566 {
3567 LPCWSTR lpstrPos = fodInfos->filter;
3568
3569 for(;;)
3570 {
3571 /* filter is a list... title\0ext\0......\0\0
3572 * Set the combo item text to the title and the item data
3573 * to the ext
3574 */
3575 LPCWSTR lpstrDisplay;
3576 LPWSTR lpstrExt;
3577
3578 /* Get the title */
3579 if(! *lpstrPos) break; /* end */
3580 lpstrDisplay = lpstrPos;
3581 lpstrPos += lstrlenW(lpstrPos) + 1;
3582
3583 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3584
3585 nFilters++;
3586
3587 /* Copy the extensions */
3588 if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3589 lstrcpyW(lpstrExt,lpstrPos);
3590 lpstrPos += lstrlenW(lpstrPos) + 1;
3591
3592 /* Add the item at the end of the combo */
3593 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3594
3595 /* malformed filters are added anyway... */
3596 if (!*lpstrExt) break;
3597 }
3598 }
3599
3600 /*
3601 * Set the current filter to the one specified
3602 * in the initialisation structure
3603 */
3604 if (fodInfos->filter || fodInfos->customfilter)
3605 {
3606 LPWSTR lpstrFilter;
3607
3608 /* Check to make sure our index isn't out of bounds. */
3609 if ( fodInfos->ofnInfos->nFilterIndex >
3610 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3611 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3612
3613 /* set default filter index */
3614 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3615 fodInfos->ofnInfos->nFilterIndex = 1;
3616
3617 /* calculate index of Combo Box item */
3618 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3619 if (fodInfos->customfilter == NULL)
3620 nFilterIndexCB--;
3621
3622 /* Set the current index selection. */
3623 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3624
3625 /* Get the corresponding text string from the combo box. */
3626 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3627 nFilterIndexCB);
3628
3629 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3630 lpstrFilter = NULL;
3631
3632 if(lpstrFilter)
3633 {
3634 DWORD len;
3635 CharLowerW(lpstrFilter); /* lowercase */
3636 len = lstrlenW(lpstrFilter)+1;
3637 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3638 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3639 }
3640 } else
3641 fodInfos->ofnInfos->nFilterIndex = 0;
3642 return S_OK;
3643}
3644
3645/***********************************************************************
3646 * FILEDLG95_FILETYPE_OnCommand
3647 *
3648 * WM_COMMAND of the file type combo box
3649 * If the function succeeds, the return value is nonzero.
3650 */
3652{
3654
3655 switch(wNotifyCode)
3656 {
3657 case CBN_SELENDOK:
3658 {
3659 LPWSTR lpstrFilter;
3660
3661 /* Get the current item of the filetype combo box */
3662 int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3663
3664 /* set the current filter index */
3665 fodInfos->ofnInfos->nFilterIndex = iItem +
3666 (fodInfos->customfilter == NULL ? 1 : 0);
3667
3668 /* Set the current filter with the current selection */
3669 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3670
3671 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3672 iItem);
3673 if((INT_PTR)lpstrFilter != CB_ERR)
3674 {
3675 DWORD len;
3676 CharLowerW(lpstrFilter); /* lowercase */
3677 len = lstrlenW(lpstrFilter)+1;
3678 fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3679 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3680 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3682 }
3683
3684 /* Refresh the actual view to display the included items*/
3685 if (fodInfos->Shell.FOIShellView)
3686 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3687 }
3688 }
3689 return FALSE;
3690}
3691/***********************************************************************
3692 * FILEDLG95_FILETYPE_SearchExt
3693 *
3694 * searches for an extension in the filetype box
3695 */
3697{
3698 int i, iCount;
3699
3700 iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3701
3702 TRACE("%s\n", debugstr_w(lpstrExt));
3703
3704 if(iCount != CB_ERR)
3705 {
3706 for(i=0;i<iCount;i++)
3707 {
3708 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3709 return i;
3710 }
3711 }
3712 return -1;
3713}
3714
3715/***********************************************************************
3716 * FILEDLG95_FILETYPE_Clean
3717 *
3718 * Clean the memory used by the filetype combo box
3719 */
3721{
3723 int iPos;
3724 int iCount;
3725
3726 iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3727
3728 TRACE("\n");
3729
3730 /* Delete each string of the combo and their associated data */
3731 if(iCount != CB_ERR)
3732 {
3733 for(iPos = iCount-1;iPos>=0;iPos--)
3734 {
3735 heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3736 SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3737 }
3738 }
3739 /* Current filter */
3740 heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3741}
3742
3743/***********************************************************************
3744 * FILEDLG95_LOOKIN_Init
3745 *
3746 * Initialisation of the look in combo box
3747 */
3748
3749/* Small helper function, to determine if the unixfs shell extension is rooted
3750 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3751 */
3753 HKEY hKey;
3754 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3755 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3756 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3757 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3758 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3759 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3760 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3761
3762 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3763 return FALSE;
3764
3766 return TRUE;
3767}
3768
3769static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3770{
3771 IShellFolder *psfRoot, *psfDrives;
3772 IEnumIDList *lpeRoot, *lpeDrives;
3773 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3774 HDC hdc;
3776 LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3777
3778 TRACE("%p\n", hwndCombo);
3779
3780 liInfos->iMaxIndentation = 0;
3781
3782 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3783
3784 hdc = GetDC( hwndCombo );
3785 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3786 GetTextMetricsW( hdc, &tm );
3787 ReleaseDC( hwndCombo, hdc );
3788
3789 /* set item height for both text field and listbox */
3790 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3791 SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3792
3793 /* Turn on the extended UI for the combo box like Windows does */
3794 SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3795
3796 /* Initialise data of Desktop folder */
3798 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3799 ILFree(pidlTmp);
3800
3802
3803 SHGetDesktopFolder(&psfRoot);
3804
3805 if (psfRoot)
3806 {
3807 /* enumerate the contents of the desktop */
3808 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3809 {
3810 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3811 {
3812 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3813
3814 /* If the unixfs extension is rooted, we don't expand the drives by default */
3816 {
3817 /* special handling for CSIDL_DRIVES */
3818 if (ILIsEqual(pidlTmp, pidlDrives))
3819 {
3820 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3821 {
3822 /* enumerate the drives */
3823 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3824 {
3825 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3826 {
3827 pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3828 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3829 ILFree(pidlAbsTmp);
3830 ILFree(pidlTmp1);
3831 }
3832 IEnumIDList_Release(lpeDrives);
3833 }
3834 IShellFolder_Release(psfDrives);
3835 }
3836 }
3837 }
3838
3839 ILFree(pidlTmp);
3840 }
3841 IEnumIDList_Release(lpeRoot);
3842 }
3843 IShellFolder_Release(psfRoot);
3844 }
3845
3846 ILFree(pidlDrives);
3847}
3848
3849/***********************************************************************
3850 * FILEDLG95_LOOKIN_DrawItem
3851 *
3852 * WM_DRAWITEM message handler
3853 */
3855{
3857 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3859 RECT rectText;
3860 RECT rectIcon;
3861 SHFILEINFOW sfi;
3862 HIMAGELIST ilItemImage;
3863 int iIndentation;
3865 LPSFOLDER tmpFolder;
3867 UINT icon_width, icon_height;
3868
3869 TRACE("\n");
3870
3871 if(pDIStruct->itemID == -1)
3872 return 0;
3873
3874 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3875 pDIStruct->itemID)))
3876 return 0;
3877
3878
3879 icon_width = GetSystemMetrics(SM_CXICON);
3880 icon_height = GetSystemMetrics(SM_CYICON);
3881 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3882 {
3883 icon_width = GetSystemMetrics(SM_CXSMICON);
3884 icon_height = GetSystemMetrics(SM_CYSMICON);
3885 shgfi_flags |= SHGFI_SMALLICON;
3886 }
3887
3888 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3889 0, &sfi, sizeof (sfi), shgfi_flags );
3890
3891 /* Is this item selected ? */
3892 if(pDIStruct->itemState & ODS_SELECTED)
3893 {
3894 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3895 SetBkColor(pDIStruct->hDC,crHighLight);
3896 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3897 }
3898 else
3899 {
3900 SetTextColor(pDIStruct->hDC,crText);
3901 SetBkColor(pDIStruct->hDC,crWin);
3902 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3903 }
3904
3905 /* Do not indent item if drawing in the edit of the combo */
3906 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3907 iIndentation = 0;
3908 else
3909 iIndentation = tmpFolder->m_iIndent;
3910
3911 /* Draw text and icon */
3912
3913 /* Initialise the icon display area */
3914 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3915 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3916 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3917 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3918
3919 /* Initialise the text display area */
3920 GetTextMetricsW(pDIStruct->hDC, &tm);
3921 rectText.left = rectIcon.right;
3922 rectText.top =
3923 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3924 rectText.right = pDIStruct->rcItem.right;
3925 rectText.bottom =
3926 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3927
3928 /* Draw the icon from the image list */
3929 ImageList_Draw(ilItemImage,
3930 sfi.iIcon,
3931 pDIStruct->hDC,
3932 rectIcon.left,
3933 rectIcon.top,
3935
3936 /* Draw the associated text */
3937 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3938 return NOERROR;
3939}
3940
3941/***********************************************************************
3942 * FILEDLG95_LOOKIN_OnCommand
3943 *
3944 * LookIn combo box WM_COMMAND message handler
3945 * If the function succeeds, the return value is nonzero.
3946 */
3948{
3950
3951 TRACE("%p\n", fodInfos);
3952
3953 switch(wNotifyCode)
3954 {
3955 case CBN_SELENDOK:
3956 {
3957 LPSFOLDER tmpFolder;
3958 int iItem;
3959
3960 iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3961
3962 if( iItem == CB_ERR) return FALSE;
3963
3964 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3965 iItem)))
3966 return FALSE;
3967
3968
3969 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3970 tmpFolder->pidlItem,
3971 SBSP_ABSOLUTE)))
3972 {
3973 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3975 return TRUE;
3976 }
3977 break;
3978 }
3979
3980 }
3981 return FALSE;
3982}
3983
3984/***********************************************************************
3985 * FILEDLG95_LOOKIN_AddItem
3986 *
3987 * Adds an absolute pidl item to the lookin combo box
3988 * returns the index of the inserted item
3989 */
3990static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3991{
3992 LPITEMIDLIST pidlNext;
3993 SHFILEINFOW sfi;
3994 SFOLDER *tmpFolder;
3995 LookInInfos *liInfos;
3996
3997 TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3998
3999 if(!pidl)
4000 return -1;
4001
4002 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
4003 return -1;
4004
4005 tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
4006 tmpFolder->m_iIndent = 0;
4007
4008 /* Calculate the indentation of the item in the lookin*/
4009 pidlNext = pidl;
4010 while ((pidlNext = ILGetNext(pidlNext)))
4011 {
4012 tmpFolder->m_iIndent++;
4013 }
4014
4015 tmpFolder->pidlItem = ILClone(pidl);
4016
4017 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
4018 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
4019
4020 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
4021 SHGetFileInfoW((LPCWSTR)pidl,
4022 0,
4023 &sfi,
4024 sizeof(sfi),
4026
4027 TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
4028
4029 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
4030 {
4031 int iItemID;
4032
4033 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
4034
4035 /* Add the item at the end of the list */
4036 if(iInsertId < 0)
4037 {
4038 iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
4039 }
4040 /* Insert the item at the iInsertId position*/
4041 else
4042 {
4043 iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
4044 }
4045
4046 SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
4047 return iItemID;
4048 }
4049
4050 ILFree( tmpFolder->pidlItem );
4051 heap_free( tmpFolder );
4052 return -1;
4053
4054}
4055
4056/***********************************************************************
4057 * FILEDLG95_LOOKIN_InsertItemAfterParent
4058 *
4059 * Insert an item below its parent
4060 */
4062{
4063
4064 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
4065 int iParentPos;
4066
4067 TRACE("\n");
4068
4069 if (pidl == pidlParent)
4070 return -1;
4071
4072 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
4073
4074 if(iParentPos < 0)
4075 {
4076 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
4077 }
4078
4079 ILFree(pidlParent);
4080
4081 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
4082}
4083
4084/***********************************************************************
4085 * FILEDLG95_LOOKIN_SelectItem
4086 *
4087 * Adds an absolute pidl item to the lookin combo box
4088 * returns the index of the inserted item
4089 */
4091{
4092 int iItemPos;
4093 LookInInfos *liInfos;
4094
4095 TRACE("%p, %p\n", hwnd, pidl);
4096