ntdll: Implement RtlValidRelativeSecurityDescriptor.
[wine.git] / dlls / comdlg32 / filedlg.c
blob1453396ccf7f21755c177e3bc6be082a5ca2a150
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
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.
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.
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
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).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winternl.h"
63 #include "winnls.h"
64 #include "wingdi.h"
65 #include "winreg.h"
66 #include "winuser.h"
67 #include "commdlg.h"
68 #include "dlgs.h"
69 #include "cdlg.h"
70 #include "cderr.h"
71 #include "shellapi.h"
72 #include "shlobj.h"
73 #include "filedlgbrowser.h"
74 #include "shlwapi.h"
76 #include "wine/unicode.h"
77 #include "wine/debug.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_DONTADDTORECENT |\
83 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
84 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
86 #define IsHooked(fodInfos) \
87 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
88 /***********************************************************************
89 * Data structure and global variables
91 typedef struct SFolder
93 int m_iImageIndex; /* Index of picture in image list */
94 HIMAGELIST hImgList;
95 int m_iIndent; /* Indentation index */
96 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
98 } SFOLDER,*LPSFOLDER;
100 typedef struct tagLookInInfo
102 int iMaxIndentation;
103 UINT uSelectedItem;
104 } LookInInfos;
107 /***********************************************************************
108 * Defines and global variables
111 /* Draw item constant */
112 #define XTEXTOFFSET 3
114 /* AddItem flags*/
115 #define LISTEND -1
117 /* SearchItem methods */
118 #define SEARCH_PIDL 1
119 #define SEARCH_EXP 2
120 #define ITEM_NOTFOUND -1
122 /* Undefined windows message sent by CreateViewObject*/
123 #define WM_GETISHELLBROWSER WM_USER+7
125 /* NOTE
126 * Those macros exist in windowsx.h. However, you can't really use them since
127 * they rely on the UNICODE defines and can't be used inside Wine itself.
130 /* Combo box macros */
131 #define CBAddString(hwnd,str) \
132 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
134 #define CBInsertString(hwnd,str,pos) \
135 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
137 #define CBDeleteString(hwnd,pos) \
138 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
140 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
141 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
143 #define CBGetItemDataPtr(hwnd,iItemId) \
144 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
146 #define CBGetLBText(hwnd,iItemId,str) \
147 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
149 #define CBGetCurSel(hwnd) \
150 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
152 #define CBSetCurSel(hwnd,pos) \
153 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
155 #define CBGetCount(hwnd) \
156 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
157 #define CBShowDropDown(hwnd,show) \
158 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
159 #define CBSetItemHeight(hwnd,index,height) \
160 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
162 #define CBSetExtendedUI(hwnd,flag) \
163 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
165 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
166 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
167 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
169 static const WCHAR LastVisitedMRUW[] =
170 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
171 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
173 'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
174 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
176 /***********************************************************************
177 * Prototypes
180 /* Internal functions used by the dialog */
181 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
182 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
184 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
185 static BOOL FILEDLG95_OnOpen(HWND hwnd);
186 static LRESULT FILEDLG95_InitControls(HWND hwnd);
187 static void FILEDLG95_Clean(HWND hwnd);
189 /* Functions used by the shell navigation */
190 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Functions for dealing with the most-recently-used registry keys */
217 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
218 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
219 static void FILEDLG95_MRU_save_filename(LPCWSTR filename);
221 /* Miscellaneous tool functions */
222 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
223 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
224 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
225 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
227 static UINT GetNumSelected( IDataObject *doSelected );
229 /* Shell memory allocation */
230 static void *MemAlloc(UINT size);
231 static void MemFree(void *mem);
233 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
234 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
235 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
236 static BOOL BrowseSelectedFolder(HWND hwnd);
238 /***********************************************************************
239 * GetFileName95
241 * Creates an Open common dialog box that lets the user select
242 * the drive, directory, and the name of a file or set of files to open.
244 * IN : The FileOpenDlgInfos structure associated with the dialog
245 * OUT : TRUE on success
246 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
248 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
251 LRESULT lRes;
252 LPCVOID origTemplate;
253 DWORD dwSize;
254 LPDLGTEMPLATEW template;
255 HRSRC hRes;
256 HANDLE hDlgTmpl = 0;
257 HRESULT hr;
259 /* test for missing functionality */
260 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
262 FIXME("Flags 0x%08x not yet implemented\n",
263 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
266 /* Create the dialog from a template */
268 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
270 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
271 return FALSE;
273 if (!(dwSize = SizeofResource(COMDLG32_hInstance, hRes)) ||
274 !(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes)) ||
275 !(origTemplate = LockResource(hDlgTmpl)))
277 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
278 return FALSE;
280 if (!(template = HeapAlloc(GetProcessHeap(), 0, dwSize)))
282 COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE);
283 return FALSE;
285 memcpy(template, origTemplate, dwSize);
287 /* msdn: explorer style dialogs permit sizing by default.
288 * The OFN_ENABLESIZING flag is only needed when a hook or
289 * custom tmeplate is provided */
290 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
291 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
292 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
294 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
296 template->style |= WS_SIZEBOX;
297 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
298 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
300 else
301 template->style &= ~WS_SIZEBOX;
304 /* old style hook messages */
305 if (IsHooked(fodInfos))
307 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
308 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
309 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
310 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
313 /* Some shell namespace extensions depend on COM being initialized. */
314 hr = OleInitialize(NULL);
316 if (fodInfos->unicode)
317 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
318 template,
319 fodInfos->ofnInfos->hwndOwner,
320 FileOpenDlgProc95,
321 (LPARAM) fodInfos);
322 else
323 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
324 template,
325 fodInfos->ofnInfos->hwndOwner,
326 FileOpenDlgProc95,
327 (LPARAM) fodInfos);
328 if (SUCCEEDED(hr))
329 OleUninitialize();
331 HeapFree(GetProcessHeap(), 0, template);
333 /* Unable to create the dialog */
334 if( lRes == -1)
335 return FALSE;
337 return lRes;
340 /***********************************************************************
341 * GetFileDialog95A
343 * Call GetFileName95 with this structure and clean the memory.
345 * IN : The OPENFILENAMEA initialisation structure passed to
346 * GetOpenFileNameA win api function (see filedlg.c)
348 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
350 BOOL ret;
351 FileOpenDlgInfos fodInfos;
352 LPSTR lpstrSavDir = NULL;
353 LPWSTR title = NULL;
354 LPWSTR defext = NULL;
355 LPWSTR filter = NULL;
356 LPWSTR customfilter = NULL;
357 INITCOMMONCONTROLSEX icc;
359 /* Initialize ComboBoxEx32 */
360 icc.dwSize = sizeof(icc);
361 icc.dwICC = ICC_USEREX_CLASSES;
362 InitCommonControlsEx(&icc);
364 /* Initialize CommDlgExtendedError() */
365 COMDLG32_SetCommDlgExtendedError(0);
367 /* Initialize FileOpenDlgInfos structure */
368 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
370 /* Pass in the original ofn */
371 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
373 /* save current directory */
374 if (ofn->Flags & OFN_NOCHANGEDIR)
376 lpstrSavDir = MemAlloc(MAX_PATH);
377 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
380 fodInfos.unicode = FALSE;
382 /* convert all the input strings to unicode */
383 if(ofn->lpstrInitialDir)
385 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
386 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
387 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
389 else
390 fodInfos.initdir = NULL;
392 if(ofn->lpstrFile)
394 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
395 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
397 else
398 fodInfos.filename = NULL;
400 if(ofn->lpstrDefExt)
402 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
403 defext = MemAlloc((len+1)*sizeof(WCHAR));
404 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
406 fodInfos.defext = defext;
408 if(ofn->lpstrTitle)
410 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
411 title = MemAlloc((len+1)*sizeof(WCHAR));
412 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
414 fodInfos.title = title;
416 if (ofn->lpstrFilter)
418 LPCSTR s;
419 int n, len;
421 /* filter is a list... title\0ext\0......\0\0 */
422 s = ofn->lpstrFilter;
423 while (*s) s = s+strlen(s)+1;
424 s++;
425 n = s - ofn->lpstrFilter;
426 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
427 filter = MemAlloc(len*sizeof(WCHAR));
428 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
430 fodInfos.filter = filter;
432 /* convert lpstrCustomFilter */
433 if (ofn->lpstrCustomFilter)
435 LPCSTR s;
436 int n, len;
438 /* customfilter contains a pair of strings... title\0ext\0 */
439 s = ofn->lpstrCustomFilter;
440 if (*s) s = s+strlen(s)+1;
441 if (*s) s = s+strlen(s)+1;
442 n = s - ofn->lpstrCustomFilter;
443 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
444 customfilter = MemAlloc(len*sizeof(WCHAR));
445 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
447 fodInfos.customfilter = customfilter;
449 /* Initialize the dialog property */
450 fodInfos.DlgInfos.dwDlgProp = 0;
451 fodInfos.DlgInfos.hwndCustomDlg = NULL;
453 switch(iDlgType)
455 case OPEN_DIALOG :
456 ret = GetFileName95(&fodInfos);
457 break;
458 case SAVE_DIALOG :
459 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
460 ret = GetFileName95(&fodInfos);
461 break;
462 default :
463 ret = FALSE;
466 if (lpstrSavDir)
468 SetCurrentDirectoryA(lpstrSavDir);
469 MemFree(lpstrSavDir);
472 MemFree(title);
473 MemFree(defext);
474 MemFree(filter);
475 MemFree(customfilter);
476 MemFree(fodInfos.initdir);
477 MemFree(fodInfos.filename);
479 TRACE("selected file: %s\n",ofn->lpstrFile);
481 return ret;
484 /***********************************************************************
485 * GetFileDialog95W
487 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
488 * Call GetFileName95 with this structure and clean the memory.
491 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
493 BOOL ret;
494 FileOpenDlgInfos fodInfos;
495 LPWSTR lpstrSavDir = NULL;
496 INITCOMMONCONTROLSEX icc;
498 /* Initialize ComboBoxEx32 */
499 icc.dwSize = sizeof(icc);
500 icc.dwICC = ICC_USEREX_CLASSES;
501 InitCommonControlsEx(&icc);
503 /* Initialize CommDlgExtendedError() */
504 COMDLG32_SetCommDlgExtendedError(0);
506 /* Initialize FileOpenDlgInfos structure */
507 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
509 /* Pass in the original ofn */
510 fodInfos.ofnInfos = ofn;
512 fodInfos.title = ofn->lpstrTitle;
513 fodInfos.defext = ofn->lpstrDefExt;
514 fodInfos.filter = ofn->lpstrFilter;
515 fodInfos.customfilter = ofn->lpstrCustomFilter;
517 /* convert string arguments, save others */
518 if(ofn->lpstrFile)
520 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
521 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
523 else
524 fodInfos.filename = NULL;
526 if(ofn->lpstrInitialDir)
528 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
529 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
530 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
531 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
533 else
534 fodInfos.initdir = NULL;
536 /* save current directory */
537 if (ofn->Flags & OFN_NOCHANGEDIR)
539 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
540 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
543 fodInfos.unicode = TRUE;
545 switch(iDlgType)
547 case OPEN_DIALOG :
548 ret = GetFileName95(&fodInfos);
549 break;
550 case SAVE_DIALOG :
551 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
552 ret = GetFileName95(&fodInfos);
553 break;
554 default :
555 ret = FALSE;
558 if (lpstrSavDir)
560 SetCurrentDirectoryW(lpstrSavDir);
561 MemFree(lpstrSavDir);
564 /* restore saved IN arguments and convert OUT arguments back */
565 MemFree(fodInfos.filename);
566 MemFree(fodInfos.initdir);
567 return ret;
570 /******************************************************************************
571 * COMDLG32_GetDisplayNameOf [internal]
573 * Helper function to get the display name for a pidl.
575 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
576 LPSHELLFOLDER psfDesktop;
577 STRRET strret;
579 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
580 return FALSE;
582 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
583 IShellFolder_Release(psfDesktop);
584 return FALSE;
587 IShellFolder_Release(psfDesktop);
588 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
591 /******************************************************************************
592 * COMDLG32_GetCanonicalPath [internal]
594 * Helper function to get the canonical path.
596 void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent,
597 LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
599 WCHAR lpstrTemp[MAX_PATH];
601 /* Get the current directory name */
602 if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
604 /* last fallback */
605 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
607 PathAddBackslashW(lpstrPathAndFile);
609 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
611 /* if the user specified a fully qualified path use it */
612 if(PathIsRelativeW(lpstrFile))
614 lstrcatW(lpstrPathAndFile, lpstrFile);
616 else
618 /* does the path have a drive letter? */
619 if (PathGetDriveNumberW(lpstrFile) == -1)
620 lstrcpyW(lpstrPathAndFile+2, lpstrFile);
621 else
622 lstrcpyW(lpstrPathAndFile, lpstrFile);
625 /* resolve "." and ".." */
626 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
627 lstrcpyW(lpstrPathAndFile, lpstrTemp);
628 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
631 /***********************************************************************
632 * COMDLG32_SplitFileNames [internal]
634 * Creates a delimited list of filenames.
636 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
638 UINT nStrCharCount = 0; /* index in src buffer */
639 UINT nFileIndex = 0; /* index in dest buffer */
640 UINT nFileCount = 0; /* number of files */
642 /* we might get single filename without any '"',
643 * so we need nStrLen + terminating \0 + end-of-list \0 */
644 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
645 *sizeUsed = 0;
647 /* build delimited file list from filenames */
648 while ( nStrCharCount <= nStrLen )
650 if ( lpstrEdit[nStrCharCount]=='"' )
652 nStrCharCount++;
653 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
655 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
656 nStrCharCount++;
658 (*lpstrFileList)[nFileIndex++] = 0;
659 nFileCount++;
661 nStrCharCount++;
664 /* single, unquoted string */
665 if ((nStrLen > 0) && (nFileIndex == 0) )
667 lstrcpyW(*lpstrFileList, lpstrEdit);
668 nFileIndex = lstrlenW(lpstrEdit) + 1;
669 nFileCount = 1;
672 /* trailing \0 */
673 (*lpstrFileList)[nFileIndex++] = '\0';
675 *sizeUsed = nFileIndex;
676 return nFileCount;
679 /***********************************************************************
680 * ArrangeCtrlPositions [internal]
682 * NOTE: Make sure to add testcases for any changes made here.
684 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
686 HWND hwndChild, hwndStc32;
687 RECT rectParent, rectChild, rectStc32;
688 INT help_fixup = 0;
689 int chgx, chgy;
691 /* Take into account if open as read only checkbox and help button
692 * are hidden
694 if (hide_help)
696 RECT rectHelp, rectCancel;
697 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
698 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
699 /* subtract the height of the help button plus the space between
700 * the help button and the cancel button to the height of the dialog
702 help_fixup = rectHelp.bottom - rectCancel.bottom;
706 There are two possibilities to add components to the default file dialog box.
708 By default, all the new components are added below the standard dialog box (the else case).
710 However, if there is a static text component with the stc32 id, a special case happens.
711 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
712 in the window and the cx and cy indicate how to size the window.
713 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
714 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
718 GetClientRect(hwndParentDlg, &rectParent);
720 /* when arranging controls we have to use fixed parent size */
721 rectParent.bottom -= help_fixup;
723 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
724 if (hwndStc32)
726 GetWindowRect(hwndStc32, &rectStc32);
727 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
729 /* set the size of the stc32 control according to the size of
730 * client area of the parent dialog
732 SetWindowPos(hwndStc32, 0,
733 0, 0,
734 rectParent.right, rectParent.bottom,
735 SWP_NOMOVE | SWP_NOZORDER);
737 else
738 SetRectEmpty(&rectStc32);
740 /* this part moves controls of the child dialog */
741 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
742 while (hwndChild)
744 if (hwndChild != hwndStc32)
746 GetWindowRect(hwndChild, &rectChild);
747 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
749 /* move only if stc32 exist */
750 if (hwndStc32 && rectChild.left > rectStc32.right)
752 /* move to the right of visible controls of the parent dialog */
753 rectChild.left += rectParent.right;
754 rectChild.left -= rectStc32.right;
756 /* move even if stc32 doesn't exist */
757 if (rectChild.top >= rectStc32.bottom)
759 /* move below visible controls of the parent dialog */
760 rectChild.top += rectParent.bottom;
761 rectChild.top -= rectStc32.bottom - rectStc32.top;
764 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
765 0, 0, SWP_NOSIZE | SWP_NOZORDER);
767 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
770 /* this part moves controls of the parent dialog */
771 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
772 while (hwndChild)
774 if (hwndChild != hwndChildDlg)
776 GetWindowRect(hwndChild, &rectChild);
777 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
779 /* left,top of stc32 marks the position of controls
780 * from the parent dialog
782 rectChild.left += rectStc32.left;
783 rectChild.top += rectStc32.top;
785 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
786 0, 0, SWP_NOSIZE | SWP_NOZORDER);
788 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
791 /* calculate the size of the resulting dialog */
793 /* here we have to use original parent size */
794 GetClientRect(hwndParentDlg, &rectParent);
795 GetClientRect(hwndChildDlg, &rectChild);
796 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
797 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
799 if (hwndStc32)
801 /* width */
802 if (rectParent.right > rectStc32.right - rectStc32.left)
803 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
804 else
805 chgx = rectChild.right - rectParent.right;
806 /* height */
807 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
808 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
809 else
810 /* Unconditionally set new dialog
811 * height to that of the child
813 chgy = rectChild.bottom - rectParent.bottom;
815 else
817 chgx = 0;
818 chgy = rectChild.bottom - help_fixup;
820 /* set the size of the parent dialog */
821 GetWindowRect(hwndParentDlg, &rectParent);
822 SetWindowPos(hwndParentDlg, 0,
823 0, 0,
824 rectParent.right - rectParent.left + chgx,
825 rectParent.bottom - rectParent.top + chgy,
826 SWP_NOMOVE | SWP_NOZORDER);
829 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
831 switch(uMsg) {
832 case WM_INITDIALOG:
833 return TRUE;
835 return FALSE;
838 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
840 LPCVOID template;
841 HRSRC hRes;
842 HANDLE hDlgTmpl = 0;
843 HWND hChildDlg = 0;
845 TRACE("\n");
848 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
849 * structure's hInstance parameter is not a HINSTANCE, but
850 * instead a pointer to a template resource to use.
852 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
854 HINSTANCE hinst;
855 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
857 hinst = COMDLG32_hInstance;
858 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
860 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
861 return NULL;
864 else
866 hinst = fodInfos->ofnInfos->hInstance;
867 if(fodInfos->unicode)
869 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
870 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
872 else
874 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
875 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
877 if (!hRes)
879 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
880 return NULL;
882 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
883 !(template = LockResource( hDlgTmpl )))
885 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
886 return NULL;
889 if (fodInfos->unicode)
890 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
891 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
892 (LPARAM)fodInfos->ofnInfos);
893 else
894 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
895 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
896 (LPARAM)fodInfos->ofnInfos);
897 return hChildDlg;
899 else if( IsHooked(fodInfos))
901 RECT rectHwnd;
902 struct {
903 DLGTEMPLATE tmplate;
904 WORD menu,class,title;
905 } temp;
906 GetClientRect(hwnd,&rectHwnd);
907 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
908 temp.tmplate.dwExtendedStyle = 0;
909 temp.tmplate.cdit = 0;
910 temp.tmplate.x = 0;
911 temp.tmplate.y = 0;
912 temp.tmplate.cx = 0;
913 temp.tmplate.cy = 0;
914 temp.menu = temp.class = temp.title = 0;
916 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
917 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
919 return hChildDlg;
921 return NULL;
924 /***********************************************************************
925 * SendCustomDlgNotificationMessage
927 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
930 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
932 LRESULT hook_result = 0;
933 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
935 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
937 if(!fodInfos) return 0;
939 if(fodInfos->DlgInfos.hwndCustomDlg)
941 TRACE("CALL NOTIFY for %x\n", uCode);
942 if(fodInfos->unicode)
944 OFNOTIFYW ofnNotify;
945 ofnNotify.hdr.hwndFrom=hwndParentDlg;
946 ofnNotify.hdr.idFrom=0;
947 ofnNotify.hdr.code = uCode;
948 ofnNotify.lpOFN = fodInfos->ofnInfos;
949 ofnNotify.pszFile = NULL;
950 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
952 else
954 OFNOTIFYA ofnNotify;
955 ofnNotify.hdr.hwndFrom=hwndParentDlg;
956 ofnNotify.hdr.idFrom=0;
957 ofnNotify.hdr.code = uCode;
958 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
959 ofnNotify.pszFile = NULL;
960 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
962 TRACE("RET NOTIFY\n");
964 TRACE("Retval: 0x%08lx\n", hook_result);
965 return hook_result;
968 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
970 UINT len, total;
971 WCHAR *p, *buffer;
972 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
974 TRACE("CDM_GETFILEPATH:\n");
976 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
977 return -1;
979 /* get path and filenames */
980 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
981 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
982 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
983 if (len)
985 p = buffer + strlenW(buffer);
986 *p++ = '\\';
987 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
989 if (fodInfos->unicode)
991 total = strlenW( buffer) + 1;
992 if (result) lstrcpynW( result, buffer, size );
993 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
995 else
997 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
998 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
999 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1001 HeapFree( GetProcessHeap(), 0, buffer );
1002 return total;
1005 /***********************************************************************
1006 * FILEDLG95_HandleCustomDialogMessages
1008 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1010 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1012 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1013 WCHAR lpstrPath[MAX_PATH];
1014 INT_PTR retval;
1016 if(!fodInfos) return FALSE;
1018 switch(uMsg)
1020 case CDM_GETFILEPATH:
1021 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
1022 break;
1024 case CDM_GETFOLDERPATH:
1025 TRACE("CDM_GETFOLDERPATH:\n");
1026 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1027 if (lParam)
1029 if (fodInfos->unicode)
1030 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1031 else
1032 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1033 (LPSTR)lParam, (int)wParam, NULL, NULL);
1035 retval = lstrlenW(lpstrPath) + 1;
1036 break;
1038 case CDM_GETFOLDERIDLIST:
1039 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1040 if (retval <= wParam)
1041 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1042 break;
1044 case CDM_GETSPEC:
1045 TRACE("CDM_GETSPEC:\n");
1046 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1047 if (lParam)
1049 if (fodInfos->unicode)
1050 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1051 else
1052 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1054 break;
1056 case CDM_SETCONTROLTEXT:
1057 TRACE("CDM_SETCONTROLTEXT:\n");
1058 if ( lParam )
1060 if( fodInfos->unicode )
1061 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
1062 else
1063 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1065 retval = TRUE;
1066 break;
1068 case CDM_HIDECONTROL:
1069 /* MSDN states that it should fail for not OFN_EXPLORER case */
1070 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1072 HWND control = GetDlgItem( hwnd, wParam );
1073 if (control) ShowWindow( control, SW_HIDE );
1074 retval = TRUE;
1076 else retval = FALSE;
1077 break;
1079 default:
1080 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1081 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1082 return FALSE;
1084 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1085 return TRUE;
1088 /***********************************************************************
1089 * FILEDLG95_OnWMGetMMI
1091 * WM_GETMINMAXINFO message handler for resizable dialogs
1093 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
1095 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1096 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1097 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1099 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1101 return TRUE;
1104 /***********************************************************************
1105 * FILEDLG95_OnWMSize
1107 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1109 * FIXME: this could be made more elaborate. Now use a simple scheme
1110 * where the file view is enlarged and the controls are either moved
1111 * vertically or horizontally to get out of the way. Only the "grip"
1112 * is moved in both directions to stay in the corner.
1114 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1116 RECT rc, rcview;
1117 int chgx, chgy;
1118 HWND ctrl;
1119 HDWP hdwp;
1120 FileOpenDlgInfos *fodInfos;
1122 if( wParam != SIZE_RESTORED) return FALSE;
1123 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1124 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1125 /* get the new dialog rectangle */
1126 GetWindowRect( hwnd, &rc);
1127 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1128 rc.right -rc.left, rc.bottom -rc.top);
1129 /* not initialized yet */
1130 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1131 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1132 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1133 return FALSE;
1134 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1135 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1136 fodInfos->sizedlg.cx = rc.right - rc.left;
1137 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1138 /* change the size of the view window */
1139 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1140 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1141 hdwp = BeginDeferWindowPos( 10);
1142 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1143 rcview.right - rcview.left + chgx,
1144 rcview.bottom - rcview.top + chgy,
1145 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1146 /* change position and sizes of the controls */
1147 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1149 int ctrlid = GetDlgCtrlID( ctrl);
1150 GetWindowRect( ctrl, &rc);
1151 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1152 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1154 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1155 0, 0,
1156 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1158 else if( rc.top > rcview.bottom)
1160 /* if it was below the shell view
1161 * move to bottom */
1162 switch( ctrlid)
1164 /* file name (edit or comboboxex) and file types combo change also width */
1165 case edt1:
1166 case cmb13:
1167 case cmb1:
1168 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1169 rc.right - rc.left + chgx, rc.bottom - rc.top,
1170 SWP_NOACTIVATE | SWP_NOZORDER);
1171 break;
1172 /* then these buttons must move out of the way */
1173 case IDOK:
1174 case IDCANCEL:
1175 case pshHelp:
1176 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1177 0, 0,
1178 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1179 break;
1180 default:
1181 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1182 0, 0,
1183 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1186 else if( rc.left > rcview.right)
1188 /* if it was to the right of the shell view
1189 * move to right */
1190 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1191 0, 0,
1192 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1194 else
1195 /* special cases */
1197 switch( ctrlid)
1199 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1200 case IDC_LOOKIN:
1201 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1202 rc.right - rc.left + chgx, rc.bottom - rc.top,
1203 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1204 break;
1205 case IDC_TOOLBARSTATIC:
1206 case IDC_TOOLBAR:
1207 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1208 0, 0,
1209 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1210 break;
1211 #endif
1212 /* not resized in windows. Since wine uses this invisible control
1213 * to size the browser view it needs to be resized */
1214 case IDC_SHELLSTATIC:
1215 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1216 rc.right - rc.left + chgx,
1217 rc.bottom - rc.top + chgy,
1218 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1219 break;
1223 if(fodInfos->DlgInfos.hwndCustomDlg &&
1224 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1226 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1227 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1229 GetWindowRect( ctrl, &rc);
1230 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1231 if( rc.top > rcview.bottom)
1233 /* if it was below the shell view
1234 * move to bottom */
1235 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1236 rc.right - rc.left, rc.bottom - rc.top,
1237 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1239 else if( rc.left > rcview.right)
1241 /* if it was to the right of the shell view
1242 * move to right */
1243 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1244 rc.right - rc.left, rc.bottom - rc.top,
1245 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1248 /* size the custom dialog at the end: some applications do some
1249 * control re-arranging at this point */
1250 GetClientRect(hwnd, &rc);
1251 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1252 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1254 EndDeferWindowPos( hdwp);
1255 /* should not be needed */
1256 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1257 return TRUE;
1260 /***********************************************************************
1261 * FileOpenDlgProc95
1263 * File open dialog procedure
1265 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1267 #if 0
1268 TRACE("%p 0x%04x\n", hwnd, uMsg);
1269 #endif
1271 switch(uMsg)
1273 case WM_INITDIALOG:
1275 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1276 RECT rc, rcstc;
1277 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1278 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1280 /* Adds the FileOpenDlgInfos in the property list of the dialog
1281 so it will be easily accessible through a GetPropA(...) */
1282 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1284 FILEDLG95_InitControls(hwnd);
1286 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1288 GetWindowRect( hwnd, &rc);
1289 fodInfos->DlgInfos.hwndGrip =
1290 CreateWindowExA( 0, "SCROLLBAR", NULL,
1291 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1292 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1293 rc.right - gripx, rc.bottom - gripy,
1294 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1297 fodInfos->DlgInfos.hwndCustomDlg =
1298 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1300 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1301 FILEDLG95_FillControls(hwnd, wParam, lParam);
1303 if( fodInfos->DlgInfos.hwndCustomDlg)
1304 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1306 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1307 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1308 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1311 /* if the app has changed the position of the invisible listbox,
1312 * change that of the listview (browser) as well */
1313 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1314 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1315 if( !EqualRect( &rc, &rcstc))
1317 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1318 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1319 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1320 SWP_NOACTIVATE | SWP_NOZORDER);
1323 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1325 GetWindowRect( hwnd, &rc);
1326 fodInfos->sizedlg.cx = rc.right - rc.left;
1327 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1328 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1329 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1330 GetClientRect( hwnd, &rc);
1331 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1332 rc.right - gripx, rc.bottom - gripy,
1333 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1334 /* resize the dialog to the previous invocation */
1335 if( MemDialogSize.cx && MemDialogSize.cy)
1336 SetWindowPos( hwnd, NULL,
1337 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1338 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1341 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1342 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1344 return 0;
1346 case WM_SIZE:
1347 return FILEDLG95_OnWMSize(hwnd, wParam);
1348 case WM_GETMINMAXINFO:
1349 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1350 case WM_COMMAND:
1351 return FILEDLG95_OnWMCommand(hwnd, wParam);
1352 case WM_DRAWITEM:
1354 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1356 case IDC_LOOKIN:
1357 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1358 return TRUE;
1361 return FALSE;
1363 case WM_GETISHELLBROWSER:
1364 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1366 case WM_DESTROY:
1368 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1369 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1370 MemDialogSize = fodInfos->sizedlg;
1371 RemovePropA(hwnd, FileOpenDlgInfosStr);
1372 return FALSE;
1374 case WM_NOTIFY:
1376 LPNMHDR lpnmh = (LPNMHDR)lParam;
1377 UINT stringId = -1;
1379 /* set up the button tooltips strings */
1380 if(TTN_GETDISPINFOA == lpnmh->code )
1382 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1383 switch(lpnmh->idFrom )
1385 /* Up folder button */
1386 case FCIDM_TB_UPFOLDER:
1387 stringId = IDS_UPFOLDER;
1388 break;
1389 /* New folder button */
1390 case FCIDM_TB_NEWFOLDER:
1391 stringId = IDS_NEWFOLDER;
1392 break;
1393 /* List option button */
1394 case FCIDM_TB_SMALLICON:
1395 stringId = IDS_LISTVIEW;
1396 break;
1397 /* Details option button */
1398 case FCIDM_TB_REPORTVIEW:
1399 stringId = IDS_REPORTVIEW;
1400 break;
1401 /* Desktop button */
1402 case FCIDM_TB_DESKTOP:
1403 stringId = IDS_TODESKTOP;
1404 break;
1405 default:
1406 stringId = 0;
1408 lpdi->hinst = COMDLG32_hInstance;
1409 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1411 return FALSE;
1413 default :
1414 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1415 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1416 return FALSE;
1420 static inline BOOL filename_is_edit( const FileOpenDlgInfos *info )
1422 return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1423 (info->ofnInfos->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE));
1426 /***********************************************************************
1427 * FILEDLG95_InitControls
1429 * WM_INITDIALOG message handler (before hook notification)
1431 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1433 BOOL win2000plus = FALSE;
1434 BOOL win98plus = FALSE;
1435 BOOL handledPath = FALSE;
1436 OSVERSIONINFOW osVi;
1437 static const WCHAR szwSlash[] = { '\\', 0 };
1438 static const WCHAR szwStar[] = { '*',0 };
1440 static const TBBUTTON tbb[] =
1442 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1443 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1444 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1445 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1446 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1447 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1448 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1449 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1450 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1452 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1454 RECT rectTB;
1455 RECT rectlook;
1457 HIMAGELIST toolbarImageList;
1458 SHFILEINFOA shFileInfo;
1459 ITEMIDLIST *desktopPidl;
1461 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1463 TRACE("%p\n", fodInfos);
1465 /* Get windows version emulating */
1466 osVi.dwOSVersionInfoSize = sizeof(osVi);
1467 GetVersionExW(&osVi);
1468 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1469 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1470 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1471 win2000plus = (osVi.dwMajorVersion > 4);
1472 if (win2000plus) win98plus = TRUE;
1474 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1477 /* Use either the edit or the comboboxex for the filename control */
1478 if (filename_is_edit( fodInfos ))
1480 DestroyWindow( GetDlgItem( hwnd, cmb13 ) );
1481 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1483 else
1485 DestroyWindow( GetDlgItem( hwnd, edt1 ) );
1486 fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1489 /* Get the hwnd of the controls */
1490 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1491 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1493 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1494 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1496 /* construct the toolbar */
1497 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1498 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1500 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1501 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1502 rectTB.left = rectlook.right;
1503 rectTB.top = rectlook.top-1;
1505 if (fodInfos->unicode)
1506 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1507 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1508 rectTB.left, rectTB.top,
1509 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1510 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1511 else
1512 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1513 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1514 rectTB.left, rectTB.top,
1515 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1516 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1518 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1520 /* FIXME: use TB_LOADIMAGES when implemented */
1521 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1522 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1523 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1525 /* Retrieve and add desktop icon to the toolbar */
1526 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1527 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1528 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1529 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1530 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1532 DestroyIcon(shFileInfo.hIcon);
1533 CoTaskMemFree(desktopPidl);
1535 /* Finish Toolbar Construction */
1536 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1537 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1539 /* Set the window text with the text specified in the OPENFILENAME structure */
1540 if(fodInfos->title)
1542 SetWindowTextW(hwnd,fodInfos->title);
1544 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1546 WCHAR buf[64];
1547 LoadStringW(COMDLG32_hInstance, IDS_SAVE_AS, buf, sizeof(buf)/sizeof(WCHAR));
1548 SetWindowTextW(hwnd, buf);
1551 /* Initialise the file name edit control */
1552 handledPath = FALSE;
1553 TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1555 if(fodInfos->filename)
1557 /* 1. If win2000 or higher and filename contains a path, use it
1558 in preference over the lpstrInitialDir */
1559 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1560 WCHAR tmpBuf[MAX_PATH];
1561 WCHAR *nameBit;
1562 DWORD result;
1564 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1565 if (result) {
1567 /* nameBit is always shorter than the original filename */
1568 lstrcpyW(fodInfos->filename,nameBit);
1570 *nameBit = 0x00;
1571 MemFree(fodInfos->initdir);
1572 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1573 lstrcpyW(fodInfos->initdir, tmpBuf);
1574 handledPath = TRUE;
1575 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1576 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1578 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1580 } else {
1581 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1585 /* 2. (All platforms) If initdir is not null, then use it */
1586 if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1588 /* Work out the proper path as supplied one might be relative */
1589 /* (Here because supplying '.' as dir browses to My Computer) */
1590 WCHAR tmpBuf[MAX_PATH];
1591 WCHAR tmpBuf2[MAX_PATH];
1592 WCHAR *nameBit;
1593 DWORD result;
1595 lstrcpyW(tmpBuf, fodInfos->initdir);
1596 if (PathFileExistsW(tmpBuf)) {
1597 /* initdir does not have to be a directory. If a file is
1598 * specified, the dir part is taken */
1599 if (PathIsDirectoryW(tmpBuf)) {
1600 PathAddBackslashW(tmpBuf);
1601 lstrcatW(tmpBuf, szwStar);
1603 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1604 if (result) {
1605 *nameBit = 0x00;
1606 MemFree(fodInfos->initdir);
1607 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1608 lstrcpyW(fodInfos->initdir, tmpBuf2);
1609 handledPath = TRUE;
1610 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1613 else if (fodInfos->initdir)
1615 MemFree(fodInfos->initdir);
1616 fodInfos->initdir = NULL;
1617 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1621 if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1623 /* 3. All except w2k+: if filename contains a path use it */
1624 if (!win2000plus && fodInfos->filename &&
1625 *fodInfos->filename &&
1626 strpbrkW(fodInfos->filename, szwSlash)) {
1627 WCHAR tmpBuf[MAX_PATH];
1628 WCHAR *nameBit;
1629 DWORD result;
1631 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1632 tmpBuf, &nameBit);
1633 if (result) {
1634 int len;
1636 /* nameBit is always shorter than the original filename */
1637 lstrcpyW(fodInfos->filename, nameBit);
1638 *nameBit = 0x00;
1640 len = lstrlenW(tmpBuf);
1641 MemFree(fodInfos->initdir);
1642 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1643 lstrcpyW(fodInfos->initdir, tmpBuf);
1645 handledPath = TRUE;
1646 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1647 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1649 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1652 /* 4. Win2000+: Recently used */
1653 if (!handledPath && win2000plus) {
1654 fodInfos->initdir = MemAlloc(MAX_PATH * sizeof(WCHAR));
1655 fodInfos->initdir[0] = '\0';
1657 FILEDLG95_MRU_load_filename(fodInfos->initdir);
1659 if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1660 handledPath = TRUE;
1661 }else{
1662 MemFree(fodInfos->initdir);
1663 fodInfos->initdir = NULL;
1667 /* 5. win98+ and win2000+ if any files of specified filter types in
1668 current directory, use it */
1669 if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1671 LPCWSTR lpstrPos = fodInfos->filter;
1672 WIN32_FIND_DATAW FindFileData;
1673 HANDLE hFind;
1675 while (1)
1677 /* filter is a list... title\0ext\0......\0\0 */
1679 /* Skip the title */
1680 if(! *lpstrPos) break; /* end */
1681 lpstrPos += lstrlenW(lpstrPos) + 1;
1683 /* See if any files exist in the current dir with this extension */
1684 if(! *lpstrPos) break; /* end */
1686 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1688 if (hFind == INVALID_HANDLE_VALUE) {
1689 /* None found - continue search */
1690 lpstrPos += lstrlenW(lpstrPos) + 1;
1692 } else {
1694 MemFree(fodInfos->initdir);
1695 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1696 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1698 handledPath = TRUE;
1699 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1700 debugstr_w(lpstrPos));
1701 FindClose(hFind);
1702 break;
1707 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1708 if (!handledPath && (win2000plus || win98plus)) {
1709 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1711 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1713 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1715 /* last fallback */
1716 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1717 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1718 } else {
1719 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1721 } else {
1722 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1724 handledPath = TRUE;
1725 } else if (!handledPath) {
1726 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1727 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1728 handledPath = TRUE;
1729 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1732 SetFocus( fodInfos->DlgInfos.hwndFileName );
1733 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1735 /* Must the open as read only check box be checked ?*/
1736 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1738 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1741 /* Must the open as read only check box be hidden? */
1742 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1744 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1745 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1748 /* Must the help button be hidden? */
1749 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1751 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1752 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1755 /* change Open to Save */
1756 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1758 WCHAR buf[16];
1759 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1760 SetDlgItemTextW(hwnd, IDOK, buf);
1761 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1762 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1765 /* Initialize the filter combo box */
1766 FILEDLG95_FILETYPE_Init(hwnd);
1768 return 0;
1771 /***********************************************************************
1772 * FILEDLG95_ResizeControls
1774 * WM_INITDIALOG message handler (after hook notification)
1776 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1778 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1780 if (fodInfos->DlgInfos.hwndCustomDlg)
1782 RECT rc;
1783 UINT flags = SWP_NOACTIVATE;
1785 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1786 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1788 /* resize the custom dialog to the parent size */
1789 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1790 GetClientRect(hwnd, &rc);
1791 else
1793 /* our own fake template is zero sized and doesn't have children, so
1794 * there is no need to resize it. Picasa depends on it.
1796 flags |= SWP_NOSIZE;
1797 SetRectEmpty(&rc);
1799 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1800 0, 0, rc.right, rc.bottom, flags);
1802 else
1804 /* Resize the height; if opened as read-only, checkbox and help button are
1805 * hidden and we are not using a custom template nor a customDialog
1807 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1808 (!(fodInfos->ofnInfos->Flags &
1809 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1811 RECT rectDlg, rectHelp, rectCancel;
1812 GetWindowRect(hwnd, &rectDlg);
1813 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1814 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1815 /* subtract the height of the help button plus the space between the help
1816 * button and the cancel button to the height of the dialog
1818 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1819 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1820 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1823 return TRUE;
1826 /***********************************************************************
1827 * FILEDLG95_FillControls
1829 * WM_INITDIALOG message handler (after hook notification)
1831 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1833 LPITEMIDLIST pidlItemId = NULL;
1835 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1837 TRACE("dir=%s file=%s\n",
1838 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1840 /* Get the initial directory pidl */
1842 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1844 WCHAR path[MAX_PATH];
1846 GetCurrentDirectoryW(MAX_PATH,path);
1847 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1850 /* Initialise shell objects */
1851 FILEDLG95_SHELL_Init(hwnd);
1853 /* Initialize the Look In combo box */
1854 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1856 /* Browse to the initial directory */
1857 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1859 /* Free pidlItem memory */
1860 COMDLG32_SHFree(pidlItemId);
1862 return TRUE;
1864 /***********************************************************************
1865 * FILEDLG95_Clean
1867 * Regroups all the cleaning functions of the filedlg
1869 void FILEDLG95_Clean(HWND hwnd)
1871 FILEDLG95_FILETYPE_Clean(hwnd);
1872 FILEDLG95_LOOKIN_Clean(hwnd);
1873 FILEDLG95_SHELL_Clean(hwnd);
1875 /***********************************************************************
1876 * FILEDLG95_OnWMCommand
1878 * WM_COMMAND message handler
1880 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1882 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1883 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1884 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1886 switch(wID)
1888 /* OK button */
1889 case IDOK:
1890 FILEDLG95_OnOpen(hwnd);
1891 break;
1892 /* Cancel button */
1893 case IDCANCEL:
1894 FILEDLG95_Clean(hwnd);
1895 EndDialog(hwnd, FALSE);
1896 break;
1897 /* Filetype combo box */
1898 case IDC_FILETYPE:
1899 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1900 break;
1901 /* LookIn combo box */
1902 case IDC_LOOKIN:
1903 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1904 break;
1906 /* --- toolbar --- */
1907 /* Up folder button */
1908 case FCIDM_TB_UPFOLDER:
1909 FILEDLG95_SHELL_UpFolder(hwnd);
1910 break;
1911 /* New folder button */
1912 case FCIDM_TB_NEWFOLDER:
1913 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1914 break;
1915 /* List option button */
1916 case FCIDM_TB_SMALLICON:
1917 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1918 break;
1919 /* Details option button */
1920 case FCIDM_TB_REPORTVIEW:
1921 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1922 break;
1923 /* Details option button */
1924 case FCIDM_TB_DESKTOP:
1925 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1926 break;
1928 case edt1:
1929 case cmb13:
1930 break;
1933 /* Do not use the listview selection anymore */
1934 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1935 return 0;
1938 /***********************************************************************
1939 * FILEDLG95_OnWMGetIShellBrowser
1941 * WM_GETISHELLBROWSER message handler
1943 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1945 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1947 TRACE("\n");
1949 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1951 return TRUE;
1955 /***********************************************************************
1956 * FILEDLG95_SendFileOK
1958 * Sends the CDN_FILEOK notification if required
1960 * RETURNS
1961 * TRUE if the dialog should close
1962 * FALSE if the dialog should not be closed
1964 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1966 /* ask the hook if we can close */
1967 if(IsHooked(fodInfos))
1969 LRESULT retval = 0;
1971 TRACE("---\n");
1972 /* First send CDN_FILEOK as MSDN doc says */
1973 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1974 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1975 if( retval)
1977 TRACE("canceled\n");
1978 return FALSE;
1981 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1982 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1983 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1984 if( retval)
1986 TRACE("canceled\n");
1987 return FALSE;
1990 return TRUE;
1993 /***********************************************************************
1994 * FILEDLG95_OnOpenMultipleFiles
1996 * Handles the opening of multiple files.
1998 * FIXME
1999 * check destination buffer size
2001 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2003 WCHAR lpstrPathSpec[MAX_PATH] = {0};
2004 UINT nCount, nSizePath;
2005 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2007 TRACE("\n");
2009 if(fodInfos->unicode)
2011 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2012 ofn->lpstrFile[0] = '\0';
2014 else
2016 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
2017 ofn->lpstrFile[0] = '\0';
2020 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2022 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2023 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2024 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2026 LPWSTR lpstrTemp = lpstrFileList;
2028 for ( nCount = 0; nCount < nFileCount; nCount++ )
2030 LPITEMIDLIST pidl;
2032 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2033 if (!pidl)
2035 WCHAR lpstrNotFound[100];
2036 WCHAR lpstrMsg[100];
2037 WCHAR tmp[400];
2038 static const WCHAR nl[] = {'\n',0};
2040 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2041 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
2043 lstrcpyW(tmp, lpstrTemp);
2044 lstrcatW(tmp, nl);
2045 lstrcatW(tmp, lpstrNotFound);
2046 lstrcatW(tmp, nl);
2047 lstrcatW(tmp, lpstrMsg);
2049 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2050 return FALSE;
2053 /* move to the next file in the list of files */
2054 lpstrTemp += lstrlenW(lpstrTemp) + 1;
2055 COMDLG32_SHFree(pidl);
2059 nSizePath = lstrlenW(lpstrPathSpec) + 1;
2060 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2062 /* For "oldstyle" dialog the components have to
2063 be separated by blanks (not '\0'!) and short
2064 filenames have to be used! */
2065 FIXME("Components have to be separated by blanks\n");
2067 if(fodInfos->unicode)
2069 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2070 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2071 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2073 else
2075 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2077 if (ofn->lpstrFile != NULL)
2079 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2080 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2081 if (ofn->nMaxFile > nSizePath)
2083 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2084 ofn->lpstrFile + nSizePath,
2085 ofn->nMaxFile - nSizePath, NULL, NULL);
2090 fodInfos->ofnInfos->nFileOffset = nSizePath;
2091 fodInfos->ofnInfos->nFileExtension = 0;
2093 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2094 return FALSE;
2096 /* clean and exit */
2097 FILEDLG95_Clean(hwnd);
2098 return EndDialog(hwnd,TRUE);
2101 /* Returns the 'slot name' of the given module_name in the registry's
2102 * most-recently-used list. This will be an ASCII value in the
2103 * range ['a','z'). Returns zero on error.
2105 * The slot's value in the registry has the form:
2106 * module_name\0mru_path\0
2108 * If stored_path is given, then stored_path will contain the path name
2109 * stored in the registry's MRU list for the given module_name.
2111 * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2112 * MRU list key for the given module_name.
2114 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret)
2116 WCHAR mru_list[32], *cur_mru_slot;
2117 BOOL taken[25] = {0};
2118 DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2119 HKEY hkey_tmp, *hkey;
2120 LONG ret;
2122 if(hkey_ret)
2123 hkey = hkey_ret;
2124 else
2125 hkey = &hkey_tmp;
2127 if(stored_path)
2128 *stored_path = '\0';
2130 ret = RegCreateKeyW(HKEY_CURRENT_USER, LastVisitedMRUW, hkey);
2131 if(ret){
2132 WARN("Unable to create MRU key: %d\n", ret);
2133 return 0;
2136 ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2137 (LPBYTE)mru_list, &mru_list_size);
2138 if(ret || key_type != REG_SZ){
2139 if(ret == ERROR_FILE_NOT_FOUND)
2140 return 'a';
2142 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2143 RegCloseKey(*hkey);
2144 return 0;
2147 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2148 WCHAR value_data[MAX_PATH], value_name[2] = {0};
2149 DWORD value_data_size = sizeof(value_data);
2151 *value_name = *cur_mru_slot;
2153 ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2154 &key_type, (LPBYTE)value_data, &value_data_size);
2155 if(ret || key_type != REG_BINARY){
2156 WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2157 continue;
2160 if(!strcmpiW(module_name, value_data)){
2161 if(!hkey_ret)
2162 RegCloseKey(*hkey);
2163 if(stored_path)
2164 lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2165 return *value_name;
2169 if(!hkey_ret)
2170 RegCloseKey(*hkey);
2172 /* the module name isn't in the registry, so find the next open slot */
2173 for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2174 taken[*cur_mru_slot - 'a'] = TRUE;
2175 for(i = 0; i < 25; ++i){
2176 if(!taken[i])
2177 return i + 'a';
2180 /* all slots are taken, so return the last one in MRUList */
2181 --cur_mru_slot;
2182 return *cur_mru_slot;
2185 /* save the given filename as most-recently-used path for this module */
2186 static void FILEDLG95_MRU_save_filename(LPCWSTR filename)
2188 WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2189 LONG ret;
2190 HKEY hkey;
2192 /* get the current executable's name */
2193 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2194 WARN("GotModuleFileName failed: %d\n", GetLastError());
2195 return;
2197 module_name = strrchrW(module_path, '\\');
2198 if(!module_name)
2199 module_name = module_path;
2200 else
2201 module_name += 1;
2203 slot = FILEDLG95_MRU_get_slot(module_name, NULL, &hkey);
2204 if(!slot)
2205 return;
2206 *slot_name = slot;
2208 { /* update the slot's info */
2209 WCHAR *path_ends, *final;
2210 DWORD path_len, final_len;
2212 /* use only the path segment of `filename' */
2213 path_ends = strrchrW(filename, '\\');
2214 path_len = path_ends - filename;
2216 final_len = path_len + lstrlenW(module_name) + 2;
2218 final = MemAlloc(final_len * sizeof(WCHAR));
2219 if(!final)
2220 return;
2221 lstrcpyW(final, module_name);
2222 memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2223 final[final_len-1] = '\0';
2225 ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2226 final_len * sizeof(WCHAR));
2227 if(ret){
2228 WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2229 MemFree(final);
2230 RegCloseKey(hkey);
2231 return;
2234 MemFree(final);
2237 { /* update MRUList value */
2238 WCHAR old_mru_list[32], new_mru_list[32];
2239 WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2240 DWORD mru_list_size = sizeof(old_mru_list), key_type;
2242 ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2243 (LPBYTE)old_mru_list, &mru_list_size);
2244 if(ret || key_type != REG_SZ){
2245 if(ret == ERROR_FILE_NOT_FOUND){
2246 new_mru_list[0] = slot;
2247 new_mru_list[1] = '\0';
2248 }else{
2249 WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2250 RegCloseKey(hkey);
2251 return;
2253 }else{
2254 /* copy old list data over so that the new slot is at the start
2255 * of the list */
2256 *new_mru_slot++ = slot;
2257 for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2258 if(*old_mru_slot != slot)
2259 *new_mru_slot++ = *old_mru_slot;
2261 *new_mru_slot = '\0';
2264 ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2265 (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2266 if(ret){
2267 WARN("Error saving MRUList data: %d\n", ret);
2268 RegCloseKey(hkey);
2269 return;
2274 /* load the most-recently-used path for this module */
2275 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2277 WCHAR module_path[MAX_PATH], *module_name;
2279 /* get the current executable's name */
2280 if(!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, sizeof(module_path)/sizeof(module_path[0]))) {
2281 WARN("GotModuleFileName failed: %d\n", GetLastError());
2282 return;
2284 module_name = strrchrW(module_path, '\\');
2285 if(!module_name)
2286 module_name = module_path;
2287 else
2288 module_name += 1;
2290 FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2291 TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2294 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2296 WCHAR strMsgTitle[MAX_PATH];
2297 WCHAR strMsgText [MAX_PATH];
2298 if (idCaption)
2299 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
2300 else
2301 strMsgTitle[0] = '\0';
2302 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
2303 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2306 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2307 HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2309 int nOpenAction = defAction;
2310 LPWSTR lpszTemp, lpszTemp1;
2311 LPITEMIDLIST pidl = NULL;
2312 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2314 /* check for invalid chars */
2315 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2317 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2318 return FALSE;
2321 if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2323 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2324 while (lpszTemp1)
2326 LPSHELLFOLDER lpsfChild;
2327 WCHAR lpwstrTemp[MAX_PATH];
2328 DWORD dwEaten, dwAttributes;
2329 LPWSTR p;
2331 lstrcpyW(lpwstrTemp, lpszTemp);
2332 p = PathFindNextComponentW(lpwstrTemp);
2334 if (!p) break; /* end of path */
2336 *p = 0;
2337 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2339 /* There are no wildcards when OFN_NOVALIDATE is set */
2340 if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2342 static const WCHAR wszWild[] = { '*', '?', 0 };
2343 /* if the last element is a wildcard do a search */
2344 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2346 nOpenAction = ONOPEN_SEARCH;
2347 break;
2350 lpszTemp1 = lpszTemp;
2352 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2354 /* append a backslash to drive letters */
2355 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2356 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2357 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2359 PathAddBackslashW(lpwstrTemp);
2362 dwAttributes = SFGAO_FOLDER;
2363 if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2365 /* the path component is valid, we have a pidl of the next path component */
2366 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2367 if(dwAttributes & SFGAO_FOLDER)
2369 if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2371 ERR("bind to failed\n"); /* should not fail */
2372 break;
2374 IShellFolder_Release(*ppsf);
2375 *ppsf = lpsfChild;
2376 lpsfChild = NULL;
2378 else
2380 TRACE("value\n");
2382 /* end dialog, return value */
2383 nOpenAction = ONOPEN_OPEN;
2384 break;
2386 COMDLG32_SHFree(pidl);
2387 pidl = NULL;
2389 else if (!(flags & OFN_NOVALIDATE))
2391 if(*lpszTemp || /* points to trailing null for last path element */
2392 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2394 if(flags & OFN_PATHMUSTEXIST)
2396 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2397 break;
2400 else
2402 if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2404 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2405 break;
2408 /* change to the current folder */
2409 nOpenAction = ONOPEN_OPEN;
2410 break;
2412 else
2414 nOpenAction = ONOPEN_OPEN;
2415 break;
2418 if(pidl) COMDLG32_SHFree(pidl);
2420 return nOpenAction;
2423 /***********************************************************************
2424 * FILEDLG95_OnOpen
2426 * Ok button WM_COMMAND message handler
2428 * If the function succeeds, the return value is nonzero.
2430 BOOL FILEDLG95_OnOpen(HWND hwnd)
2432 LPWSTR lpstrFileList;
2433 UINT nFileCount = 0;
2434 UINT sizeUsed = 0;
2435 BOOL ret = TRUE;
2436 WCHAR lpstrPathAndFile[MAX_PATH];
2437 LPSHELLFOLDER lpsf = NULL;
2438 int nOpenAction;
2439 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2441 TRACE("hwnd=%p\n", hwnd);
2443 /* try to browse the selected item */
2444 if(BrowseSelectedFolder(hwnd))
2445 return FALSE;
2447 /* get the files from the edit control */
2448 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2450 if(nFileCount == 0)
2451 return FALSE;
2453 if(nFileCount > 1)
2455 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2456 goto ret;
2459 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2462 Step 1: Build a complete path name from the current folder and
2463 the filename or path in the edit box.
2464 Special cases:
2465 - the path in the edit box is a root path
2466 (with or without drive letter)
2467 - the edit box contains ".." (or a path with ".." in it)
2470 COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2471 MemFree(lpstrFileList);
2474 Step 2: here we have a cleaned up path
2476 We have to parse the path step by step to see if we have to browse
2477 to a folder if the path points to a directory or the last
2478 valid element is a directory.
2480 valid variables:
2481 lpstrPathAndFile: cleaned up path
2484 if (nFileCount &&
2485 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2486 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2487 nOpenAction = ONOPEN_OPEN;
2488 else
2489 nOpenAction = ONOPEN_BROWSE;
2491 nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2492 fodInfos->ofnInfos->Flags,
2493 fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2494 nOpenAction);
2495 if(!nOpenAction)
2496 goto ret;
2499 Step 3: here we have a cleaned up and validated path
2501 valid variables:
2502 lpsf: ShellFolder bound to the rightmost valid path component
2503 lpstrPathAndFile: cleaned up path
2504 nOpenAction: action to do
2506 TRACE("end validate sf=%p\n", lpsf);
2508 switch(nOpenAction)
2510 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2511 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2513 int iPos;
2514 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2515 DWORD len;
2517 /* replace the current filter */
2518 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2519 len = lstrlenW(lpszTemp)+1;
2520 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2521 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2523 /* set the filter cb to the extension when possible */
2524 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2525 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2527 /* fall through */
2528 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2529 TRACE("ONOPEN_BROWSE\n");
2531 IPersistFolder2 * ppf2;
2532 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2534 LPITEMIDLIST pidlCurrent;
2535 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2536 IPersistFolder2_Release(ppf2);
2537 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2539 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2540 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2542 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2545 else if( nOpenAction == ONOPEN_SEARCH )
2547 if (fodInfos->Shell.FOIShellView)
2548 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2550 COMDLG32_SHFree(pidlCurrent);
2551 if (filename_is_edit( fodInfos ))
2552 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2555 ret = FALSE;
2556 break;
2557 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2558 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2560 WCHAR *ext = NULL;
2562 /* update READONLY check box flag */
2563 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2564 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2565 else
2566 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2568 /* Attach the file extension with file name*/
2569 ext = PathFindExtensionW(lpstrPathAndFile);
2570 if (! *ext && fodInfos->defext)
2572 /* if no extension is specified with file name, then */
2573 /* attach the extension from file filter or default one */
2575 WCHAR *filterExt = NULL;
2576 LPWSTR lpstrFilter = NULL;
2577 static const WCHAR szwDot[] = {'.',0};
2578 int PathLength = lstrlenW(lpstrPathAndFile);
2580 /*Get the file extension from file type filter*/
2581 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2582 fodInfos->ofnInfos->nFilterIndex-1);
2584 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2586 WCHAR* filterSearchIndex;
2587 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2588 strcpyW(filterExt, lpstrFilter);
2590 /* if a semicolon-separated list of file extensions was given, do not include the
2591 semicolon or anything after it in the extension.
2592 example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2593 filterSearchIndex = strchrW(filterExt, ';');
2594 if (filterSearchIndex)
2596 filterSearchIndex[0] = '\0';
2599 /* find the file extension by searching for the first dot in filterExt */
2600 /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2601 /* if the extension is invalid or contains a glob, ignore it */
2602 filterSearchIndex = strchrW(filterExt, '.');
2603 if (filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2605 strcpyW(filterExt, filterSearchIndex);
2607 else
2609 HeapFree(GetProcessHeap(), 0, filterExt);
2610 filterExt = NULL;
2614 if (!filterExt)
2616 /* use the default file extension */
2617 filterExt = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2618 strcpyW(filterExt, fodInfos->defext);
2621 if (*filterExt) /* ignore filterExt="" */
2623 /* Attach the dot*/
2624 lstrcatW(lpstrPathAndFile, szwDot);
2625 /* Attach the extension */
2626 lstrcatW(lpstrPathAndFile, filterExt);
2629 HeapFree(GetProcessHeap(), 0, filterExt);
2631 /* In Open dialog: if file does not exist try without extension */
2632 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2633 lpstrPathAndFile[PathLength] = '\0';
2635 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2636 if (*ext)
2637 ext++;
2638 if (!lstrcmpiW(fodInfos->defext, ext))
2639 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2640 else
2641 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2644 /* In Save dialog: check if the file already exists */
2645 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2646 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2647 && PathFileExistsW(lpstrPathAndFile))
2649 WCHAR lpstrOverwrite[100];
2650 int answer;
2652 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2653 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2654 MB_YESNO | MB_ICONEXCLAMATION);
2655 if (answer == IDNO || answer == IDCANCEL)
2657 ret = FALSE;
2658 goto ret;
2662 /* In Open dialog: check if it should be created if it doesn't exist */
2663 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2664 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2665 && !PathFileExistsW(lpstrPathAndFile))
2667 WCHAR lpstrCreate[100];
2668 int answer;
2670 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2671 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2672 MB_YESNO | MB_ICONEXCLAMATION);
2673 if (answer == IDNO || answer == IDCANCEL)
2675 ret = FALSE;
2676 goto ret;
2680 /* Check that the size of the file does not exceed buffer size.
2681 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2682 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2683 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2686 /* fill destination buffer */
2687 if (fodInfos->ofnInfos->lpstrFile)
2689 if(fodInfos->unicode)
2691 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2693 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2694 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2695 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2697 else
2699 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2701 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2702 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2703 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2704 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2708 if(fodInfos->unicode)
2710 LPWSTR lpszTemp;
2712 /* set filename offset */
2713 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2714 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2716 /* set extension offset */
2717 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2718 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2720 else
2722 LPSTR lpszTemp;
2723 CHAR tempFileA[MAX_PATH];
2725 /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2726 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2727 tempFileA, sizeof(tempFileA), NULL, NULL);
2729 /* set filename offset */
2730 lpszTemp = PathFindFileNameA(tempFileA);
2731 fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2733 /* set extension offset */
2734 lpszTemp = PathFindExtensionA(tempFileA);
2735 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2738 /* set the lpstrFileTitle */
2739 if(fodInfos->ofnInfos->lpstrFileTitle)
2741 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2742 if(fodInfos->unicode)
2744 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2745 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2747 else
2749 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2750 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2751 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2755 /* copy currently selected filter to lpstrCustomFilter */
2756 if (fodInfos->ofnInfos->lpstrCustomFilter)
2758 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2759 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2760 NULL, 0, NULL, NULL);
2761 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2763 LPSTR s = ofn->lpstrCustomFilter;
2764 s += strlen(ofn->lpstrCustomFilter)+1;
2765 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2766 s, len, NULL, NULL);
2771 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2772 goto ret;
2774 FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2776 TRACE("close\n");
2777 FILEDLG95_Clean(hwnd);
2778 ret = EndDialog(hwnd, TRUE);
2780 else
2782 WORD size;
2784 size = lstrlenW(lpstrPathAndFile) + 1;
2785 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2786 size += 1;
2787 /* return needed size in first two bytes of lpstrFile */
2788 if(fodInfos->ofnInfos->lpstrFile)
2789 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2790 FILEDLG95_Clean(hwnd);
2791 ret = EndDialog(hwnd, FALSE);
2792 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2795 break;
2798 ret:
2799 if(lpsf) IShellFolder_Release(lpsf);
2800 return ret;
2803 /***********************************************************************
2804 * FILEDLG95_SHELL_Init
2806 * Initialisation of the shell objects
2808 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2810 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2812 TRACE("\n");
2815 * Initialisation of the FileOpenDialogInfos structure
2818 /* Shell */
2820 /*ShellInfos */
2821 fodInfos->ShellInfos.hwndOwner = hwnd;
2823 /* Disable multi-select if flag not set */
2824 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2826 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2828 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2829 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2831 /* Construct the IShellBrowser interface */
2832 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2834 return NOERROR;
2837 /***********************************************************************
2838 * FILEDLG95_SHELL_ExecuteCommand
2840 * Change the folder option and refresh the view
2841 * If the function succeeds, the return value is nonzero.
2843 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2845 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2846 IContextMenu * pcm;
2848 TRACE("(%p,%p)\n", hwnd, lpVerb);
2850 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2851 SVGIO_BACKGROUND,
2852 &IID_IContextMenu,
2853 (LPVOID*)&pcm)))
2855 CMINVOKECOMMANDINFO ci;
2856 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2857 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2858 ci.lpVerb = lpVerb;
2859 ci.hwnd = hwnd;
2861 IContextMenu_InvokeCommand(pcm, &ci);
2862 IContextMenu_Release(pcm);
2865 return FALSE;
2868 /***********************************************************************
2869 * FILEDLG95_SHELL_UpFolder
2871 * Browse to the specified object
2872 * If the function succeeds, the return value is nonzero.
2874 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2876 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2878 TRACE("\n");
2880 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2881 NULL,
2882 SBSP_PARENT)))
2884 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2885 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2886 return TRUE;
2888 return FALSE;
2891 /***********************************************************************
2892 * FILEDLG95_SHELL_BrowseToDesktop
2894 * Browse to the Desktop
2895 * If the function succeeds, the return value is nonzero.
2897 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2899 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2900 LPITEMIDLIST pidl;
2901 HRESULT hres;
2903 TRACE("\n");
2905 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2906 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2907 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2908 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2909 COMDLG32_SHFree(pidl);
2910 return SUCCEEDED(hres);
2912 /***********************************************************************
2913 * FILEDLG95_SHELL_Clean
2915 * Cleans the memory used by shell objects
2917 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2919 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2921 TRACE("\n");
2923 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2925 /* clean Shell interfaces */
2926 if (fodInfos->Shell.FOIShellView)
2928 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2929 IShellView_Release(fodInfos->Shell.FOIShellView);
2931 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2932 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2933 if (fodInfos->Shell.FOIDataObject)
2934 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2937 /***********************************************************************
2938 * FILEDLG95_FILETYPE_Init
2940 * Initialisation of the file type combo box
2942 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2944 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2945 int nFilters = 0; /* number of filters */
2946 int nFilterIndexCB;
2948 TRACE("\n");
2950 if(fodInfos->customfilter)
2952 /* customfilter has one entry... title\0ext\0
2953 * Set first entry of combo box item with customfilter
2955 LPWSTR lpstrExt;
2956 LPCWSTR lpstrPos = fodInfos->customfilter;
2958 /* Get the title */
2959 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2961 /* Copy the extensions */
2962 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2963 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2964 lstrcpyW(lpstrExt,lpstrPos);
2966 /* Add the item at the end of the combo */
2967 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2968 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2969 nFilters++;
2971 if(fodInfos->filter)
2973 LPCWSTR lpstrPos = fodInfos->filter;
2975 for(;;)
2977 /* filter is a list... title\0ext\0......\0\0
2978 * Set the combo item text to the title and the item data
2979 * to the ext
2981 LPCWSTR lpstrDisplay;
2982 LPWSTR lpstrExt;
2984 /* Get the title */
2985 if(! *lpstrPos) break; /* end */
2986 lpstrDisplay = lpstrPos;
2987 lpstrPos += lstrlenW(lpstrPos) + 1;
2989 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2991 nFilters++;
2993 /* Copy the extensions */
2994 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2995 lstrcpyW(lpstrExt,lpstrPos);
2996 lpstrPos += lstrlenW(lpstrPos) + 1;
2998 /* Add the item at the end of the combo */
2999 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
3001 /* malformed filters are added anyway... */
3002 if (!*lpstrExt) break;
3007 * Set the current filter to the one specified
3008 * in the initialisation structure
3010 if (fodInfos->filter || fodInfos->customfilter)
3012 LPWSTR lpstrFilter;
3014 /* Check to make sure our index isn't out of bounds. */
3015 if ( fodInfos->ofnInfos->nFilterIndex >
3016 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3017 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3019 /* set default filter index */
3020 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3021 fodInfos->ofnInfos->nFilterIndex = 1;
3023 /* calculate index of Combo Box item */
3024 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3025 if (fodInfos->customfilter == NULL)
3026 nFilterIndexCB--;
3028 /* Set the current index selection. */
3029 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
3031 /* Get the corresponding text string from the combo box. */
3032 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3033 nFilterIndexCB);
3035 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3036 lpstrFilter = NULL;
3038 if(lpstrFilter)
3040 DWORD len;
3041 CharLowerW(lpstrFilter); /* lowercase */
3042 len = lstrlenW(lpstrFilter)+1;
3043 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3044 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3046 } else
3047 fodInfos->ofnInfos->nFilterIndex = 0;
3048 return S_OK;
3051 /***********************************************************************
3052 * FILEDLG95_FILETYPE_OnCommand
3054 * WM_COMMAND of the file type combo box
3055 * If the function succeeds, the return value is nonzero.
3057 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
3059 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3061 switch(wNotifyCode)
3063 case CBN_SELENDOK:
3065 LPWSTR lpstrFilter;
3067 /* Get the current item of the filetype combo box */
3068 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
3070 /* set the current filter index */
3071 fodInfos->ofnInfos->nFilterIndex = iItem +
3072 (fodInfos->customfilter == NULL ? 1 : 0);
3074 /* Set the current filter with the current selection */
3075 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3077 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3078 iItem);
3079 if((INT_PTR)lpstrFilter != CB_ERR)
3081 DWORD len;
3082 CharLowerW(lpstrFilter); /* lowercase */
3083 len = lstrlenW(lpstrFilter)+1;
3084 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
3085 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3086 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3087 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
3090 /* Refresh the actual view to display the included items*/
3091 if (fodInfos->Shell.FOIShellView)
3092 IShellView_Refresh(fodInfos->Shell.FOIShellView);
3095 return FALSE;
3097 /***********************************************************************
3098 * FILEDLG95_FILETYPE_SearchExt
3100 * searches for an extension in the filetype box
3102 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
3104 int i, iCount = CBGetCount(hwnd);
3106 TRACE("%s\n", debugstr_w(lpstrExt));
3108 if(iCount != CB_ERR)
3110 for(i=0;i<iCount;i++)
3112 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3113 return i;
3116 return -1;
3119 /***********************************************************************
3120 * FILEDLG95_FILETYPE_Clean
3122 * Clean the memory used by the filetype combo box
3124 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
3126 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3127 int iPos;
3128 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
3130 TRACE("\n");
3132 /* Delete each string of the combo and their associated data */
3133 if(iCount != CB_ERR)
3135 for(iPos = iCount-1;iPos>=0;iPos--)
3137 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3138 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
3141 /* Current filter */
3142 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
3146 /***********************************************************************
3147 * FILEDLG95_LOOKIN_Init
3149 * Initialisation of the look in combo box
3152 /* Small helper function, to determine if the unixfs shell extension is rooted
3153 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3155 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
3156 HKEY hKey;
3157 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3158 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3160 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3161 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3162 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3163 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3165 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3166 return FALSE;
3168 RegCloseKey(hKey);
3169 return TRUE;
3172 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3174 IShellFolder *psfRoot, *psfDrives;
3175 IEnumIDList *lpeRoot, *lpeDrives;
3176 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3177 HDC hdc;
3178 TEXTMETRICW tm;
3179 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
3181 TRACE("\n");
3183 liInfos->iMaxIndentation = 0;
3185 SetPropA(hwndCombo, LookInInfosStr, liInfos);
3187 hdc = GetDC( hwndCombo );
3188 SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3189 GetTextMetricsW( hdc, &tm );
3190 ReleaseDC( hwndCombo, hdc );
3192 /* set item height for both text field and listbox */
3193 CBSetItemHeight( hwndCombo, -1, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3194 CBSetItemHeight( hwndCombo, 0, max( tm.tmHeight, GetSystemMetrics(SM_CYSMICON) ));
3196 /* Turn on the extended UI for the combo box like Windows does */
3197 CBSetExtendedUI(hwndCombo, TRUE);
3199 /* Initialise data of Desktop folder */
3200 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
3201 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3202 COMDLG32_SHFree(pidlTmp);
3204 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
3206 SHGetDesktopFolder(&psfRoot);
3208 if (psfRoot)
3210 /* enumerate the contents of the desktop */
3211 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3213 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3215 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3217 /* If the unixfs extension is rooted, we don't expand the drives by default */
3218 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
3220 /* special handling for CSIDL_DRIVES */
3221 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
3223 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3225 /* enumerate the drives */
3226 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3228 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3230 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
3231 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3232 COMDLG32_SHFree(pidlAbsTmp);
3233 COMDLG32_SHFree(pidlTmp1);
3235 IEnumIDList_Release(lpeDrives);
3237 IShellFolder_Release(psfDrives);
3242 COMDLG32_SHFree(pidlTmp);
3244 IEnumIDList_Release(lpeRoot);
3246 IShellFolder_Release(psfRoot);
3249 COMDLG32_SHFree(pidlDrives);
3252 /***********************************************************************
3253 * FILEDLG95_LOOKIN_DrawItem
3255 * WM_DRAWITEM message handler
3257 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
3259 COLORREF crWin = GetSysColor(COLOR_WINDOW);
3260 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3261 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
3262 RECT rectText;
3263 RECT rectIcon;
3264 SHFILEINFOW sfi;
3265 HIMAGELIST ilItemImage;
3266 int iIndentation;
3267 TEXTMETRICW tm;
3268 LPSFOLDER tmpFolder;
3269 UINT shgfi_flags = SHGFI_PIDL | SHGFI_OPENICON | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME;
3270 UINT icon_width, icon_height;
3272 TRACE("\n");
3274 if(pDIStruct->itemID == -1)
3275 return 0;
3277 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3278 pDIStruct->itemID)))
3279 return 0;
3282 icon_width = GetSystemMetrics(SM_CXICON);
3283 icon_height = GetSystemMetrics(SM_CYICON);
3284 if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3286 icon_width = GetSystemMetrics(SM_CXSMICON);
3287 icon_height = GetSystemMetrics(SM_CYSMICON);
3288 shgfi_flags |= SHGFI_SMALLICON;
3291 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3292 0, &sfi, sizeof (sfi), shgfi_flags );
3294 /* Is this item selected ? */
3295 if(pDIStruct->itemState & ODS_SELECTED)
3297 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3298 SetBkColor(pDIStruct->hDC,crHighLight);
3299 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3301 else
3303 SetTextColor(pDIStruct->hDC,crText);
3304 SetBkColor(pDIStruct->hDC,crWin);
3305 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3308 /* Do not indent item if drawing in the edit of the combo */
3309 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3310 iIndentation = 0;
3311 else
3312 iIndentation = tmpFolder->m_iIndent;
3314 /* Draw text and icon */
3316 /* Initialise the icon display area */
3317 rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3318 rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3319 rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3320 rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3322 /* Initialise the text display area */
3323 GetTextMetricsW(pDIStruct->hDC, &tm);
3324 rectText.left = rectIcon.right;
3325 rectText.top =
3326 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3327 rectText.right = pDIStruct->rcItem.right;
3328 rectText.bottom =
3329 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3331 /* Draw the icon from the image list */
3332 ImageList_Draw(ilItemImage,
3333 sfi.iIcon,
3334 pDIStruct->hDC,
3335 rectIcon.left,
3336 rectIcon.top,
3337 ILD_TRANSPARENT );
3339 /* Draw the associated text */
3340 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3341 return NOERROR;
3344 /***********************************************************************
3345 * FILEDLG95_LOOKIN_OnCommand
3347 * LookIn combo box WM_COMMAND message handler
3348 * If the function succeeds, the return value is nonzero.
3350 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3352 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3354 TRACE("%p\n", fodInfos);
3356 switch(wNotifyCode)
3358 case CBN_SELENDOK:
3360 LPSFOLDER tmpFolder;
3361 int iItem;
3363 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3365 if( iItem == CB_ERR) return FALSE;
3367 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3368 iItem)))
3369 return FALSE;
3372 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3373 tmpFolder->pidlItem,
3374 SBSP_ABSOLUTE)))
3376 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3377 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3378 return TRUE;
3380 break;
3384 return FALSE;
3387 /***********************************************************************
3388 * FILEDLG95_LOOKIN_AddItem
3390 * Adds an absolute pidl item to the lookin combo box
3391 * returns the index of the inserted item
3393 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3395 LPITEMIDLIST pidlNext;
3396 SHFILEINFOW sfi;
3397 SFOLDER *tmpFolder;
3398 LookInInfos *liInfos;
3400 TRACE("%08x\n", iInsertId);
3402 if(!pidl)
3403 return -1;
3405 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3406 return -1;
3408 tmpFolder = MemAlloc(sizeof(SFOLDER));
3409 tmpFolder->m_iIndent = 0;
3411 /* Calculate the indentation of the item in the lookin*/
3412 pidlNext = pidl;
3413 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3415 tmpFolder->m_iIndent++;
3418 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3420 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3421 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3423 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3424 SHGetFileInfoW((LPCWSTR)pidl,
3426 &sfi,
3427 sizeof(sfi),
3428 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3429 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3431 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3433 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3435 int iItemID;
3437 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3439 /* Add the item at the end of the list */
3440 if(iInsertId < 0)
3442 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3444 /* Insert the item at the iInsertId position*/
3445 else
3447 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3450 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3451 return iItemID;
3454 COMDLG32_SHFree( tmpFolder->pidlItem );
3455 MemFree( tmpFolder );
3456 return -1;
3460 /***********************************************************************
3461 * FILEDLG95_LOOKIN_InsertItemAfterParent
3463 * Insert an item below its parent
3465 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3468 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3469 int iParentPos;
3471 TRACE("\n");
3473 if (pidl == pidlParent)
3474 return -1;
3476 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3478 if(iParentPos < 0)
3480 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3483 /* Free pidlParent memory */
3484 COMDLG32_SHFree(pidlParent);
3486 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3489 /***********************************************************************
3490 * FILEDLG95_LOOKIN_SelectItem
3492 * Adds an absolute pidl item to the lookin combo box
3493 * returns the index of the inserted item
3495 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3497 int iItemPos;
3498 LookInInfos *liInfos;
3500 TRACE("\n");
3502 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3504 liInfos = GetPropA(hwnd,LookInInfosStr);
3506 if(iItemPos < 0)
3508 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3509 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3512 else
3514 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3515 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3517 int iRemovedItem;
3519 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3520 break;
3521 if(iRemovedItem < iItemPos)
3522 iItemPos--;
3526 CBSetCurSel(hwnd,iItemPos);
3527 liInfos->uSelectedItem = iItemPos;
3529 return 0;
3533 /***********************************************************************
3534 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3536 * Remove the item with an expansion level over iExpansionLevel
3538 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3540 int iItemPos;
3541 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3543 TRACE("\n");
3545 if(liInfos->iMaxIndentation <= 2)
3546 return -1;
3548 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3550 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3551 COMDLG32_SHFree(tmpFolder->pidlItem);
3552 MemFree(tmpFolder);
3553 CBDeleteString(hwnd,iItemPos);
3554 liInfos->iMaxIndentation--;
3556 return iItemPos;
3559 return -1;
3562 /***********************************************************************
3563 * FILEDLG95_LOOKIN_SearchItem
3565 * Search for pidl in the lookin combo box
3566 * returns the index of the found item
3568 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3570 int i = 0;
3571 int iCount = CBGetCount(hwnd);
3573 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3575 if (iCount != CB_ERR)
3577 for(;i<iCount;i++)
3579 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3581 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3582 return i;
3583 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3584 return i;
3588 return -1;
3591 /***********************************************************************
3592 * FILEDLG95_LOOKIN_Clean
3594 * Clean the memory used by the lookin combo box
3596 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3598 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3599 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3600 int iPos;
3601 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3603 TRACE("\n");
3605 /* Delete each string of the combo and their associated data */
3606 if (iCount != CB_ERR)
3608 for(iPos = iCount-1;iPos>=0;iPos--)
3610 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3611 COMDLG32_SHFree(tmpFolder->pidlItem);
3612 MemFree(tmpFolder);
3613 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3617 /* LookInInfos structure */
3618 MemFree(liInfos);
3619 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3622 /***********************************************************************
3623 * FILEDLG95_FILENAME_FillFromSelection
3625 * fills the edit box from the cached DataObject
3627 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3629 FileOpenDlgInfos *fodInfos;
3630 LPITEMIDLIST pidl;
3631 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3632 WCHAR lpstrTemp[MAX_PATH];
3633 LPWSTR lpstrAllFile, lpstrCurrFile;
3635 TRACE("\n");
3636 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3638 /* Count how many files we have */
3639 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3641 /* calculate the string length, count files */
3642 if (nFileSelected >= 1)
3644 nLength += 3; /* first and last quotes, trailing \0 */
3645 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3647 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3649 if (pidl)
3651 /* get the total length of the selected file names */
3652 lpstrTemp[0] = '\0';
3653 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3655 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3657 nLength += lstrlenW( lpstrTemp ) + 3;
3658 nFiles++;
3660 COMDLG32_SHFree( pidl );
3665 /* allocate the buffer */
3666 if (nFiles <= 1) nLength = MAX_PATH;
3667 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3669 /* Generate the string for the edit control */
3670 if(nFiles >= 1)
3672 lpstrCurrFile = lpstrAllFile;
3673 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3675 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3677 if (pidl)
3679 /* get the file name */
3680 lpstrTemp[0] = '\0';
3681 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3683 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3685 if ( nFiles > 1)
3687 *lpstrCurrFile++ = '\"';
3688 lstrcpyW( lpstrCurrFile, lpstrTemp );
3689 lpstrCurrFile += lstrlenW( lpstrTemp );
3690 *lpstrCurrFile++ = '\"';
3691 *lpstrCurrFile++ = ' ';
3692 *lpstrCurrFile = 0;
3694 else
3696 lstrcpyW( lpstrAllFile, lpstrTemp );
3699 COMDLG32_SHFree( pidl );
3702 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3704 /* Select the file name like Windows does */
3705 if (filename_is_edit( fodInfos ))
3706 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3708 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3712 /* copied from shell32 to avoid linking to it
3713 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3714 * is dependent on whether emulated OS is unicode or not.
3716 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3718 switch (src->uType)
3720 case STRRET_WSTR:
3721 lstrcpynW(dest, src->u.pOleStr, len);
3722 COMDLG32_SHFree(src->u.pOleStr);
3723 break;
3725 case STRRET_CSTR:
3726 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3727 dest[len-1] = 0;
3728 break;
3730 case STRRET_OFFSET:
3731 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3732 dest[len-1] = 0;
3733 break;
3735 default:
3736 FIXME("unknown type %x!\n", src->uType);
3737 if (len) *dest = '\0';
3738 return E_FAIL;
3740 return S_OK;
3743 /***********************************************************************
3744 * FILEDLG95_FILENAME_GetFileNames
3746 * Copies the filenames to a delimited string list.
3748 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3750 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3751 UINT nFileCount = 0; /* number of files */
3752 UINT nStrLen = 0; /* length of string in edit control */
3753 LPWSTR lpstrEdit; /* buffer for string from edit control */
3755 TRACE("\n");
3757 /* get the filenames from the filename control */
3758 nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3759 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3760 GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3762 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3764 nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3765 MemFree(lpstrEdit);
3766 return nFileCount;
3769 #define SETDefFormatEtc(fe,cf,med) \
3771 (fe).cfFormat = cf;\
3772 (fe).dwAspect = DVASPECT_CONTENT; \
3773 (fe).ptd =NULL;\
3774 (fe).tymed = med;\
3775 (fe).lindex = -1;\
3779 * DATAOBJECT Helper functions
3782 /***********************************************************************
3783 * COMCTL32_ReleaseStgMedium
3785 * like ReleaseStgMedium from ole32
3787 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3789 if(medium.pUnkForRelease)
3791 IUnknown_Release(medium.pUnkForRelease);
3793 else
3795 GlobalUnlock(medium.u.hGlobal);
3796 GlobalFree(medium.u.hGlobal);
3800 /***********************************************************************
3801 * GetPidlFromDataObject
3803 * Return pidl(s) by number from the cached DataObject
3805 * nPidlIndex=0 gets the fully qualified root path
3807 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3810 STGMEDIUM medium;
3811 FORMATETC formatetc;
3812 LPITEMIDLIST pidl = NULL;
3814 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3816 if (!doSelected)
3817 return NULL;
3819 /* Set the FORMATETC structure*/
3820 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3822 /* Get the pidls from IDataObject */
3823 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3825 LPIDA cida = GlobalLock(medium.u.hGlobal);
3826 if(nPidlIndex <= cida->cidl)
3828 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3830 COMCTL32_ReleaseStgMedium(medium);
3832 return pidl;
3835 /***********************************************************************
3836 * GetNumSelected
3838 * Return the number of selected items in the DataObject.
3841 static UINT GetNumSelected( IDataObject *doSelected )
3843 UINT retVal = 0;
3844 STGMEDIUM medium;
3845 FORMATETC formatetc;
3847 TRACE("sv=%p\n", doSelected);
3849 if (!doSelected) return 0;
3851 /* Set the FORMATETC structure*/
3852 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3854 /* Get the pidls from IDataObject */
3855 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3857 LPIDA cida = GlobalLock(medium.u.hGlobal);
3858 retVal = cida->cidl;
3859 COMCTL32_ReleaseStgMedium(medium);
3860 return retVal;
3862 return 0;
3866 * TOOLS
3869 /***********************************************************************
3870 * GetName
3872 * Get the pidl's display name (relative to folder) and
3873 * put it in lpstrFileName.
3875 * Return NOERROR on success,
3876 * E_FAIL otherwise
3879 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3881 STRRET str;
3882 HRESULT hRes;
3884 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3886 if(!lpsf)
3888 SHGetDesktopFolder(&lpsf);
3889 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3890 IShellFolder_Release(lpsf);
3891 return hRes;
3894 /* Get the display name of the pidl relative to the folder */
3895 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3897 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3899 return E_FAIL;
3902 /***********************************************************************
3903 * GetShellFolderFromPidl
3905 * pidlRel is the item pidl relative
3906 * Return the IShellFolder of the absolute pidl
3908 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3910 IShellFolder *psf = NULL,*psfParent;
3912 TRACE("%p\n", pidlAbs);
3914 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3916 psf = psfParent;
3917 if(pidlAbs && pidlAbs->mkid.cb)
3919 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3921 IShellFolder_Release(psfParent);
3922 return psf;
3925 /* return the desktop */
3926 return psfParent;
3928 return NULL;
3931 /***********************************************************************
3932 * GetParentPidl
3934 * Return the LPITEMIDLIST to the parent of the pidl in the list
3936 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3938 LPITEMIDLIST pidlParent;
3940 TRACE("%p\n", pidl);
3942 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3943 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3945 return pidlParent;
3948 /***********************************************************************
3949 * GetPidlFromName
3951 * returns the pidl of the file name relative to folder
3952 * NULL if an error occurred
3954 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3956 LPITEMIDLIST pidl = NULL;
3957 ULONG ulEaten;
3959 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3961 if(!lpcstrFileName) return NULL;
3962 if(!*lpcstrFileName) return NULL;
3964 if(!lpsf)
3966 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3967 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3968 IShellFolder_Release(lpsf);
3971 else
3973 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3975 return pidl;
3980 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3982 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3983 HRESULT ret;
3985 TRACE("%p, %p\n", psf, pidl);
3987 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3989 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3990 /* see documentation shell 4.1*/
3991 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3994 /***********************************************************************
3995 * BrowseSelectedFolder
3997 static BOOL BrowseSelectedFolder(HWND hwnd)
3999 BOOL bBrowseSelFolder = FALSE;
4000 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
4002 TRACE("\n");
4004 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4006 LPITEMIDLIST pidlSelection;
4008 /* get the file selected */
4009 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4010 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4012 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4013 pidlSelection, SBSP_RELATIVE ) ) )
4015 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
4016 ' ','n','o','t',' ','e','x','i','s','t',0};
4017 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4019 bBrowseSelFolder = TRUE;
4020 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4021 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
4023 COMDLG32_SHFree( pidlSelection );
4026 return bBrowseSelFolder;
4030 * Memory allocation methods */
4031 static void *MemAlloc(UINT size)
4033 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
4036 static void MemFree(void *mem)
4038 HeapFree(GetProcessHeap(),0,mem);
4041 static inline BOOL valid_struct_size( DWORD size )
4043 return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4044 (size == sizeof( OPENFILENAMEW ));
4047 static inline BOOL is_win16_looks(DWORD flags)
4049 return (flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE) &&
4050 !(flags & OFN_EXPLORER));
4053 /* ------------------ APIs ---------------------- */
4055 /***********************************************************************
4056 * GetOpenFileNameA (COMDLG32.@)
4058 * Creates a dialog box for the user to select a file to open.
4060 * RETURNS
4061 * TRUE on success: user enters a valid file
4062 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4065 BOOL WINAPI GetOpenFileNameA(
4066 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4068 TRACE("flags %08x\n", ofn->Flags);
4070 if (!valid_struct_size( ofn->lStructSize ))
4072 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4073 return FALSE;
4076 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4077 if (ofn->Flags & OFN_FILEMUSTEXIST)
4078 ofn->Flags |= OFN_PATHMUSTEXIST;
4080 if (is_win16_looks(ofn->Flags))
4081 return GetFileName31A(ofn, OPEN_DIALOG);
4082 else
4083 return GetFileDialog95A(ofn, OPEN_DIALOG);
4086 /***********************************************************************
4087 * GetOpenFileNameW (COMDLG32.@)
4089 * Creates a dialog box for the user to select a file to open.
4091 * RETURNS
4092 * TRUE on success: user enters a valid file
4093 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4096 BOOL WINAPI GetOpenFileNameW(
4097 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4099 TRACE("flags %08x\n", ofn->Flags);
4101 if (!valid_struct_size( ofn->lStructSize ))
4103 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4104 return FALSE;
4107 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4108 if (ofn->Flags & OFN_FILEMUSTEXIST)
4109 ofn->Flags |= OFN_PATHMUSTEXIST;
4111 if (is_win16_looks(ofn->Flags))
4112 return GetFileName31W(ofn, OPEN_DIALOG);
4113 else
4114 return GetFileDialog95W(ofn, OPEN_DIALOG);
4118 /***********************************************************************
4119 * GetSaveFileNameA (COMDLG32.@)
4121 * Creates a dialog box for the user to select a file to save.
4123 * RETURNS
4124 * TRUE on success: user enters a valid file
4125 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4128 BOOL WINAPI GetSaveFileNameA(
4129 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4131 if (!valid_struct_size( ofn->lStructSize ))
4133 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4134 return FALSE;
4137 if (is_win16_looks(ofn->Flags))
4138 return GetFileName31A(ofn, SAVE_DIALOG);
4139 else
4140 return GetFileDialog95A(ofn, SAVE_DIALOG);
4143 /***********************************************************************
4144 * GetSaveFileNameW (COMDLG32.@)
4146 * Creates a dialog box for the user to select a file to save.
4148 * RETURNS
4149 * TRUE on success: user enters a valid file
4150 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4153 BOOL WINAPI GetSaveFileNameW(
4154 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4156 if (!valid_struct_size( ofn->lStructSize ))
4158 COMDLG32_SetCommDlgExtendedError( CDERR_STRUCTSIZE );
4159 return FALSE;
4162 if (is_win16_looks(ofn->Flags))
4163 return GetFileName31W(ofn, SAVE_DIALOG);
4164 else
4165 return GetFileDialog95W(ofn, SAVE_DIALOG);
4168 /***********************************************************************
4169 * GetFileTitleA (COMDLG32.@)
4171 * See GetFileTitleW.
4173 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4175 int ret;
4176 UNICODE_STRING strWFile;
4177 LPWSTR lpWTitle;
4179 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4180 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4181 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4182 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4183 RtlFreeUnicodeString( &strWFile );
4184 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4185 return ret;
4189 /***********************************************************************
4190 * GetFileTitleW (COMDLG32.@)
4192 * Get the name of a file.
4194 * PARAMS
4195 * lpFile [I] name and location of file
4196 * lpTitle [O] returned file name
4197 * cbBuf [I] buffer size of lpTitle
4199 * RETURNS
4200 * Success: zero
4201 * Failure: negative number.
4203 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4205 int i, len;
4206 static const WCHAR brkpoint[] = {'*','[',']',0};
4207 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4209 if(lpFile == NULL || lpTitle == NULL)
4210 return -1;
4212 len = lstrlenW(lpFile);
4214 if (len == 0)
4215 return -1;
4217 if(strpbrkW(lpFile, brkpoint))
4218 return -1;
4220 len--;
4222 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4223 return -1;
4225 for(i = len; i >= 0; i--)
4227 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4229 i++;
4230 break;
4234 if(i == -1)
4235 i++;
4237 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4239 len = lstrlenW(lpFile+i)+1;
4240 if(cbBuf < len)
4241 return len;
4243 lstrcpyW(lpTitle, &lpFile[i]);
4244 return 0;