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
108 typedef struct tagFD32_PRIVATE
110 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
111 } FD32_PRIVATE, *PFD32_PRIVATE;
114 /***********************************************************************
115 * Defines and global variables
118 /* Draw item constant */
120 #define XTEXTOFFSET 3
125 /* SearchItem methods */
126 #define SEARCH_PIDL 1
128 #define ITEM_NOTFOUND -1
130 /* Undefined windows message sent by CreateViewObject*/
131 #define WM_GETISHELLBROWSER WM_USER+7
134 * Those macros exist in windowsx.h. However, you can't really use them since
135 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 /* Combo box macros */
139 #define CBAddString(hwnd,str) \
140 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
142 #define CBInsertString(hwnd,str,pos) \
143 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
145 #define CBDeleteString(hwnd,pos) \
146 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
148 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
149 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
151 #define CBGetItemDataPtr(hwnd,iItemId) \
152 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
154 #define CBGetLBText(hwnd,iItemId,str) \
155 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
157 #define CBGetCurSel(hwnd) \
158 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
160 #define CBSetCurSel(hwnd,pos) \
161 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
163 #define CBGetCount(hwnd) \
164 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
165 #define CBShowDropDown(hwnd,show) \
166 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
167 #define CBSetItemHeight(hwnd,index,height) \
168 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
170 #define CBSetExtendedUI(hwnd,flag) \
171 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
173 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
174 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
176 /***********************************************************************
180 /* Internal functions used by the dialog */
181 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
182 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
185 static BOOL FILEDLG95_OnOpen(HWND hwnd);
186 static LRESULT FILEDLG95_InitControls(HWND hwnd);
187 static void FILEDLG95_Clean(HWND hwnd);
189 /* Functions used by the shell navigation */
190 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Miscellaneous tool functions */
217 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
218 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
219 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
220 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
221 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
222 static UINT GetNumSelected( IDataObject *doSelected );
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size);
226 static void MemFree(void *mem);
228 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
231 static BOOL BrowseSelectedFolder(HWND hwnd);
233 /***********************************************************************
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
273 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
275 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
276 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
277 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
280 /* old style hook messages */
281 if (IsHooked(fodInfos))
283 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
284 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
285 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
286 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
289 /* Some shell namespace extensions depend on COM being initialized. */
290 hr = OleInitialize(NULL);
292 if (fodInfos->unicode)
293 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
295 fodInfos->ofnInfos->hwndOwner,
299 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
301 fodInfos->ofnInfos->hwndOwner,
307 /* Unable to create the dialog */
314 /***********************************************************************
317 * Call GetFileName95 with this structure and clean the memory.
319 * IN : The OPENFILENAMEA initialisation structure passed to
320 * GetOpenFileNameA win api function (see filedlg.c)
322 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
325 FileOpenDlgInfos fodInfos;
326 LPSTR lpstrSavDir = NULL;
328 LPWSTR defext = NULL;
329 LPWSTR filter = NULL;
330 LPWSTR customfilter = NULL;
332 /* Initialize CommDlgExtendedError() */
333 COMDLG32_SetCommDlgExtendedError(0);
335 /* Initialize FileOpenDlgInfos structure */
336 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
338 /* Pass in the original ofn */
339 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
341 /* save current directory */
342 if (ofn->Flags & OFN_NOCHANGEDIR)
344 lpstrSavDir = MemAlloc(MAX_PATH);
345 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
348 fodInfos.unicode = FALSE;
350 /* convert all the input strings to unicode */
351 if(ofn->lpstrInitialDir)
353 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
354 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
355 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
358 fodInfos.initdir = NULL;
362 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
363 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
366 fodInfos.filename = NULL;
370 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
371 defext = MemAlloc((len+1)*sizeof(WCHAR));
372 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
374 fodInfos.defext = defext;
378 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
379 title = MemAlloc((len+1)*sizeof(WCHAR));
380 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
382 fodInfos.title = title;
384 if (ofn->lpstrFilter)
389 /* filter is a list... title\0ext\0......\0\0 */
390 s = ofn->lpstrFilter;
391 while (*s) s = s+strlen(s)+1;
393 n = s - ofn->lpstrFilter;
394 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
395 filter = MemAlloc(len*sizeof(WCHAR));
396 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
398 fodInfos.filter = filter;
400 /* convert lpstrCustomFilter */
401 if (ofn->lpstrCustomFilter)
406 /* customfilter contains a pair of strings... title\0ext\0 */
407 s = ofn->lpstrCustomFilter;
408 if (*s) s = s+strlen(s)+1;
409 if (*s) s = s+strlen(s)+1;
410 n = s - ofn->lpstrCustomFilter;
411 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
412 customfilter = MemAlloc(len*sizeof(WCHAR));
413 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
415 fodInfos.customfilter = customfilter;
417 /* Initialize the dialog property */
418 fodInfos.DlgInfos.dwDlgProp = 0;
419 fodInfos.DlgInfos.hwndCustomDlg = NULL;
424 ret = GetFileName95(&fodInfos);
427 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
428 ret = GetFileName95(&fodInfos);
436 SetCurrentDirectoryA(lpstrSavDir);
437 MemFree(lpstrSavDir);
443 MemFree(customfilter);
444 MemFree(fodInfos.initdir);
445 MemFree(fodInfos.filename);
447 TRACE("selected file: %s\n",ofn->lpstrFile);
452 /***********************************************************************
455 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
456 * Call GetFileName95 with this structure and clean the memory.
459 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
462 FileOpenDlgInfos fodInfos;
463 LPWSTR lpstrSavDir = NULL;
465 /* Initialize CommDlgExtendedError() */
466 COMDLG32_SetCommDlgExtendedError(0);
468 /* Initialize FileOpenDlgInfos structure */
469 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
471 /* Pass in the original ofn */
472 fodInfos.ofnInfos = ofn;
474 fodInfos.title = ofn->lpstrTitle;
475 fodInfos.defext = ofn->lpstrDefExt;
476 fodInfos.filter = ofn->lpstrFilter;
477 fodInfos.customfilter = ofn->lpstrCustomFilter;
479 /* convert string arguments, save others */
482 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
483 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
486 fodInfos.filename = NULL;
488 if(ofn->lpstrInitialDir)
490 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
491 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
492 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
493 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
496 fodInfos.initdir = NULL;
498 /* save current directory */
499 if (ofn->Flags & OFN_NOCHANGEDIR)
501 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
502 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
505 fodInfos.unicode = TRUE;
510 ret = GetFileName95(&fodInfos);
513 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
514 ret = GetFileName95(&fodInfos);
522 SetCurrentDirectoryW(lpstrSavDir);
523 MemFree(lpstrSavDir);
526 /* restore saved IN arguments and convert OUT arguments back */
527 MemFree(fodInfos.filename);
528 MemFree(fodInfos.initdir);
532 /******************************************************************************
533 * COMDLG32_GetDisplayNameOf [internal]
535 * Helper function to get the display name for a pidl.
537 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
538 LPSHELLFOLDER psfDesktop;
541 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
544 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
545 IShellFolder_Release(psfDesktop);
549 IShellFolder_Release(psfDesktop);
550 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
553 /***********************************************************************
554 * ArrangeCtrlPositions [internal]
556 * NOTE: Do not change anything here without a lot of testing.
558 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
560 HWND hwndChild, hwndStc32;
561 RECT rectParent, rectChild, rectStc32;
562 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
564 /* Take into account if open as read only checkbox and help button
569 RECT rectHelp, rectCancel;
570 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
571 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
572 /* subtract the height of the help button plus the space between
573 * the help button and the cancel button to the height of the dialog
575 help_fixup = rectHelp.bottom - rectCancel.bottom;
579 There are two possibilities to add components to the default file dialog box.
581 By default, all the new components are added below the standard dialog box (the else case).
583 However, if there is a static text component with the stc32 id, a special case happens.
584 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
585 in the window and the cx and cy indicate how to size the window.
586 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
587 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
591 GetClientRect(hwndParentDlg, &rectParent);
593 /* when arranging controls we have to use fixed parent size */
594 rectParent.bottom -= help_fixup;
596 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
599 GetWindowRect(hwndStc32, &rectStc32);
600 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
602 /* set the size of the stc32 control according to the size of
603 * client area of the parent dialog
605 SetWindowPos(hwndStc32, 0,
607 rectParent.right, rectParent.bottom,
608 SWP_NOMOVE | SWP_NOZORDER);
611 SetRectEmpty(&rectStc32);
613 /* this part moves controls of the child dialog */
614 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
617 if (hwndChild != hwndStc32)
619 GetWindowRect(hwndChild, &rectChild);
620 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
622 /* move only if stc32 exist */
623 if (hwndStc32 && rectChild.left > rectStc32.right)
625 LONG old_left = rectChild.left;
627 /* move to the right of visible controls of the parent dialog */
628 rectChild.left += rectParent.right;
629 rectChild.left -= rectStc32.right;
631 child_width_fixup = rectChild.left - old_left;
633 /* move even if stc32 doesn't exist */
634 if (rectChild.top >= rectStc32.bottom)
636 LONG old_top = rectChild.top;
638 /* move below visible controls of the parent dialog */
639 rectChild.top += rectParent.bottom;
640 rectChild.top -= rectStc32.bottom - rectStc32.top;
642 child_height_fixup = rectChild.top - old_top;
645 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
646 0, 0, SWP_NOSIZE | SWP_NOZORDER);
648 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
651 /* this part moves controls of the parent dialog */
652 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
655 if (hwndChild != hwndChildDlg)
657 GetWindowRect(hwndChild, &rectChild);
658 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
660 /* left,top of stc32 marks the position of controls
661 * from the parent dialog
663 rectChild.left += rectStc32.left;
664 rectChild.top += rectStc32.top;
666 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
667 0, 0, SWP_NOSIZE | SWP_NOZORDER);
669 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
672 /* calculate the size of the resulting dialog */
674 /* here we have to use original parent size */
675 GetClientRect(hwndParentDlg, &rectParent);
676 GetClientRect(hwndChildDlg, &rectChild);
680 rectChild.right += child_width_fixup;
681 rectChild.bottom += child_height_fixup;
683 if (rectParent.right > rectChild.right)
685 rectParent.right += rectChild.right;
686 rectParent.right -= rectStc32.right - rectStc32.left;
690 rectParent.right = rectChild.right;
693 if (rectParent.bottom > rectChild.bottom)
695 rectParent.bottom += rectChild.bottom;
696 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
700 /* child dialog is higher, unconditionally set new dialog
701 * height to its size (help_fixup will be subtracted below)
703 rectParent.bottom = rectChild.bottom + help_fixup;
708 rectParent.bottom += rectChild.bottom;
711 /* finally use fixed parent size */
712 rectParent.bottom -= help_fixup;
714 /* set the size of the parent dialog */
715 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
716 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
717 SetWindowPos(hwndParentDlg, 0,
719 rectParent.right - rectParent.left,
720 rectParent.bottom - rectParent.top,
721 SWP_NOMOVE | SWP_NOZORDER);
724 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
733 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
743 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
744 * structure's hInstance parameter is not a HINSTANCE, but
745 * instead a pointer to a template resource to use.
747 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
750 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
752 hinst = COMDLG32_hInstance;
753 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
755 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
761 hinst = fodInfos->ofnInfos->hInstance;
762 if(fodInfos->unicode)
764 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
765 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
769 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
770 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
774 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
777 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
778 !(template = LockResource( hDlgTmpl )))
780 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
784 if (fodInfos->unicode)
785 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
786 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
787 (LPARAM)fodInfos->ofnInfos);
789 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
790 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
791 (LPARAM)fodInfos->ofnInfos);
794 else if( IsHooked(fodInfos))
799 WORD menu,class,title;
801 GetClientRect(hwnd,&rectHwnd);
802 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
803 temp.tmplate.dwExtendedStyle = 0;
804 temp.tmplate.cdit = 0;
809 temp.menu = temp.class = temp.title = 0;
811 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
812 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
819 /***********************************************************************
820 * SendCustomDlgNotificationMessage
822 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
825 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
827 LRESULT hook_result = 0;
828 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
830 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
832 if(!fodInfos) return 0;
834 if(fodInfos->DlgInfos.hwndCustomDlg)
836 TRACE("CALL NOTIFY for %x\n", uCode);
837 if(fodInfos->unicode)
840 ofnNotify.hdr.hwndFrom=hwndParentDlg;
841 ofnNotify.hdr.idFrom=0;
842 ofnNotify.hdr.code = uCode;
843 ofnNotify.lpOFN = fodInfos->ofnInfos;
844 ofnNotify.pszFile = NULL;
845 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
850 ofnNotify.hdr.hwndFrom=hwndParentDlg;
851 ofnNotify.hdr.idFrom=0;
852 ofnNotify.hdr.code = uCode;
853 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
854 ofnNotify.pszFile = NULL;
855 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
857 TRACE("RET NOTIFY\n");
859 TRACE("Retval: 0x%08lx\n", hook_result);
863 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
867 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
869 TRACE("CDM_GETFILEPATH:\n");
871 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
874 /* get path and filenames */
875 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
876 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
877 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
880 p = buffer + strlenW(buffer);
882 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
884 if (fodInfos->unicode)
886 total = strlenW( buffer) + 1;
887 if (result) lstrcpynW( result, buffer, size );
888 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
892 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
893 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
894 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
896 HeapFree( GetProcessHeap(), 0, buffer );
900 /***********************************************************************
901 * FILEDLG95_HandleCustomDialogMessages
903 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
905 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
907 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
908 WCHAR lpstrPath[MAX_PATH];
911 if(!fodInfos) return FALSE;
915 case CDM_GETFILEPATH:
916 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
919 case CDM_GETFOLDERPATH:
920 TRACE("CDM_GETFOLDERPATH:\n");
921 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
924 if (fodInfos->unicode)
925 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
927 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
928 (LPSTR)lParam, (int)wParam, NULL, NULL);
930 retval = lstrlenW(lpstrPath);
933 case CDM_GETFOLDERIDLIST:
934 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
935 if (retval <= wParam)
936 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
940 TRACE("CDM_GETSPEC:\n");
941 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
944 if (fodInfos->unicode)
945 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
947 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
951 case CDM_SETCONTROLTEXT:
952 TRACE("CDM_SETCONTROLTEXT:\n");
955 if( fodInfos->unicode )
956 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
958 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
963 case CDM_HIDECONTROL:
964 /* MSDN states that it should fail for not OFN_EXPLORER case */
965 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
967 HWND control = GetDlgItem( hwnd, wParam );
968 if (control) ShowWindow( control, SW_HIDE );
975 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
976 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
979 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
983 /***********************************************************************
984 * FILEDLG95_OnWMGetMMI
986 * WM_GETMINMAXINFO message handler for resizable dialogs
988 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
990 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
991 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
992 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
994 mmiptr->ptMinTrackSize = fodInfos->initial_size;
999 /***********************************************************************
1000 * FILEDLG95_OnWMSize
1002 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1004 * FIXME: this could be made more elaborate. Now use a simple scheme
1005 * where the file view is enlarged and the controls are either moved
1006 * vertically or horizontally to get out of the way. Only the "grip"
1007 * is moved in both directions to stay in the corner.
1009 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1015 FileOpenDlgInfos *fodInfos;
1017 if( wParam != SIZE_RESTORED) return FALSE;
1018 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1019 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1020 /* get the new dialog rectangle */
1021 GetWindowRect( hwnd, &rc);
1022 /* not initialized yet */
1023 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1024 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1025 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1027 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1028 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1029 fodInfos->sizedlg.cx = rc.right - rc.left;
1030 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1031 /* change the size of the view window */
1032 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1033 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1034 hdwp = BeginDeferWindowPos( 10);
1035 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1036 rcview.right - rcview.left + chgx,
1037 rcview.bottom - rcview.top + chgy,
1038 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1039 /* change position and sizes of the controls */
1040 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1042 GetWindowRect( ctrl, &rc);
1043 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1044 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1046 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1048 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1050 else if( GetDlgCtrlID( ctrl) == IDC_SHELLSTATIC)
1052 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1053 rc.right - rc.left + chgx,
1054 rc.bottom - rc.top + chgy,
1055 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1057 else if( rc.top > rcview.bottom)
1059 /* if it was below the shell view
1061 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1062 rc.right - rc.left, rc.bottom - rc.top,
1063 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,
1070 rc.right - rc.left, rc.bottom - rc.top,
1071 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1074 if(fodInfos->DlgInfos.hwndCustomDlg &&
1075 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1077 GetClientRect(hwnd, &rc);
1078 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1079 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1080 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1081 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1083 GetWindowRect( ctrl, &rc);
1084 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1085 if( rc.top > rcview.bottom)
1087 /* if it was below the shell view
1089 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1090 rc.right - rc.left, rc.bottom - rc.top,
1091 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1093 else if( rc.left > rcview.right)
1095 /* if it was to the right of the shell view
1097 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1098 rc.right - rc.left, rc.bottom - rc.top,
1099 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1103 EndDeferWindowPos( hdwp);
1104 /* should not be needed */
1105 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1109 /***********************************************************************
1112 * File open dialog procedure
1114 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1117 TRACE("%p 0x%04x\n", hwnd, uMsg);
1124 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1126 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1127 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1129 /* Adds the FileOpenDlgInfos in the property list of the dialog
1130 so it will be easily accessible through a GetPropA(...) */
1131 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1133 FILEDLG95_InitControls(hwnd);
1135 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1137 GetWindowRect( hwnd, &rc);
1138 fodInfos->DlgInfos.hwndGrip =
1139 CreateWindowExA( 0, "SCROLLBAR", NULL,
1140 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1141 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1142 rc.right - gripx, rc.bottom - gripy,
1143 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1146 fodInfos->DlgInfos.hwndCustomDlg =
1147 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1149 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1150 FILEDLG95_FillControls(hwnd, wParam, lParam);
1152 if( fodInfos->DlgInfos.hwndCustomDlg)
1153 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1155 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1156 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1158 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1160 GetWindowRect( hwnd, &rc);
1161 /* FIXME: should remember sizes of last invocation */
1162 fodInfos->sizedlg.cx = rc.right - rc.left;
1163 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1164 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1165 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1166 GetClientRect( hwnd, &rc);
1167 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1168 rc.right - gripx, rc.bottom - gripy,
1169 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1172 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1174 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1175 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1180 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1181 case WM_GETMINMAXINFO:
1182 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1184 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1187 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1190 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1196 case WM_GETISHELLBROWSER:
1197 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1200 RemovePropA(hwnd, FileOpenDlgInfosStr);
1205 LPNMHDR lpnmh = (LPNMHDR)lParam;
1208 /* set up the button tooltips strings */
1209 if(TTN_GETDISPINFOA == lpnmh->code )
1211 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1212 switch(lpnmh->idFrom )
1214 /* Up folder button */
1215 case FCIDM_TB_UPFOLDER:
1216 stringId = IDS_UPFOLDER;
1218 /* New folder button */
1219 case FCIDM_TB_NEWFOLDER:
1220 stringId = IDS_NEWFOLDER;
1222 /* List option button */
1223 case FCIDM_TB_SMALLICON:
1224 stringId = IDS_LISTVIEW;
1226 /* Details option button */
1227 case FCIDM_TB_REPORTVIEW:
1228 stringId = IDS_REPORTVIEW;
1230 /* Desktop button */
1231 case FCIDM_TB_DESKTOP:
1232 stringId = IDS_TODESKTOP;
1237 lpdi->hinst = COMDLG32_hInstance;
1238 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1243 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1244 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1249 /***********************************************************************
1250 * FILEDLG95_InitControls
1252 * WM_INITDIALOG message handler (before hook notification)
1254 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1256 int win2000plus = 0;
1258 int handledPath = FALSE;
1259 OSVERSIONINFOW osVi;
1260 static const WCHAR szwSlash[] = { '\\', 0 };
1261 static const WCHAR szwStar[] = { '*',0 };
1263 static const TBBUTTON tbb[] =
1265 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1266 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1267 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1268 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1269 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1270 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1271 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1272 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1273 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1278 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1280 tba[0].hInst = HINST_COMMCTRL;
1281 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1282 tba[1].hInst = COMDLG32_hInstance;
1285 TRACE("%p\n", fodInfos);
1287 /* Get windows version emulating */
1288 osVi.dwOSVersionInfoSize = sizeof(osVi);
1289 GetVersionExW(&osVi);
1290 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1291 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1292 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1293 win2000plus = (osVi.dwMajorVersion > 4);
1294 if (win2000plus) win98plus = TRUE;
1296 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1298 /* Get the hwnd of the controls */
1299 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1300 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1301 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1303 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1304 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1306 /* construct the toolbar */
1307 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1308 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1310 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1311 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1312 rectTB.left = rectlook.right;
1313 rectTB.top = rectlook.top-1;
1315 if (fodInfos->unicode)
1316 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1317 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1318 rectTB.left, rectTB.top,
1319 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1320 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1322 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1323 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1324 rectTB.left, rectTB.top,
1325 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1326 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1328 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1330 /* FIXME: use TB_LOADIMAGES when implemented */
1331 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1332 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1333 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1335 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1336 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1338 /* Set the window text with the text specified in the OPENFILENAME structure */
1341 SetWindowTextW(hwnd,fodInfos->title);
1343 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1346 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1347 SetWindowTextW(hwnd, buf);
1350 /* Initialise the file name edit control */
1351 handledPath = FALSE;
1352 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1354 if(fodInfos->filename)
1356 /* 1. If win2000 or higher and filename contains a path, use it
1357 in preference over the lpstrInitialDir */
1358 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1359 WCHAR tmpBuf[MAX_PATH];
1363 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1366 /* nameBit is always shorter than the original filename */
1367 lstrcpyW(fodInfos->filename,nameBit);
1370 if (fodInfos->initdir == NULL)
1371 MemFree(fodInfos->initdir);
1372 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1373 lstrcpyW(fodInfos->initdir, tmpBuf);
1375 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1376 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1378 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1381 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1385 /* 2. (All platforms) If initdir is not null, then use it */
1386 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1387 (*fodInfos->initdir!=0x00))
1389 /* Work out the proper path as supplied one might be relative */
1390 /* (Here because supplying '.' as dir browses to My Computer) */
1391 if (handledPath==FALSE) {
1392 WCHAR tmpBuf[MAX_PATH];
1393 WCHAR tmpBuf2[MAX_PATH];
1397 lstrcpyW(tmpBuf, fodInfos->initdir);
1398 if( PathFileExistsW(tmpBuf) ) {
1399 /* initdir does not have to be a directory. If a file is
1400 * specified, the dir part is taken */
1401 if( PathIsDirectoryW(tmpBuf)) {
1402 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1403 lstrcatW(tmpBuf, szwSlash);
1405 lstrcatW(tmpBuf, szwStar);
1407 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1410 MemFree(fodInfos->initdir);
1411 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1412 lstrcpyW(fodInfos->initdir, tmpBuf2);
1414 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1417 else if (fodInfos->initdir)
1419 MemFree(fodInfos->initdir);
1420 fodInfos->initdir = NULL;
1421 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1426 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1427 (*fodInfos->initdir==0x00)))
1429 /* 3. All except w2k+: if filename contains a path use it */
1430 if (!win2000plus && fodInfos->filename &&
1431 *fodInfos->filename &&
1432 strpbrkW(fodInfos->filename, szwSlash)) {
1433 WCHAR tmpBuf[MAX_PATH];
1437 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1442 /* nameBit is always shorter than the original filename */
1443 lstrcpyW(fodInfos->filename, nameBit);
1446 len = lstrlenW(tmpBuf);
1447 MemFree(fodInfos->initdir);
1448 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1449 lstrcpyW(fodInfos->initdir, tmpBuf);
1452 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1453 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1455 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1458 /* 4. win98+ and win2000+ if any files of specified filter types in
1459 current directory, use it */
1460 if ( win98plus && handledPath == FALSE &&
1461 fodInfos->filter && *fodInfos->filter) {
1463 BOOL searchMore = TRUE;
1464 LPCWSTR lpstrPos = fodInfos->filter;
1465 WIN32_FIND_DATAW FindFileData;
1470 /* filter is a list... title\0ext\0......\0\0 */
1472 /* Skip the title */
1473 if(! *lpstrPos) break; /* end */
1474 lpstrPos += lstrlenW(lpstrPos) + 1;
1476 /* See if any files exist in the current dir with this extension */
1477 if(! *lpstrPos) break; /* end */
1479 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1481 if (hFind == INVALID_HANDLE_VALUE) {
1482 /* None found - continue search */
1483 lpstrPos += lstrlenW(lpstrPos) + 1;
1488 MemFree(fodInfos->initdir);
1489 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1490 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1493 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1494 debugstr_w(lpstrPos));
1500 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1502 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1503 if (handledPath == FALSE && (win2000plus || win98plus)) {
1504 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1506 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1508 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1511 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1512 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1514 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1517 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1520 } else if (handledPath==FALSE) {
1521 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1522 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1524 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1527 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1528 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1530 /* Must the open as read only check box be checked ?*/
1531 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1533 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1536 /* Must the open as read only check box be hidden? */
1537 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1539 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1540 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1543 /* Must the help button be hidden? */
1544 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1546 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1547 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1550 /* change Open to Save */
1551 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1554 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1555 SetDlgItemTextW(hwnd, IDOK, buf);
1556 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1557 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1560 /* Initialize the filter combo box */
1561 FILEDLG95_FILETYPE_Init(hwnd);
1566 /***********************************************************************
1567 * FILEDLG95_ResizeControls
1569 * WM_INITDIALOG message handler (after hook notification)
1571 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1573 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1575 if (fodInfos->DlgInfos.hwndCustomDlg)
1578 UINT flags = SWP_NOACTIVATE;
1580 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1581 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1583 /* resize the custom dialog to the parent size */
1584 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1585 GetClientRect(hwnd, &rc);
1588 /* our own fake template is zero sized and doesn't have children, so
1589 * there is no need to resize it. Picasa depends on it.
1591 flags |= SWP_NOSIZE;
1594 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1595 0, 0, rc.right, rc.bottom, flags);
1599 /* Resize the height, if open as read only checkbox ad help button are
1600 * hidden and we are not using a custom template nor a customDialog
1602 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1603 (!(fodInfos->ofnInfos->Flags &
1604 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1606 RECT rectDlg, rectHelp, rectCancel;
1607 GetWindowRect(hwnd, &rectDlg);
1608 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1609 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1610 /* subtract the height of the help button plus the space between the help
1611 * button and the cancel button to the height of the dialog
1613 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1614 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1615 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1621 /***********************************************************************
1622 * FILEDLG95_FillControls
1624 * WM_INITDIALOG message handler (after hook notification)
1626 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1628 LPITEMIDLIST pidlItemId = NULL;
1630 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1632 TRACE("dir=%s file=%s\n",
1633 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1635 /* Get the initial directory pidl */
1637 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1639 WCHAR path[MAX_PATH];
1641 GetCurrentDirectoryW(MAX_PATH,path);
1642 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1645 /* Initialise shell objects */
1646 FILEDLG95_SHELL_Init(hwnd);
1648 /* Initialize the Look In combo box */
1649 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1651 /* Browse to the initial directory */
1652 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1654 /* Free pidlItem memory */
1655 COMDLG32_SHFree(pidlItemId);
1659 /***********************************************************************
1662 * Regroups all the cleaning functions of the filedlg
1664 void FILEDLG95_Clean(HWND hwnd)
1666 FILEDLG95_FILETYPE_Clean(hwnd);
1667 FILEDLG95_LOOKIN_Clean(hwnd);
1668 FILEDLG95_SHELL_Clean(hwnd);
1670 /***********************************************************************
1671 * FILEDLG95_OnWMCommand
1673 * WM_COMMAND message handler
1675 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1677 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1678 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1679 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1685 FILEDLG95_OnOpen(hwnd);
1689 FILEDLG95_Clean(hwnd);
1690 EndDialog(hwnd, FALSE);
1692 /* Filetype combo box */
1694 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1696 /* LookIn combo box */
1698 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1701 /* --- toolbar --- */
1702 /* Up folder button */
1703 case FCIDM_TB_UPFOLDER:
1704 FILEDLG95_SHELL_UpFolder(hwnd);
1706 /* New folder button */
1707 case FCIDM_TB_NEWFOLDER:
1708 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1710 /* List option button */
1711 case FCIDM_TB_SMALLICON:
1712 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1714 /* Details option button */
1715 case FCIDM_TB_REPORTVIEW:
1716 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1718 /* Details option button */
1719 case FCIDM_TB_DESKTOP:
1720 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1727 /* Do not use the listview selection anymore */
1728 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1732 /***********************************************************************
1733 * FILEDLG95_OnWMGetIShellBrowser
1735 * WM_GETISHELLBROWSER message handler
1737 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1739 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1743 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1749 /***********************************************************************
1750 * FILEDLG95_SendFileOK
1752 * Sends the CDN_FILEOK notification if required
1755 * TRUE if the dialog should close
1756 * FALSE if the dialog should not be closed
1758 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1760 /* ask the hook if we can close */
1761 if(IsHooked(fodInfos))
1766 /* First send CDN_FILEOK as MSDN doc says */
1767 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1768 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1771 TRACE("canceled\n");
1775 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1776 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1777 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1780 TRACE("canceled\n");
1787 /***********************************************************************
1788 * FILEDLG95_OnOpenMultipleFiles
1790 * Handles the opening of multiple files.
1793 * check destination buffer size
1795 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1797 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1798 UINT nCount, nSizePath;
1799 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1803 if(fodInfos->unicode)
1805 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1806 ofn->lpstrFile[0] = '\0';
1810 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1811 ofn->lpstrFile[0] = '\0';
1814 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1816 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1817 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1818 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1820 LPWSTR lpstrTemp = lpstrFileList;
1822 for ( nCount = 0; nCount < nFileCount; nCount++ )
1826 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1829 WCHAR lpstrNotFound[100];
1830 WCHAR lpstrMsg[100];
1832 static const WCHAR nl[] = {'\n',0};
1834 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1835 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1837 lstrcpyW(tmp, lpstrTemp);
1839 lstrcatW(tmp, lpstrNotFound);
1841 lstrcatW(tmp, lpstrMsg);
1843 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1847 /* move to the next file in the list of files */
1848 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1849 COMDLG32_SHFree(pidl);
1853 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1854 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1856 /* For "oldstyle" dialog the components have to
1857 be separated by blanks (not '\0'!) and short
1858 filenames have to be used! */
1859 FIXME("Components have to be separated by blanks\n");
1861 if(fodInfos->unicode)
1863 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1864 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1865 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1869 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1871 if (ofn->lpstrFile != NULL)
1873 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1874 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1875 if (ofn->nMaxFile > nSizePath)
1877 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1878 ofn->lpstrFile + nSizePath,
1879 ofn->nMaxFile - nSizePath, NULL, NULL);
1884 fodInfos->ofnInfos->nFileOffset = nSizePath;
1885 fodInfos->ofnInfos->nFileExtension = 0;
1887 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1890 /* clean and exit */
1891 FILEDLG95_Clean(hwnd);
1892 return EndDialog(hwnd,TRUE);
1895 /***********************************************************************
1898 * Ok button WM_COMMAND message handler
1900 * If the function succeeds, the return value is nonzero.
1902 #define ONOPEN_BROWSE 1
1903 #define ONOPEN_OPEN 2
1904 #define ONOPEN_SEARCH 3
1905 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1907 WCHAR strMsgTitle[MAX_PATH];
1908 WCHAR strMsgText [MAX_PATH];
1910 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1912 strMsgTitle[0] = '\0';
1913 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1914 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1917 BOOL FILEDLG95_OnOpen(HWND hwnd)
1919 LPWSTR lpstrFileList;
1920 UINT nFileCount = 0;
1923 WCHAR lpstrPathAndFile[MAX_PATH];
1924 WCHAR lpstrTemp[MAX_PATH];
1925 LPSHELLFOLDER lpsf = NULL;
1927 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1929 TRACE("hwnd=%p\n", hwnd);
1931 /* get the files from the edit control */
1932 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1934 /* try if the user selected a folder in the shellview */
1937 BrowseSelectedFolder(hwnd);
1943 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1947 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1950 Step 1: Build a complete path name from the current folder and
1951 the filename or path in the edit box.
1953 - the path in the edit box is a root path
1954 (with or without drive letter)
1955 - the edit box contains ".." (or a path with ".." in it)
1958 /* Get the current directory name */
1959 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1962 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1964 PathAddBackslashW(lpstrPathAndFile);
1966 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1968 /* if the user specified a fully qualified path use it */
1969 if(PathIsRelativeW(lpstrFileList))
1971 lstrcatW(lpstrPathAndFile, lpstrFileList);
1975 /* does the path have a drive letter? */
1976 if (PathGetDriveNumberW(lpstrFileList) == -1)
1977 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1979 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1982 /* resolve "." and ".." */
1983 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1984 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1985 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1987 MemFree(lpstrFileList);
1990 Step 2: here we have a cleaned up path
1992 We have to parse the path step by step to see if we have to browse
1993 to a folder if the path points to a directory or the last
1994 valid element is a directory.
1997 lpstrPathAndFile: cleaned up path
2001 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2002 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2003 nOpenAction = ONOPEN_OPEN;
2005 nOpenAction = ONOPEN_BROWSE;
2007 /* don't apply any checks with OFN_NOVALIDATE */
2009 LPWSTR lpszTemp, lpszTemp1;
2010 LPITEMIDLIST pidl = NULL;
2011 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2013 /* check for invalid chars */
2014 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2016 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2021 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2023 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2026 LPSHELLFOLDER lpsfChild;
2027 WCHAR lpwstrTemp[MAX_PATH];
2028 DWORD dwEaten, dwAttributes;
2031 lstrcpyW(lpwstrTemp, lpszTemp);
2032 p = PathFindNextComponentW(lpwstrTemp);
2034 if (!p) break; /* end of path */
2037 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2039 /* There are no wildcards when OFN_NOVALIDATE is set */
2040 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2042 static const WCHAR wszWild[] = { '*', '?', 0 };
2043 /* if the last element is a wildcard do a search */
2044 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2046 nOpenAction = ONOPEN_SEARCH;
2050 lpszTemp1 = lpszTemp;
2052 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2054 /* append a backslash to drive letters */
2055 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2056 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2057 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2059 PathAddBackslashW(lpwstrTemp);
2062 dwAttributes = SFGAO_FOLDER;
2063 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2065 /* the path component is valid, we have a pidl of the next path component */
2066 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2067 if(dwAttributes & SFGAO_FOLDER)
2069 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2071 ERR("bind to failed\n"); /* should not fail */
2074 IShellFolder_Release(lpsf);
2082 /* end dialog, return value */
2083 nOpenAction = ONOPEN_OPEN;
2086 COMDLG32_SHFree(pidl);
2089 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2091 if(*lpszTemp || /* points to trailing null for last path element */
2092 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2094 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2096 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2102 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2103 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2105 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2109 /* change to the current folder */
2110 nOpenAction = ONOPEN_OPEN;
2115 nOpenAction = ONOPEN_OPEN;
2119 if(pidl) COMDLG32_SHFree(pidl);
2123 Step 3: here we have a cleaned up and validated path
2126 lpsf: ShellFolder bound to the rightmost valid path component
2127 lpstrPathAndFile: cleaned up path
2128 nOpenAction: action to do
2130 TRACE("end validate sf=%p\n", lpsf);
2134 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2135 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2138 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2141 /* replace the current filter */
2142 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2143 len = lstrlenW(lpszTemp)+1;
2144 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2145 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2147 /* set the filter cb to the extension when possible */
2148 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2149 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2152 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2153 TRACE("ONOPEN_BROWSE\n");
2155 IPersistFolder2 * ppf2;
2156 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2158 LPITEMIDLIST pidlCurrent;
2159 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2160 IPersistFolder2_Release(ppf2);
2161 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2163 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2164 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2166 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2169 else if( nOpenAction == ONOPEN_SEARCH )
2171 if (fodInfos->Shell.FOIShellView)
2172 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2174 COMDLG32_SHFree(pidlCurrent);
2175 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2180 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2181 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2185 /* update READONLY check box flag */
2186 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2187 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2189 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2191 /* Attach the file extension with file name*/
2192 ext = PathFindExtensionW(lpstrPathAndFile);
2195 /* if no extension is specified with file name, then */
2196 /* attach the extension from file filter or default one */
2198 WCHAR *filterExt = NULL;
2199 LPWSTR lpstrFilter = NULL;
2200 static const WCHAR szwDot[] = {'.',0};
2201 int PathLength = lstrlenW(lpstrPathAndFile);
2204 lstrcatW(lpstrPathAndFile, szwDot);
2206 /*Get the file extension from file type filter*/
2207 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2208 fodInfos->ofnInfos->nFilterIndex-1);
2210 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2211 filterExt = PathFindExtensionW(lpstrFilter);
2213 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2214 lstrcatW(lpstrPathAndFile, filterExt + 1);
2215 else if ( fodInfos->defext ) /* attach the default file extension*/
2216 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2218 /* In Open dialog: if file does not exist try without extension */
2219 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2220 lpstrPathAndFile[PathLength] = '\0';
2223 if (fodInfos->defext) /* add default extension */
2225 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2228 if (!lstrcmpiW(fodInfos->defext, ext))
2229 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2231 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2234 /* In Save dialog: check if the file already exists */
2235 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2236 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2237 && PathFileExistsW(lpstrPathAndFile))
2239 WCHAR lpstrOverwrite[100];
2242 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2243 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2244 MB_YESNO | MB_ICONEXCLAMATION);
2252 /* In Open dialog: check if it should be created if it doesn't exist */
2253 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2254 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2255 && !PathFileExistsW(lpstrPathAndFile))
2257 WCHAR lpstrCreate[100];
2260 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2261 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2262 MB_YESNO | MB_ICONEXCLAMATION);
2270 /* Check that the size of the file does not exceed buffer size.
2271 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2272 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2273 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2276 /* fill destination buffer */
2277 if (fodInfos->ofnInfos->lpstrFile)
2279 if(fodInfos->unicode)
2281 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2283 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2284 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2285 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2289 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2291 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2292 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2293 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2294 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2298 if(fodInfos->unicode)
2302 /* set filename offset */
2303 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2304 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2306 /* set extension offset */
2307 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2308 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2313 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2315 /* set filename offset */
2316 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2317 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2319 /* set extension offset */
2320 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2321 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2324 /* set the lpstrFileTitle */
2325 if(fodInfos->ofnInfos->lpstrFileTitle)
2327 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2328 if(fodInfos->unicode)
2330 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2331 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2335 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2336 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2337 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2341 /* copy currently selected filter to lpstrCustomFilter */
2342 if (fodInfos->ofnInfos->lpstrCustomFilter)
2344 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2345 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2346 NULL, 0, NULL, NULL);
2347 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2349 LPSTR s = ofn->lpstrCustomFilter;
2350 s += strlen(ofn->lpstrCustomFilter)+1;
2351 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2352 s, len, NULL, NULL);
2357 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2361 FILEDLG95_Clean(hwnd);
2362 ret = EndDialog(hwnd, TRUE);
2368 size = lstrlenW(lpstrPathAndFile) + 1;
2369 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2371 /* return needed size in first two bytes of lpstrFile */
2372 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2373 FILEDLG95_Clean(hwnd);
2374 ret = EndDialog(hwnd, FALSE);
2375 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2382 if(lpsf) IShellFolder_Release(lpsf);
2386 /***********************************************************************
2387 * FILEDLG95_SHELL_Init
2389 * Initialisation of the shell objects
2391 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2393 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2398 * Initialisation of the FileOpenDialogInfos structure
2404 fodInfos->ShellInfos.hwndOwner = hwnd;
2406 /* Disable multi-select if flag not set */
2407 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2409 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2411 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2412 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2414 /* Construct the IShellBrowser interface */
2415 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2420 /***********************************************************************
2421 * FILEDLG95_SHELL_ExecuteCommand
2423 * Change the folder option and refresh the view
2424 * If the function succeeds, the return value is nonzero.
2426 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2428 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2431 TRACE("(%p,%p)\n", hwnd, lpVerb);
2433 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2438 CMINVOKECOMMANDINFO ci;
2439 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2440 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2444 IContextMenu_InvokeCommand(pcm, &ci);
2445 IContextMenu_Release(pcm);
2451 /***********************************************************************
2452 * FILEDLG95_SHELL_UpFolder
2454 * Browse to the specified object
2455 * If the function succeeds, the return value is nonzero.
2457 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2459 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2463 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2467 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2468 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2474 /***********************************************************************
2475 * FILEDLG95_SHELL_BrowseToDesktop
2477 * Browse to the Desktop
2478 * If the function succeeds, the return value is nonzero.
2480 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2482 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2488 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2489 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2490 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2491 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2492 COMDLG32_SHFree(pidl);
2493 return SUCCEEDED(hres);
2495 /***********************************************************************
2496 * FILEDLG95_SHELL_Clean
2498 * Cleans the memory used by shell objects
2500 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2502 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2506 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2508 /* clean Shell interfaces */
2509 if (fodInfos->Shell.FOIShellView)
2511 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2512 IShellView_Release(fodInfos->Shell.FOIShellView);
2514 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2515 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2516 if (fodInfos->Shell.FOIDataObject)
2517 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2520 /***********************************************************************
2521 * FILEDLG95_FILETYPE_Init
2523 * Initialisation of the file type combo box
2525 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2527 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2528 int nFilters = 0; /* number of filters */
2533 if(fodInfos->customfilter)
2535 /* customfilter has one entry... title\0ext\0
2536 * Set first entry of combo box item with customfilter
2539 LPCWSTR lpstrPos = fodInfos->customfilter;
2542 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2544 /* Copy the extensions */
2545 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2546 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2547 lstrcpyW(lpstrExt,lpstrPos);
2549 /* Add the item at the end of the combo */
2550 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2551 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2554 if(fodInfos->filter)
2556 LPCWSTR lpstrPos = fodInfos->filter;
2560 /* filter is a list... title\0ext\0......\0\0
2561 * Set the combo item text to the title and the item data
2564 LPCWSTR lpstrDisplay;
2568 if(! *lpstrPos) break; /* end */
2569 lpstrDisplay = lpstrPos;
2570 lpstrPos += lstrlenW(lpstrPos) + 1;
2572 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2576 /* Copy the extensions */
2577 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2578 lstrcpyW(lpstrExt,lpstrPos);
2579 lpstrPos += lstrlenW(lpstrPos) + 1;
2581 /* Add the item at the end of the combo */
2582 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2584 /* malformed filters are added anyway... */
2585 if (!*lpstrExt) break;
2590 * Set the current filter to the one specified
2591 * in the initialisation structure
2593 if (fodInfos->filter || fodInfos->customfilter)
2597 /* Check to make sure our index isn't out of bounds. */
2598 if ( fodInfos->ofnInfos->nFilterIndex >
2599 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2600 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2602 /* set default filter index */
2603 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2604 fodInfos->ofnInfos->nFilterIndex = 1;
2606 /* calculate index of Combo Box item */
2607 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2608 if (fodInfos->customfilter == NULL)
2611 /* Set the current index selection. */
2612 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2614 /* Get the corresponding text string from the combo box. */
2615 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2618 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2624 CharLowerW(lpstrFilter); /* lowercase */
2625 len = lstrlenW(lpstrFilter)+1;
2626 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2627 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2630 fodInfos->ofnInfos->nFilterIndex = 0;
2634 /***********************************************************************
2635 * FILEDLG95_FILETYPE_OnCommand
2637 * WM_COMMAND of the file type combo box
2638 * If the function succeeds, the return value is nonzero.
2640 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2642 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2650 /* Get the current item of the filetype combo box */
2651 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2653 /* set the current filter index */
2654 fodInfos->ofnInfos->nFilterIndex = iItem +
2655 (fodInfos->customfilter == NULL ? 1 : 0);
2657 /* Set the current filter with the current selection */
2658 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2660 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2662 if((INT_PTR)lpstrFilter != CB_ERR)
2665 CharLowerW(lpstrFilter); /* lowercase */
2666 len = lstrlenW(lpstrFilter)+1;
2667 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2668 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2669 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2670 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2673 /* Refresh the actual view to display the included items*/
2674 if (fodInfos->Shell.FOIShellView)
2675 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2680 /***********************************************************************
2681 * FILEDLG95_FILETYPE_SearchExt
2683 * searches for an extension in the filetype box
2685 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2687 int i, iCount = CBGetCount(hwnd);
2689 TRACE("%s\n", debugstr_w(lpstrExt));
2691 if(iCount != CB_ERR)
2693 for(i=0;i<iCount;i++)
2695 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2702 /***********************************************************************
2703 * FILEDLG95_FILETYPE_Clean
2705 * Clean the memory used by the filetype combo box
2707 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2709 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2711 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2715 /* Delete each string of the combo and their associated data */
2716 if(iCount != CB_ERR)
2718 for(iPos = iCount-1;iPos>=0;iPos--)
2720 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2721 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2724 /* Current filter */
2725 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2729 /***********************************************************************
2730 * FILEDLG95_LOOKIN_Init
2732 * Initialisation of the look in combo box
2735 /* Small helper function, to determine if the unixfs shell extension is rooted
2736 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2738 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2740 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2741 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2742 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2743 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2744 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2745 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2746 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2748 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2755 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2757 IShellFolder *psfRoot, *psfDrives;
2758 IEnumIDList *lpeRoot, *lpeDrives;
2759 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2761 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2765 liInfos->iMaxIndentation = 0;
2767 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2769 /* set item height for both text field and listbox */
2770 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2771 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2773 /* Turn on the extended UI for the combo box like Windows does */
2774 CBSetExtendedUI(hwndCombo, TRUE);
2776 /* Initialise data of Desktop folder */
2777 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2778 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2779 COMDLG32_SHFree(pidlTmp);
2781 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2783 SHGetDesktopFolder(&psfRoot);
2787 /* enumerate the contents of the desktop */
2788 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2790 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2792 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2794 /* If the unixfs extension is rooted, we don't expand the drives by default */
2795 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2797 /* special handling for CSIDL_DRIVES */
2798 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2800 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2802 /* enumerate the drives */
2803 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2805 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2807 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2808 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2809 COMDLG32_SHFree(pidlAbsTmp);
2810 COMDLG32_SHFree(pidlTmp1);
2812 IEnumIDList_Release(lpeDrives);
2814 IShellFolder_Release(psfDrives);
2819 COMDLG32_SHFree(pidlTmp);
2821 IEnumIDList_Release(lpeRoot);
2823 IShellFolder_Release(psfRoot);
2826 COMDLG32_SHFree(pidlDrives);
2829 /***********************************************************************
2830 * FILEDLG95_LOOKIN_DrawItem
2832 * WM_DRAWITEM message handler
2834 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2836 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2837 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2838 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2842 HIMAGELIST ilItemImage;
2845 LPSFOLDER tmpFolder;
2846 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2850 if(pDIStruct->itemID == -1)
2853 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2854 pDIStruct->itemID)))
2858 if(pDIStruct->itemID == liInfos->uSelectedItem)
2860 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2864 SHGFI_PIDL | SHGFI_SMALLICON |
2865 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2866 SHGFI_DISPLAYNAME );
2870 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2874 SHGFI_PIDL | SHGFI_SMALLICON |
2875 SHGFI_SYSICONINDEX |
2879 /* Is this item selected ? */
2880 if(pDIStruct->itemState & ODS_SELECTED)
2882 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2883 SetBkColor(pDIStruct->hDC,crHighLight);
2884 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2888 SetTextColor(pDIStruct->hDC,crText);
2889 SetBkColor(pDIStruct->hDC,crWin);
2890 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2893 /* Do not indent item if drawing in the edit of the combo */
2894 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2897 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2901 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2902 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2907 iIndentation = tmpFolder->m_iIndent;
2909 /* Draw text and icon */
2911 /* Initialise the icon display area */
2912 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2913 rectIcon.top = pDIStruct->rcItem.top;
2914 rectIcon.right = rectIcon.left + ICONWIDTH;
2915 rectIcon.bottom = pDIStruct->rcItem.bottom;
2917 /* Initialise the text display area */
2918 GetTextMetricsW(pDIStruct->hDC, &tm);
2919 rectText.left = rectIcon.right;
2921 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2922 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2924 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2926 /* Draw the icon from the image list */
2927 ImageList_Draw(ilItemImage,
2934 /* Draw the associated text */
2935 if(sfi.szDisplayName)
2936 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2942 /***********************************************************************
2943 * FILEDLG95_LOOKIN_OnCommand
2945 * LookIn combo box WM_COMMAND message handler
2946 * If the function succeeds, the return value is nonzero.
2948 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2950 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2952 TRACE("%p\n", fodInfos);
2958 LPSFOLDER tmpFolder;
2961 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2963 if( iItem == CB_ERR) return FALSE;
2965 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2970 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2971 tmpFolder->pidlItem,
2974 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2975 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2985 /***********************************************************************
2986 * FILEDLG95_LOOKIN_AddItem
2988 * Adds an absolute pidl item to the lookin combo box
2989 * returns the index of the inserted item
2991 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2993 LPITEMIDLIST pidlNext;
2996 LookInInfos *liInfos;
2998 TRACE("%08x\n", iInsertId);
3003 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3006 tmpFolder = MemAlloc(sizeof(SFOLDER));
3007 tmpFolder->m_iIndent = 0;
3009 /* Calculate the indentation of the item in the lookin*/
3011 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3013 tmpFolder->m_iIndent++;
3016 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3018 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3019 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3021 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3022 SHGetFileInfoW((LPCWSTR)pidl,
3026 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3027 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3029 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3031 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3035 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3037 /* Add the item at the end of the list */
3040 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3042 /* Insert the item at the iInsertId position*/
3045 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3048 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3052 COMDLG32_SHFree( tmpFolder->pidlItem );
3053 MemFree( tmpFolder );
3058 /***********************************************************************
3059 * FILEDLG95_LOOKIN_InsertItemAfterParent
3061 * Insert an item below its parent
3063 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3066 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3071 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3075 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3078 /* Free pidlParent memory */
3079 COMDLG32_SHFree(pidlParent);
3081 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3084 /***********************************************************************
3085 * FILEDLG95_LOOKIN_SelectItem
3087 * Adds an absolute pidl item to the lookin combo box
3088 * returns the index of the inserted item
3090 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3093 LookInInfos *liInfos;
3097 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3099 liInfos = GetPropA(hwnd,LookInInfosStr);
3103 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3104 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3109 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3110 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3114 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3116 if(iRemovedItem < iItemPos)
3121 CBSetCurSel(hwnd,iItemPos);
3122 liInfos->uSelectedItem = iItemPos;
3128 /***********************************************************************
3129 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3131 * Remove the item with an expansion level over iExpansionLevel
3133 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3136 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3140 if(liInfos->iMaxIndentation <= 2)
3143 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3145 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3146 COMDLG32_SHFree(tmpFolder->pidlItem);
3148 CBDeleteString(hwnd,iItemPos);
3149 liInfos->iMaxIndentation--;
3157 /***********************************************************************
3158 * FILEDLG95_LOOKIN_SearchItem
3160 * Search for pidl in the lookin combo box
3161 * returns the index of the found item
3163 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3166 int iCount = CBGetCount(hwnd);
3168 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3170 if (iCount != CB_ERR)
3174 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3176 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3178 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3186 /***********************************************************************
3187 * FILEDLG95_LOOKIN_Clean
3189 * Clean the memory used by the lookin combo box
3191 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3193 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3195 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3199 /* Delete each string of the combo and their associated data */
3200 if (iCount != CB_ERR)
3202 for(iPos = iCount-1;iPos>=0;iPos--)
3204 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3205 COMDLG32_SHFree(tmpFolder->pidlItem);
3207 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3211 /* LookInInfos structure */
3212 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3215 /***********************************************************************
3216 * FILEDLG95_FILENAME_FillFromSelection
3218 * fills the edit box from the cached DataObject
3220 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3222 FileOpenDlgInfos *fodInfos;
3224 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3225 WCHAR lpstrTemp[MAX_PATH];
3226 LPWSTR lpstrAllFile, lpstrCurrFile;
3229 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3231 /* Count how many files we have */
3232 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3234 /* calculate the string length, count files */
3235 if (nFileSelected >= 1)
3237 nLength += 3; /* first and last quotes, trailing \0 */
3238 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3240 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3244 /* get the total length of the selected file names */
3245 lpstrTemp[0] = '\0';
3246 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3248 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3250 nLength += lstrlenW( lpstrTemp ) + 3;
3253 COMDLG32_SHFree( pidl );
3258 /* allocate the buffer */
3259 if (nFiles <= 1) nLength = MAX_PATH;
3260 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3262 /* Generate the string for the edit control */
3265 lpstrCurrFile = lpstrAllFile;
3266 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3268 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3272 /* get the file name */
3273 lpstrTemp[0] = '\0';
3274 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3276 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3280 *lpstrCurrFile++ = '\"';
3281 lstrcpyW( lpstrCurrFile, lpstrTemp );
3282 lpstrCurrFile += lstrlenW( lpstrTemp );
3283 *lpstrCurrFile++ = '\"';
3284 *lpstrCurrFile++ = ' ';
3289 lstrcpyW( lpstrAllFile, lpstrTemp );
3292 COMDLG32_SHFree( pidl );
3295 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3297 /* Select the file name like Windows does */
3298 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3300 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3304 /* copied from shell32 to avoid linking to it
3305 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3306 * is dependent on whether emulated OS is unicode or not.
3308 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3313 lstrcpynW(dest, src->u.pOleStr, len);
3314 COMDLG32_SHFree(src->u.pOleStr);
3318 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3323 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3328 FIXME("unknown type %x!\n", src->uType);
3329 if (len) *dest = '\0';
3335 /***********************************************************************
3336 * FILEDLG95_FILENAME_GetFileNames
3338 * Copies the filenames to a delimited string list.
3339 * The delimiter is specified by the parameter 'separator',
3340 * usually either a space or a nul
3342 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3344 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3345 UINT nStrCharCount = 0; /* index in src buffer */
3346 UINT nFileIndex = 0; /* index in dest buffer */
3347 UINT nFileCount = 0; /* number of files */
3348 UINT nStrLen = 0; /* length of string in edit control */
3349 LPWSTR lpstrEdit; /* buffer for string from edit control */
3353 /* get the filenames from the edit control */
3354 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3355 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3356 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3358 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3360 /* we might get single filename without any '"',
3361 * so we need nStrLen + terminating \0 + end-of-list \0 */
3362 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3365 /* build delimited file list from filenames */
3366 while ( nStrCharCount <= nStrLen )
3368 if ( lpstrEdit[nStrCharCount]=='"' )
3371 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3373 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3376 (*lpstrFileList)[nFileIndex++] = 0;
3382 /* single, unquoted string */
3383 if ((nStrLen > 0) && (nFileIndex == 0) )
3385 lstrcpyW(*lpstrFileList, lpstrEdit);
3386 nFileIndex = lstrlenW(lpstrEdit) + 1;
3391 (*lpstrFileList)[nFileIndex++] = '\0';
3393 *sizeUsed = nFileIndex;
3398 #define SETDefFormatEtc(fe,cf,med) \
3400 (fe).cfFormat = cf;\
3401 (fe).dwAspect = DVASPECT_CONTENT; \
3408 * DATAOBJECT Helper functions
3411 /***********************************************************************
3412 * COMCTL32_ReleaseStgMedium
3414 * like ReleaseStgMedium from ole32
3416 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3418 if(medium.pUnkForRelease)
3420 IUnknown_Release(medium.pUnkForRelease);
3424 GlobalUnlock(medium.u.hGlobal);
3425 GlobalFree(medium.u.hGlobal);
3429 /***********************************************************************
3430 * GetPidlFromDataObject
3432 * Return pidl(s) by number from the cached DataObject
3434 * nPidlIndex=0 gets the fully qualified root path
3436 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3440 FORMATETC formatetc;
3441 LPITEMIDLIST pidl = NULL;
3443 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3448 /* Set the FORMATETC structure*/
3449 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3451 /* Get the pidls from IDataObject */
3452 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3454 LPIDA cida = GlobalLock(medium.u.hGlobal);
3455 if(nPidlIndex <= cida->cidl)
3457 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3459 COMCTL32_ReleaseStgMedium(medium);
3464 /***********************************************************************
3467 * Return the number of selected items in the DataObject.
3470 static UINT GetNumSelected( IDataObject *doSelected )
3474 FORMATETC formatetc;
3476 TRACE("sv=%p\n", doSelected);
3478 if (!doSelected) return 0;
3480 /* Set the FORMATETC structure*/
3481 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3483 /* Get the pidls from IDataObject */
3484 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3486 LPIDA cida = GlobalLock(medium.u.hGlobal);
3487 retVal = cida->cidl;
3488 COMCTL32_ReleaseStgMedium(medium);
3498 /***********************************************************************
3501 * Get the pidl's display name (relative to folder) and
3502 * put it in lpstrFileName.
3504 * Return NOERROR on success,
3508 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3513 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3517 SHGetDesktopFolder(&lpsf);
3518 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3519 IShellFolder_Release(lpsf);
3523 /* Get the display name of the pidl relative to the folder */
3524 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3526 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3531 /***********************************************************************
3532 * GetShellFolderFromPidl
3534 * pidlRel is the item pidl relative
3535 * Return the IShellFolder of the absolute pidl
3537 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3539 IShellFolder *psf = NULL,*psfParent;
3541 TRACE("%p\n", pidlAbs);
3543 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3546 if(pidlAbs && pidlAbs->mkid.cb)
3548 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3550 IShellFolder_Release(psfParent);
3554 /* return the desktop */
3560 /***********************************************************************
3563 * Return the LPITEMIDLIST to the parent of the pidl in the list
3565 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3567 LPITEMIDLIST pidlParent;
3569 TRACE("%p\n", pidl);
3571 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3572 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3577 /***********************************************************************
3580 * returns the pidl of the file name relative to folder
3581 * NULL if an error occurred
3583 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3585 LPITEMIDLIST pidl = NULL;
3588 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3590 if(!lpcstrFileName) return NULL;
3591 if(!*lpcstrFileName) return NULL;
3595 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3596 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3597 IShellFolder_Release(lpsf);
3602 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3609 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3611 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3614 TRACE("%p, %p\n", psf, pidl);
3616 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3618 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3619 /* see documentation shell 4.1*/
3620 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3623 /***********************************************************************
3624 * BrowseSelectedFolder
3626 static BOOL BrowseSelectedFolder(HWND hwnd)
3628 BOOL bBrowseSelFolder = FALSE;
3629 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3633 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3635 LPITEMIDLIST pidlSelection;
3637 /* get the file selected */
3638 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3639 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3641 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3642 pidlSelection, SBSP_RELATIVE ) ) )
3644 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3645 ' ','n','o','t',' ','e','x','i','s','t',0};
3646 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3648 bBrowseSelFolder = TRUE;
3649 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3650 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3652 COMDLG32_SHFree( pidlSelection );
3655 return bBrowseSelFolder;
3659 * Memory allocation methods */
3660 static void *MemAlloc(UINT size)
3662 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3665 static void MemFree(void *mem)
3667 HeapFree(GetProcessHeap(),0,mem);
3671 * Old-style (win3.1) dialogs */
3673 /***********************************************************************
3674 * FD32_GetTemplate [internal]
3676 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3677 * by a 32 bits application
3680 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3682 LPOPENFILENAMEW ofnW = lfs->ofnW;
3683 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3686 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3688 if (!(lfs->template = LockResource( ofnW->hInstance )))
3690 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3694 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3698 hResInfo = FindResourceA(priv->ofnA->hInstance,
3699 priv->ofnA->lpTemplateName,
3702 hResInfo = FindResourceW(ofnW->hInstance,
3703 ofnW->lpTemplateName,
3707 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3710 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3712 !(lfs->template = LockResource(hDlgTmpl)))
3714 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3717 } else { /* get it from internal Wine resource */
3719 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3720 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3722 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3725 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3726 !(lfs->template = LockResource( hDlgTmpl )))
3728 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3736 /************************************************************************
3737 * FD32_Init [internal]
3738 * called from the common 16/32 code to initialize 32 bit data
3740 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3742 BOOL IsUnicode = (BOOL) data;
3745 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3746 lfs->private1632 = priv;
3747 if (NULL == lfs->private1632) return FALSE;
3750 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3751 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3752 if (lfs->ofnW->lpfnHook)
3757 priv->ofnA = (LPOPENFILENAMEA) lParam;
3758 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3759 if (priv->ofnA->lpfnHook)
3761 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3762 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3765 if (! FD32_GetTemplate(lfs)) return FALSE;
3770 /***********************************************************************
3771 * FD32_CallWindowProc [internal]
3773 * called from the common 16/32 code to call the appropriate hook
3775 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3779 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3783 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3784 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3785 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3786 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3787 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3791 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3792 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3793 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3794 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3795 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3799 /***********************************************************************
3800 * FD32_UpdateResult [internal]
3801 * update the real client structures if any
3803 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3805 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3806 LPOPENFILENAMEW ofnW = lfs->ofnW;
3811 if (ofnW->nMaxFile &&
3812 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3813 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3814 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3816 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3817 /* set filename offset */
3818 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3819 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3821 /* set extension offset */
3822 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3823 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3827 /***********************************************************************
3828 * FD32_UpdateFileTitle [internal]
3829 * update the real client structures if any
3831 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3833 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3834 LPOPENFILENAMEW ofnW = lfs->ofnW;
3838 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3839 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3840 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3845 /***********************************************************************
3846 * FD32_SendLbGetCurSel [internal]
3847 * retrieve selected listbox item
3849 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3851 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3855 /************************************************************************
3856 * FD32_Destroy [internal]
3857 * called from the common 16/32 code to cleanup 32 bit data
3859 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3861 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3863 /* if ofnW has been allocated, have to free everything in it */
3864 if (NULL != priv && NULL != priv->ofnA)
3866 FD31_FreeOfnW(lfs->ofnW);
3867 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3871 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3873 callbacks->Init = FD32_Init;
3874 callbacks->CWP = FD32_CallWindowProc;
3875 callbacks->UpdateResult = FD32_UpdateResult;
3876 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3877 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3878 callbacks->Destroy = FD32_Destroy;
3881 /***********************************************************************
3882 * FD32_WMMeasureItem [internal]
3884 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3886 LPMEASUREITEMSTRUCT lpmeasure;
3888 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3889 lpmeasure->itemHeight = FD31_GetFldrHeight();
3894 /***********************************************************************
3895 * FileOpenDlgProc [internal]
3896 * Used for open and save, in fact.
3898 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3899 WPARAM wParam, LPARAM lParam)
3901 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3903 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3904 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3907 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3909 return lRet; /* else continue message processing */
3914 return FD31_WMInitDialog(hWnd, wParam, lParam);
3916 case WM_MEASUREITEM:
3917 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3920 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3923 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3926 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3927 switch (HIWORD(lParam))
3930 SetTextColor((HDC16)wParam, 0x00000000);
3932 case CTLCOLOR_STATIC:
3933 SetTextColor((HDC16)wParam, 0x00000000);
3943 /***********************************************************************
3944 * GetFileName31A [internal]
3946 * Creates a win31 style dialog box for the user to select a file to open/save.
3948 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3949 UINT dlgType /* type dialogue : open/save */
3955 FD31_CALLBACKS callbacks;
3957 if (!lpofn || !FD31_Init()) return FALSE;
3959 TRACE("ofn flags %08x\n", lpofn->Flags);
3960 FD32_SetupCallbacks(&callbacks);
3961 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3964 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3965 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3966 FD32_FileOpenDlgProc, (LPARAM)lfs);
3967 FD31_DestroyPrivate(lfs);
3970 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3974 /***********************************************************************
3975 * GetFileName31W [internal]
3977 * Creates a win31 style dialog box for the user to select a file to open/save
3979 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3980 UINT dlgType /* type dialogue : open/save */
3986 FD31_CALLBACKS callbacks;
3988 if (!lpofn || !FD31_Init()) return FALSE;
3990 FD32_SetupCallbacks(&callbacks);
3991 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3994 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3995 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3996 FD32_FileOpenDlgProc, (LPARAM)lfs);
3997 FD31_DestroyPrivate(lfs);
4000 TRACE("file %s, file offset %d, ext offset %d\n",
4001 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4005 /* ------------------ APIs ---------------------- */
4007 /***********************************************************************
4008 * GetOpenFileNameA (COMDLG32.@)
4010 * Creates a dialog box for the user to select a file to open.
4013 * TRUE on success: user enters a valid file
4014 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4017 BOOL WINAPI GetOpenFileNameA(
4018 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4020 BOOL win16look = FALSE;
4022 TRACE("flags %08x\n", ofn->Flags);
4024 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4025 if (ofn->Flags & OFN_FILEMUSTEXIST)
4026 ofn->Flags |= OFN_PATHMUSTEXIST;
4028 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4029 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4032 return GetFileName31A(ofn, OPEN_DIALOG);
4034 return GetFileDialog95A(ofn, OPEN_DIALOG);
4037 /***********************************************************************
4038 * GetOpenFileNameW (COMDLG32.@)
4040 * Creates a dialog box for the user to select a file to open.
4043 * TRUE on success: user enters a valid file
4044 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4047 BOOL WINAPI GetOpenFileNameW(
4048 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4050 BOOL win16look = FALSE;
4052 TRACE("flags %08x\n", ofn->Flags);
4054 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4055 if (ofn->Flags & OFN_FILEMUSTEXIST)
4056 ofn->Flags |= OFN_PATHMUSTEXIST;
4058 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4059 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4062 return GetFileName31W(ofn, OPEN_DIALOG);
4064 return GetFileDialog95W(ofn, OPEN_DIALOG);
4068 /***********************************************************************
4069 * GetSaveFileNameA (COMDLG32.@)
4071 * Creates a dialog box for the user to select a file to save.
4074 * TRUE on success: user enters a valid file
4075 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4078 BOOL WINAPI GetSaveFileNameA(
4079 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4081 BOOL win16look = FALSE;
4083 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4084 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4087 return GetFileName31A(ofn, SAVE_DIALOG);
4089 return GetFileDialog95A(ofn, SAVE_DIALOG);
4092 /***********************************************************************
4093 * GetSaveFileNameW (COMDLG32.@)
4095 * Creates a dialog box for the user to select a file to save.
4098 * TRUE on success: user enters a valid file
4099 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4102 BOOL WINAPI GetSaveFileNameW(
4103 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4105 BOOL win16look = FALSE;
4107 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4108 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4111 return GetFileName31W(ofn, SAVE_DIALOG);
4113 return GetFileDialog95W(ofn, SAVE_DIALOG);
4116 /***********************************************************************
4117 * GetFileTitleA (COMDLG32.@)
4119 * See GetFileTitleW.
4121 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4124 UNICODE_STRING strWFile;
4127 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4128 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4129 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4130 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4131 RtlFreeUnicodeString( &strWFile );
4132 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4137 /***********************************************************************
4138 * GetFileTitleW (COMDLG32.@)
4140 * Get the name of a file.
4143 * lpFile [I] name and location of file
4144 * lpTitle [O] returned file name
4145 * cbBuf [I] buffer size of lpTitle
4149 * Failure: negative number.
4151 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4154 static const WCHAR brkpoint[] = {'*','[',']',0};
4155 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4157 if(lpFile == NULL || lpTitle == NULL)
4160 len = lstrlenW(lpFile);
4165 if(strpbrkW(lpFile, brkpoint))
4170 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4173 for(i = len; i >= 0; i--)
4175 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4185 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4187 len = lstrlenW(lpFile+i)+1;
4191 lstrcpyW(lpTitle, &lpFile[i]);