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 */
175 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
177 /***********************************************************************
181 /* Internal functions used by the dialog */
182 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186 static BOOL FILEDLG95_OnOpen(HWND hwnd);
187 static LRESULT FILEDLG95_InitControls(HWND hwnd);
188 static void FILEDLG95_Clean(HWND hwnd);
190 /* Functions used by the shell navigation */
191 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
200 /* Functions used by the filetype combo box */
201 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
202 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
204 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
206 /* Functions used by the Look In combo box */
207 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
208 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
209 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
210 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
211 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
212 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
213 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
214 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
215 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
217 /* Miscellaneous tool functions */
218 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
221 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
222 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
223 static UINT GetNumSelected( IDataObject *doSelected );
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size);
227 static void MemFree(void *mem);
229 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
253 /* test for missing functionality */
254 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 FIXME("Flags 0x%08x not yet implemented\n",
257 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
260 /* Create the dialog from a template */
262 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268 !(template = LockResource( hDlgTmpl )))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
274 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
276 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
277 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
278 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
281 /* old style hook messages */
282 if (IsHooked(fodInfos))
284 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
285 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
286 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
287 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
290 /* Some shell namespace extensions depend on COM being initialized. */
291 hr = OleInitialize(NULL);
293 if (fodInfos->unicode)
294 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
296 fodInfos->ofnInfos->hwndOwner,
300 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
302 fodInfos->ofnInfos->hwndOwner,
308 /* Unable to create the dialog */
315 /***********************************************************************
318 * Call GetFileName95 with this structure and clean the memory.
320 * IN : The OPENFILENAMEA initialisation structure passed to
321 * GetOpenFileNameA win api function (see filedlg.c)
323 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
326 FileOpenDlgInfos fodInfos;
327 LPSTR lpstrSavDir = NULL;
329 LPWSTR defext = NULL;
330 LPWSTR filter = NULL;
331 LPWSTR customfilter = NULL;
333 /* Initialize CommDlgExtendedError() */
334 COMDLG32_SetCommDlgExtendedError(0);
336 /* Initialize FileOpenDlgInfos structure */
337 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
339 /* Pass in the original ofn */
340 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
342 /* save current directory */
343 if (ofn->Flags & OFN_NOCHANGEDIR)
345 lpstrSavDir = MemAlloc(MAX_PATH);
346 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
349 fodInfos.unicode = FALSE;
351 /* convert all the input strings to unicode */
352 if(ofn->lpstrInitialDir)
354 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
355 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
359 fodInfos.initdir = NULL;
363 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
364 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
367 fodInfos.filename = NULL;
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
372 defext = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
375 fodInfos.defext = defext;
379 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
380 title = MemAlloc((len+1)*sizeof(WCHAR));
381 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
383 fodInfos.title = title;
385 if (ofn->lpstrFilter)
390 /* filter is a list... title\0ext\0......\0\0 */
391 s = ofn->lpstrFilter;
392 while (*s) s = s+strlen(s)+1;
394 n = s - ofn->lpstrFilter;
395 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
396 filter = MemAlloc(len*sizeof(WCHAR));
397 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
399 fodInfos.filter = filter;
401 /* convert lpstrCustomFilter */
402 if (ofn->lpstrCustomFilter)
407 /* customfilter contains a pair of strings... title\0ext\0 */
408 s = ofn->lpstrCustomFilter;
409 if (*s) s = s+strlen(s)+1;
410 if (*s) s = s+strlen(s)+1;
411 n = s - ofn->lpstrCustomFilter;
412 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
413 customfilter = MemAlloc(len*sizeof(WCHAR));
414 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
416 fodInfos.customfilter = customfilter;
418 /* Initialize the dialog property */
419 fodInfos.DlgInfos.dwDlgProp = 0;
420 fodInfos.DlgInfos.hwndCustomDlg = NULL;
425 ret = GetFileName95(&fodInfos);
428 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
429 ret = GetFileName95(&fodInfos);
437 SetCurrentDirectoryA(lpstrSavDir);
438 MemFree(lpstrSavDir);
444 MemFree(customfilter);
445 MemFree(fodInfos.initdir);
446 MemFree(fodInfos.filename);
448 TRACE("selected file: %s\n",ofn->lpstrFile);
453 /***********************************************************************
456 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
457 * Call GetFileName95 with this structure and clean the memory.
460 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
463 FileOpenDlgInfos fodInfos;
464 LPWSTR lpstrSavDir = NULL;
466 /* Initialize CommDlgExtendedError() */
467 COMDLG32_SetCommDlgExtendedError(0);
469 /* Initialize FileOpenDlgInfos structure */
470 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
472 /* Pass in the original ofn */
473 fodInfos.ofnInfos = ofn;
475 fodInfos.title = ofn->lpstrTitle;
476 fodInfos.defext = ofn->lpstrDefExt;
477 fodInfos.filter = ofn->lpstrFilter;
478 fodInfos.customfilter = ofn->lpstrCustomFilter;
480 /* convert string arguments, save others */
483 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
484 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
487 fodInfos.filename = NULL;
489 if(ofn->lpstrInitialDir)
491 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
492 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
493 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
494 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
497 fodInfos.initdir = NULL;
499 /* save current directory */
500 if (ofn->Flags & OFN_NOCHANGEDIR)
502 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
503 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
506 fodInfos.unicode = TRUE;
511 ret = GetFileName95(&fodInfos);
514 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
515 ret = GetFileName95(&fodInfos);
523 SetCurrentDirectoryW(lpstrSavDir);
524 MemFree(lpstrSavDir);
527 /* restore saved IN arguments and convert OUT arguments back */
528 MemFree(fodInfos.filename);
529 MemFree(fodInfos.initdir);
533 /******************************************************************************
534 * COMDLG32_GetDisplayNameOf [internal]
536 * Helper function to get the display name for a pidl.
538 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
539 LPSHELLFOLDER psfDesktop;
542 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
545 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
546 IShellFolder_Release(psfDesktop);
550 IShellFolder_Release(psfDesktop);
551 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
554 /***********************************************************************
555 * ArrangeCtrlPositions [internal]
557 * NOTE: Do not change anything here without a lot of testing.
559 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
561 HWND hwndChild, hwndStc32;
562 RECT rectParent, rectChild, rectStc32;
563 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
565 /* Take into account if open as read only checkbox and help button
570 RECT rectHelp, rectCancel;
571 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
572 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
573 /* subtract the height of the help button plus the space between
574 * the help button and the cancel button to the height of the dialog
576 help_fixup = rectHelp.bottom - rectCancel.bottom;
580 There are two possibilities to add components to the default file dialog box.
582 By default, all the new components are added below the standard dialog box (the else case).
584 However, if there is a static text component with the stc32 id, a special case happens.
585 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
586 in the window and the cx and cy indicate how to size the window.
587 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
588 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
592 GetClientRect(hwndParentDlg, &rectParent);
594 /* when arranging controls we have to use fixed parent size */
595 rectParent.bottom -= help_fixup;
597 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
600 GetWindowRect(hwndStc32, &rectStc32);
601 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
603 /* set the size of the stc32 control according to the size of
604 * client area of the parent dialog
606 SetWindowPos(hwndStc32, 0,
608 rectParent.right, rectParent.bottom,
609 SWP_NOMOVE | SWP_NOZORDER);
612 SetRectEmpty(&rectStc32);
614 /* this part moves controls of the child dialog */
615 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
618 if (hwndChild != hwndStc32)
620 GetWindowRect(hwndChild, &rectChild);
621 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
623 /* move only if stc32 exist */
624 if (hwndStc32 && rectChild.left > rectStc32.right)
626 LONG old_left = rectChild.left;
628 /* move to the right of visible controls of the parent dialog */
629 rectChild.left += rectParent.right;
630 rectChild.left -= rectStc32.right;
632 child_width_fixup = rectChild.left - old_left;
634 /* move even if stc32 doesn't exist */
635 if (rectChild.top >= rectStc32.bottom)
637 LONG old_top = rectChild.top;
639 /* move below visible controls of the parent dialog */
640 rectChild.top += rectParent.bottom;
641 rectChild.top -= rectStc32.bottom - rectStc32.top;
643 child_height_fixup = rectChild.top - old_top;
646 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
647 0, 0, SWP_NOSIZE | SWP_NOZORDER);
649 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
652 /* this part moves controls of the parent dialog */
653 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
656 if (hwndChild != hwndChildDlg)
658 GetWindowRect(hwndChild, &rectChild);
659 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
661 /* left,top of stc32 marks the position of controls
662 * from the parent dialog
664 rectChild.left += rectStc32.left;
665 rectChild.top += rectStc32.top;
667 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
668 0, 0, SWP_NOSIZE | SWP_NOZORDER);
670 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
673 /* calculate the size of the resulting dialog */
675 /* here we have to use original parent size */
676 GetClientRect(hwndParentDlg, &rectParent);
677 GetClientRect(hwndChildDlg, &rectChild);
681 rectChild.right += child_width_fixup;
682 rectChild.bottom += child_height_fixup;
684 if (rectParent.right > rectChild.right)
686 rectParent.right += rectChild.right;
687 rectParent.right -= rectStc32.right - rectStc32.left;
691 rectParent.right = rectChild.right;
694 if (rectParent.bottom > rectChild.bottom)
696 rectParent.bottom += rectChild.bottom;
697 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
701 /* child dialog is higher, unconditionally set new dialog
702 * height to its size (help_fixup will be subtracted below)
704 rectParent.bottom = rectChild.bottom + help_fixup;
709 rectParent.bottom += rectChild.bottom;
712 /* finally use fixed parent size */
713 rectParent.bottom -= help_fixup;
715 /* set the size of the parent dialog */
716 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
717 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
718 SetWindowPos(hwndParentDlg, 0,
720 rectParent.right - rectParent.left,
721 rectParent.bottom - rectParent.top,
722 SWP_NOMOVE | SWP_NOZORDER);
725 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
734 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
744 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
745 * structure's hInstance parameter is not a HINSTANCE, but
746 * instead a pointer to a template resource to use.
748 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
751 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
753 hinst = COMDLG32_hInstance;
754 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
756 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
762 hinst = fodInfos->ofnInfos->hInstance;
763 if(fodInfos->unicode)
765 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
766 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
770 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
771 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
775 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
778 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
779 !(template = LockResource( hDlgTmpl )))
781 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
785 if (fodInfos->unicode)
786 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
787 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
788 (LPARAM)fodInfos->ofnInfos);
790 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
791 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
792 (LPARAM)fodInfos->ofnInfos);
795 else if( IsHooked(fodInfos))
800 WORD menu,class,title;
802 GetClientRect(hwnd,&rectHwnd);
803 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
804 temp.tmplate.dwExtendedStyle = 0;
805 temp.tmplate.cdit = 0;
810 temp.menu = temp.class = temp.title = 0;
812 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
813 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
820 /***********************************************************************
821 * SendCustomDlgNotificationMessage
823 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
826 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
828 LRESULT hook_result = 0;
829 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
831 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
833 if(!fodInfos) return 0;
835 if(fodInfos->DlgInfos.hwndCustomDlg)
837 TRACE("CALL NOTIFY for %x\n", uCode);
838 if(fodInfos->unicode)
841 ofnNotify.hdr.hwndFrom=hwndParentDlg;
842 ofnNotify.hdr.idFrom=0;
843 ofnNotify.hdr.code = uCode;
844 ofnNotify.lpOFN = fodInfos->ofnInfos;
845 ofnNotify.pszFile = NULL;
846 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
851 ofnNotify.hdr.hwndFrom=hwndParentDlg;
852 ofnNotify.hdr.idFrom=0;
853 ofnNotify.hdr.code = uCode;
854 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
855 ofnNotify.pszFile = NULL;
856 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
858 TRACE("RET NOTIFY\n");
860 TRACE("Retval: 0x%08lx\n", hook_result);
864 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
868 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
870 TRACE("CDM_GETFILEPATH:\n");
872 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
875 /* get path and filenames */
876 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
877 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
878 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
881 p = buffer + strlenW(buffer);
883 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
885 if (fodInfos->unicode)
887 total = strlenW( buffer) + 1;
888 if (result) lstrcpynW( result, buffer, size );
889 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
893 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
894 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
895 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
897 HeapFree( GetProcessHeap(), 0, buffer );
901 /***********************************************************************
902 * FILEDLG95_HandleCustomDialogMessages
904 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
906 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
908 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
909 WCHAR lpstrPath[MAX_PATH];
912 if(!fodInfos) return FALSE;
916 case CDM_GETFILEPATH:
917 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
920 case CDM_GETFOLDERPATH:
921 TRACE("CDM_GETFOLDERPATH:\n");
922 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
925 if (fodInfos->unicode)
926 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
928 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
929 (LPSTR)lParam, (int)wParam, NULL, NULL);
931 retval = lstrlenW(lpstrPath);
934 case CDM_GETFOLDERIDLIST:
935 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
936 if (retval <= wParam)
937 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
941 TRACE("CDM_GETSPEC:\n");
942 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
945 if (fodInfos->unicode)
946 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
948 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
952 case CDM_SETCONTROLTEXT:
953 TRACE("CDM_SETCONTROLTEXT:\n");
956 if( fodInfos->unicode )
957 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
959 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
964 case CDM_HIDECONTROL:
965 /* MSDN states that it should fail for not OFN_EXPLORER case */
966 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
968 HWND control = GetDlgItem( hwnd, wParam );
969 if (control) ShowWindow( control, SW_HIDE );
976 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
977 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
980 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
984 /***********************************************************************
985 * FILEDLG95_OnWMGetMMI
987 * WM_GETMINMAXINFO message handler for resizable dialogs
989 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
991 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
992 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
993 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
995 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1000 /***********************************************************************
1001 * FILEDLG95_OnWMSize
1003 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1005 * FIXME: this could be made more elaborate. Now use a simple scheme
1006 * where the file view is enlarged and the controls are either moved
1007 * vertically or horizontally to get out of the way. Only the "grip"
1008 * is moved in both directions to stay in the corner.
1010 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1016 FileOpenDlgInfos *fodInfos;
1018 if( wParam != SIZE_RESTORED) return FALSE;
1019 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1020 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1021 /* get the new dialog rectangle */
1022 GetWindowRect( hwnd, &rc);
1023 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1024 rc.right -rc.left, rc.bottom -rc.top);
1025 /* not initialized yet */
1026 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1027 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1028 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1030 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1031 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1032 fodInfos->sizedlg.cx = rc.right - rc.left;
1033 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1034 /* change the size of the view window */
1035 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1036 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1037 hdwp = BeginDeferWindowPos( 10);
1038 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1039 rcview.right - rcview.left + chgx,
1040 rcview.bottom - rcview.top + chgy,
1041 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1042 /* change position and sizes of the controls */
1043 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1045 int ctrlid = GetDlgCtrlID( ctrl);
1046 GetWindowRect( ctrl, &rc);
1047 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1048 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1050 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1052 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1054 else if( rc.top > rcview.bottom)
1056 /* if it was below the shell view
1060 /* file name box and file types combo change also width */
1063 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1064 rc.right - rc.left + chgx, rc.bottom - rc.top,
1065 SWP_NOACTIVATE | SWP_NOZORDER);
1067 /* then these buttons must move out of the way */
1071 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1073 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1076 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1078 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1081 else if( rc.left > rcview.right)
1083 /* if it was to the right of the shell view
1085 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1087 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1094 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1096 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1097 rc.right - rc.left + chgx, rc.bottom - rc.top,
1098 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1100 case IDC_TOOLBARSTATIC:
1102 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1104 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1107 /* not resized in windows. Since wine uses this invisible control
1108 * to size the browser view it needs to be resized */
1109 case IDC_SHELLSTATIC:
1110 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1111 rc.right - rc.left + chgx,
1112 rc.bottom - rc.top + chgy,
1113 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1118 if(fodInfos->DlgInfos.hwndCustomDlg &&
1119 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1121 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1122 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1124 GetWindowRect( ctrl, &rc);
1125 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1126 if( rc.top > rcview.bottom)
1128 /* if it was below the shell view
1130 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1131 rc.right - rc.left, rc.bottom - rc.top,
1132 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1134 else if( rc.left > rcview.right)
1136 /* if it was to the right of the shell view
1138 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1139 rc.right - rc.left, rc.bottom - rc.top,
1140 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1143 /* size the custom dialog at the end: some applications do some
1144 * control re-arranging at this point */
1145 GetClientRect(hwnd, &rc);
1146 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1147 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1149 EndDeferWindowPos( hdwp);
1150 /* should not be needed */
1151 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1155 /***********************************************************************
1158 * File open dialog procedure
1160 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1163 TRACE("%p 0x%04x\n", hwnd, uMsg);
1170 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1172 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1173 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1175 /* Adds the FileOpenDlgInfos in the property list of the dialog
1176 so it will be easily accessible through a GetPropA(...) */
1177 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1179 FILEDLG95_InitControls(hwnd);
1181 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1183 GetWindowRect( hwnd, &rc);
1184 fodInfos->DlgInfos.hwndGrip =
1185 CreateWindowExA( 0, "SCROLLBAR", NULL,
1186 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1187 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1188 rc.right - gripx, rc.bottom - gripy,
1189 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1192 fodInfos->DlgInfos.hwndCustomDlg =
1193 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1195 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1196 FILEDLG95_FillControls(hwnd, wParam, lParam);
1198 if( fodInfos->DlgInfos.hwndCustomDlg)
1199 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1201 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1202 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1203 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1206 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1208 GetWindowRect( hwnd, &rc);
1209 fodInfos->sizedlg.cx = rc.right - rc.left;
1210 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1211 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1212 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1213 GetClientRect( hwnd, &rc);
1214 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1215 rc.right - gripx, rc.bottom - gripy,
1216 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1217 /* resize the dialog to the previous invocation */
1218 if( MemDialogSize.cx && MemDialogSize.cy)
1219 SetWindowPos( hwnd, NULL,
1220 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1221 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1224 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1225 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1230 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1231 case WM_GETMINMAXINFO:
1232 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1234 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1237 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1240 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1246 case WM_GETISHELLBROWSER:
1247 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1251 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1252 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1253 MemDialogSize = fodInfos->sizedlg;
1254 RemovePropA(hwnd, FileOpenDlgInfosStr);
1259 LPNMHDR lpnmh = (LPNMHDR)lParam;
1262 /* set up the button tooltips strings */
1263 if(TTN_GETDISPINFOA == lpnmh->code )
1265 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1266 switch(lpnmh->idFrom )
1268 /* Up folder button */
1269 case FCIDM_TB_UPFOLDER:
1270 stringId = IDS_UPFOLDER;
1272 /* New folder button */
1273 case FCIDM_TB_NEWFOLDER:
1274 stringId = IDS_NEWFOLDER;
1276 /* List option button */
1277 case FCIDM_TB_SMALLICON:
1278 stringId = IDS_LISTVIEW;
1280 /* Details option button */
1281 case FCIDM_TB_REPORTVIEW:
1282 stringId = IDS_REPORTVIEW;
1284 /* Desktop button */
1285 case FCIDM_TB_DESKTOP:
1286 stringId = IDS_TODESKTOP;
1291 lpdi->hinst = COMDLG32_hInstance;
1292 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1297 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1298 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1303 /***********************************************************************
1304 * FILEDLG95_InitControls
1306 * WM_INITDIALOG message handler (before hook notification)
1308 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1310 int win2000plus = 0;
1312 int handledPath = FALSE;
1313 OSVERSIONINFOW osVi;
1314 static const WCHAR szwSlash[] = { '\\', 0 };
1315 static const WCHAR szwStar[] = { '*',0 };
1317 static const TBBUTTON tbb[] =
1319 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1320 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1321 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1322 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1323 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1324 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1325 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1326 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1327 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1332 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1334 tba[0].hInst = HINST_COMMCTRL;
1335 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1336 tba[1].hInst = COMDLG32_hInstance;
1339 TRACE("%p\n", fodInfos);
1341 /* Get windows version emulating */
1342 osVi.dwOSVersionInfoSize = sizeof(osVi);
1343 GetVersionExW(&osVi);
1344 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1345 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1346 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1347 win2000plus = (osVi.dwMajorVersion > 4);
1348 if (win2000plus) win98plus = TRUE;
1350 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1352 /* Get the hwnd of the controls */
1353 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1354 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1355 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1357 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1358 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1360 /* construct the toolbar */
1361 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1362 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1364 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1365 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1366 rectTB.left = rectlook.right;
1367 rectTB.top = rectlook.top-1;
1369 if (fodInfos->unicode)
1370 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1371 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1372 rectTB.left, rectTB.top,
1373 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1374 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1376 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1377 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1378 rectTB.left, rectTB.top,
1379 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1380 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1382 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1384 /* FIXME: use TB_LOADIMAGES when implemented */
1385 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1386 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1387 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1389 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1390 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1392 /* Set the window text with the text specified in the OPENFILENAME structure */
1395 SetWindowTextW(hwnd,fodInfos->title);
1397 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1400 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1401 SetWindowTextW(hwnd, buf);
1404 /* Initialise the file name edit control */
1405 handledPath = FALSE;
1406 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1408 if(fodInfos->filename)
1410 /* 1. If win2000 or higher and filename contains a path, use it
1411 in preference over the lpstrInitialDir */
1412 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1413 WCHAR tmpBuf[MAX_PATH];
1417 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1420 /* nameBit is always shorter than the original filename */
1421 lstrcpyW(fodInfos->filename,nameBit);
1424 if (fodInfos->initdir == NULL)
1425 MemFree(fodInfos->initdir);
1426 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1427 lstrcpyW(fodInfos->initdir, tmpBuf);
1429 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1430 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1432 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1435 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1439 /* 2. (All platforms) If initdir is not null, then use it */
1440 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1441 (*fodInfos->initdir!=0x00))
1443 /* Work out the proper path as supplied one might be relative */
1444 /* (Here because supplying '.' as dir browses to My Computer) */
1445 if (handledPath==FALSE) {
1446 WCHAR tmpBuf[MAX_PATH];
1447 WCHAR tmpBuf2[MAX_PATH];
1451 lstrcpyW(tmpBuf, fodInfos->initdir);
1452 if( PathFileExistsW(tmpBuf) ) {
1453 /* initdir does not have to be a directory. If a file is
1454 * specified, the dir part is taken */
1455 if( PathIsDirectoryW(tmpBuf)) {
1456 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1457 lstrcatW(tmpBuf, szwSlash);
1459 lstrcatW(tmpBuf, szwStar);
1461 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1464 MemFree(fodInfos->initdir);
1465 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1466 lstrcpyW(fodInfos->initdir, tmpBuf2);
1468 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1471 else if (fodInfos->initdir)
1473 MemFree(fodInfos->initdir);
1474 fodInfos->initdir = NULL;
1475 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1480 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1481 (*fodInfos->initdir==0x00)))
1483 /* 3. All except w2k+: if filename contains a path use it */
1484 if (!win2000plus && fodInfos->filename &&
1485 *fodInfos->filename &&
1486 strpbrkW(fodInfos->filename, szwSlash)) {
1487 WCHAR tmpBuf[MAX_PATH];
1491 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1496 /* nameBit is always shorter than the original filename */
1497 lstrcpyW(fodInfos->filename, nameBit);
1500 len = lstrlenW(tmpBuf);
1501 MemFree(fodInfos->initdir);
1502 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1503 lstrcpyW(fodInfos->initdir, tmpBuf);
1506 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1507 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1509 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1512 /* 4. win98+ and win2000+ if any files of specified filter types in
1513 current directory, use it */
1514 if ( win98plus && handledPath == FALSE &&
1515 fodInfos->filter && *fodInfos->filter) {
1517 BOOL searchMore = TRUE;
1518 LPCWSTR lpstrPos = fodInfos->filter;
1519 WIN32_FIND_DATAW FindFileData;
1524 /* filter is a list... title\0ext\0......\0\0 */
1526 /* Skip the title */
1527 if(! *lpstrPos) break; /* end */
1528 lpstrPos += lstrlenW(lpstrPos) + 1;
1530 /* See if any files exist in the current dir with this extension */
1531 if(! *lpstrPos) break; /* end */
1533 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1535 if (hFind == INVALID_HANDLE_VALUE) {
1536 /* None found - continue search */
1537 lpstrPos += lstrlenW(lpstrPos) + 1;
1542 MemFree(fodInfos->initdir);
1543 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1544 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1547 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1548 debugstr_w(lpstrPos));
1554 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1556 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1557 if (handledPath == FALSE && (win2000plus || win98plus)) {
1558 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1560 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1562 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1565 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1566 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1568 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1571 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1574 } else if (handledPath==FALSE) {
1575 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1576 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1578 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1581 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1582 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1584 /* Must the open as read only check box be checked ?*/
1585 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1587 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1590 /* Must the open as read only check box be hidden? */
1591 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1593 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1594 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1597 /* Must the help button be hidden? */
1598 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1600 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1601 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1604 /* change Open to Save */
1605 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1608 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1609 SetDlgItemTextW(hwnd, IDOK, buf);
1610 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1611 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1614 /* Initialize the filter combo box */
1615 FILEDLG95_FILETYPE_Init(hwnd);
1620 /***********************************************************************
1621 * FILEDLG95_ResizeControls
1623 * WM_INITDIALOG message handler (after hook notification)
1625 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1627 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1629 if (fodInfos->DlgInfos.hwndCustomDlg)
1632 UINT flags = SWP_NOACTIVATE;
1634 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1635 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1637 /* resize the custom dialog to the parent size */
1638 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1639 GetClientRect(hwnd, &rc);
1642 /* our own fake template is zero sized and doesn't have children, so
1643 * there is no need to resize it. Picasa depends on it.
1645 flags |= SWP_NOSIZE;
1648 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1649 0, 0, rc.right, rc.bottom, flags);
1653 /* Resize the height, if open as read only checkbox ad help button are
1654 * hidden and we are not using a custom template nor a customDialog
1656 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1657 (!(fodInfos->ofnInfos->Flags &
1658 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1660 RECT rectDlg, rectHelp, rectCancel;
1661 GetWindowRect(hwnd, &rectDlg);
1662 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1663 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1664 /* subtract the height of the help button plus the space between the help
1665 * button and the cancel button to the height of the dialog
1667 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1668 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1669 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1675 /***********************************************************************
1676 * FILEDLG95_FillControls
1678 * WM_INITDIALOG message handler (after hook notification)
1680 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1682 LPITEMIDLIST pidlItemId = NULL;
1684 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1686 TRACE("dir=%s file=%s\n",
1687 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1689 /* Get the initial directory pidl */
1691 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1693 WCHAR path[MAX_PATH];
1695 GetCurrentDirectoryW(MAX_PATH,path);
1696 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1699 /* Initialise shell objects */
1700 FILEDLG95_SHELL_Init(hwnd);
1702 /* Initialize the Look In combo box */
1703 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1705 /* Browse to the initial directory */
1706 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1708 /* Free pidlItem memory */
1709 COMDLG32_SHFree(pidlItemId);
1713 /***********************************************************************
1716 * Regroups all the cleaning functions of the filedlg
1718 void FILEDLG95_Clean(HWND hwnd)
1720 FILEDLG95_FILETYPE_Clean(hwnd);
1721 FILEDLG95_LOOKIN_Clean(hwnd);
1722 FILEDLG95_SHELL_Clean(hwnd);
1724 /***********************************************************************
1725 * FILEDLG95_OnWMCommand
1727 * WM_COMMAND message handler
1729 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1731 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1732 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1733 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1739 FILEDLG95_OnOpen(hwnd);
1743 FILEDLG95_Clean(hwnd);
1744 EndDialog(hwnd, FALSE);
1746 /* Filetype combo box */
1748 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1750 /* LookIn combo box */
1752 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1755 /* --- toolbar --- */
1756 /* Up folder button */
1757 case FCIDM_TB_UPFOLDER:
1758 FILEDLG95_SHELL_UpFolder(hwnd);
1760 /* New folder button */
1761 case FCIDM_TB_NEWFOLDER:
1762 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1764 /* List option button */
1765 case FCIDM_TB_SMALLICON:
1766 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1768 /* Details option button */
1769 case FCIDM_TB_REPORTVIEW:
1770 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1772 /* Details option button */
1773 case FCIDM_TB_DESKTOP:
1774 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1781 /* Do not use the listview selection anymore */
1782 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1786 /***********************************************************************
1787 * FILEDLG95_OnWMGetIShellBrowser
1789 * WM_GETISHELLBROWSER message handler
1791 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1793 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1797 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1803 /***********************************************************************
1804 * FILEDLG95_SendFileOK
1806 * Sends the CDN_FILEOK notification if required
1809 * TRUE if the dialog should close
1810 * FALSE if the dialog should not be closed
1812 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1814 /* ask the hook if we can close */
1815 if(IsHooked(fodInfos))
1820 /* First send CDN_FILEOK as MSDN doc says */
1821 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1822 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1825 TRACE("canceled\n");
1829 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1830 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1831 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1834 TRACE("canceled\n");
1841 /***********************************************************************
1842 * FILEDLG95_OnOpenMultipleFiles
1844 * Handles the opening of multiple files.
1847 * check destination buffer size
1849 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1851 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1852 UINT nCount, nSizePath;
1853 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1857 if(fodInfos->unicode)
1859 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1860 ofn->lpstrFile[0] = '\0';
1864 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1865 ofn->lpstrFile[0] = '\0';
1868 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1870 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1871 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1872 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1874 LPWSTR lpstrTemp = lpstrFileList;
1876 for ( nCount = 0; nCount < nFileCount; nCount++ )
1880 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1883 WCHAR lpstrNotFound[100];
1884 WCHAR lpstrMsg[100];
1886 static const WCHAR nl[] = {'\n',0};
1888 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1889 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1891 lstrcpyW(tmp, lpstrTemp);
1893 lstrcatW(tmp, lpstrNotFound);
1895 lstrcatW(tmp, lpstrMsg);
1897 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1901 /* move to the next file in the list of files */
1902 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1903 COMDLG32_SHFree(pidl);
1907 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1908 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1910 /* For "oldstyle" dialog the components have to
1911 be separated by blanks (not '\0'!) and short
1912 filenames have to be used! */
1913 FIXME("Components have to be separated by blanks\n");
1915 if(fodInfos->unicode)
1917 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1918 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1919 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1923 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1925 if (ofn->lpstrFile != NULL)
1927 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1928 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1929 if (ofn->nMaxFile > nSizePath)
1931 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1932 ofn->lpstrFile + nSizePath,
1933 ofn->nMaxFile - nSizePath, NULL, NULL);
1938 fodInfos->ofnInfos->nFileOffset = nSizePath;
1939 fodInfos->ofnInfos->nFileExtension = 0;
1941 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1944 /* clean and exit */
1945 FILEDLG95_Clean(hwnd);
1946 return EndDialog(hwnd,TRUE);
1949 /***********************************************************************
1952 * Ok button WM_COMMAND message handler
1954 * If the function succeeds, the return value is nonzero.
1956 #define ONOPEN_BROWSE 1
1957 #define ONOPEN_OPEN 2
1958 #define ONOPEN_SEARCH 3
1959 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1961 WCHAR strMsgTitle[MAX_PATH];
1962 WCHAR strMsgText [MAX_PATH];
1964 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1966 strMsgTitle[0] = '\0';
1967 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1968 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1971 BOOL FILEDLG95_OnOpen(HWND hwnd)
1973 LPWSTR lpstrFileList;
1974 UINT nFileCount = 0;
1977 WCHAR lpstrPathAndFile[MAX_PATH];
1978 WCHAR lpstrTemp[MAX_PATH];
1979 LPSHELLFOLDER lpsf = NULL;
1981 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1983 TRACE("hwnd=%p\n", hwnd);
1985 /* get the files from the edit control */
1986 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1988 /* try if the user selected a folder in the shellview */
1991 BrowseSelectedFolder(hwnd);
1997 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2001 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2004 Step 1: Build a complete path name from the current folder and
2005 the filename or path in the edit box.
2007 - the path in the edit box is a root path
2008 (with or without drive letter)
2009 - the edit box contains ".." (or a path with ".." in it)
2012 /* Get the current directory name */
2013 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2016 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2018 PathAddBackslashW(lpstrPathAndFile);
2020 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2022 /* if the user specified a fully qualified path use it */
2023 if(PathIsRelativeW(lpstrFileList))
2025 lstrcatW(lpstrPathAndFile, lpstrFileList);
2029 /* does the path have a drive letter? */
2030 if (PathGetDriveNumberW(lpstrFileList) == -1)
2031 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2033 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2036 /* resolve "." and ".." */
2037 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2038 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2039 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2041 MemFree(lpstrFileList);
2044 Step 2: here we have a cleaned up path
2046 We have to parse the path step by step to see if we have to browse
2047 to a folder if the path points to a directory or the last
2048 valid element is a directory.
2051 lpstrPathAndFile: cleaned up path
2055 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2056 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2057 nOpenAction = ONOPEN_OPEN;
2059 nOpenAction = ONOPEN_BROWSE;
2061 /* don't apply any checks with OFN_NOVALIDATE */
2063 LPWSTR lpszTemp, lpszTemp1;
2064 LPITEMIDLIST pidl = NULL;
2065 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2067 /* check for invalid chars */
2068 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2070 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2075 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2077 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2080 LPSHELLFOLDER lpsfChild;
2081 WCHAR lpwstrTemp[MAX_PATH];
2082 DWORD dwEaten, dwAttributes;
2085 lstrcpyW(lpwstrTemp, lpszTemp);
2086 p = PathFindNextComponentW(lpwstrTemp);
2088 if (!p) break; /* end of path */
2091 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2093 /* There are no wildcards when OFN_NOVALIDATE is set */
2094 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2096 static const WCHAR wszWild[] = { '*', '?', 0 };
2097 /* if the last element is a wildcard do a search */
2098 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2100 nOpenAction = ONOPEN_SEARCH;
2104 lpszTemp1 = lpszTemp;
2106 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2108 /* append a backslash to drive letters */
2109 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2110 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2111 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2113 PathAddBackslashW(lpwstrTemp);
2116 dwAttributes = SFGAO_FOLDER;
2117 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2119 /* the path component is valid, we have a pidl of the next path component */
2120 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2121 if(dwAttributes & SFGAO_FOLDER)
2123 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2125 ERR("bind to failed\n"); /* should not fail */
2128 IShellFolder_Release(lpsf);
2136 /* end dialog, return value */
2137 nOpenAction = ONOPEN_OPEN;
2140 COMDLG32_SHFree(pidl);
2143 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2145 if(*lpszTemp || /* points to trailing null for last path element */
2146 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2148 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2150 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2156 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2157 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2159 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2163 /* change to the current folder */
2164 nOpenAction = ONOPEN_OPEN;
2169 nOpenAction = ONOPEN_OPEN;
2173 if(pidl) COMDLG32_SHFree(pidl);
2177 Step 3: here we have a cleaned up and validated path
2180 lpsf: ShellFolder bound to the rightmost valid path component
2181 lpstrPathAndFile: cleaned up path
2182 nOpenAction: action to do
2184 TRACE("end validate sf=%p\n", lpsf);
2188 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2189 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2192 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2195 /* replace the current filter */
2196 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2197 len = lstrlenW(lpszTemp)+1;
2198 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2199 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2201 /* set the filter cb to the extension when possible */
2202 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2203 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2206 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2207 TRACE("ONOPEN_BROWSE\n");
2209 IPersistFolder2 * ppf2;
2210 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2212 LPITEMIDLIST pidlCurrent;
2213 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2214 IPersistFolder2_Release(ppf2);
2215 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2217 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2218 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2220 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2223 else if( nOpenAction == ONOPEN_SEARCH )
2225 if (fodInfos->Shell.FOIShellView)
2226 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2228 COMDLG32_SHFree(pidlCurrent);
2229 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2234 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2235 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2239 /* update READONLY check box flag */
2240 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2241 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2243 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2245 /* Attach the file extension with file name*/
2246 ext = PathFindExtensionW(lpstrPathAndFile);
2249 /* if no extension is specified with file name, then */
2250 /* attach the extension from file filter or default one */
2252 WCHAR *filterExt = NULL;
2253 LPWSTR lpstrFilter = NULL;
2254 static const WCHAR szwDot[] = {'.',0};
2255 int PathLength = lstrlenW(lpstrPathAndFile);
2258 lstrcatW(lpstrPathAndFile, szwDot);
2260 /*Get the file extension from file type filter*/
2261 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2262 fodInfos->ofnInfos->nFilterIndex-1);
2264 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2265 filterExt = PathFindExtensionW(lpstrFilter);
2267 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2268 lstrcatW(lpstrPathAndFile, filterExt + 1);
2269 else if ( fodInfos->defext ) /* attach the default file extension*/
2270 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2272 /* In Open dialog: if file does not exist try without extension */
2273 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2274 lpstrPathAndFile[PathLength] = '\0';
2277 if (fodInfos->defext) /* add default extension */
2279 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2282 if (!lstrcmpiW(fodInfos->defext, ext))
2283 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2285 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2288 /* In Save dialog: check if the file already exists */
2289 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2290 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2291 && PathFileExistsW(lpstrPathAndFile))
2293 WCHAR lpstrOverwrite[100];
2296 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2297 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2298 MB_YESNO | MB_ICONEXCLAMATION);
2306 /* In Open dialog: check if it should be created if it doesn't exist */
2307 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2308 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2309 && !PathFileExistsW(lpstrPathAndFile))
2311 WCHAR lpstrCreate[100];
2314 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2315 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2316 MB_YESNO | MB_ICONEXCLAMATION);
2324 /* Check that the size of the file does not exceed buffer size.
2325 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2326 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2327 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2330 /* fill destination buffer */
2331 if (fodInfos->ofnInfos->lpstrFile)
2333 if(fodInfos->unicode)
2335 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2337 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2338 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2339 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2343 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2345 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2346 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2347 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2348 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2352 if(fodInfos->unicode)
2356 /* set filename offset */
2357 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2358 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2360 /* set extension offset */
2361 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2362 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2367 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2369 /* set filename offset */
2370 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2371 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2373 /* set extension offset */
2374 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2375 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2378 /* set the lpstrFileTitle */
2379 if(fodInfos->ofnInfos->lpstrFileTitle)
2381 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2382 if(fodInfos->unicode)
2384 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2385 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2389 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2390 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2391 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2395 /* copy currently selected filter to lpstrCustomFilter */
2396 if (fodInfos->ofnInfos->lpstrCustomFilter)
2398 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2399 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2400 NULL, 0, NULL, NULL);
2401 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2403 LPSTR s = ofn->lpstrCustomFilter;
2404 s += strlen(ofn->lpstrCustomFilter)+1;
2405 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2406 s, len, NULL, NULL);
2411 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2415 FILEDLG95_Clean(hwnd);
2416 ret = EndDialog(hwnd, TRUE);
2422 size = lstrlenW(lpstrPathAndFile) + 1;
2423 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2425 /* return needed size in first two bytes of lpstrFile */
2426 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2427 FILEDLG95_Clean(hwnd);
2428 ret = EndDialog(hwnd, FALSE);
2429 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2436 if(lpsf) IShellFolder_Release(lpsf);
2440 /***********************************************************************
2441 * FILEDLG95_SHELL_Init
2443 * Initialisation of the shell objects
2445 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2447 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2452 * Initialisation of the FileOpenDialogInfos structure
2458 fodInfos->ShellInfos.hwndOwner = hwnd;
2460 /* Disable multi-select if flag not set */
2461 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2463 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2465 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2466 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2468 /* Construct the IShellBrowser interface */
2469 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2474 /***********************************************************************
2475 * FILEDLG95_SHELL_ExecuteCommand
2477 * Change the folder option and refresh the view
2478 * If the function succeeds, the return value is nonzero.
2480 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2482 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2485 TRACE("(%p,%p)\n", hwnd, lpVerb);
2487 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2492 CMINVOKECOMMANDINFO ci;
2493 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2494 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2498 IContextMenu_InvokeCommand(pcm, &ci);
2499 IContextMenu_Release(pcm);
2505 /***********************************************************************
2506 * FILEDLG95_SHELL_UpFolder
2508 * Browse to the specified object
2509 * If the function succeeds, the return value is nonzero.
2511 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2513 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2517 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2521 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2522 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2528 /***********************************************************************
2529 * FILEDLG95_SHELL_BrowseToDesktop
2531 * Browse to the Desktop
2532 * If the function succeeds, the return value is nonzero.
2534 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2536 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2542 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2543 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2544 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2545 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2546 COMDLG32_SHFree(pidl);
2547 return SUCCEEDED(hres);
2549 /***********************************************************************
2550 * FILEDLG95_SHELL_Clean
2552 * Cleans the memory used by shell objects
2554 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2556 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2560 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2562 /* clean Shell interfaces */
2563 if (fodInfos->Shell.FOIShellView)
2565 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2566 IShellView_Release(fodInfos->Shell.FOIShellView);
2568 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2569 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2570 if (fodInfos->Shell.FOIDataObject)
2571 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2574 /***********************************************************************
2575 * FILEDLG95_FILETYPE_Init
2577 * Initialisation of the file type combo box
2579 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2581 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2582 int nFilters = 0; /* number of filters */
2587 if(fodInfos->customfilter)
2589 /* customfilter has one entry... title\0ext\0
2590 * Set first entry of combo box item with customfilter
2593 LPCWSTR lpstrPos = fodInfos->customfilter;
2596 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2598 /* Copy the extensions */
2599 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2600 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2601 lstrcpyW(lpstrExt,lpstrPos);
2603 /* Add the item at the end of the combo */
2604 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2605 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2608 if(fodInfos->filter)
2610 LPCWSTR lpstrPos = fodInfos->filter;
2614 /* filter is a list... title\0ext\0......\0\0
2615 * Set the combo item text to the title and the item data
2618 LPCWSTR lpstrDisplay;
2622 if(! *lpstrPos) break; /* end */
2623 lpstrDisplay = lpstrPos;
2624 lpstrPos += lstrlenW(lpstrPos) + 1;
2626 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2630 /* Copy the extensions */
2631 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2632 lstrcpyW(lpstrExt,lpstrPos);
2633 lpstrPos += lstrlenW(lpstrPos) + 1;
2635 /* Add the item at the end of the combo */
2636 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2638 /* malformed filters are added anyway... */
2639 if (!*lpstrExt) break;
2644 * Set the current filter to the one specified
2645 * in the initialisation structure
2647 if (fodInfos->filter || fodInfos->customfilter)
2651 /* Check to make sure our index isn't out of bounds. */
2652 if ( fodInfos->ofnInfos->nFilterIndex >
2653 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2654 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2656 /* set default filter index */
2657 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2658 fodInfos->ofnInfos->nFilterIndex = 1;
2660 /* calculate index of Combo Box item */
2661 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2662 if (fodInfos->customfilter == NULL)
2665 /* Set the current index selection. */
2666 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2668 /* Get the corresponding text string from the combo box. */
2669 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2672 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2678 CharLowerW(lpstrFilter); /* lowercase */
2679 len = lstrlenW(lpstrFilter)+1;
2680 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2681 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2684 fodInfos->ofnInfos->nFilterIndex = 0;
2688 /***********************************************************************
2689 * FILEDLG95_FILETYPE_OnCommand
2691 * WM_COMMAND of the file type combo box
2692 * If the function succeeds, the return value is nonzero.
2694 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2696 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2704 /* Get the current item of the filetype combo box */
2705 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2707 /* set the current filter index */
2708 fodInfos->ofnInfos->nFilterIndex = iItem +
2709 (fodInfos->customfilter == NULL ? 1 : 0);
2711 /* Set the current filter with the current selection */
2712 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2714 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2716 if((INT_PTR)lpstrFilter != CB_ERR)
2719 CharLowerW(lpstrFilter); /* lowercase */
2720 len = lstrlenW(lpstrFilter)+1;
2721 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2722 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2723 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2724 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2727 /* Refresh the actual view to display the included items*/
2728 if (fodInfos->Shell.FOIShellView)
2729 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2734 /***********************************************************************
2735 * FILEDLG95_FILETYPE_SearchExt
2737 * searches for an extension in the filetype box
2739 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2741 int i, iCount = CBGetCount(hwnd);
2743 TRACE("%s\n", debugstr_w(lpstrExt));
2745 if(iCount != CB_ERR)
2747 for(i=0;i<iCount;i++)
2749 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2756 /***********************************************************************
2757 * FILEDLG95_FILETYPE_Clean
2759 * Clean the memory used by the filetype combo box
2761 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2763 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2765 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2769 /* Delete each string of the combo and their associated data */
2770 if(iCount != CB_ERR)
2772 for(iPos = iCount-1;iPos>=0;iPos--)
2774 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2775 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2778 /* Current filter */
2779 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2783 /***********************************************************************
2784 * FILEDLG95_LOOKIN_Init
2786 * Initialisation of the look in combo box
2789 /* Small helper function, to determine if the unixfs shell extension is rooted
2790 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2792 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2794 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2795 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2796 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2797 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2798 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2799 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2800 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2802 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2809 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2811 IShellFolder *psfRoot, *psfDrives;
2812 IEnumIDList *lpeRoot, *lpeDrives;
2813 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2815 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2819 liInfos->iMaxIndentation = 0;
2821 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2823 /* set item height for both text field and listbox */
2824 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2825 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2827 /* Turn on the extended UI for the combo box like Windows does */
2828 CBSetExtendedUI(hwndCombo, TRUE);
2830 /* Initialise data of Desktop folder */
2831 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2832 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2833 COMDLG32_SHFree(pidlTmp);
2835 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2837 SHGetDesktopFolder(&psfRoot);
2841 /* enumerate the contents of the desktop */
2842 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2844 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2846 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2848 /* If the unixfs extension is rooted, we don't expand the drives by default */
2849 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2851 /* special handling for CSIDL_DRIVES */
2852 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2854 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2856 /* enumerate the drives */
2857 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2859 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2861 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2862 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2863 COMDLG32_SHFree(pidlAbsTmp);
2864 COMDLG32_SHFree(pidlTmp1);
2866 IEnumIDList_Release(lpeDrives);
2868 IShellFolder_Release(psfDrives);
2873 COMDLG32_SHFree(pidlTmp);
2875 IEnumIDList_Release(lpeRoot);
2877 IShellFolder_Release(psfRoot);
2880 COMDLG32_SHFree(pidlDrives);
2883 /***********************************************************************
2884 * FILEDLG95_LOOKIN_DrawItem
2886 * WM_DRAWITEM message handler
2888 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2890 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2891 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2892 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2896 HIMAGELIST ilItemImage;
2899 LPSFOLDER tmpFolder;
2900 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2904 if(pDIStruct->itemID == -1)
2907 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2908 pDIStruct->itemID)))
2912 if(pDIStruct->itemID == liInfos->uSelectedItem)
2914 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2918 SHGFI_PIDL | SHGFI_SMALLICON |
2919 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2920 SHGFI_DISPLAYNAME );
2924 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2928 SHGFI_PIDL | SHGFI_SMALLICON |
2929 SHGFI_SYSICONINDEX |
2933 /* Is this item selected ? */
2934 if(pDIStruct->itemState & ODS_SELECTED)
2936 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2937 SetBkColor(pDIStruct->hDC,crHighLight);
2938 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2942 SetTextColor(pDIStruct->hDC,crText);
2943 SetBkColor(pDIStruct->hDC,crWin);
2944 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2947 /* Do not indent item if drawing in the edit of the combo */
2948 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2951 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2955 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2956 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2961 iIndentation = tmpFolder->m_iIndent;
2963 /* Draw text and icon */
2965 /* Initialise the icon display area */
2966 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2967 rectIcon.top = pDIStruct->rcItem.top;
2968 rectIcon.right = rectIcon.left + ICONWIDTH;
2969 rectIcon.bottom = pDIStruct->rcItem.bottom;
2971 /* Initialise the text display area */
2972 GetTextMetricsW(pDIStruct->hDC, &tm);
2973 rectText.left = rectIcon.right;
2975 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2976 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2978 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2980 /* Draw the icon from the image list */
2981 ImageList_Draw(ilItemImage,
2988 /* Draw the associated text */
2989 if(sfi.szDisplayName)
2990 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2996 /***********************************************************************
2997 * FILEDLG95_LOOKIN_OnCommand
2999 * LookIn combo box WM_COMMAND message handler
3000 * If the function succeeds, the return value is nonzero.
3002 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3004 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3006 TRACE("%p\n", fodInfos);
3012 LPSFOLDER tmpFolder;
3015 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3017 if( iItem == CB_ERR) return FALSE;
3019 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3024 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3025 tmpFolder->pidlItem,
3028 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3029 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3039 /***********************************************************************
3040 * FILEDLG95_LOOKIN_AddItem
3042 * Adds an absolute pidl item to the lookin combo box
3043 * returns the index of the inserted item
3045 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3047 LPITEMIDLIST pidlNext;
3050 LookInInfos *liInfos;
3052 TRACE("%08x\n", iInsertId);
3057 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3060 tmpFolder = MemAlloc(sizeof(SFOLDER));
3061 tmpFolder->m_iIndent = 0;
3063 /* Calculate the indentation of the item in the lookin*/
3065 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3067 tmpFolder->m_iIndent++;
3070 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3072 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3073 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3075 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3076 SHGetFileInfoW((LPCWSTR)pidl,
3080 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3081 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3083 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3085 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3089 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3091 /* Add the item at the end of the list */
3094 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3096 /* Insert the item at the iInsertId position*/
3099 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3102 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3106 COMDLG32_SHFree( tmpFolder->pidlItem );
3107 MemFree( tmpFolder );
3112 /***********************************************************************
3113 * FILEDLG95_LOOKIN_InsertItemAfterParent
3115 * Insert an item below its parent
3117 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3120 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3125 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3129 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3132 /* Free pidlParent memory */
3133 COMDLG32_SHFree(pidlParent);
3135 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3138 /***********************************************************************
3139 * FILEDLG95_LOOKIN_SelectItem
3141 * Adds an absolute pidl item to the lookin combo box
3142 * returns the index of the inserted item
3144 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3147 LookInInfos *liInfos;
3151 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3153 liInfos = GetPropA(hwnd,LookInInfosStr);
3157 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3158 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3163 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3164 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3168 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3170 if(iRemovedItem < iItemPos)
3175 CBSetCurSel(hwnd,iItemPos);
3176 liInfos->uSelectedItem = iItemPos;
3182 /***********************************************************************
3183 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3185 * Remove the item with an expansion level over iExpansionLevel
3187 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3190 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3194 if(liInfos->iMaxIndentation <= 2)
3197 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3199 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3200 COMDLG32_SHFree(tmpFolder->pidlItem);
3202 CBDeleteString(hwnd,iItemPos);
3203 liInfos->iMaxIndentation--;
3211 /***********************************************************************
3212 * FILEDLG95_LOOKIN_SearchItem
3214 * Search for pidl in the lookin combo box
3215 * returns the index of the found item
3217 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3220 int iCount = CBGetCount(hwnd);
3222 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3224 if (iCount != CB_ERR)
3228 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3230 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3232 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3240 /***********************************************************************
3241 * FILEDLG95_LOOKIN_Clean
3243 * Clean the memory used by the lookin combo box
3245 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3247 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3249 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3253 /* Delete each string of the combo and their associated data */
3254 if (iCount != CB_ERR)
3256 for(iPos = iCount-1;iPos>=0;iPos--)
3258 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3259 COMDLG32_SHFree(tmpFolder->pidlItem);
3261 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3265 /* LookInInfos structure */
3266 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3269 /***********************************************************************
3270 * FILEDLG95_FILENAME_FillFromSelection
3272 * fills the edit box from the cached DataObject
3274 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3276 FileOpenDlgInfos *fodInfos;
3278 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3279 WCHAR lpstrTemp[MAX_PATH];
3280 LPWSTR lpstrAllFile, lpstrCurrFile;
3283 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3285 /* Count how many files we have */
3286 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3288 /* calculate the string length, count files */
3289 if (nFileSelected >= 1)
3291 nLength += 3; /* first and last quotes, trailing \0 */
3292 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3294 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3298 /* get the total length of the selected file names */
3299 lpstrTemp[0] = '\0';
3300 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3302 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3304 nLength += lstrlenW( lpstrTemp ) + 3;
3307 COMDLG32_SHFree( pidl );
3312 /* allocate the buffer */
3313 if (nFiles <= 1) nLength = MAX_PATH;
3314 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3316 /* Generate the string for the edit control */
3319 lpstrCurrFile = lpstrAllFile;
3320 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3322 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3326 /* get the file name */
3327 lpstrTemp[0] = '\0';
3328 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3330 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3334 *lpstrCurrFile++ = '\"';
3335 lstrcpyW( lpstrCurrFile, lpstrTemp );
3336 lpstrCurrFile += lstrlenW( lpstrTemp );
3337 *lpstrCurrFile++ = '\"';
3338 *lpstrCurrFile++ = ' ';
3343 lstrcpyW( lpstrAllFile, lpstrTemp );
3346 COMDLG32_SHFree( pidl );
3349 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3351 /* Select the file name like Windows does */
3352 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3354 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3358 /* copied from shell32 to avoid linking to it
3359 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3360 * is dependent on whether emulated OS is unicode or not.
3362 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3367 lstrcpynW(dest, src->u.pOleStr, len);
3368 COMDLG32_SHFree(src->u.pOleStr);
3372 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3377 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3382 FIXME("unknown type %x!\n", src->uType);
3383 if (len) *dest = '\0';
3389 /***********************************************************************
3390 * FILEDLG95_FILENAME_GetFileNames
3392 * Copies the filenames to a delimited string list.
3393 * The delimiter is specified by the parameter 'separator',
3394 * usually either a space or a nul
3396 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3398 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3399 UINT nStrCharCount = 0; /* index in src buffer */
3400 UINT nFileIndex = 0; /* index in dest buffer */
3401 UINT nFileCount = 0; /* number of files */
3402 UINT nStrLen = 0; /* length of string in edit control */
3403 LPWSTR lpstrEdit; /* buffer for string from edit control */
3407 /* get the filenames from the edit control */
3408 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3409 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3410 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3412 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3414 /* we might get single filename without any '"',
3415 * so we need nStrLen + terminating \0 + end-of-list \0 */
3416 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3419 /* build delimited file list from filenames */
3420 while ( nStrCharCount <= nStrLen )
3422 if ( lpstrEdit[nStrCharCount]=='"' )
3425 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3427 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3430 (*lpstrFileList)[nFileIndex++] = 0;
3436 /* single, unquoted string */
3437 if ((nStrLen > 0) && (nFileIndex == 0) )
3439 lstrcpyW(*lpstrFileList, lpstrEdit);
3440 nFileIndex = lstrlenW(lpstrEdit) + 1;
3445 (*lpstrFileList)[nFileIndex++] = '\0';
3447 *sizeUsed = nFileIndex;
3452 #define SETDefFormatEtc(fe,cf,med) \
3454 (fe).cfFormat = cf;\
3455 (fe).dwAspect = DVASPECT_CONTENT; \
3462 * DATAOBJECT Helper functions
3465 /***********************************************************************
3466 * COMCTL32_ReleaseStgMedium
3468 * like ReleaseStgMedium from ole32
3470 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3472 if(medium.pUnkForRelease)
3474 IUnknown_Release(medium.pUnkForRelease);
3478 GlobalUnlock(medium.u.hGlobal);
3479 GlobalFree(medium.u.hGlobal);
3483 /***********************************************************************
3484 * GetPidlFromDataObject
3486 * Return pidl(s) by number from the cached DataObject
3488 * nPidlIndex=0 gets the fully qualified root path
3490 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3494 FORMATETC formatetc;
3495 LPITEMIDLIST pidl = NULL;
3497 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3502 /* Set the FORMATETC structure*/
3503 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3505 /* Get the pidls from IDataObject */
3506 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3508 LPIDA cida = GlobalLock(medium.u.hGlobal);
3509 if(nPidlIndex <= cida->cidl)
3511 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3513 COMCTL32_ReleaseStgMedium(medium);
3518 /***********************************************************************
3521 * Return the number of selected items in the DataObject.
3524 static UINT GetNumSelected( IDataObject *doSelected )
3528 FORMATETC formatetc;
3530 TRACE("sv=%p\n", doSelected);
3532 if (!doSelected) return 0;
3534 /* Set the FORMATETC structure*/
3535 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3537 /* Get the pidls from IDataObject */
3538 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3540 LPIDA cida = GlobalLock(medium.u.hGlobal);
3541 retVal = cida->cidl;
3542 COMCTL32_ReleaseStgMedium(medium);
3552 /***********************************************************************
3555 * Get the pidl's display name (relative to folder) and
3556 * put it in lpstrFileName.
3558 * Return NOERROR on success,
3562 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3567 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3571 SHGetDesktopFolder(&lpsf);
3572 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3573 IShellFolder_Release(lpsf);
3577 /* Get the display name of the pidl relative to the folder */
3578 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3580 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3585 /***********************************************************************
3586 * GetShellFolderFromPidl
3588 * pidlRel is the item pidl relative
3589 * Return the IShellFolder of the absolute pidl
3591 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3593 IShellFolder *psf = NULL,*psfParent;
3595 TRACE("%p\n", pidlAbs);
3597 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3600 if(pidlAbs && pidlAbs->mkid.cb)
3602 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3604 IShellFolder_Release(psfParent);
3608 /* return the desktop */
3614 /***********************************************************************
3617 * Return the LPITEMIDLIST to the parent of the pidl in the list
3619 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3621 LPITEMIDLIST pidlParent;
3623 TRACE("%p\n", pidl);
3625 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3626 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3631 /***********************************************************************
3634 * returns the pidl of the file name relative to folder
3635 * NULL if an error occurred
3637 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3639 LPITEMIDLIST pidl = NULL;
3642 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3644 if(!lpcstrFileName) return NULL;
3645 if(!*lpcstrFileName) return NULL;
3649 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3650 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3651 IShellFolder_Release(lpsf);
3656 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3663 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3665 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3668 TRACE("%p, %p\n", psf, pidl);
3670 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3672 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3673 /* see documentation shell 4.1*/
3674 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3677 /***********************************************************************
3678 * BrowseSelectedFolder
3680 static BOOL BrowseSelectedFolder(HWND hwnd)
3682 BOOL bBrowseSelFolder = FALSE;
3683 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3687 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3689 LPITEMIDLIST pidlSelection;
3691 /* get the file selected */
3692 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3693 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3695 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3696 pidlSelection, SBSP_RELATIVE ) ) )
3698 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3699 ' ','n','o','t',' ','e','x','i','s','t',0};
3700 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3702 bBrowseSelFolder = TRUE;
3703 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3704 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3706 COMDLG32_SHFree( pidlSelection );
3709 return bBrowseSelFolder;
3713 * Memory allocation methods */
3714 static void *MemAlloc(UINT size)
3716 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3719 static void MemFree(void *mem)
3721 HeapFree(GetProcessHeap(),0,mem);
3725 * Old-style (win3.1) dialogs */
3727 /***********************************************************************
3728 * FD32_GetTemplate [internal]
3730 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3731 * by a 32 bits application
3734 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3736 LPOPENFILENAMEW ofnW = lfs->ofnW;
3737 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3740 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3742 if (!(lfs->template = LockResource( ofnW->hInstance )))
3744 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3748 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3752 hResInfo = FindResourceA(priv->ofnA->hInstance,
3753 priv->ofnA->lpTemplateName,
3756 hResInfo = FindResourceW(ofnW->hInstance,
3757 ofnW->lpTemplateName,
3761 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3764 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3766 !(lfs->template = LockResource(hDlgTmpl)))
3768 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3771 } else { /* get it from internal Wine resource */
3773 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3774 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3776 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3779 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3780 !(lfs->template = LockResource( hDlgTmpl )))
3782 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3790 /************************************************************************
3791 * FD32_Init [internal]
3792 * called from the common 16/32 code to initialize 32 bit data
3794 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3796 BOOL IsUnicode = (BOOL) data;
3799 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3800 lfs->private1632 = priv;
3801 if (NULL == lfs->private1632) return FALSE;
3804 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3805 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3806 if (lfs->ofnW->lpfnHook)
3811 priv->ofnA = (LPOPENFILENAMEA) lParam;
3812 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3813 if (priv->ofnA->lpfnHook)
3815 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3816 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3819 if (! FD32_GetTemplate(lfs)) return FALSE;
3824 /***********************************************************************
3825 * FD32_CallWindowProc [internal]
3827 * called from the common 16/32 code to call the appropriate hook
3829 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3833 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3837 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3838 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3839 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3840 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3841 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3845 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3846 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3847 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3848 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3849 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3853 /***********************************************************************
3854 * FD32_UpdateResult [internal]
3855 * update the real client structures if any
3857 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3859 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3860 LPOPENFILENAMEW ofnW = lfs->ofnW;
3865 if (ofnW->nMaxFile &&
3866 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3867 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3868 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3870 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3871 /* set filename offset */
3872 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3873 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3875 /* set extension offset */
3876 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3877 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3881 /***********************************************************************
3882 * FD32_UpdateFileTitle [internal]
3883 * update the real client structures if any
3885 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3887 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3888 LPOPENFILENAMEW ofnW = lfs->ofnW;
3892 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3893 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3894 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3899 /***********************************************************************
3900 * FD32_SendLbGetCurSel [internal]
3901 * retrieve selected listbox item
3903 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3905 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3909 /************************************************************************
3910 * FD32_Destroy [internal]
3911 * called from the common 16/32 code to cleanup 32 bit data
3913 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3915 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3917 /* if ofnW has been allocated, have to free everything in it */
3918 if (NULL != priv && NULL != priv->ofnA)
3920 FD31_FreeOfnW(lfs->ofnW);
3921 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3925 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3927 callbacks->Init = FD32_Init;
3928 callbacks->CWP = FD32_CallWindowProc;
3929 callbacks->UpdateResult = FD32_UpdateResult;
3930 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3931 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3932 callbacks->Destroy = FD32_Destroy;
3935 /***********************************************************************
3936 * FD32_WMMeasureItem [internal]
3938 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3940 LPMEASUREITEMSTRUCT lpmeasure;
3942 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3943 lpmeasure->itemHeight = FD31_GetFldrHeight();
3948 /***********************************************************************
3949 * FileOpenDlgProc [internal]
3950 * Used for open and save, in fact.
3952 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3953 WPARAM wParam, LPARAM lParam)
3955 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3957 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3958 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3961 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3963 return lRet; /* else continue message processing */
3968 return FD31_WMInitDialog(hWnd, wParam, lParam);
3970 case WM_MEASUREITEM:
3971 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3974 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3977 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3980 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3981 switch (HIWORD(lParam))
3984 SetTextColor((HDC16)wParam, 0x00000000);
3986 case CTLCOLOR_STATIC:
3987 SetTextColor((HDC16)wParam, 0x00000000);
3997 /***********************************************************************
3998 * GetFileName31A [internal]
4000 * Creates a win31 style dialog box for the user to select a file to open/save.
4002 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4003 UINT dlgType /* type dialogue : open/save */
4009 FD31_CALLBACKS callbacks;
4011 if (!lpofn || !FD31_Init()) return FALSE;
4013 TRACE("ofn flags %08x\n", lpofn->Flags);
4014 FD32_SetupCallbacks(&callbacks);
4015 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
4018 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4019 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
4020 FD32_FileOpenDlgProc, (LPARAM)lfs);
4021 FD31_DestroyPrivate(lfs);
4024 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4028 /***********************************************************************
4029 * GetFileName31W [internal]
4031 * Creates a win31 style dialog box for the user to select a file to open/save
4033 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4034 UINT dlgType /* type dialogue : open/save */
4040 FD31_CALLBACKS callbacks;
4042 if (!lpofn || !FD31_Init()) return FALSE;
4044 FD32_SetupCallbacks(&callbacks);
4045 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
4048 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4049 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
4050 FD32_FileOpenDlgProc, (LPARAM)lfs);
4051 FD31_DestroyPrivate(lfs);
4054 TRACE("file %s, file offset %d, ext offset %d\n",
4055 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4059 /* ------------------ APIs ---------------------- */
4061 /***********************************************************************
4062 * GetOpenFileNameA (COMDLG32.@)
4064 * Creates a dialog box for the user to select a file to open.
4067 * TRUE on success: user enters a valid file
4068 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4071 BOOL WINAPI GetOpenFileNameA(
4072 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4074 BOOL win16look = FALSE;
4076 TRACE("flags %08x\n", ofn->Flags);
4078 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4079 if (ofn->Flags & OFN_FILEMUSTEXIST)
4080 ofn->Flags |= OFN_PATHMUSTEXIST;
4082 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4083 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4086 return GetFileName31A(ofn, OPEN_DIALOG);
4088 return GetFileDialog95A(ofn, OPEN_DIALOG);
4091 /***********************************************************************
4092 * GetOpenFileNameW (COMDLG32.@)
4094 * Creates a dialog box for the user to select a file to open.
4097 * TRUE on success: user enters a valid file
4098 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4101 BOOL WINAPI GetOpenFileNameW(
4102 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4104 BOOL win16look = FALSE;
4106 TRACE("flags %08x\n", ofn->Flags);
4108 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4109 if (ofn->Flags & OFN_FILEMUSTEXIST)
4110 ofn->Flags |= OFN_PATHMUSTEXIST;
4112 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4113 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4116 return GetFileName31W(ofn, OPEN_DIALOG);
4118 return GetFileDialog95W(ofn, OPEN_DIALOG);
4122 /***********************************************************************
4123 * GetSaveFileNameA (COMDLG32.@)
4125 * Creates a dialog box for the user to select a file to save.
4128 * TRUE on success: user enters a valid file
4129 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4132 BOOL WINAPI GetSaveFileNameA(
4133 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4135 BOOL win16look = FALSE;
4137 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4138 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4141 return GetFileName31A(ofn, SAVE_DIALOG);
4143 return GetFileDialog95A(ofn, SAVE_DIALOG);
4146 /***********************************************************************
4147 * GetSaveFileNameW (COMDLG32.@)
4149 * Creates a dialog box for the user to select a file to save.
4152 * TRUE on success: user enters a valid file
4153 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4156 BOOL WINAPI GetSaveFileNameW(
4157 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4159 BOOL win16look = FALSE;
4161 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4162 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4165 return GetFileName31W(ofn, SAVE_DIALOG);
4167 return GetFileDialog95W(ofn, SAVE_DIALOG);
4170 /***********************************************************************
4171 * GetFileTitleA (COMDLG32.@)
4173 * See GetFileTitleW.
4175 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4178 UNICODE_STRING strWFile;
4181 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4182 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4183 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4184 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4185 RtlFreeUnicodeString( &strWFile );
4186 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4191 /***********************************************************************
4192 * GetFileTitleW (COMDLG32.@)
4194 * Get the name of a file.
4197 * lpFile [I] name and location of file
4198 * lpTitle [O] returned file name
4199 * cbBuf [I] buffer size of lpTitle
4203 * Failure: negative number.
4205 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4208 static const WCHAR brkpoint[] = {'*','[',']',0};
4209 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4211 if(lpFile == NULL || lpTitle == NULL)
4214 len = lstrlenW(lpFile);
4219 if(strpbrkW(lpFile, brkpoint))
4224 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4227 for(i = len; i >= 0; i--)
4229 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4239 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4241 len = lstrlenW(lpFile+i)+1;
4245 lstrcpyW(lpTitle, &lpFile[i]);