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