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_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
72 #include "filedlg31.h"
76 #include "filedlgbrowser.h"
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
122 #define XTEXTOFFSET 3
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
159 #define CBGetCurSel(hwnd) \
160 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
165 #define CBGetCount(hwnd) \
166 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
175 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
176 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
178 /***********************************************************************
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
218 /* Miscellaneous tool functions */
219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size);
226 static void MemFree(void *mem);
228 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
231 static BOOL BrowseSelectedFolder(HWND hwnd);
233 /***********************************************************************
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
282 /* Some shell namespace extensions depend on COM being initialized. */
283 hr = OleInitialize(NULL);
285 if (fodInfos->unicode)
286 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
288 fodInfos->ofnInfos->hwndOwner,
292 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
293 (LPCDLGTEMPLATEA) template,
294 fodInfos->ofnInfos->hwndOwner,
300 /* Unable to create the dialog */
307 /***********************************************************************
310 * Call GetFileName95 with this structure and clean the memory.
312 * IN : The OPENFILENAMEA initialisation structure passed to
313 * GetOpenFileNameA win api function (see filedlg.c)
315 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
318 FileOpenDlgInfos fodInfos;
319 LPSTR lpstrSavDir = NULL;
321 LPWSTR defext = NULL;
322 LPWSTR filter = NULL;
323 LPWSTR customfilter = NULL;
325 /* Initialize CommDlgExtendedError() */
326 COMDLG32_SetCommDlgExtendedError(0);
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
351 fodInfos.initdir = NULL;
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
359 fodInfos.filename = NULL;
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
417 ret = GetFileName95(&fodInfos);
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
445 /***********************************************************************
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize CommDlgExtendedError() */
459 COMDLG32_SetCommDlgExtendedError(0);
461 /* Initialize FileOpenDlgInfos structure */
462 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
464 /* Pass in the original ofn */
465 fodInfos.ofnInfos = ofn;
467 fodInfos.title = ofn->lpstrTitle;
468 fodInfos.defext = ofn->lpstrDefExt;
469 fodInfos.filter = ofn->lpstrFilter;
470 fodInfos.customfilter = ofn->lpstrCustomFilter;
472 /* convert string arguments, save others */
475 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
476 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
479 fodInfos.filename = NULL;
481 if(ofn->lpstrInitialDir)
483 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
484 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
485 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
486 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
489 fodInfos.initdir = NULL;
491 /* save current directory */
492 if (ofn->Flags & OFN_NOCHANGEDIR)
494 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
495 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
498 fodInfos.unicode = TRUE;
503 ret = GetFileName95(&fodInfos);
506 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
507 ret = GetFileName95(&fodInfos);
515 SetCurrentDirectoryW(lpstrSavDir);
516 MemFree(lpstrSavDir);
519 /* restore saved IN arguments and convert OUT arguments back */
520 MemFree(fodInfos.filename);
521 MemFree(fodInfos.initdir);
525 /******************************************************************************
526 * COMDLG32_GetDisplayNameOf [internal]
528 * Helper function to get the display name for a pidl.
530 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
531 LPSHELLFOLDER psfDesktop;
534 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
537 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
538 IShellFolder_Release(psfDesktop);
542 IShellFolder_Release(psfDesktop);
543 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
546 /***********************************************************************
547 * ArrangeCtrlPositions [internal]
549 * NOTE: Do not change anything here without a lot of testing.
551 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
553 HWND hwndChild, hwndStc32;
554 RECT rectParent, rectChild, rectStc32;
555 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
557 /* Take into account if open as read only checkbox and help button
562 RECT rectHelp, rectCancel;
563 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
564 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
565 /* subtract the height of the help button plus the space between
566 * the help button and the cancel button to the height of the dialog
568 help_fixup = rectHelp.bottom - rectCancel.bottom;
572 There are two possibilities to add components to the default file dialog box.
574 By default, all the new components are added below the standard dialog box (the else case).
576 However, if there is a static text component with the stc32 id, a special case happens.
577 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
578 in the window and the cx and cy indicate how to size the window.
579 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
580 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
584 GetClientRect(hwndParentDlg, &rectParent);
586 /* when arranging controls we have to use fixed parent size */
587 rectParent.bottom -= help_fixup;
589 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
592 GetWindowRect(hwndStc32, &rectStc32);
593 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
595 /* set the size of the stc32 control according to the size of
596 * client area of the parent dialog
598 SetWindowPos(hwndStc32, 0,
600 rectParent.right, rectParent.bottom,
601 SWP_NOMOVE | SWP_NOZORDER);
604 SetRectEmpty(&rectStc32);
606 /* this part moves controls of the child dialog */
607 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
610 if (hwndChild != hwndStc32)
612 GetWindowRect(hwndChild, &rectChild);
613 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
615 /* move only if stc32 exist */
616 if (hwndStc32 && rectChild.left > rectStc32.right)
618 LONG old_left = rectChild.left;
620 /* move to the right of visible controls of the parent dialog */
621 rectChild.left += rectParent.right;
622 rectChild.left -= rectStc32.right;
624 child_width_fixup = rectChild.left - old_left;
626 /* move even if stc32 doesn't exist */
627 if (rectChild.top >= rectStc32.bottom)
629 LONG old_top = rectChild.top;
631 /* move below visible controls of the parent dialog */
632 rectChild.top += rectParent.bottom;
633 rectChild.top -= rectStc32.bottom - rectStc32.top;
635 child_height_fixup = rectChild.top - old_top;
638 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
639 0, 0, SWP_NOSIZE | SWP_NOZORDER);
641 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
644 /* this part moves controls of the parent dialog */
645 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
648 if (hwndChild != hwndChildDlg)
650 GetWindowRect(hwndChild, &rectChild);
651 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
653 /* left,top of stc32 marks the position of controls
654 * from the parent dialog
656 rectChild.left += rectStc32.left;
657 rectChild.top += rectStc32.top;
659 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
660 0, 0, SWP_NOSIZE | SWP_NOZORDER);
662 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
665 /* calculate the size of the resulting dialog */
667 /* here we have to use original parent size */
668 GetClientRect(hwndParentDlg, &rectParent);
669 GetClientRect(hwndChildDlg, &rectChild);
673 rectChild.right += child_width_fixup;
674 rectChild.bottom += child_height_fixup;
676 if (rectParent.right > rectChild.right)
678 rectParent.right += rectChild.right;
679 rectParent.right -= rectStc32.right - rectStc32.left;
683 rectParent.right = rectChild.right;
686 if (rectParent.bottom > rectChild.bottom)
688 rectParent.bottom += rectChild.bottom;
689 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
693 /* child dialog is higher, unconditionally set new dialog
694 * height to its size (help_fixup will be subtracted below)
696 rectParent.bottom = rectChild.bottom + help_fixup;
701 rectParent.bottom += rectChild.bottom;
704 /* finally use fixed parent size */
705 rectParent.bottom -= help_fixup;
707 /* set the size of the parent dialog */
708 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
709 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
710 SetWindowPos(hwndParentDlg, 0,
712 rectParent.right - rectParent.left,
713 rectParent.bottom - rectParent.top,
714 SWP_NOMOVE | SWP_NOZORDER);
717 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
726 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
736 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
737 * structure's hInstance parameter is not a HINSTANCE, but
738 * instead a pointer to a template resource to use.
740 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
743 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
745 hinst = COMDLG32_hInstance;
746 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
754 hinst = fodInfos->ofnInfos->hInstance;
755 if(fodInfos->unicode)
757 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
758 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
762 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
763 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
767 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
770 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
771 !(template = LockResource( hDlgTmpl )))
773 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
777 if (fodInfos->unicode)
778 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
779 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
780 (LPARAM)fodInfos->ofnInfos);
782 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
783 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
784 (LPARAM)fodInfos->ofnInfos);
787 ShowWindow(hChildDlg,SW_SHOW);
791 else if( IsHooked(fodInfos))
796 WORD menu,class,title;
798 GetClientRect(hwnd,&rectHwnd);
799 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
800 temp.tmplate.dwExtendedStyle = 0;
801 temp.tmplate.cdit = 0;
806 temp.menu = temp.class = temp.title = 0;
808 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
809 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
816 /***********************************************************************
817 * SendCustomDlgNotificationMessage
819 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
822 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
824 LRESULT hook_result = 0;
826 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
828 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
830 if(!fodInfos) return 0;
832 if(fodInfos->DlgInfos.hwndCustomDlg)
834 TRACE("CALL NOTIFY for %x\n", uCode);
835 if(fodInfos->unicode)
838 ofnNotify.hdr.hwndFrom=hwndParentDlg;
839 ofnNotify.hdr.idFrom=0;
840 ofnNotify.hdr.code = uCode;
841 ofnNotify.lpOFN = fodInfos->ofnInfos;
842 ofnNotify.pszFile = NULL;
843 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
848 ofnNotify.hdr.hwndFrom=hwndParentDlg;
849 ofnNotify.hdr.idFrom=0;
850 ofnNotify.hdr.code = uCode;
851 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
852 ofnNotify.pszFile = NULL;
853 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
855 TRACE("RET NOTIFY\n");
857 TRACE("Retval: 0x%08lx\n", hook_result);
861 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
865 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
867 TRACE("CDM_GETFILEPATH:\n");
869 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
872 /* get path and filenames */
873 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
874 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
875 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
878 p = buffer + strlenW(buffer);
880 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
882 if (fodInfos->unicode)
884 total = strlenW( buffer) + 1;
885 if (result) lstrcpynW( result, buffer, size );
886 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
890 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
891 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
892 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
894 HeapFree( GetProcessHeap(), 0, buffer );
898 /***********************************************************************
899 * FILEDLG95_HandleCustomDialogMessages
901 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
903 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
905 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
906 WCHAR lpstrPath[MAX_PATH];
909 if(!fodInfos) return FALSE;
913 case CDM_GETFILEPATH:
914 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
917 case CDM_GETFOLDERPATH:
918 TRACE("CDM_GETFOLDERPATH:\n");
919 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
922 if (fodInfos->unicode)
923 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
925 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
926 (LPSTR)lParam, (int)wParam, NULL, NULL);
928 retval = lstrlenW(lpstrPath);
932 TRACE("CDM_GETSPEC:\n");
933 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
936 if (fodInfos->unicode)
937 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
939 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
943 case CDM_SETCONTROLTEXT:
944 TRACE("CDM_SETCONTROLTEXT:\n");
947 if( fodInfos->unicode )
948 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
950 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
955 case CDM_HIDECONTROL:
956 /* MSDN states that it should fail for not OFN_EXPLORER case */
957 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
959 HWND control = GetDlgItem( hwnd, wParam );
960 if (control) ShowWindow( control, SW_HIDE );
967 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
968 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
971 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
975 /***********************************************************************
978 * File open dialog procedure
980 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
983 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
990 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
992 /* Adds the FileOpenDlgInfos in the property list of the dialog
993 so it will be easily accessible through a GetPropA(...) */
994 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
996 FILEDLG95_InitControls(hwnd);
998 fodInfos->DlgInfos.hwndCustomDlg =
999 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1001 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1002 FILEDLG95_FillControls(hwnd, wParam, lParam);
1004 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1005 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1006 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1010 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1013 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1016 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1022 case WM_GETISHELLBROWSER:
1023 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1026 RemovePropA(hwnd, FileOpenDlgInfosStr);
1031 LPNMHDR lpnmh = (LPNMHDR)lParam;
1034 /* set up the button tooltips strings */
1035 if(TTN_GETDISPINFOA == lpnmh->code )
1037 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1038 switch(lpnmh->idFrom )
1040 /* Up folder button */
1041 case FCIDM_TB_UPFOLDER:
1042 stringId = IDS_UPFOLDER;
1044 /* New folder button */
1045 case FCIDM_TB_NEWFOLDER:
1046 stringId = IDS_NEWFOLDER;
1048 /* List option button */
1049 case FCIDM_TB_SMALLICON:
1050 stringId = IDS_LISTVIEW;
1052 /* Details option button */
1053 case FCIDM_TB_REPORTVIEW:
1054 stringId = IDS_REPORTVIEW;
1056 /* Desktop button */
1057 case FCIDM_TB_DESKTOP:
1058 stringId = IDS_TODESKTOP;
1063 lpdi->hinst = COMDLG32_hInstance;
1064 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1069 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1070 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1075 /***********************************************************************
1076 * FILEDLG95_InitControls
1078 * WM_INITDIALOG message handler (before hook notification)
1080 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1082 int win2000plus = 0;
1084 int handledPath = FALSE;
1085 OSVERSIONINFOW osVi;
1086 static const WCHAR szwSlash[] = { '\\', 0 };
1087 static const WCHAR szwStar[] = { '*',0 };
1089 static const TBBUTTON tbb[] =
1091 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1092 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1093 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1094 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1095 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1096 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1097 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1098 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1099 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1104 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1106 tba[0].hInst = HINST_COMMCTRL;
1107 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1108 tba[1].hInst = COMDLG32_hInstance;
1111 TRACE("%p\n", fodInfos);
1113 /* Get windows version emulating */
1114 osVi.dwOSVersionInfoSize = sizeof(osVi);
1115 GetVersionExW(&osVi);
1116 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1117 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1118 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1119 win2000plus = (osVi.dwMajorVersion > 4);
1120 if (win2000plus) win98plus = TRUE;
1122 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1124 /* Get the hwnd of the controls */
1125 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1126 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1127 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1129 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1130 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1132 /* construct the toolbar */
1133 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1134 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1136 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1137 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1138 rectTB.left = rectlook.right;
1139 rectTB.top = rectlook.top-1;
1141 if (fodInfos->unicode)
1142 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1143 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1144 rectTB.left, rectTB.top,
1145 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1146 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1148 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1149 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1150 rectTB.left, rectTB.top,
1151 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1152 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1154 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1156 /* FIXME: use TB_LOADIMAGES when implemented */
1157 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1158 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1159 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1161 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1162 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1164 /* Set the window text with the text specified in the OPENFILENAME structure */
1167 SetWindowTextW(hwnd,fodInfos->title);
1169 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1172 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1173 SetWindowTextW(hwnd, buf);
1176 /* Initialise the file name edit control */
1177 handledPath = FALSE;
1178 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1180 if(fodInfos->filename)
1182 /* 1. If win2000 or higher and filename contains a path, use it
1183 in preference over the lpstrInitialDir */
1184 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1185 WCHAR tmpBuf[MAX_PATH];
1189 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1192 /* nameBit is always shorter than the original filename */
1193 lstrcpyW(fodInfos->filename,nameBit);
1196 if (fodInfos->initdir == NULL)
1197 MemFree(fodInfos->initdir);
1198 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1199 lstrcpyW(fodInfos->initdir, tmpBuf);
1201 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1202 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1204 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1207 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1211 /* 2. (All platforms) If initdir is not null, then use it */
1212 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1213 (*fodInfos->initdir!=0x00))
1215 /* Work out the proper path as supplied one might be relative */
1216 /* (Here because supplying '.' as dir browses to My Computer) */
1217 if (handledPath==FALSE) {
1218 WCHAR tmpBuf[MAX_PATH];
1219 WCHAR tmpBuf2[MAX_PATH];
1223 lstrcpyW(tmpBuf, fodInfos->initdir);
1224 if( PathFileExistsW(tmpBuf) ) {
1225 /* initdir does not have to be a directory. If a file is
1226 * specified, the dir part is taken */
1227 if( PathIsDirectoryW(tmpBuf)) {
1228 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1229 lstrcatW(tmpBuf, szwSlash);
1231 lstrcatW(tmpBuf, szwStar);
1233 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1236 MemFree(fodInfos->initdir);
1237 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1238 lstrcpyW(fodInfos->initdir, tmpBuf2);
1240 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1243 else if (fodInfos->initdir)
1245 MemFree(fodInfos->initdir);
1246 fodInfos->initdir = NULL;
1247 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1252 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1253 (*fodInfos->initdir==0x00)))
1255 /* 3. All except w2k+: if filename contains a path use it */
1256 if (!win2000plus && fodInfos->filename &&
1257 *fodInfos->filename &&
1258 strpbrkW(fodInfos->filename, szwSlash)) {
1259 WCHAR tmpBuf[MAX_PATH];
1263 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1268 /* nameBit is always shorter than the original filename */
1269 lstrcpyW(fodInfos->filename, nameBit);
1272 len = lstrlenW(tmpBuf);
1273 MemFree(fodInfos->initdir);
1274 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1275 lstrcpyW(fodInfos->initdir, tmpBuf);
1278 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1279 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1281 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1284 /* 4. win98+ and win2000+ if any files of specified filter types in
1285 current directory, use it */
1286 if ( win98plus && handledPath == FALSE &&
1287 fodInfos->filter && *fodInfos->filter) {
1289 BOOL searchMore = TRUE;
1290 LPCWSTR lpstrPos = fodInfos->filter;
1291 WIN32_FIND_DATAW FindFileData;
1296 /* filter is a list... title\0ext\0......\0\0 */
1298 /* Skip the title */
1299 if(! *lpstrPos) break; /* end */
1300 lpstrPos += lstrlenW(lpstrPos) + 1;
1302 /* See if any files exist in the current dir with this extension */
1303 if(! *lpstrPos) break; /* end */
1305 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1307 if (hFind == INVALID_HANDLE_VALUE) {
1308 /* None found - continue search */
1309 lpstrPos += lstrlenW(lpstrPos) + 1;
1314 MemFree(fodInfos->initdir);
1315 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1316 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1319 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1320 debugstr_w(lpstrPos));
1326 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1328 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1329 if (handledPath == FALSE && (win2000plus || win98plus)) {
1330 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1332 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1334 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1337 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1338 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1340 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1343 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1346 } else if (handledPath==FALSE) {
1347 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1348 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1350 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1353 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1354 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1356 /* Must the open as read only check box be checked ?*/
1357 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1359 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1362 /* Must the open as read only check box be hidden? */
1363 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1365 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1366 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1369 /* Must the help button be hidden? */
1370 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1372 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1373 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1376 /* change Open to Save */
1377 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1380 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1381 SetDlgItemTextW(hwnd, IDOK, buf);
1382 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1383 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1388 /***********************************************************************
1389 * FILEDLG95_ResizeControls
1391 * WM_INITDIALOG message handler (after hook notification)
1393 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1395 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1397 if (fodInfos->DlgInfos.hwndCustomDlg)
1400 UINT flags = SWP_NOACTIVATE;
1402 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1403 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1405 /* resize the custom dialog to the parent size */
1406 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1407 GetClientRect(hwnd, &rc);
1410 /* our own fake template is zero sized and doesn't have children, so
1411 * there is no need to resize it. Picasa depends on it.
1413 flags |= SWP_NOSIZE;
1416 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1417 0, 0, rc.right, rc.bottom, flags);
1421 /* Resize the height, if open as read only checkbox ad help button are
1422 * hidden and we are not using a custom template nor a customDialog
1424 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1425 (!(fodInfos->ofnInfos->Flags &
1426 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1428 RECT rectDlg, rectHelp, rectCancel;
1429 GetWindowRect(hwnd, &rectDlg);
1430 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1431 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1432 /* subtract the height of the help button plus the space between the help
1433 * button and the cancel button to the height of the dialog
1435 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1436 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1437 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1443 /***********************************************************************
1444 * FILEDLG95_FillControls
1446 * WM_INITDIALOG message handler (after hook notification)
1448 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1450 LPITEMIDLIST pidlItemId = NULL;
1452 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1454 TRACE("dir=%s file=%s\n",
1455 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1457 /* Get the initial directory pidl */
1459 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1461 WCHAR path[MAX_PATH];
1463 GetCurrentDirectoryW(MAX_PATH,path);
1464 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1467 /* Initialise shell objects */
1468 FILEDLG95_SHELL_Init(hwnd);
1470 /* Initialize the Look In combo box */
1471 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1473 /* Initialize the filter combo box */
1474 FILEDLG95_FILETYPE_Init(hwnd);
1476 /* Browse to the initial directory */
1477 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1479 /* Free pidlItem memory */
1480 COMDLG32_SHFree(pidlItemId);
1484 /***********************************************************************
1487 * Regroups all the cleaning functions of the filedlg
1489 void FILEDLG95_Clean(HWND hwnd)
1491 FILEDLG95_FILETYPE_Clean(hwnd);
1492 FILEDLG95_LOOKIN_Clean(hwnd);
1493 FILEDLG95_SHELL_Clean(hwnd);
1495 /***********************************************************************
1496 * FILEDLG95_OnWMCommand
1498 * WM_COMMAND message handler
1500 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1502 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1503 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1504 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1510 FILEDLG95_OnOpen(hwnd);
1514 FILEDLG95_Clean(hwnd);
1515 EndDialog(hwnd, FALSE);
1517 /* Filetype combo box */
1519 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1521 /* LookIn combo box */
1523 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1526 /* --- toolbar --- */
1527 /* Up folder button */
1528 case FCIDM_TB_UPFOLDER:
1529 FILEDLG95_SHELL_UpFolder(hwnd);
1531 /* New folder button */
1532 case FCIDM_TB_NEWFOLDER:
1533 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1535 /* List option button */
1536 case FCIDM_TB_SMALLICON:
1537 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1539 /* Details option button */
1540 case FCIDM_TB_REPORTVIEW:
1541 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1543 /* Details option button */
1544 case FCIDM_TB_DESKTOP:
1545 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1552 /* Do not use the listview selection anymore */
1553 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1557 /***********************************************************************
1558 * FILEDLG95_OnWMGetIShellBrowser
1560 * WM_GETISHELLBROWSER message handler
1562 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1565 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1569 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1575 /***********************************************************************
1576 * FILEDLG95_SendFileOK
1578 * Sends the CDN_FILEOK notification if required
1581 * TRUE if the dialog should close
1582 * FALSE if the dialog should not be closed
1584 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1586 /* ask the hook if we can close */
1587 if(IsHooked(fodInfos))
1592 /* First send CDN_FILEOK as MSDN doc says */
1593 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1594 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1596 TRACE("canceled\n");
1597 return (retval == 0);
1600 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1601 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1602 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1603 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1605 TRACE("canceled\n");
1606 return (retval == 0);
1612 /***********************************************************************
1613 * FILEDLG95_OnOpenMultipleFiles
1615 * Handles the opening of multiple files.
1618 * check destination buffer size
1620 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1622 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1623 UINT nCount, nSizePath;
1624 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1628 if(fodInfos->unicode)
1630 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1631 ofn->lpstrFile[0] = '\0';
1635 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1636 ofn->lpstrFile[0] = '\0';
1639 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1641 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1642 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1643 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1645 LPWSTR lpstrTemp = lpstrFileList;
1647 for ( nCount = 0; nCount < nFileCount; nCount++ )
1651 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1654 WCHAR lpstrNotFound[100];
1655 WCHAR lpstrMsg[100];
1657 static const WCHAR nl[] = {'\n',0};
1659 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1660 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1662 lstrcpyW(tmp, lpstrTemp);
1664 lstrcatW(tmp, lpstrNotFound);
1666 lstrcatW(tmp, lpstrMsg);
1668 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1672 /* move to the next file in the list of files */
1673 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1674 COMDLG32_SHFree(pidl);
1678 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1679 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1681 /* For "oldstyle" dialog the components have to
1682 be separated by blanks (not '\0'!) and short
1683 filenames have to be used! */
1684 FIXME("Components have to be separated by blanks\n");
1686 if(fodInfos->unicode)
1688 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1689 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1690 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1694 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1696 if (ofn->lpstrFile != NULL)
1698 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1699 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1700 if (ofn->nMaxFile > nSizePath)
1702 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1703 ofn->lpstrFile + nSizePath,
1704 ofn->nMaxFile - nSizePath, NULL, NULL);
1709 fodInfos->ofnInfos->nFileOffset = nSizePath;
1710 fodInfos->ofnInfos->nFileExtension = 0;
1712 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1715 /* clean and exit */
1716 FILEDLG95_Clean(hwnd);
1717 return EndDialog(hwnd,TRUE);
1720 /***********************************************************************
1723 * Ok button WM_COMMAND message handler
1725 * If the function succeeds, the return value is nonzero.
1727 #define ONOPEN_BROWSE 1
1728 #define ONOPEN_OPEN 2
1729 #define ONOPEN_SEARCH 3
1730 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1732 WCHAR strMsgTitle[MAX_PATH];
1733 WCHAR strMsgText [MAX_PATH];
1735 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1737 strMsgTitle[0] = '\0';
1738 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1739 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1742 BOOL FILEDLG95_OnOpen(HWND hwnd)
1744 LPWSTR lpstrFileList;
1745 UINT nFileCount = 0;
1748 WCHAR lpstrPathAndFile[MAX_PATH];
1749 WCHAR lpstrTemp[MAX_PATH];
1750 LPSHELLFOLDER lpsf = NULL;
1752 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1754 TRACE("hwnd=%p\n", hwnd);
1756 /* get the files from the edit control */
1757 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1759 /* try if the user selected a folder in the shellview */
1762 BrowseSelectedFolder(hwnd);
1768 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1772 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1775 Step 1: Build a complete path name from the current folder and
1776 the filename or path in the edit box.
1778 - the path in the edit box is a root path
1779 (with or without drive letter)
1780 - the edit box contains ".." (or a path with ".." in it)
1783 /* Get the current directory name */
1784 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1787 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1789 PathAddBackslashW(lpstrPathAndFile);
1791 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1793 /* if the user specified a fully qualified path use it */
1794 if(PathIsRelativeW(lpstrFileList))
1796 lstrcatW(lpstrPathAndFile, lpstrFileList);
1800 /* does the path have a drive letter? */
1801 if (PathGetDriveNumberW(lpstrFileList) == -1)
1802 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1804 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1807 /* resolve "." and ".." */
1808 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1809 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1810 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1812 MemFree(lpstrFileList);
1815 Step 2: here we have a cleaned up path
1817 We have to parse the path step by step to see if we have to browse
1818 to a folder if the path points to a directory or the last
1819 valid element is a directory.
1822 lpstrPathAndFile: cleaned up path
1826 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1827 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1828 nOpenAction = ONOPEN_OPEN;
1830 nOpenAction = ONOPEN_BROWSE;
1832 /* don't apply any checks with OFN_NOVALIDATE */
1834 LPWSTR lpszTemp, lpszTemp1;
1835 LPITEMIDLIST pidl = NULL;
1836 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1838 /* check for invalid chars */
1839 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1841 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1846 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1848 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1851 LPSHELLFOLDER lpsfChild;
1852 WCHAR lpwstrTemp[MAX_PATH];
1853 DWORD dwEaten, dwAttributes;
1856 lstrcpyW(lpwstrTemp, lpszTemp);
1857 p = PathFindNextComponentW(lpwstrTemp);
1859 if (!p) break; /* end of path */
1862 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1864 /* There are no wildcards when OFN_NOVALIDATE is set */
1865 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1867 static const WCHAR wszWild[] = { '*', '?', 0 };
1868 /* if the last element is a wildcard do a search */
1869 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1871 nOpenAction = ONOPEN_SEARCH;
1875 lpszTemp1 = lpszTemp;
1877 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1879 /* append a backslash to drive letters */
1880 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1881 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1882 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1884 PathAddBackslashW(lpwstrTemp);
1887 dwAttributes = SFGAO_FOLDER;
1888 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1890 /* the path component is valid, we have a pidl of the next path component */
1891 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1892 if(dwAttributes & SFGAO_FOLDER)
1894 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1896 ERR("bind to failed\n"); /* should not fail */
1899 IShellFolder_Release(lpsf);
1907 /* end dialog, return value */
1908 nOpenAction = ONOPEN_OPEN;
1911 COMDLG32_SHFree(pidl);
1914 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1916 if(*lpszTemp || /* points to trailing null for last path element */
1917 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1919 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1921 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1927 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1928 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1930 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1934 /* change to the current folder */
1935 nOpenAction = ONOPEN_OPEN;
1940 nOpenAction = ONOPEN_OPEN;
1944 if(pidl) COMDLG32_SHFree(pidl);
1948 Step 3: here we have a cleaned up and validated path
1951 lpsf: ShellFolder bound to the rightmost valid path component
1952 lpstrPathAndFile: cleaned up path
1953 nOpenAction: action to do
1955 TRACE("end validate sf=%p\n", lpsf);
1959 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1960 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1963 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1966 /* replace the current filter */
1967 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1968 len = lstrlenW(lpszTemp)+1;
1969 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1970 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1972 /* set the filter cb to the extension when possible */
1973 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1974 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1977 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1978 TRACE("ONOPEN_BROWSE\n");
1980 IPersistFolder2 * ppf2;
1981 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1983 LPITEMIDLIST pidlCurrent;
1984 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1985 IPersistFolder2_Release(ppf2);
1986 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1988 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
1990 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1993 else if( nOpenAction == ONOPEN_SEARCH )
1995 if (fodInfos->Shell.FOIShellView)
1996 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1998 COMDLG32_SHFree(pidlCurrent);
1999 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2004 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2005 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2009 /* update READONLY check box flag */
2010 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2011 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2013 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2015 /* Attach the file extension with file name*/
2016 ext = PathFindExtensionW(lpstrPathAndFile);
2019 /* if no extension is specified with file name, then */
2020 /* attach the extension from file filter or default one */
2022 WCHAR *filterExt = NULL;
2023 LPWSTR lpstrFilter = NULL;
2024 static const WCHAR szwDot[] = {'.',0};
2025 int PathLength = lstrlenW(lpstrPathAndFile);
2028 lstrcatW(lpstrPathAndFile, szwDot);
2030 /*Get the file extension from file type filter*/
2031 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2032 fodInfos->ofnInfos->nFilterIndex-1);
2034 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2035 filterExt = PathFindExtensionW(lpstrFilter);
2037 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2038 lstrcatW(lpstrPathAndFile, filterExt + 1);
2039 else if ( fodInfos->defext ) /* attach the default file extension*/
2040 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2042 /* In Open dialog: if file does not exist try without extension */
2043 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2044 lpstrPathAndFile[PathLength] = '\0';
2047 if (fodInfos->defext) /* add default extension */
2049 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2052 if (!lstrcmpiW(fodInfos->defext, ext))
2053 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2055 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2058 /* In Save dialog: check if the file already exists */
2059 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2060 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2061 && PathFileExistsW(lpstrPathAndFile))
2063 WCHAR lpstrOverwrite[100];
2066 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2067 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2068 MB_YESNO | MB_ICONEXCLAMATION);
2076 /* In Open dialog: check if it should be created if it doesn't exist */
2077 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2078 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2079 && !PathFileExistsW(lpstrPathAndFile))
2081 WCHAR lpstrCreate[100];
2084 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2085 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2086 MB_YESNO | MB_ICONEXCLAMATION);
2094 /* Check that the size of the file does not exceed buffer size.
2095 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2096 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2097 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2100 /* fill destination buffer */
2101 if (fodInfos->ofnInfos->lpstrFile)
2103 if(fodInfos->unicode)
2105 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2107 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2108 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2109 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2113 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2115 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2116 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2117 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2118 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2122 if(fodInfos->unicode)
2126 /* set filename offset */
2127 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2128 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2130 /* set extension offset */
2131 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2132 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2137 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2139 /* set filename offset */
2140 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2141 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2143 /* set extension offset */
2144 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2145 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2148 /* set the lpstrFileTitle */
2149 if(fodInfos->ofnInfos->lpstrFileTitle)
2151 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2152 if(fodInfos->unicode)
2154 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2155 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2159 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2160 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2161 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2165 /* copy currently selected filter to lpstrCustomFilter */
2166 if (fodInfos->ofnInfos->lpstrCustomFilter)
2168 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2169 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2170 NULL, 0, NULL, NULL);
2171 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2173 LPSTR s = ofn->lpstrCustomFilter;
2174 s += strlen(ofn->lpstrCustomFilter)+1;
2175 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2176 s, len, NULL, NULL);
2181 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2185 FILEDLG95_Clean(hwnd);
2186 ret = EndDialog(hwnd, TRUE);
2192 size = lstrlenW(lpstrPathAndFile) + 1;
2193 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2195 /* return needed size in first two bytes of lpstrFile */
2196 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2197 FILEDLG95_Clean(hwnd);
2198 ret = EndDialog(hwnd, FALSE);
2199 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2207 if(lpsf) IShellFolder_Release(lpsf);
2211 /***********************************************************************
2212 * FILEDLG95_SHELL_Init
2214 * Initialisation of the shell objects
2216 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2218 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2223 * Initialisation of the FileOpenDialogInfos structure
2229 fodInfos->ShellInfos.hwndOwner = hwnd;
2231 /* Disable multi-select if flag not set */
2232 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2234 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2236 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2237 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2239 /* Construct the IShellBrowser interface */
2240 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2245 /***********************************************************************
2246 * FILEDLG95_SHELL_ExecuteCommand
2248 * Change the folder option and refresh the view
2249 * If the function succeeds, the return value is nonzero.
2251 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2253 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2256 TRACE("(%p,%p)\n", hwnd, lpVerb);
2258 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2263 CMINVOKECOMMANDINFO ci;
2264 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2265 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2269 IContextMenu_InvokeCommand(pcm, &ci);
2270 IContextMenu_Release(pcm);
2276 /***********************************************************************
2277 * FILEDLG95_SHELL_UpFolder
2279 * Browse to the specified object
2280 * If the function succeeds, the return value is nonzero.
2282 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2284 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2288 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2292 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2298 /***********************************************************************
2299 * FILEDLG95_SHELL_BrowseToDesktop
2301 * Browse to the Desktop
2302 * If the function succeeds, the return value is nonzero.
2304 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2306 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2312 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2313 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2314 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2315 COMDLG32_SHFree(pidl);
2316 return SUCCEEDED(hres);
2318 /***********************************************************************
2319 * FILEDLG95_SHELL_Clean
2321 * Cleans the memory used by shell objects
2323 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2325 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2329 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2331 /* clean Shell interfaces */
2332 if (fodInfos->Shell.FOIShellView)
2334 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2335 IShellView_Release(fodInfos->Shell.FOIShellView);
2337 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2338 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2339 if (fodInfos->Shell.FOIDataObject)
2340 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2343 /***********************************************************************
2344 * FILEDLG95_FILETYPE_Init
2346 * Initialisation of the file type combo box
2348 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2350 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2351 int nFilters = 0; /* number of filters */
2356 if(fodInfos->customfilter)
2358 /* customfilter has one entry... title\0ext\0
2359 * Set first entry of combo box item with customfilter
2362 LPCWSTR lpstrPos = fodInfos->customfilter;
2365 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2367 /* Copy the extensions */
2368 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2369 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2370 lstrcpyW(lpstrExt,lpstrPos);
2372 /* Add the item at the end of the combo */
2373 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2374 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2377 if(fodInfos->filter)
2379 LPCWSTR lpstrPos = fodInfos->filter;
2383 /* filter is a list... title\0ext\0......\0\0
2384 * Set the combo item text to the title and the item data
2387 LPCWSTR lpstrDisplay;
2391 if(! *lpstrPos) break; /* end */
2392 lpstrDisplay = lpstrPos;
2393 lpstrPos += lstrlenW(lpstrPos) + 1;
2395 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2399 /* Copy the extensions */
2400 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2401 lstrcpyW(lpstrExt,lpstrPos);
2402 lpstrPos += lstrlenW(lpstrPos) + 1;
2404 /* Add the item at the end of the combo */
2405 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2407 /* malformed filters are added anyway... */
2408 if (!*lpstrExt) break;
2413 * Set the current filter to the one specified
2414 * in the initialisation structure
2416 if (fodInfos->filter || fodInfos->customfilter)
2420 /* Check to make sure our index isn't out of bounds. */
2421 if ( fodInfos->ofnInfos->nFilterIndex >
2422 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2423 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2425 /* set default filter index */
2426 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2427 fodInfos->ofnInfos->nFilterIndex = 1;
2429 /* calculate index of Combo Box item */
2430 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2431 if (fodInfos->customfilter == NULL)
2434 /* Set the current index selection. */
2435 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2437 /* Get the corresponding text string from the combo box. */
2438 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2441 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2447 CharLowerW(lpstrFilter); /* lowercase */
2448 len = lstrlenW(lpstrFilter)+1;
2449 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2450 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2453 fodInfos->ofnInfos->nFilterIndex = 0;
2457 /***********************************************************************
2458 * FILEDLG95_FILETYPE_OnCommand
2460 * WM_COMMAND of the file type combo box
2461 * If the function succeeds, the return value is nonzero.
2463 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2465 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2473 /* Get the current item of the filetype combo box */
2474 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2476 /* set the current filter index */
2477 fodInfos->ofnInfos->nFilterIndex = iItem +
2478 (fodInfos->customfilter == NULL ? 1 : 0);
2480 /* Set the current filter with the current selection */
2481 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2483 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2485 if((INT_PTR)lpstrFilter != CB_ERR)
2488 CharLowerW(lpstrFilter); /* lowercase */
2489 len = lstrlenW(lpstrFilter)+1;
2490 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2491 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2492 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2495 /* Refresh the actual view to display the included items*/
2496 if (fodInfos->Shell.FOIShellView)
2497 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2502 /***********************************************************************
2503 * FILEDLG95_FILETYPE_SearchExt
2505 * searches for an extension in the filetype box
2507 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2509 int i, iCount = CBGetCount(hwnd);
2511 TRACE("%s\n", debugstr_w(lpstrExt));
2513 if(iCount != CB_ERR)
2515 for(i=0;i<iCount;i++)
2517 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2524 /***********************************************************************
2525 * FILEDLG95_FILETYPE_Clean
2527 * Clean the memory used by the filetype combo box
2529 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2531 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2533 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2537 /* Delete each string of the combo and their associated data */
2538 if(iCount != CB_ERR)
2540 for(iPos = iCount-1;iPos>=0;iPos--)
2542 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2543 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2546 /* Current filter */
2547 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2551 /***********************************************************************
2552 * FILEDLG95_LOOKIN_Init
2554 * Initialisation of the look in combo box
2557 /* Small helper function, to determine if the unixfs shell extension is rooted
2558 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2560 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2562 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2563 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2564 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2565 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2566 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2567 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2568 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2570 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2577 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2579 IShellFolder *psfRoot, *psfDrives;
2580 IEnumIDList *lpeRoot, *lpeDrives;
2581 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2583 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2587 liInfos->iMaxIndentation = 0;
2589 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2591 /* set item height for both text field and listbox */
2592 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2593 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2595 /* Turn on the extended UI for the combo box like Windows does */
2596 CBSetExtendedUI(hwndCombo, TRUE);
2598 /* Initialise data of Desktop folder */
2599 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2600 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2601 COMDLG32_SHFree(pidlTmp);
2603 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2605 SHGetDesktopFolder(&psfRoot);
2609 /* enumerate the contents of the desktop */
2610 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2612 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2614 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2616 /* If the unixfs extension is rooted, we don't expand the drives by default */
2617 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2619 /* special handling for CSIDL_DRIVES */
2620 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2622 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2624 /* enumerate the drives */
2625 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2627 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2629 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2630 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2631 COMDLG32_SHFree(pidlAbsTmp);
2632 COMDLG32_SHFree(pidlTmp1);
2634 IEnumIDList_Release(lpeDrives);
2636 IShellFolder_Release(psfDrives);
2641 COMDLG32_SHFree(pidlTmp);
2643 IEnumIDList_Release(lpeRoot);
2645 IShellFolder_Release(psfRoot);
2648 COMDLG32_SHFree(pidlDrives);
2651 /***********************************************************************
2652 * FILEDLG95_LOOKIN_DrawItem
2654 * WM_DRAWITEM message handler
2656 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2658 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2659 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2660 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2664 HIMAGELIST ilItemImage;
2667 LPSFOLDER tmpFolder;
2670 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2674 if(pDIStruct->itemID == -1)
2677 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2678 pDIStruct->itemID)))
2682 if(pDIStruct->itemID == liInfos->uSelectedItem)
2684 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2688 SHGFI_PIDL | SHGFI_SMALLICON |
2689 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2690 SHGFI_DISPLAYNAME );
2694 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2698 SHGFI_PIDL | SHGFI_SMALLICON |
2699 SHGFI_SYSICONINDEX |
2703 /* Is this item selected ? */
2704 if(pDIStruct->itemState & ODS_SELECTED)
2706 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2707 SetBkColor(pDIStruct->hDC,crHighLight);
2708 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2712 SetTextColor(pDIStruct->hDC,crText);
2713 SetBkColor(pDIStruct->hDC,crWin);
2714 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2717 /* Do not indent item if drawing in the edit of the combo */
2718 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2721 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2725 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2726 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2731 iIndentation = tmpFolder->m_iIndent;
2733 /* Draw text and icon */
2735 /* Initialise the icon display area */
2736 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2737 rectIcon.top = pDIStruct->rcItem.top;
2738 rectIcon.right = rectIcon.left + ICONWIDTH;
2739 rectIcon.bottom = pDIStruct->rcItem.bottom;
2741 /* Initialise the text display area */
2742 GetTextMetricsW(pDIStruct->hDC, &tm);
2743 rectText.left = rectIcon.right;
2745 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2746 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2748 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2750 /* Draw the icon from the image list */
2751 ImageList_Draw(ilItemImage,
2758 /* Draw the associated text */
2759 if(sfi.szDisplayName)
2760 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2766 /***********************************************************************
2767 * FILEDLG95_LOOKIN_OnCommand
2769 * LookIn combo box WM_COMMAND message handler
2770 * If the function succeeds, the return value is nonzero.
2772 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2774 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2776 TRACE("%p\n", fodInfos);
2782 LPSFOLDER tmpFolder;
2785 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2787 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2792 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2793 tmpFolder->pidlItem,
2796 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2806 /***********************************************************************
2807 * FILEDLG95_LOOKIN_AddItem
2809 * Adds an absolute pidl item to the lookin combo box
2810 * returns the index of the inserted item
2812 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2814 LPITEMIDLIST pidlNext;
2817 LookInInfos *liInfos;
2819 TRACE("%08x\n", iInsertId);
2824 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2827 tmpFolder = MemAlloc(sizeof(SFOLDER));
2828 tmpFolder->m_iIndent = 0;
2830 /* Calculate the indentation of the item in the lookin*/
2832 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2834 tmpFolder->m_iIndent++;
2837 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2839 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2840 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2842 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2843 SHGetFileInfoW((LPCWSTR)pidl,
2847 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2848 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2850 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2852 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2856 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2858 /* Add the item at the end of the list */
2861 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2863 /* Insert the item at the iInsertId position*/
2866 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2869 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2873 COMDLG32_SHFree( tmpFolder->pidlItem );
2874 MemFree( tmpFolder );
2879 /***********************************************************************
2880 * FILEDLG95_LOOKIN_InsertItemAfterParent
2882 * Insert an item below its parent
2884 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2887 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2892 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2896 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2899 /* Free pidlParent memory */
2900 COMDLG32_SHFree((LPVOID)pidlParent);
2902 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2905 /***********************************************************************
2906 * FILEDLG95_LOOKIN_SelectItem
2908 * Adds an absolute pidl item to the lookin combo box
2909 * returns the index of the inserted item
2911 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2914 LookInInfos *liInfos;
2918 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2920 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2924 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2925 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2930 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2931 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2935 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2937 if(iRemovedItem < iItemPos)
2942 CBSetCurSel(hwnd,iItemPos);
2943 liInfos->uSelectedItem = iItemPos;
2949 /***********************************************************************
2950 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2952 * Remove the item with an expansion level over iExpansionLevel
2954 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2958 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2962 if(liInfos->iMaxIndentation <= 2)
2965 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2967 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2968 COMDLG32_SHFree(tmpFolder->pidlItem);
2970 CBDeleteString(hwnd,iItemPos);
2971 liInfos->iMaxIndentation--;
2979 /***********************************************************************
2980 * FILEDLG95_LOOKIN_SearchItem
2982 * Search for pidl in the lookin combo box
2983 * returns the index of the found item
2985 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2988 int iCount = CBGetCount(hwnd);
2990 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
2992 if (iCount != CB_ERR)
2996 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2998 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3000 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3008 /***********************************************************************
3009 * FILEDLG95_LOOKIN_Clean
3011 * Clean the memory used by the lookin combo box
3013 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3015 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3017 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3021 /* Delete each string of the combo and their associated data */
3022 if (iCount != CB_ERR)
3024 for(iPos = iCount-1;iPos>=0;iPos--)
3026 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3027 COMDLG32_SHFree(tmpFolder->pidlItem);
3029 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3033 /* LookInInfos structure */
3034 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3037 /***********************************************************************
3038 * FILEDLG95_FILENAME_FillFromSelection
3040 * fills the edit box from the cached DataObject
3042 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3044 FileOpenDlgInfos *fodInfos;
3046 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3047 WCHAR lpstrTemp[MAX_PATH];
3048 LPWSTR lpstrAllFile, lpstrCurrFile;
3051 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3053 /* Count how many files we have */
3054 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3056 /* calculate the string length, count files */
3057 if (nFileSelected >= 1)
3059 nLength += 3; /* first and last quotes, trailing \0 */
3060 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3062 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3066 /* get the total length of the selected file names */
3067 lpstrTemp[0] = '\0';
3068 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3070 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3072 nLength += lstrlenW( lpstrTemp ) + 3;
3075 COMDLG32_SHFree( pidl );
3080 /* allocate the buffer */
3081 if (nFiles <= 1) nLength = MAX_PATH;
3082 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3084 /* Generate the string for the edit control */
3087 lpstrCurrFile = lpstrAllFile;
3088 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3090 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3094 /* get the file name */
3095 lpstrTemp[0] = '\0';
3096 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3098 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3102 *lpstrCurrFile++ = '\"';
3103 lstrcpyW( lpstrCurrFile, lpstrTemp );
3104 lpstrCurrFile += lstrlenW( lpstrTemp );
3105 *lpstrCurrFile++ = '\"';
3106 *lpstrCurrFile++ = ' ';
3111 lstrcpyW( lpstrAllFile, lpstrTemp );
3114 COMDLG32_SHFree( (LPVOID) pidl );
3117 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3119 /* Select the file name like Windows does */
3120 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3122 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3126 /* copied from shell32 to avoid linking to it
3127 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3128 * is dependent on whether emulated OS is unicode or not.
3130 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3135 lstrcpynW(dest, src->u.pOleStr, len);
3136 COMDLG32_SHFree(src->u.pOleStr);
3140 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3145 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3150 FIXME("unknown type %x!\n", src->uType);
3151 if (len) *dest = '\0';
3157 /***********************************************************************
3158 * FILEDLG95_FILENAME_GetFileNames
3160 * Copies the filenames to a delimited string list.
3161 * The delimiter is specified by the parameter 'separator',
3162 * usually either a space or a nul
3164 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3166 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3167 UINT nStrCharCount = 0; /* index in src buffer */
3168 UINT nFileIndex = 0; /* index in dest buffer */
3169 UINT nFileCount = 0; /* number of files */
3170 UINT nStrLen = 0; /* length of string in edit control */
3171 LPWSTR lpstrEdit; /* buffer for string from edit control */
3175 /* get the filenames from the edit control */
3176 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3177 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3178 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3180 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3182 /* we might get single filename without any '"',
3183 * so we need nStrLen + terminating \0 + end-of-list \0 */
3184 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3187 /* build delimited file list from filenames */
3188 while ( nStrCharCount <= nStrLen )
3190 if ( lpstrEdit[nStrCharCount]=='"' )
3193 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3195 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3198 (*lpstrFileList)[nFileIndex++] = 0;
3204 /* single, unquoted string */
3205 if ((nStrLen > 0) && (nFileIndex == 0) )
3207 lstrcpyW(*lpstrFileList, lpstrEdit);
3208 nFileIndex = lstrlenW(lpstrEdit) + 1;
3213 (*lpstrFileList)[nFileIndex++] = '\0';
3215 *sizeUsed = nFileIndex;
3220 #define SETDefFormatEtc(fe,cf,med) \
3222 (fe).cfFormat = cf;\
3223 (fe).dwAspect = DVASPECT_CONTENT; \
3230 * DATAOBJECT Helper functions
3233 /***********************************************************************
3234 * COMCTL32_ReleaseStgMedium
3236 * like ReleaseStgMedium from ole32
3238 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3240 if(medium.pUnkForRelease)
3242 IUnknown_Release(medium.pUnkForRelease);
3246 GlobalUnlock(medium.u.hGlobal);
3247 GlobalFree(medium.u.hGlobal);
3251 /***********************************************************************
3252 * GetPidlFromDataObject
3254 * Return pidl(s) by number from the cached DataObject
3256 * nPidlIndex=0 gets the fully qualified root path
3258 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3262 FORMATETC formatetc;
3263 LPITEMIDLIST pidl = NULL;
3265 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3270 /* Set the FORMATETC structure*/
3271 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3273 /* Get the pidls from IDataObject */
3274 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3276 LPIDA cida = GlobalLock(medium.u.hGlobal);
3277 if(nPidlIndex <= cida->cidl)
3279 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3281 COMCTL32_ReleaseStgMedium(medium);
3286 /***********************************************************************
3289 * Return the number of selected items in the DataObject.
3292 UINT GetNumSelected( IDataObject *doSelected )
3296 FORMATETC formatetc;
3298 TRACE("sv=%p\n", doSelected);
3300 if (!doSelected) return 0;
3302 /* Set the FORMATETC structure*/
3303 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3305 /* Get the pidls from IDataObject */
3306 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3308 LPIDA cida = GlobalLock(medium.u.hGlobal);
3309 retVal = cida->cidl;
3310 COMCTL32_ReleaseStgMedium(medium);
3320 /***********************************************************************
3323 * Get the pidl's display name (relative to folder) and
3324 * put it in lpstrFileName.
3326 * Return NOERROR on success,
3330 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3335 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3339 SHGetDesktopFolder(&lpsf);
3340 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3341 IShellFolder_Release(lpsf);
3345 /* Get the display name of the pidl relative to the folder */
3346 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3348 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3353 /***********************************************************************
3354 * GetShellFolderFromPidl
3356 * pidlRel is the item pidl relative
3357 * Return the IShellFolder of the absolute pidl
3359 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3361 IShellFolder *psf = NULL,*psfParent;
3363 TRACE("%p\n", pidlAbs);
3365 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3368 if(pidlAbs && pidlAbs->mkid.cb)
3370 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3372 IShellFolder_Release(psfParent);
3376 /* return the desktop */
3382 /***********************************************************************
3385 * Return the LPITEMIDLIST to the parent of the pidl in the list
3387 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3389 LPITEMIDLIST pidlParent;
3391 TRACE("%p\n", pidl);
3393 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3394 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3399 /***********************************************************************
3402 * returns the pidl of the file name relative to folder
3403 * NULL if an error occurred
3405 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3407 LPITEMIDLIST pidl = NULL;
3410 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3412 if(!lpcstrFileName) return NULL;
3413 if(!*lpcstrFileName) return NULL;
3417 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3418 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3419 IShellFolder_Release(lpsf);
3424 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3431 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3433 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3436 TRACE("%p, %p\n", psf, pidl);
3438 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3440 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3441 /* see documentation shell 4.1*/
3442 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3445 /***********************************************************************
3446 * BrowseSelectedFolder
3448 static BOOL BrowseSelectedFolder(HWND hwnd)
3450 BOOL bBrowseSelFolder = FALSE;
3451 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3455 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3457 LPITEMIDLIST pidlSelection;
3459 /* get the file selected */
3460 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3461 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3463 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3464 pidlSelection, SBSP_RELATIVE ) ) )
3466 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3467 ' ','n','o','t',' ','e','x','i','s','t',0};
3468 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3470 bBrowseSelFolder = TRUE;
3471 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3473 COMDLG32_SHFree( pidlSelection );
3476 return bBrowseSelFolder;
3480 * Memory allocation methods */
3481 static void *MemAlloc(UINT size)
3483 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3486 static void MemFree(void *mem)
3488 HeapFree(GetProcessHeap(),0,mem);
3492 * Old-style (win3.1) dialogs */
3494 /***********************************************************************
3495 * FD32_GetTemplate [internal]
3497 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3498 * by a 32 bits application
3501 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3503 LPOPENFILENAMEW ofnW = lfs->ofnW;
3504 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3507 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3509 if (!(lfs->template = LockResource( ofnW->hInstance )))
3511 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3515 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3519 hResInfo = FindResourceA(priv->ofnA->hInstance,
3520 priv->ofnA->lpTemplateName,
3523 hResInfo = FindResourceW(ofnW->hInstance,
3524 ofnW->lpTemplateName,
3528 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3531 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3533 !(lfs->template = LockResource(hDlgTmpl)))
3535 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3538 } else { /* get it from internal Wine resource */
3540 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3541 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3543 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3546 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3547 !(lfs->template = LockResource( hDlgTmpl )))
3549 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3557 /************************************************************************
3558 * FD32_Init [internal]
3559 * called from the common 16/32 code to initialize 32 bit data
3561 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3563 BOOL IsUnicode = (BOOL) data;
3566 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3567 lfs->private1632 = priv;
3568 if (NULL == lfs->private1632) return FALSE;
3571 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3572 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3573 if (lfs->ofnW->lpfnHook)
3578 priv->ofnA = (LPOPENFILENAMEA) lParam;
3579 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3580 if (priv->ofnA->lpfnHook)
3582 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3583 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3586 if (! FD32_GetTemplate(lfs)) return FALSE;
3591 /***********************************************************************
3592 * FD32_CallWindowProc [internal]
3594 * called from the common 16/32 code to call the appropriate hook
3596 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3600 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3604 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3605 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3606 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3607 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3608 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3612 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3613 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3614 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3615 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3616 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3620 /***********************************************************************
3621 * FD32_UpdateResult [internal]
3622 * update the real client structures if any
3624 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3626 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3627 LPOPENFILENAMEW ofnW = lfs->ofnW;
3632 if (ofnW->nMaxFile &&
3633 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3634 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3635 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3637 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3638 /* set filename offset */
3639 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3640 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3642 /* set extension offset */
3643 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3644 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3648 /***********************************************************************
3649 * FD32_UpdateFileTitle [internal]
3650 * update the real client structures if any
3652 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3654 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3655 LPOPENFILENAMEW ofnW = lfs->ofnW;
3659 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3660 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3661 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3666 /***********************************************************************
3667 * FD32_SendLbGetCurSel [internal]
3668 * retrieve selected listbox item
3670 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3672 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3676 /************************************************************************
3677 * FD32_Destroy [internal]
3678 * called from the common 16/32 code to cleanup 32 bit data
3680 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3682 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3684 /* if ofnW has been allocated, have to free everything in it */
3685 if (NULL != priv && NULL != priv->ofnA)
3687 FD31_FreeOfnW(lfs->ofnW);
3688 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3692 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3694 callbacks->Init = FD32_Init;
3695 callbacks->CWP = FD32_CallWindowProc;
3696 callbacks->UpdateResult = FD32_UpdateResult;
3697 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3698 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3699 callbacks->Destroy = FD32_Destroy;
3702 /***********************************************************************
3703 * FD32_WMMeasureItem [internal]
3705 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3707 LPMEASUREITEMSTRUCT lpmeasure;
3709 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3710 lpmeasure->itemHeight = FD31_GetFldrHeight();
3715 /***********************************************************************
3716 * FileOpenDlgProc [internal]
3717 * Used for open and save, in fact.
3719 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3720 WPARAM wParam, LPARAM lParam)
3722 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3724 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3725 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3728 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3730 return lRet; /* else continue message processing */
3735 return FD31_WMInitDialog(hWnd, wParam, lParam);
3737 case WM_MEASUREITEM:
3738 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3741 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3744 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3747 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3748 switch (HIWORD(lParam))
3751 SetTextColor((HDC16)wParam, 0x00000000);
3753 case CTLCOLOR_STATIC:
3754 SetTextColor((HDC16)wParam, 0x00000000);
3764 /***********************************************************************
3765 * GetFileName31A [internal]
3767 * Creates a win31 style dialog box for the user to select a file to open/save.
3769 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3770 UINT dlgType /* type dialogue : open/save */
3776 FD31_CALLBACKS callbacks;
3778 if (!lpofn || !FD31_Init()) return FALSE;
3780 TRACE("ofn flags %08x\n", lpofn->Flags);
3781 FD32_SetupCallbacks(&callbacks);
3782 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3785 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3786 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3787 FD32_FileOpenDlgProc, (LPARAM)lfs);
3788 FD31_DestroyPrivate(lfs);
3791 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3795 /***********************************************************************
3796 * GetFileName31W [internal]
3798 * Creates a win31 style dialog box for the user to select a file to open/save
3800 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3801 UINT dlgType /* type dialogue : open/save */
3807 FD31_CALLBACKS callbacks;
3809 if (!lpofn || !FD31_Init()) return FALSE;
3811 FD32_SetupCallbacks(&callbacks);
3812 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3815 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3816 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3817 FD32_FileOpenDlgProc, (LPARAM)lfs);
3818 FD31_DestroyPrivate(lfs);
3821 TRACE("file %s, file offset %d, ext offset %d\n",
3822 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3826 /* ------------------ APIs ---------------------- */
3828 /***********************************************************************
3829 * GetOpenFileNameA (COMDLG32.@)
3831 * Creates a dialog box for the user to select a file to open.
3834 * TRUE on success: user enters a valid file
3835 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3838 BOOL WINAPI GetOpenFileNameA(
3839 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3841 BOOL win16look = FALSE;
3843 TRACE("flags %08x\n", ofn->Flags);
3845 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3846 if (ofn->Flags & OFN_FILEMUSTEXIST)
3847 ofn->Flags |= OFN_PATHMUSTEXIST;
3849 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3850 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3853 return GetFileName31A(ofn, OPEN_DIALOG);
3855 return GetFileDialog95A(ofn, OPEN_DIALOG);
3858 /***********************************************************************
3859 * GetOpenFileNameW (COMDLG32.@)
3861 * Creates a dialog box for the user to select a file to open.
3864 * TRUE on success: user enters a valid file
3865 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3868 BOOL WINAPI GetOpenFileNameW(
3869 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3871 BOOL win16look = FALSE;
3873 TRACE("flags %08x\n", ofn->Flags);
3875 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3876 if (ofn->Flags & OFN_FILEMUSTEXIST)
3877 ofn->Flags |= OFN_PATHMUSTEXIST;
3879 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3880 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3883 return GetFileName31W(ofn, OPEN_DIALOG);
3885 return GetFileDialog95W(ofn, OPEN_DIALOG);
3889 /***********************************************************************
3890 * GetSaveFileNameA (COMDLG32.@)
3892 * Creates a dialog box for the user to select a file to save.
3895 * TRUE on success: user enters a valid file
3896 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3899 BOOL WINAPI GetSaveFileNameA(
3900 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3902 BOOL win16look = FALSE;
3904 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3905 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3908 return GetFileName31A(ofn, SAVE_DIALOG);
3910 return GetFileDialog95A(ofn, SAVE_DIALOG);
3913 /***********************************************************************
3914 * GetSaveFileNameW (COMDLG32.@)
3916 * Creates a dialog box for the user to select a file to save.
3919 * TRUE on success: user enters a valid file
3920 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3923 BOOL WINAPI GetSaveFileNameW(
3924 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3926 BOOL win16look = FALSE;
3928 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3929 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3932 return GetFileName31W(ofn, SAVE_DIALOG);
3934 return GetFileDialog95W(ofn, SAVE_DIALOG);
3937 /***********************************************************************
3938 * GetFileTitleA (COMDLG32.@)
3940 * See GetFileTitleW.
3942 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3945 UNICODE_STRING strWFile;
3948 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3949 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3950 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3951 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3952 RtlFreeUnicodeString( &strWFile );
3953 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3958 /***********************************************************************
3959 * GetFileTitleW (COMDLG32.@)
3961 * Get the name of a file.
3964 * lpFile [I] name and location of file
3965 * lpTitle [O] returned file name
3966 * cbBuf [I] buffer size of lpTitle
3970 * Failure: negative number.
3972 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3975 static const WCHAR brkpoint[] = {'*','[',']',0};
3976 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3978 if(lpFile == NULL || lpTitle == NULL)
3981 len = lstrlenW(lpFile);
3986 if(strpbrkW(lpFile, brkpoint))
3991 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3994 for(i = len; i >= 0; i--)
3996 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4006 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4008 len = lstrlenW(lpFile+i)+1;
4012 lstrcpyW(lpTitle, &lpFile[i]);