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)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
71 #include "filedlg31.h"
75 #include "filedlgbrowser.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
109 /***********************************************************************
110 * Defines and global variables
113 /* Draw item constant */
115 #define XTEXTOFFSET 3
120 /* SearchItem methods */
121 #define SEARCH_PIDL 1
123 #define ITEM_NOTFOUND -1
125 /* Undefined windows message sent by CreateViewObject*/
126 #define WM_GETISHELLBROWSER WM_USER+7
129 * Those macros exist in windowsx.h. However, you can't really use them since
130 * they rely on the UNICODE defines and can't be used inside Wine itself.
133 /* Combo box macros */
134 #define CBAddString(hwnd,str) \
135 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
137 #define CBInsertString(hwnd,str,pos) \
138 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
140 #define CBDeleteString(hwnd,pos) \
141 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
143 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
144 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
146 #define CBGetItemDataPtr(hwnd,iItemId) \
147 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
149 #define CBGetLBText(hwnd,iItemId,str) \
150 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
152 #define CBGetCurSel(hwnd) \
153 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
155 #define CBSetCurSel(hwnd,pos) \
156 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
158 #define CBGetCount(hwnd) \
159 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
160 #define CBShowDropDown(hwnd,show) \
161 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
162 #define CBSetItemHeight(hwnd,index,height) \
163 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
165 #define CBSetExtendedUI(hwnd,flag) \
166 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
168 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
169 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
170 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
172 /***********************************************************************
176 /* Internal functions used by the dialog */
177 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
178 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
179 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
180 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
181 static BOOL FILEDLG95_OnOpen(HWND hwnd);
182 static LRESULT FILEDLG95_InitControls(HWND hwnd);
183 static void FILEDLG95_Clean(HWND hwnd);
185 /* Functions used by the shell navigation */
186 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
187 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
188 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
189 static void FILEDLG95_SHELL_Clean(HWND hwnd);
190 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
192 /* Functions used by the EDIT box */
193 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
195 /* Functions used by the filetype combo box */
196 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
197 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
198 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
199 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
201 /* Functions used by the Look In combo box */
202 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
203 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
204 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
206 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
207 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
208 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
209 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
210 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
212 /* Miscellaneous tool functions */
213 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
214 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
215 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
216 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
217 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
218 static UINT GetNumSelected( IDataObject *doSelected );
220 /* Shell memory allocation */
221 static void *MemAlloc(UINT size);
222 static void MemFree(void *mem);
224 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
225 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
226 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
227 static BOOL BrowseSelectedFolder(HWND hwnd);
229 /***********************************************************************
232 * Creates an Open common dialog box that lets the user select
233 * the drive, directory, and the name of a file or set of files to open.
235 * IN : The FileOpenDlgInfos structure associated with the dialog
236 * OUT : TRUE on success
237 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
239 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
248 /* test for missing functionality */
249 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
251 FIXME("Flags 0x%08x not yet implemented\n",
252 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
255 /* Create the dialog from a template */
257 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
259 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
262 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
263 !(template = LockResource( hDlgTmpl )))
265 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
269 /* msdn: explorer style dialogs permit sizing by default.
270 * The OFN_ENABLESIZING flag is only needed when a hook or
271 * custom tmeplate is provided */
272 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
273 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
274 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
276 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
278 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
279 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
280 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
283 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
286 /* old style hook messages */
287 if (IsHooked(fodInfos))
289 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
290 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
291 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
292 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
295 /* Some shell namespace extensions depend on COM being initialized. */
296 hr = OleInitialize(NULL);
298 if (fodInfos->unicode)
299 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
301 fodInfos->ofnInfos->hwndOwner,
305 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
307 fodInfos->ofnInfos->hwndOwner,
313 /* Unable to create the dialog */
320 /***********************************************************************
323 * Call GetFileName95 with this structure and clean the memory.
325 * IN : The OPENFILENAMEA initialisation structure passed to
326 * GetOpenFileNameA win api function (see filedlg.c)
328 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
331 FileOpenDlgInfos fodInfos;
332 LPSTR lpstrSavDir = NULL;
334 LPWSTR defext = NULL;
335 LPWSTR filter = NULL;
336 LPWSTR customfilter = NULL;
338 /* Initialize CommDlgExtendedError() */
339 COMDLG32_SetCommDlgExtendedError(0);
341 /* Initialize FileOpenDlgInfos structure */
342 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
344 /* Pass in the original ofn */
345 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
347 /* save current directory */
348 if (ofn->Flags & OFN_NOCHANGEDIR)
350 lpstrSavDir = MemAlloc(MAX_PATH);
351 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
354 fodInfos.unicode = FALSE;
356 /* convert all the input strings to unicode */
357 if(ofn->lpstrInitialDir)
359 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
360 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
361 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
364 fodInfos.initdir = NULL;
368 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
369 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
372 fodInfos.filename = NULL;
376 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
377 defext = MemAlloc((len+1)*sizeof(WCHAR));
378 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
380 fodInfos.defext = defext;
384 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
385 title = MemAlloc((len+1)*sizeof(WCHAR));
386 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
388 fodInfos.title = title;
390 if (ofn->lpstrFilter)
395 /* filter is a list... title\0ext\0......\0\0 */
396 s = ofn->lpstrFilter;
397 while (*s) s = s+strlen(s)+1;
399 n = s - ofn->lpstrFilter;
400 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
401 filter = MemAlloc(len*sizeof(WCHAR));
402 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
404 fodInfos.filter = filter;
406 /* convert lpstrCustomFilter */
407 if (ofn->lpstrCustomFilter)
412 /* customfilter contains a pair of strings... title\0ext\0 */
413 s = ofn->lpstrCustomFilter;
414 if (*s) s = s+strlen(s)+1;
415 if (*s) s = s+strlen(s)+1;
416 n = s - ofn->lpstrCustomFilter;
417 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
418 customfilter = MemAlloc(len*sizeof(WCHAR));
419 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
421 fodInfos.customfilter = customfilter;
423 /* Initialize the dialog property */
424 fodInfos.DlgInfos.dwDlgProp = 0;
425 fodInfos.DlgInfos.hwndCustomDlg = NULL;
430 ret = GetFileName95(&fodInfos);
433 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
434 ret = GetFileName95(&fodInfos);
442 SetCurrentDirectoryA(lpstrSavDir);
443 MemFree(lpstrSavDir);
449 MemFree(customfilter);
450 MemFree(fodInfos.initdir);
451 MemFree(fodInfos.filename);
453 TRACE("selected file: %s\n",ofn->lpstrFile);
458 /***********************************************************************
461 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
462 * Call GetFileName95 with this structure and clean the memory.
465 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
468 FileOpenDlgInfos fodInfos;
469 LPWSTR lpstrSavDir = NULL;
471 /* Initialize CommDlgExtendedError() */
472 COMDLG32_SetCommDlgExtendedError(0);
474 /* Initialize FileOpenDlgInfos structure */
475 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
477 /* Pass in the original ofn */
478 fodInfos.ofnInfos = ofn;
480 fodInfos.title = ofn->lpstrTitle;
481 fodInfos.defext = ofn->lpstrDefExt;
482 fodInfos.filter = ofn->lpstrFilter;
483 fodInfos.customfilter = ofn->lpstrCustomFilter;
485 /* convert string arguments, save others */
488 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
489 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
492 fodInfos.filename = NULL;
494 if(ofn->lpstrInitialDir)
496 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
497 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
498 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
499 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
502 fodInfos.initdir = NULL;
504 /* save current directory */
505 if (ofn->Flags & OFN_NOCHANGEDIR)
507 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
508 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
511 fodInfos.unicode = TRUE;
516 ret = GetFileName95(&fodInfos);
519 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
520 ret = GetFileName95(&fodInfos);
528 SetCurrentDirectoryW(lpstrSavDir);
529 MemFree(lpstrSavDir);
532 /* restore saved IN arguments and convert OUT arguments back */
533 MemFree(fodInfos.filename);
534 MemFree(fodInfos.initdir);
538 /******************************************************************************
539 * COMDLG32_GetDisplayNameOf [internal]
541 * Helper function to get the display name for a pidl.
543 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
544 LPSHELLFOLDER psfDesktop;
547 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
550 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
551 IShellFolder_Release(psfDesktop);
555 IShellFolder_Release(psfDesktop);
556 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
559 /***********************************************************************
560 * ArrangeCtrlPositions [internal]
562 * NOTE: Make sure to add testcases for any changes made here.
564 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
566 HWND hwndChild, hwndStc32;
567 RECT rectParent, rectChild, rectStc32;
571 /* Take into account if open as read only checkbox and help button
576 RECT rectHelp, rectCancel;
577 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
578 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
579 /* subtract the height of the help button plus the space between
580 * the help button and the cancel button to the height of the dialog
582 help_fixup = rectHelp.bottom - rectCancel.bottom;
586 There are two possibilities to add components to the default file dialog box.
588 By default, all the new components are added below the standard dialog box (the else case).
590 However, if there is a static text component with the stc32 id, a special case happens.
591 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
592 in the window and the cx and cy indicate how to size the window.
593 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
594 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
598 GetClientRect(hwndParentDlg, &rectParent);
600 /* when arranging controls we have to use fixed parent size */
601 rectParent.bottom -= help_fixup;
603 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
606 GetWindowRect(hwndStc32, &rectStc32);
607 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
609 /* set the size of the stc32 control according to the size of
610 * client area of the parent dialog
612 SetWindowPos(hwndStc32, 0,
614 rectParent.right, rectParent.bottom,
615 SWP_NOMOVE | SWP_NOZORDER);
618 SetRectEmpty(&rectStc32);
620 /* this part moves controls of the child dialog */
621 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
624 if (hwndChild != hwndStc32)
626 GetWindowRect(hwndChild, &rectChild);
627 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
629 /* move only if stc32 exist */
630 if (hwndStc32 && rectChild.left > rectStc32.right)
632 /* move to the right of visible controls of the parent dialog */
633 rectChild.left += rectParent.right;
634 rectChild.left -= rectStc32.right;
636 /* move even if stc32 doesn't exist */
637 if (rectChild.top >= rectStc32.bottom)
639 /* move below visible controls of the parent dialog */
640 rectChild.top += rectParent.bottom;
641 rectChild.top -= rectStc32.bottom - rectStc32.top;
644 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
645 0, 0, SWP_NOSIZE | SWP_NOZORDER);
647 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
650 /* this part moves controls of the parent dialog */
651 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
654 if (hwndChild != hwndChildDlg)
656 GetWindowRect(hwndChild, &rectChild);
657 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
659 /* left,top of stc32 marks the position of controls
660 * from the parent dialog
662 rectChild.left += rectStc32.left;
663 rectChild.top += rectStc32.top;
665 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
666 0, 0, SWP_NOSIZE | SWP_NOZORDER);
668 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
671 /* calculate the size of the resulting dialog */
673 /* here we have to use original parent size */
674 GetClientRect(hwndParentDlg, &rectParent);
675 GetClientRect(hwndChildDlg, &rectChild);
676 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
677 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
682 if (rectParent.right > rectStc32.right - rectStc32.left)
683 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
685 chgx = rectChild.right - rectParent.right;
687 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
688 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
690 /* Unconditionally set new dialog
691 * height to that of the child
693 chgy = rectChild.bottom - rectParent.bottom;
698 chgy = rectChild.bottom - help_fixup;
700 /* set the size of the parent dialog */
701 GetWindowRect(hwndParentDlg, &rectParent);
702 SetWindowPos(hwndParentDlg, 0,
704 rectParent.right - rectParent.left + chgx,
705 rectParent.bottom - rectParent.top + chgy,
706 SWP_NOMOVE | SWP_NOZORDER);
709 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
718 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
728 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
729 * structure's hInstance parameter is not a HINSTANCE, but
730 * instead a pointer to a template resource to use.
732 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
735 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
737 hinst = COMDLG32_hInstance;
738 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
740 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
746 hinst = fodInfos->ofnInfos->hInstance;
747 if(fodInfos->unicode)
749 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
750 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
754 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
755 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
759 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
762 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
763 !(template = LockResource( hDlgTmpl )))
765 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
769 if (fodInfos->unicode)
770 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
771 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
772 (LPARAM)fodInfos->ofnInfos);
774 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
775 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
776 (LPARAM)fodInfos->ofnInfos);
779 else if( IsHooked(fodInfos))
784 WORD menu,class,title;
786 GetClientRect(hwnd,&rectHwnd);
787 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
788 temp.tmplate.dwExtendedStyle = 0;
789 temp.tmplate.cdit = 0;
794 temp.menu = temp.class = temp.title = 0;
796 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
797 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
804 /***********************************************************************
805 * SendCustomDlgNotificationMessage
807 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
810 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
812 LRESULT hook_result = 0;
813 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
815 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
817 if(!fodInfos) return 0;
819 if(fodInfos->DlgInfos.hwndCustomDlg)
821 TRACE("CALL NOTIFY for %x\n", uCode);
822 if(fodInfos->unicode)
825 ofnNotify.hdr.hwndFrom=hwndParentDlg;
826 ofnNotify.hdr.idFrom=0;
827 ofnNotify.hdr.code = uCode;
828 ofnNotify.lpOFN = fodInfos->ofnInfos;
829 ofnNotify.pszFile = NULL;
830 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
835 ofnNotify.hdr.hwndFrom=hwndParentDlg;
836 ofnNotify.hdr.idFrom=0;
837 ofnNotify.hdr.code = uCode;
838 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
839 ofnNotify.pszFile = NULL;
840 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
842 TRACE("RET NOTIFY\n");
844 TRACE("Retval: 0x%08lx\n", hook_result);
848 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
852 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
854 TRACE("CDM_GETFILEPATH:\n");
856 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
859 /* get path and filenames */
860 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
861 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
862 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
865 p = buffer + strlenW(buffer);
867 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
869 if (fodInfos->unicode)
871 total = strlenW( buffer) + 1;
872 if (result) lstrcpynW( result, buffer, size );
873 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
877 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
878 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
879 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
881 HeapFree( GetProcessHeap(), 0, buffer );
885 /***********************************************************************
886 * FILEDLG95_HandleCustomDialogMessages
888 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
890 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
892 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
893 WCHAR lpstrPath[MAX_PATH];
896 if(!fodInfos) return FALSE;
900 case CDM_GETFILEPATH:
901 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
904 case CDM_GETFOLDERPATH:
905 TRACE("CDM_GETFOLDERPATH:\n");
906 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
909 if (fodInfos->unicode)
910 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
912 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
913 (LPSTR)lParam, (int)wParam, NULL, NULL);
915 retval = lstrlenW(lpstrPath) + 1;
918 case CDM_GETFOLDERIDLIST:
919 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
920 if (retval <= wParam)
921 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
925 TRACE("CDM_GETSPEC:\n");
926 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
929 if (fodInfos->unicode)
930 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
932 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
936 case CDM_SETCONTROLTEXT:
937 TRACE("CDM_SETCONTROLTEXT:\n");
940 if( fodInfos->unicode )
941 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
943 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
948 case CDM_HIDECONTROL:
949 /* MSDN states that it should fail for not OFN_EXPLORER case */
950 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
952 HWND control = GetDlgItem( hwnd, wParam );
953 if (control) ShowWindow( control, SW_HIDE );
960 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
961 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
964 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
968 /***********************************************************************
969 * FILEDLG95_OnWMGetMMI
971 * WM_GETMINMAXINFO message handler for resizable dialogs
973 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
975 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
976 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
977 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
979 mmiptr->ptMinTrackSize = fodInfos->initial_size;
984 /***********************************************************************
987 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
989 * FIXME: this could be made more elaborate. Now use a simple scheme
990 * where the file view is enlarged and the controls are either moved
991 * vertically or horizontally to get out of the way. Only the "grip"
992 * is moved in both directions to stay in the corner.
994 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
1000 FileOpenDlgInfos *fodInfos;
1002 if( wParam != SIZE_RESTORED) return FALSE;
1003 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1004 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1005 /* get the new dialog rectangle */
1006 GetWindowRect( hwnd, &rc);
1007 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1008 rc.right -rc.left, rc.bottom -rc.top);
1009 /* not initialized yet */
1010 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1011 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1012 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1014 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1015 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1016 fodInfos->sizedlg.cx = rc.right - rc.left;
1017 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1018 /* change the size of the view window */
1019 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1020 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1021 hdwp = BeginDeferWindowPos( 10);
1022 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1023 rcview.right - rcview.left + chgx,
1024 rcview.bottom - rcview.top + chgy,
1025 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1026 /* change position and sizes of the controls */
1027 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1029 int ctrlid = GetDlgCtrlID( ctrl);
1030 GetWindowRect( ctrl, &rc);
1031 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1032 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1034 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1036 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1038 else if( rc.top > rcview.bottom)
1040 /* if it was below the shell view
1044 /* file name box and file types combo change also width */
1047 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1048 rc.right - rc.left + chgx, rc.bottom - rc.top,
1049 SWP_NOACTIVATE | SWP_NOZORDER);
1051 /* then these buttons must move out of the way */
1055 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1057 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1060 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1062 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1065 else if( rc.left > rcview.right)
1067 /* if it was to the right of the shell view
1069 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1071 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1078 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1080 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1081 rc.right - rc.left + chgx, rc.bottom - rc.top,
1082 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1084 case IDC_TOOLBARSTATIC:
1086 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1088 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1091 /* not resized in windows. Since wine uses this invisible control
1092 * to size the browser view it needs to be resized */
1093 case IDC_SHELLSTATIC:
1094 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1095 rc.right - rc.left + chgx,
1096 rc.bottom - rc.top + chgy,
1097 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1102 if(fodInfos->DlgInfos.hwndCustomDlg &&
1103 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1105 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1106 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1108 GetWindowRect( ctrl, &rc);
1109 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1110 if( rc.top > rcview.bottom)
1112 /* if it was below the shell view
1114 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1115 rc.right - rc.left, rc.bottom - rc.top,
1116 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1118 else if( rc.left > rcview.right)
1120 /* if it was to the right of the shell view
1122 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1123 rc.right - rc.left, rc.bottom - rc.top,
1124 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1127 /* size the custom dialog at the end: some applications do some
1128 * control re-arranging at this point */
1129 GetClientRect(hwnd, &rc);
1130 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1131 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1133 EndDeferWindowPos( hdwp);
1134 /* should not be needed */
1135 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1139 /***********************************************************************
1142 * File open dialog procedure
1144 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1147 TRACE("%p 0x%04x\n", hwnd, uMsg);
1154 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1156 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1157 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1159 /* Adds the FileOpenDlgInfos in the property list of the dialog
1160 so it will be easily accessible through a GetPropA(...) */
1161 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1163 FILEDLG95_InitControls(hwnd);
1165 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1167 GetWindowRect( hwnd, &rc);
1168 fodInfos->DlgInfos.hwndGrip =
1169 CreateWindowExA( 0, "SCROLLBAR", NULL,
1170 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1171 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1172 rc.right - gripx, rc.bottom - gripy,
1173 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1176 fodInfos->DlgInfos.hwndCustomDlg =
1177 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1179 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1180 FILEDLG95_FillControls(hwnd, wParam, lParam);
1182 if( fodInfos->DlgInfos.hwndCustomDlg)
1183 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1185 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1186 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1187 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1190 /* if the app has changed the position of the invisible listbox,
1191 * change that of the listview (browser) as well */
1192 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1193 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1194 if( !EqualRect( &rc, &rcstc))
1196 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1197 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1198 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1199 SWP_NOACTIVATE | SWP_NOZORDER);
1202 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1204 GetWindowRect( hwnd, &rc);
1205 fodInfos->sizedlg.cx = rc.right - rc.left;
1206 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1207 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1208 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1209 GetClientRect( hwnd, &rc);
1210 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1211 rc.right - gripx, rc.bottom - gripy,
1212 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1213 /* resize the dialog to the previous invocation */
1214 if( MemDialogSize.cx && MemDialogSize.cy)
1215 SetWindowPos( hwnd, NULL,
1216 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1217 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1220 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1221 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1226 return FILEDLG95_OnWMSize(hwnd, wParam);
1227 case WM_GETMINMAXINFO:
1228 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1230 return FILEDLG95_OnWMCommand(hwnd, wParam);
1233 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1236 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1242 case WM_GETISHELLBROWSER:
1243 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1247 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1248 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1249 MemDialogSize = fodInfos->sizedlg;
1250 RemovePropA(hwnd, FileOpenDlgInfosStr);
1255 LPNMHDR lpnmh = (LPNMHDR)lParam;
1258 /* set up the button tooltips strings */
1259 if(TTN_GETDISPINFOA == lpnmh->code )
1261 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1262 switch(lpnmh->idFrom )
1264 /* Up folder button */
1265 case FCIDM_TB_UPFOLDER:
1266 stringId = IDS_UPFOLDER;
1268 /* New folder button */
1269 case FCIDM_TB_NEWFOLDER:
1270 stringId = IDS_NEWFOLDER;
1272 /* List option button */
1273 case FCIDM_TB_SMALLICON:
1274 stringId = IDS_LISTVIEW;
1276 /* Details option button */
1277 case FCIDM_TB_REPORTVIEW:
1278 stringId = IDS_REPORTVIEW;
1280 /* Desktop button */
1281 case FCIDM_TB_DESKTOP:
1282 stringId = IDS_TODESKTOP;
1287 lpdi->hinst = COMDLG32_hInstance;
1288 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1293 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1294 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1299 /***********************************************************************
1300 * FILEDLG95_InitControls
1302 * WM_INITDIALOG message handler (before hook notification)
1304 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1306 int win2000plus = 0;
1308 int handledPath = FALSE;
1309 OSVERSIONINFOW osVi;
1310 static const WCHAR szwSlash[] = { '\\', 0 };
1311 static const WCHAR szwStar[] = { '*',0 };
1313 static const TBBUTTON tbb[] =
1315 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1316 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1317 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1318 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1319 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1320 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1321 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1322 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1323 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1325 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1330 HIMAGELIST toolbarImageList;
1331 SHFILEINFOA shFileInfo;
1332 ITEMIDLIST *desktopPidl;
1334 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1336 TRACE("%p\n", fodInfos);
1338 /* Get windows version emulating */
1339 osVi.dwOSVersionInfoSize = sizeof(osVi);
1340 GetVersionExW(&osVi);
1341 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1342 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1343 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1344 win2000plus = (osVi.dwMajorVersion > 4);
1345 if (win2000plus) win98plus = TRUE;
1347 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1349 /* Get the hwnd of the controls */
1350 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1351 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1352 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1354 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1355 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1357 /* construct the toolbar */
1358 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1359 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1361 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1362 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1363 rectTB.left = rectlook.right;
1364 rectTB.top = rectlook.top-1;
1366 if (fodInfos->unicode)
1367 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1368 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1369 rectTB.left, rectTB.top,
1370 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1371 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1373 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1374 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1375 rectTB.left, rectTB.top,
1376 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1377 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1379 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1381 /* FIXME: use TB_LOADIMAGES when implemented */
1382 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1383 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1384 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1386 /* Retrieve and add desktop icon to the toolbar */
1387 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1388 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1389 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1390 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1391 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1393 DestroyIcon(shFileInfo.hIcon);
1394 CoTaskMemFree(desktopPidl);
1396 /* Finish Toolbar Construction */
1397 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1398 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1400 /* Set the window text with the text specified in the OPENFILENAME structure */
1403 SetWindowTextW(hwnd,fodInfos->title);
1405 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1408 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1409 SetWindowTextW(hwnd, buf);
1412 /* Initialise the file name edit control */
1413 handledPath = FALSE;
1414 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1416 if(fodInfos->filename)
1418 /* 1. If win2000 or higher and filename contains a path, use it
1419 in preference over the lpstrInitialDir */
1420 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1421 WCHAR tmpBuf[MAX_PATH];
1425 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1428 /* nameBit is always shorter than the original filename */
1429 lstrcpyW(fodInfos->filename,nameBit);
1432 if (fodInfos->initdir == NULL)
1433 MemFree(fodInfos->initdir);
1434 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1435 lstrcpyW(fodInfos->initdir, tmpBuf);
1437 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1438 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1440 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1443 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1447 /* 2. (All platforms) If initdir is not null, then use it */
1448 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1449 (*fodInfos->initdir!=0x00))
1451 /* Work out the proper path as supplied one might be relative */
1452 /* (Here because supplying '.' as dir browses to My Computer) */
1453 if (handledPath==FALSE) {
1454 WCHAR tmpBuf[MAX_PATH];
1455 WCHAR tmpBuf2[MAX_PATH];
1459 lstrcpyW(tmpBuf, fodInfos->initdir);
1460 if( PathFileExistsW(tmpBuf) ) {
1461 /* initdir does not have to be a directory. If a file is
1462 * specified, the dir part is taken */
1463 if( PathIsDirectoryW(tmpBuf)) {
1464 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1465 lstrcatW(tmpBuf, szwSlash);
1467 lstrcatW(tmpBuf, szwStar);
1469 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1472 MemFree(fodInfos->initdir);
1473 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1474 lstrcpyW(fodInfos->initdir, tmpBuf2);
1476 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1479 else if (fodInfos->initdir)
1481 MemFree(fodInfos->initdir);
1482 fodInfos->initdir = NULL;
1483 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1488 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1489 (*fodInfos->initdir==0x00)))
1491 /* 3. All except w2k+: if filename contains a path use it */
1492 if (!win2000plus && fodInfos->filename &&
1493 *fodInfos->filename &&
1494 strpbrkW(fodInfos->filename, szwSlash)) {
1495 WCHAR tmpBuf[MAX_PATH];
1499 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1504 /* nameBit is always shorter than the original filename */
1505 lstrcpyW(fodInfos->filename, nameBit);
1508 len = lstrlenW(tmpBuf);
1509 MemFree(fodInfos->initdir);
1510 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1511 lstrcpyW(fodInfos->initdir, tmpBuf);
1514 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1515 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1517 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1520 /* 4. win98+ and win2000+ if any files of specified filter types in
1521 current directory, use it */
1522 if ( win98plus && handledPath == FALSE &&
1523 fodInfos->filter && *fodInfos->filter) {
1525 LPCWSTR lpstrPos = fodInfos->filter;
1526 WIN32_FIND_DATAW FindFileData;
1531 /* filter is a list... title\0ext\0......\0\0 */
1533 /* Skip the title */
1534 if(! *lpstrPos) break; /* end */
1535 lpstrPos += lstrlenW(lpstrPos) + 1;
1537 /* See if any files exist in the current dir with this extension */
1538 if(! *lpstrPos) break; /* end */
1540 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1542 if (hFind == INVALID_HANDLE_VALUE) {
1543 /* None found - continue search */
1544 lpstrPos += lstrlenW(lpstrPos) + 1;
1548 MemFree(fodInfos->initdir);
1549 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1550 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1553 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1554 debugstr_w(lpstrPos));
1561 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1563 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1564 if (handledPath == FALSE && (win2000plus || win98plus)) {
1565 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1567 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1569 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1572 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1573 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1575 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1578 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1581 } else if (handledPath==FALSE) {
1582 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1583 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1585 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1588 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1589 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1591 /* Must the open as read only check box be checked ?*/
1592 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1594 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1597 /* Must the open as read only check box be hidden? */
1598 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1600 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1601 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1604 /* Must the help button be hidden? */
1605 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1607 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1608 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1611 /* change Open to Save */
1612 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1615 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1616 SetDlgItemTextW(hwnd, IDOK, buf);
1617 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1618 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1621 /* Initialize the filter combo box */
1622 FILEDLG95_FILETYPE_Init(hwnd);
1627 /***********************************************************************
1628 * FILEDLG95_ResizeControls
1630 * WM_INITDIALOG message handler (after hook notification)
1632 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1634 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1636 if (fodInfos->DlgInfos.hwndCustomDlg)
1639 UINT flags = SWP_NOACTIVATE;
1641 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1642 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1644 /* resize the custom dialog to the parent size */
1645 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1646 GetClientRect(hwnd, &rc);
1649 /* our own fake template is zero sized and doesn't have children, so
1650 * there is no need to resize it. Picasa depends on it.
1652 flags |= SWP_NOSIZE;
1655 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1656 0, 0, rc.right, rc.bottom, flags);
1660 /* Resize the height, if open as read only checkbox ad help button are
1661 * hidden and we are not using a custom template nor a customDialog
1663 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1664 (!(fodInfos->ofnInfos->Flags &
1665 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1667 RECT rectDlg, rectHelp, rectCancel;
1668 GetWindowRect(hwnd, &rectDlg);
1669 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1670 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1671 /* subtract the height of the help button plus the space between the help
1672 * button and the cancel button to the height of the dialog
1674 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1675 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1676 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1682 /***********************************************************************
1683 * FILEDLG95_FillControls
1685 * WM_INITDIALOG message handler (after hook notification)
1687 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1689 LPITEMIDLIST pidlItemId = NULL;
1691 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1693 TRACE("dir=%s file=%s\n",
1694 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1696 /* Get the initial directory pidl */
1698 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1700 WCHAR path[MAX_PATH];
1702 GetCurrentDirectoryW(MAX_PATH,path);
1703 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1706 /* Initialise shell objects */
1707 FILEDLG95_SHELL_Init(hwnd);
1709 /* Initialize the Look In combo box */
1710 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1712 /* Browse to the initial directory */
1713 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1715 /* Free pidlItem memory */
1716 COMDLG32_SHFree(pidlItemId);
1720 /***********************************************************************
1723 * Regroups all the cleaning functions of the filedlg
1725 void FILEDLG95_Clean(HWND hwnd)
1727 FILEDLG95_FILETYPE_Clean(hwnd);
1728 FILEDLG95_LOOKIN_Clean(hwnd);
1729 FILEDLG95_SHELL_Clean(hwnd);
1731 /***********************************************************************
1732 * FILEDLG95_OnWMCommand
1734 * WM_COMMAND message handler
1736 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1738 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1739 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1740 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1746 FILEDLG95_OnOpen(hwnd);
1750 FILEDLG95_Clean(hwnd);
1751 EndDialog(hwnd, FALSE);
1753 /* Filetype combo box */
1755 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1757 /* LookIn combo box */
1759 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1762 /* --- toolbar --- */
1763 /* Up folder button */
1764 case FCIDM_TB_UPFOLDER:
1765 FILEDLG95_SHELL_UpFolder(hwnd);
1767 /* New folder button */
1768 case FCIDM_TB_NEWFOLDER:
1769 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1771 /* List option button */
1772 case FCIDM_TB_SMALLICON:
1773 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1775 /* Details option button */
1776 case FCIDM_TB_REPORTVIEW:
1777 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1779 /* Details option button */
1780 case FCIDM_TB_DESKTOP:
1781 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1788 /* Do not use the listview selection anymore */
1789 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1793 /***********************************************************************
1794 * FILEDLG95_OnWMGetIShellBrowser
1796 * WM_GETISHELLBROWSER message handler
1798 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1800 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1804 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1810 /***********************************************************************
1811 * FILEDLG95_SendFileOK
1813 * Sends the CDN_FILEOK notification if required
1816 * TRUE if the dialog should close
1817 * FALSE if the dialog should not be closed
1819 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1821 /* ask the hook if we can close */
1822 if(IsHooked(fodInfos))
1827 /* First send CDN_FILEOK as MSDN doc says */
1828 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1829 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1832 TRACE("canceled\n");
1836 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1837 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1838 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1841 TRACE("canceled\n");
1848 /***********************************************************************
1849 * FILEDLG95_OnOpenMultipleFiles
1851 * Handles the opening of multiple files.
1854 * check destination buffer size
1856 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1858 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1859 UINT nCount, nSizePath;
1860 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1864 if(fodInfos->unicode)
1866 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1867 ofn->lpstrFile[0] = '\0';
1871 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1872 ofn->lpstrFile[0] = '\0';
1875 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1877 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1878 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1879 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1881 LPWSTR lpstrTemp = lpstrFileList;
1883 for ( nCount = 0; nCount < nFileCount; nCount++ )
1887 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1890 WCHAR lpstrNotFound[100];
1891 WCHAR lpstrMsg[100];
1893 static const WCHAR nl[] = {'\n',0};
1895 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1896 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1898 lstrcpyW(tmp, lpstrTemp);
1900 lstrcatW(tmp, lpstrNotFound);
1902 lstrcatW(tmp, lpstrMsg);
1904 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1908 /* move to the next file in the list of files */
1909 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1910 COMDLG32_SHFree(pidl);
1914 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1915 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1917 /* For "oldstyle" dialog the components have to
1918 be separated by blanks (not '\0'!) and short
1919 filenames have to be used! */
1920 FIXME("Components have to be separated by blanks\n");
1922 if(fodInfos->unicode)
1924 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1925 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1926 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1930 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1932 if (ofn->lpstrFile != NULL)
1934 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1935 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1936 if (ofn->nMaxFile > nSizePath)
1938 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1939 ofn->lpstrFile + nSizePath,
1940 ofn->nMaxFile - nSizePath, NULL, NULL);
1945 fodInfos->ofnInfos->nFileOffset = nSizePath;
1946 fodInfos->ofnInfos->nFileExtension = 0;
1948 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1951 /* clean and exit */
1952 FILEDLG95_Clean(hwnd);
1953 return EndDialog(hwnd,TRUE);
1956 /***********************************************************************
1959 * Ok button WM_COMMAND message handler
1961 * If the function succeeds, the return value is nonzero.
1963 #define ONOPEN_BROWSE 1
1964 #define ONOPEN_OPEN 2
1965 #define ONOPEN_SEARCH 3
1966 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1968 WCHAR strMsgTitle[MAX_PATH];
1969 WCHAR strMsgText [MAX_PATH];
1971 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1973 strMsgTitle[0] = '\0';
1974 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1975 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1978 BOOL FILEDLG95_OnOpen(HWND hwnd)
1980 LPWSTR lpstrFileList;
1981 UINT nFileCount = 0;
1984 WCHAR lpstrPathAndFile[MAX_PATH];
1985 WCHAR lpstrTemp[MAX_PATH];
1986 LPSHELLFOLDER lpsf = NULL;
1988 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1990 TRACE("hwnd=%p\n", hwnd);
1992 /* try to browse the selected item */
1993 if(BrowseSelectedFolder(hwnd))
1996 /* get the files from the edit control */
1997 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2004 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2008 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2011 Step 1: Build a complete path name from the current folder and
2012 the filename or path in the edit box.
2014 - the path in the edit box is a root path
2015 (with or without drive letter)
2016 - the edit box contains ".." (or a path with ".." in it)
2019 /* Get the current directory name */
2020 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2023 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2025 PathAddBackslashW(lpstrPathAndFile);
2027 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2029 /* if the user specified a fully qualified path use it */
2030 if(PathIsRelativeW(lpstrFileList))
2032 lstrcatW(lpstrPathAndFile, lpstrFileList);
2036 /* does the path have a drive letter? */
2037 if (PathGetDriveNumberW(lpstrFileList) == -1)
2038 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2040 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2043 /* resolve "." and ".." */
2044 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2045 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2046 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2048 MemFree(lpstrFileList);
2051 Step 2: here we have a cleaned up path
2053 We have to parse the path step by step to see if we have to browse
2054 to a folder if the path points to a directory or the last
2055 valid element is a directory.
2058 lpstrPathAndFile: cleaned up path
2062 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2063 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2064 nOpenAction = ONOPEN_OPEN;
2066 nOpenAction = ONOPEN_BROWSE;
2068 /* don't apply any checks with OFN_NOVALIDATE */
2070 LPWSTR lpszTemp, lpszTemp1;
2071 LPITEMIDLIST pidl = NULL;
2072 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2074 /* check for invalid chars */
2075 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2077 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2082 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2084 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2087 LPSHELLFOLDER lpsfChild;
2088 WCHAR lpwstrTemp[MAX_PATH];
2089 DWORD dwEaten, dwAttributes;
2092 lstrcpyW(lpwstrTemp, lpszTemp);
2093 p = PathFindNextComponentW(lpwstrTemp);
2095 if (!p) break; /* end of path */
2098 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2100 /* There are no wildcards when OFN_NOVALIDATE is set */
2101 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2103 static const WCHAR wszWild[] = { '*', '?', 0 };
2104 /* if the last element is a wildcard do a search */
2105 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2107 nOpenAction = ONOPEN_SEARCH;
2111 lpszTemp1 = lpszTemp;
2113 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2115 /* append a backslash to drive letters */
2116 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2117 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2118 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2120 PathAddBackslashW(lpwstrTemp);
2123 dwAttributes = SFGAO_FOLDER;
2124 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2126 /* the path component is valid, we have a pidl of the next path component */
2127 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2128 if(dwAttributes & SFGAO_FOLDER)
2130 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2132 ERR("bind to failed\n"); /* should not fail */
2135 IShellFolder_Release(lpsf);
2143 /* end dialog, return value */
2144 nOpenAction = ONOPEN_OPEN;
2147 COMDLG32_SHFree(pidl);
2150 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2152 if(*lpszTemp || /* points to trailing null for last path element */
2153 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2155 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2157 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2163 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2164 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2166 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2170 /* change to the current folder */
2171 nOpenAction = ONOPEN_OPEN;
2176 nOpenAction = ONOPEN_OPEN;
2180 if(pidl) COMDLG32_SHFree(pidl);
2184 Step 3: here we have a cleaned up and validated path
2187 lpsf: ShellFolder bound to the rightmost valid path component
2188 lpstrPathAndFile: cleaned up path
2189 nOpenAction: action to do
2191 TRACE("end validate sf=%p\n", lpsf);
2195 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2196 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2199 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2202 /* replace the current filter */
2203 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2204 len = lstrlenW(lpszTemp)+1;
2205 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2206 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2208 /* set the filter cb to the extension when possible */
2209 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2210 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2213 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2214 TRACE("ONOPEN_BROWSE\n");
2216 IPersistFolder2 * ppf2;
2217 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2219 LPITEMIDLIST pidlCurrent;
2220 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2221 IPersistFolder2_Release(ppf2);
2222 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2224 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2225 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2227 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2230 else if( nOpenAction == ONOPEN_SEARCH )
2232 if (fodInfos->Shell.FOIShellView)
2233 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2235 COMDLG32_SHFree(pidlCurrent);
2236 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2241 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2242 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2246 /* update READONLY check box flag */
2247 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2248 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2250 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2252 /* Attach the file extension with file name*/
2253 ext = PathFindExtensionW(lpstrPathAndFile);
2256 /* if no extension is specified with file name, then */
2257 /* attach the extension from file filter or default one */
2259 WCHAR *filterExt = NULL;
2260 LPWSTR lpstrFilter = NULL;
2261 static const WCHAR szwDot[] = {'.',0};
2262 int PathLength = lstrlenW(lpstrPathAndFile);
2265 lstrcatW(lpstrPathAndFile, szwDot);
2267 /*Get the file extension from file type filter*/
2268 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2269 fodInfos->ofnInfos->nFilterIndex-1);
2271 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2272 filterExt = PathFindExtensionW(lpstrFilter);
2274 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2275 lstrcatW(lpstrPathAndFile, filterExt + 1);
2276 else if ( fodInfos->defext ) /* attach the default file extension*/
2277 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2279 /* In Open dialog: if file does not exist try without extension */
2280 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2281 lpstrPathAndFile[PathLength] = '\0';
2284 if (fodInfos->defext) /* add default extension */
2286 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2289 if (!lstrcmpiW(fodInfos->defext, ext))
2290 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2292 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2295 /* In Save dialog: check if the file already exists */
2296 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2297 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2298 && PathFileExistsW(lpstrPathAndFile))
2300 WCHAR lpstrOverwrite[100];
2303 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2304 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2305 MB_YESNO | MB_ICONEXCLAMATION);
2313 /* In Open dialog: check if it should be created if it doesn't exist */
2314 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2315 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2316 && !PathFileExistsW(lpstrPathAndFile))
2318 WCHAR lpstrCreate[100];
2321 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2322 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2323 MB_YESNO | MB_ICONEXCLAMATION);
2331 /* Check that the size of the file does not exceed buffer size.
2332 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2333 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2334 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2337 /* fill destination buffer */
2338 if (fodInfos->ofnInfos->lpstrFile)
2340 if(fodInfos->unicode)
2342 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2344 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2345 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2346 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2350 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2352 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2353 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2354 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2355 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2359 if(fodInfos->unicode)
2363 /* set filename offset */
2364 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2365 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2367 /* set extension offset */
2368 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2369 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2374 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2376 /* set filename offset */
2377 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2378 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2380 /* set extension offset */
2381 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2382 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2385 /* set the lpstrFileTitle */
2386 if(fodInfos->ofnInfos->lpstrFileTitle)
2388 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2389 if(fodInfos->unicode)
2391 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2392 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2396 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2397 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2398 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2402 /* copy currently selected filter to lpstrCustomFilter */
2403 if (fodInfos->ofnInfos->lpstrCustomFilter)
2405 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2406 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2407 NULL, 0, NULL, NULL);
2408 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2410 LPSTR s = ofn->lpstrCustomFilter;
2411 s += strlen(ofn->lpstrCustomFilter)+1;
2412 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2413 s, len, NULL, NULL);
2418 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2422 FILEDLG95_Clean(hwnd);
2423 ret = EndDialog(hwnd, TRUE);
2429 size = lstrlenW(lpstrPathAndFile) + 1;
2430 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2432 /* return needed size in first two bytes of lpstrFile */
2433 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2434 FILEDLG95_Clean(hwnd);
2435 ret = EndDialog(hwnd, FALSE);
2436 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2443 if(lpsf) IShellFolder_Release(lpsf);
2447 /***********************************************************************
2448 * FILEDLG95_SHELL_Init
2450 * Initialisation of the shell objects
2452 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2454 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2459 * Initialisation of the FileOpenDialogInfos structure
2465 fodInfos->ShellInfos.hwndOwner = hwnd;
2467 /* Disable multi-select if flag not set */
2468 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2470 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2472 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2473 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2475 /* Construct the IShellBrowser interface */
2476 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2481 /***********************************************************************
2482 * FILEDLG95_SHELL_ExecuteCommand
2484 * Change the folder option and refresh the view
2485 * If the function succeeds, the return value is nonzero.
2487 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2489 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2492 TRACE("(%p,%p)\n", hwnd, lpVerb);
2494 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2499 CMINVOKECOMMANDINFO ci;
2500 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2501 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2505 IContextMenu_InvokeCommand(pcm, &ci);
2506 IContextMenu_Release(pcm);
2512 /***********************************************************************
2513 * FILEDLG95_SHELL_UpFolder
2515 * Browse to the specified object
2516 * If the function succeeds, the return value is nonzero.
2518 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2520 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2524 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2528 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2529 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2535 /***********************************************************************
2536 * FILEDLG95_SHELL_BrowseToDesktop
2538 * Browse to the Desktop
2539 * If the function succeeds, the return value is nonzero.
2541 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2543 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2549 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2550 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2551 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2552 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2553 COMDLG32_SHFree(pidl);
2554 return SUCCEEDED(hres);
2556 /***********************************************************************
2557 * FILEDLG95_SHELL_Clean
2559 * Cleans the memory used by shell objects
2561 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2563 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2567 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2569 /* clean Shell interfaces */
2570 if (fodInfos->Shell.FOIShellView)
2572 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2573 IShellView_Release(fodInfos->Shell.FOIShellView);
2575 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2576 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2577 if (fodInfos->Shell.FOIDataObject)
2578 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2581 /***********************************************************************
2582 * FILEDLG95_FILETYPE_Init
2584 * Initialisation of the file type combo box
2586 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2588 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2589 int nFilters = 0; /* number of filters */
2594 if(fodInfos->customfilter)
2596 /* customfilter has one entry... title\0ext\0
2597 * Set first entry of combo box item with customfilter
2600 LPCWSTR lpstrPos = fodInfos->customfilter;
2603 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2605 /* Copy the extensions */
2606 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2607 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2608 lstrcpyW(lpstrExt,lpstrPos);
2610 /* Add the item at the end of the combo */
2611 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2612 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2615 if(fodInfos->filter)
2617 LPCWSTR lpstrPos = fodInfos->filter;
2621 /* filter is a list... title\0ext\0......\0\0
2622 * Set the combo item text to the title and the item data
2625 LPCWSTR lpstrDisplay;
2629 if(! *lpstrPos) break; /* end */
2630 lpstrDisplay = lpstrPos;
2631 lpstrPos += lstrlenW(lpstrPos) + 1;
2633 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2637 /* Copy the extensions */
2638 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2639 lstrcpyW(lpstrExt,lpstrPos);
2640 lpstrPos += lstrlenW(lpstrPos) + 1;
2642 /* Add the item at the end of the combo */
2643 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2645 /* malformed filters are added anyway... */
2646 if (!*lpstrExt) break;
2651 * Set the current filter to the one specified
2652 * in the initialisation structure
2654 if (fodInfos->filter || fodInfos->customfilter)
2658 /* Check to make sure our index isn't out of bounds. */
2659 if ( fodInfos->ofnInfos->nFilterIndex >
2660 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2661 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2663 /* set default filter index */
2664 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2665 fodInfos->ofnInfos->nFilterIndex = 1;
2667 /* calculate index of Combo Box item */
2668 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2669 if (fodInfos->customfilter == NULL)
2672 /* Set the current index selection. */
2673 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2675 /* Get the corresponding text string from the combo box. */
2676 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2679 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2685 CharLowerW(lpstrFilter); /* lowercase */
2686 len = lstrlenW(lpstrFilter)+1;
2687 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2688 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2691 fodInfos->ofnInfos->nFilterIndex = 0;
2695 /***********************************************************************
2696 * FILEDLG95_FILETYPE_OnCommand
2698 * WM_COMMAND of the file type combo box
2699 * If the function succeeds, the return value is nonzero.
2701 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2703 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2711 /* Get the current item of the filetype combo box */
2712 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2714 /* set the current filter index */
2715 fodInfos->ofnInfos->nFilterIndex = iItem +
2716 (fodInfos->customfilter == NULL ? 1 : 0);
2718 /* Set the current filter with the current selection */
2719 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2721 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2723 if((INT_PTR)lpstrFilter != CB_ERR)
2726 CharLowerW(lpstrFilter); /* lowercase */
2727 len = lstrlenW(lpstrFilter)+1;
2728 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2729 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2730 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2731 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2734 /* Refresh the actual view to display the included items*/
2735 if (fodInfos->Shell.FOIShellView)
2736 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2741 /***********************************************************************
2742 * FILEDLG95_FILETYPE_SearchExt
2744 * searches for an extension in the filetype box
2746 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2748 int i, iCount = CBGetCount(hwnd);
2750 TRACE("%s\n", debugstr_w(lpstrExt));
2752 if(iCount != CB_ERR)
2754 for(i=0;i<iCount;i++)
2756 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2763 /***********************************************************************
2764 * FILEDLG95_FILETYPE_Clean
2766 * Clean the memory used by the filetype combo box
2768 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2770 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2772 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2776 /* Delete each string of the combo and their associated data */
2777 if(iCount != CB_ERR)
2779 for(iPos = iCount-1;iPos>=0;iPos--)
2781 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2782 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2785 /* Current filter */
2786 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2790 /***********************************************************************
2791 * FILEDLG95_LOOKIN_Init
2793 * Initialisation of the look in combo box
2796 /* Small helper function, to determine if the unixfs shell extension is rooted
2797 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2799 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2801 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2802 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2803 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2804 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2805 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2806 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2807 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2809 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2816 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2818 IShellFolder *psfRoot, *psfDrives;
2819 IEnumIDList *lpeRoot, *lpeDrives;
2820 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2822 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2826 liInfos->iMaxIndentation = 0;
2828 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2830 /* set item height for both text field and listbox */
2831 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2832 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2834 /* Turn on the extended UI for the combo box like Windows does */
2835 CBSetExtendedUI(hwndCombo, TRUE);
2837 /* Initialise data of Desktop folder */
2838 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2839 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2840 COMDLG32_SHFree(pidlTmp);
2842 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2844 SHGetDesktopFolder(&psfRoot);
2848 /* enumerate the contents of the desktop */
2849 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2851 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2853 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2855 /* If the unixfs extension is rooted, we don't expand the drives by default */
2856 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2858 /* special handling for CSIDL_DRIVES */
2859 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2861 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2863 /* enumerate the drives */
2864 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2866 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2868 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2869 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2870 COMDLG32_SHFree(pidlAbsTmp);
2871 COMDLG32_SHFree(pidlTmp1);
2873 IEnumIDList_Release(lpeDrives);
2875 IShellFolder_Release(psfDrives);
2880 COMDLG32_SHFree(pidlTmp);
2882 IEnumIDList_Release(lpeRoot);
2884 IShellFolder_Release(psfRoot);
2887 COMDLG32_SHFree(pidlDrives);
2890 /***********************************************************************
2891 * FILEDLG95_LOOKIN_DrawItem
2893 * WM_DRAWITEM message handler
2895 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2897 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2898 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2899 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2903 HIMAGELIST ilItemImage;
2906 LPSFOLDER tmpFolder;
2907 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2911 if(pDIStruct->itemID == -1)
2914 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2915 pDIStruct->itemID)))
2919 if(pDIStruct->itemID == liInfos->uSelectedItem)
2921 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2925 SHGFI_PIDL | SHGFI_SMALLICON |
2926 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2927 SHGFI_DISPLAYNAME );
2931 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2935 SHGFI_PIDL | SHGFI_SMALLICON |
2936 SHGFI_SYSICONINDEX |
2940 /* Is this item selected ? */
2941 if(pDIStruct->itemState & ODS_SELECTED)
2943 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2944 SetBkColor(pDIStruct->hDC,crHighLight);
2945 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2949 SetTextColor(pDIStruct->hDC,crText);
2950 SetBkColor(pDIStruct->hDC,crWin);
2951 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2954 /* Do not indent item if drawing in the edit of the combo */
2955 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2958 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2962 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2963 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2968 iIndentation = tmpFolder->m_iIndent;
2970 /* Draw text and icon */
2972 /* Initialise the icon display area */
2973 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2974 rectIcon.top = pDIStruct->rcItem.top;
2975 rectIcon.right = rectIcon.left + ICONWIDTH;
2976 rectIcon.bottom = pDIStruct->rcItem.bottom;
2978 /* Initialise the text display area */
2979 GetTextMetricsW(pDIStruct->hDC, &tm);
2980 rectText.left = rectIcon.right;
2982 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2983 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2985 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2987 /* Draw the icon from the image list */
2988 ImageList_Draw(ilItemImage,
2995 /* Draw the associated text */
2996 if(sfi.szDisplayName)
2997 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3003 /***********************************************************************
3004 * FILEDLG95_LOOKIN_OnCommand
3006 * LookIn combo box WM_COMMAND message handler
3007 * If the function succeeds, the return value is nonzero.
3009 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3011 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3013 TRACE("%p\n", fodInfos);
3019 LPSFOLDER tmpFolder;
3022 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3024 if( iItem == CB_ERR) return FALSE;
3026 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3031 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3032 tmpFolder->pidlItem,
3035 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3036 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3046 /***********************************************************************
3047 * FILEDLG95_LOOKIN_AddItem
3049 * Adds an absolute pidl item to the lookin combo box
3050 * returns the index of the inserted item
3052 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3054 LPITEMIDLIST pidlNext;
3057 LookInInfos *liInfos;
3059 TRACE("%08x\n", iInsertId);
3064 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3067 tmpFolder = MemAlloc(sizeof(SFOLDER));
3068 tmpFolder->m_iIndent = 0;
3070 /* Calculate the indentation of the item in the lookin*/
3072 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3074 tmpFolder->m_iIndent++;
3077 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3079 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3080 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3082 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3083 SHGetFileInfoW((LPCWSTR)pidl,
3087 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3088 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3090 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3092 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3096 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3098 /* Add the item at the end of the list */
3101 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3103 /* Insert the item at the iInsertId position*/
3106 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3109 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3113 COMDLG32_SHFree( tmpFolder->pidlItem );
3114 MemFree( tmpFolder );
3119 /***********************************************************************
3120 * FILEDLG95_LOOKIN_InsertItemAfterParent
3122 * Insert an item below its parent
3124 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3127 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3132 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3136 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3139 /* Free pidlParent memory */
3140 COMDLG32_SHFree(pidlParent);
3142 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3145 /***********************************************************************
3146 * FILEDLG95_LOOKIN_SelectItem
3148 * Adds an absolute pidl item to the lookin combo box
3149 * returns the index of the inserted item
3151 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3154 LookInInfos *liInfos;
3158 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3160 liInfos = GetPropA(hwnd,LookInInfosStr);
3164 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3165 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3170 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3171 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3175 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3177 if(iRemovedItem < iItemPos)
3182 CBSetCurSel(hwnd,iItemPos);
3183 liInfos->uSelectedItem = iItemPos;
3189 /***********************************************************************
3190 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3192 * Remove the item with an expansion level over iExpansionLevel
3194 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3197 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3201 if(liInfos->iMaxIndentation <= 2)
3204 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3206 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3207 COMDLG32_SHFree(tmpFolder->pidlItem);
3209 CBDeleteString(hwnd,iItemPos);
3210 liInfos->iMaxIndentation--;
3218 /***********************************************************************
3219 * FILEDLG95_LOOKIN_SearchItem
3221 * Search for pidl in the lookin combo box
3222 * returns the index of the found item
3224 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3227 int iCount = CBGetCount(hwnd);
3229 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3231 if (iCount != CB_ERR)
3235 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3237 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3239 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3247 /***********************************************************************
3248 * FILEDLG95_LOOKIN_Clean
3250 * Clean the memory used by the lookin combo box
3252 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3254 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3255 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3257 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3261 /* Delete each string of the combo and their associated data */
3262 if (iCount != CB_ERR)
3264 for(iPos = iCount-1;iPos>=0;iPos--)
3266 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3267 COMDLG32_SHFree(tmpFolder->pidlItem);
3269 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3273 /* LookInInfos structure */
3275 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3278 /***********************************************************************
3279 * FILEDLG95_FILENAME_FillFromSelection
3281 * fills the edit box from the cached DataObject
3283 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3285 FileOpenDlgInfos *fodInfos;
3287 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3288 WCHAR lpstrTemp[MAX_PATH];
3289 LPWSTR lpstrAllFile, lpstrCurrFile;
3292 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3294 /* Count how many files we have */
3295 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3297 /* calculate the string length, count files */
3298 if (nFileSelected >= 1)
3300 nLength += 3; /* first and last quotes, trailing \0 */
3301 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3303 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3307 /* get the total length of the selected file names */
3308 lpstrTemp[0] = '\0';
3309 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3311 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3313 nLength += lstrlenW( lpstrTemp ) + 3;
3316 COMDLG32_SHFree( pidl );
3321 /* allocate the buffer */
3322 if (nFiles <= 1) nLength = MAX_PATH;
3323 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3325 /* Generate the string for the edit control */
3328 lpstrCurrFile = lpstrAllFile;
3329 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3331 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3335 /* get the file name */
3336 lpstrTemp[0] = '\0';
3337 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3339 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3343 *lpstrCurrFile++ = '\"';
3344 lstrcpyW( lpstrCurrFile, lpstrTemp );
3345 lpstrCurrFile += lstrlenW( lpstrTemp );
3346 *lpstrCurrFile++ = '\"';
3347 *lpstrCurrFile++ = ' ';
3352 lstrcpyW( lpstrAllFile, lpstrTemp );
3355 COMDLG32_SHFree( pidl );
3358 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3360 /* Select the file name like Windows does */
3361 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3363 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3367 /* copied from shell32 to avoid linking to it
3368 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3369 * is dependent on whether emulated OS is unicode or not.
3371 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3376 lstrcpynW(dest, src->u.pOleStr, len);
3377 COMDLG32_SHFree(src->u.pOleStr);
3381 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3386 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3391 FIXME("unknown type %x!\n", src->uType);
3392 if (len) *dest = '\0';
3398 /***********************************************************************
3399 * FILEDLG95_FILENAME_GetFileNames
3401 * Copies the filenames to a delimited string list.
3402 * The delimiter is specified by the parameter 'separator',
3403 * usually either a space or a nul
3405 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3407 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3408 UINT nStrCharCount = 0; /* index in src buffer */
3409 UINT nFileIndex = 0; /* index in dest buffer */
3410 UINT nFileCount = 0; /* number of files */
3411 UINT nStrLen = 0; /* length of string in edit control */
3412 LPWSTR lpstrEdit; /* buffer for string from edit control */
3416 /* get the filenames from the edit control */
3417 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3418 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3419 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3421 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3423 /* we might get single filename without any '"',
3424 * so we need nStrLen + terminating \0 + end-of-list \0 */
3425 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3428 /* build delimited file list from filenames */
3429 while ( nStrCharCount <= nStrLen )
3431 if ( lpstrEdit[nStrCharCount]=='"' )
3434 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3436 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3439 (*lpstrFileList)[nFileIndex++] = 0;
3445 /* single, unquoted string */
3446 if ((nStrLen > 0) && (nFileIndex == 0) )
3448 lstrcpyW(*lpstrFileList, lpstrEdit);
3449 nFileIndex = lstrlenW(lpstrEdit) + 1;
3454 (*lpstrFileList)[nFileIndex++] = '\0';
3456 *sizeUsed = nFileIndex;
3461 #define SETDefFormatEtc(fe,cf,med) \
3463 (fe).cfFormat = cf;\
3464 (fe).dwAspect = DVASPECT_CONTENT; \
3471 * DATAOBJECT Helper functions
3474 /***********************************************************************
3475 * COMCTL32_ReleaseStgMedium
3477 * like ReleaseStgMedium from ole32
3479 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3481 if(medium.pUnkForRelease)
3483 IUnknown_Release(medium.pUnkForRelease);
3487 GlobalUnlock(medium.u.hGlobal);
3488 GlobalFree(medium.u.hGlobal);
3492 /***********************************************************************
3493 * GetPidlFromDataObject
3495 * Return pidl(s) by number from the cached DataObject
3497 * nPidlIndex=0 gets the fully qualified root path
3499 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3503 FORMATETC formatetc;
3504 LPITEMIDLIST pidl = NULL;
3506 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3511 /* Set the FORMATETC structure*/
3512 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3514 /* Get the pidls from IDataObject */
3515 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3517 LPIDA cida = GlobalLock(medium.u.hGlobal);
3518 if(nPidlIndex <= cida->cidl)
3520 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3522 COMCTL32_ReleaseStgMedium(medium);
3527 /***********************************************************************
3530 * Return the number of selected items in the DataObject.
3533 static UINT GetNumSelected( IDataObject *doSelected )
3537 FORMATETC formatetc;
3539 TRACE("sv=%p\n", doSelected);
3541 if (!doSelected) return 0;
3543 /* Set the FORMATETC structure*/
3544 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3546 /* Get the pidls from IDataObject */
3547 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3549 LPIDA cida = GlobalLock(medium.u.hGlobal);
3550 retVal = cida->cidl;
3551 COMCTL32_ReleaseStgMedium(medium);
3561 /***********************************************************************
3564 * Get the pidl's display name (relative to folder) and
3565 * put it in lpstrFileName.
3567 * Return NOERROR on success,
3571 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3576 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3580 SHGetDesktopFolder(&lpsf);
3581 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3582 IShellFolder_Release(lpsf);
3586 /* Get the display name of the pidl relative to the folder */
3587 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3589 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3594 /***********************************************************************
3595 * GetShellFolderFromPidl
3597 * pidlRel is the item pidl relative
3598 * Return the IShellFolder of the absolute pidl
3600 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3602 IShellFolder *psf = NULL,*psfParent;
3604 TRACE("%p\n", pidlAbs);
3606 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3609 if(pidlAbs && pidlAbs->mkid.cb)
3611 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3613 IShellFolder_Release(psfParent);
3617 /* return the desktop */
3623 /***********************************************************************
3626 * Return the LPITEMIDLIST to the parent of the pidl in the list
3628 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3630 LPITEMIDLIST pidlParent;
3632 TRACE("%p\n", pidl);
3634 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3635 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3640 /***********************************************************************
3643 * returns the pidl of the file name relative to folder
3644 * NULL if an error occurred
3646 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3648 LPITEMIDLIST pidl = NULL;
3651 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3653 if(!lpcstrFileName) return NULL;
3654 if(!*lpcstrFileName) return NULL;
3658 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3659 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3660 IShellFolder_Release(lpsf);
3665 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3672 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3674 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3677 TRACE("%p, %p\n", psf, pidl);
3679 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3681 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3682 /* see documentation shell 4.1*/
3683 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3686 /***********************************************************************
3687 * BrowseSelectedFolder
3689 static BOOL BrowseSelectedFolder(HWND hwnd)
3691 BOOL bBrowseSelFolder = FALSE;
3692 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3696 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3698 LPITEMIDLIST pidlSelection;
3700 /* get the file selected */
3701 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3702 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3704 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3705 pidlSelection, SBSP_RELATIVE ) ) )
3707 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3708 ' ','n','o','t',' ','e','x','i','s','t',0};
3709 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3711 bBrowseSelFolder = TRUE;
3712 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3713 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3715 COMDLG32_SHFree( pidlSelection );
3718 return bBrowseSelFolder;
3722 * Memory allocation methods */
3723 static void *MemAlloc(UINT size)
3725 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3728 static void MemFree(void *mem)
3730 HeapFree(GetProcessHeap(),0,mem);
3734 * Old-style (win3.1) dialogs */
3736 /***********************************************************************
3737 * FD32_GetTemplate [internal]
3739 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3740 * by a 32 bits application
3743 BOOL FD32_GetTemplate(PFD31_DATA lfs)
3745 LPOPENFILENAMEW ofnW = lfs->ofnW;
3746 LPOPENFILENAMEA ofnA = lfs->ofnA;
3749 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3751 if (!(lfs->template = LockResource( ofnW->hInstance )))
3753 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3757 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3761 hResInfo = FindResourceA(ofnA->hInstance,
3762 ofnA->lpTemplateName,
3765 hResInfo = FindResourceW(ofnW->hInstance,
3766 ofnW->lpTemplateName,
3770 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3773 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3775 !(lfs->template = LockResource(hDlgTmpl)))
3777 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3780 } else { /* get it from internal Wine resource */
3782 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3783 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3785 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3788 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3789 !(lfs->template = LockResource( hDlgTmpl )))
3791 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3799 /***********************************************************************
3800 * FD32_WMMeasureItem [internal]
3802 static LONG FD32_WMMeasureItem(LPARAM lParam)
3804 LPMEASUREITEMSTRUCT lpmeasure;
3806 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3807 lpmeasure->itemHeight = FD31_GetFldrHeight();
3812 /***********************************************************************
3813 * FileOpenDlgProc [internal]
3814 * Used for open and save, in fact.
3816 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3817 WPARAM wParam, LPARAM lParam)
3819 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3821 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3822 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3825 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3827 return lRet; /* else continue message processing */
3832 return FD31_WMInitDialog(hWnd, wParam, lParam);
3834 case WM_MEASUREITEM:
3835 return FD32_WMMeasureItem(lParam);
3838 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3841 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3844 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3845 switch (HIWORD(lParam))
3848 SetTextColor((HDC16)wParam, 0x00000000);
3850 case CTLCOLOR_STATIC:
3851 SetTextColor((HDC16)wParam, 0x00000000);
3861 /***********************************************************************
3862 * GetFileName31A [internal]
3864 * Creates a win31 style dialog box for the user to select a file to open/save.
3866 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3867 UINT dlgType /* type dialogue : open/save */
3873 if (!lpofn || !FD31_Init()) return FALSE;
3875 TRACE("ofn flags %08x\n", lpofn->Flags);
3876 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
3879 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
3880 FD32_FileOpenDlgProc, (LPARAM)lfs);
3881 FD31_DestroyPrivate(lfs);
3884 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3888 /***********************************************************************
3889 * GetFileName31W [internal]
3891 * Creates a win31 style dialog box for the user to select a file to open/save
3893 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3894 UINT dlgType /* type dialogue : open/save */
3900 if (!lpofn || !FD31_Init()) return FALSE;
3902 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
3905 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
3906 FD32_FileOpenDlgProc, (LPARAM)lfs);
3907 FD31_DestroyPrivate(lfs);
3910 TRACE("file %s, file offset %d, ext offset %d\n",
3911 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3915 /* ------------------ APIs ---------------------- */
3917 /***********************************************************************
3918 * GetOpenFileNameA (COMDLG32.@)
3920 * Creates a dialog box for the user to select a file to open.
3923 * TRUE on success: user enters a valid file
3924 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3927 BOOL WINAPI GetOpenFileNameA(
3928 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3930 BOOL win16look = FALSE;
3932 TRACE("flags %08x\n", ofn->Flags);
3934 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3935 if (ofn->Flags & OFN_FILEMUSTEXIST)
3936 ofn->Flags |= OFN_PATHMUSTEXIST;
3938 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3939 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3942 return GetFileName31A(ofn, OPEN_DIALOG);
3944 return GetFileDialog95A(ofn, OPEN_DIALOG);
3947 /***********************************************************************
3948 * GetOpenFileNameW (COMDLG32.@)
3950 * Creates a dialog box for the user to select a file to open.
3953 * TRUE on success: user enters a valid file
3954 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3957 BOOL WINAPI GetOpenFileNameW(
3958 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3960 BOOL win16look = FALSE;
3962 TRACE("flags %08x\n", ofn->Flags);
3964 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3965 if (ofn->Flags & OFN_FILEMUSTEXIST)
3966 ofn->Flags |= OFN_PATHMUSTEXIST;
3968 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3969 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3972 return GetFileName31W(ofn, OPEN_DIALOG);
3974 return GetFileDialog95W(ofn, OPEN_DIALOG);
3978 /***********************************************************************
3979 * GetSaveFileNameA (COMDLG32.@)
3981 * Creates a dialog box for the user to select a file to save.
3984 * TRUE on success: user enters a valid file
3985 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3988 BOOL WINAPI GetSaveFileNameA(
3989 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3991 BOOL win16look = FALSE;
3993 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3994 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3997 return GetFileName31A(ofn, SAVE_DIALOG);
3999 return GetFileDialog95A(ofn, SAVE_DIALOG);
4002 /***********************************************************************
4003 * GetSaveFileNameW (COMDLG32.@)
4005 * Creates a dialog box for the user to select a file to save.
4008 * TRUE on success: user enters a valid file
4009 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4012 BOOL WINAPI GetSaveFileNameW(
4013 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4015 BOOL win16look = FALSE;
4017 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4018 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4021 return GetFileName31W(ofn, SAVE_DIALOG);
4023 return GetFileDialog95W(ofn, SAVE_DIALOG);
4026 /***********************************************************************
4027 * GetFileTitleA (COMDLG32.@)
4029 * See GetFileTitleW.
4031 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4034 UNICODE_STRING strWFile;
4037 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4038 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4039 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4040 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4041 RtlFreeUnicodeString( &strWFile );
4042 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4047 /***********************************************************************
4048 * GetFileTitleW (COMDLG32.@)
4050 * Get the name of a file.
4053 * lpFile [I] name and location of file
4054 * lpTitle [O] returned file name
4055 * cbBuf [I] buffer size of lpTitle
4059 * Failure: negative number.
4061 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4064 static const WCHAR brkpoint[] = {'*','[',']',0};
4065 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4067 if(lpFile == NULL || lpTitle == NULL)
4070 len = lstrlenW(lpFile);
4075 if(strpbrkW(lpFile, brkpoint))
4080 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4083 for(i = len; i >= 0; i--)
4085 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4095 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4097 len = lstrlenW(lpFile+i)+1;
4101 lstrcpyW(lpTitle, &lpFile[i]);