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_CREATEPROMPT, 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
67 #include "wine/unicode.h"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
80 #include "filedlgbrowser.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
123 #define XTEXTOFFSET 3
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
179 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
185 /* Internal functions used by the dialog */
186 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
189 BOOL FILEDLG95_OnOpen(HWND hwnd);
190 static LRESULT FILEDLG95_InitControls(HWND hwnd);
191 static void FILEDLG95_Clean(HWND hwnd);
193 /* Functions used by the shell navigation */
194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
203 /* Functions used by the filetype combo box */
204 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
205 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
211 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
212 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
220 /* Miscellaneous tool functions */
221 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
222 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
223 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
224 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
230 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
232 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
233 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
234 static BOOL BrowseSelectedFolder(HWND hwnd);
236 /***********************************************************************
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
255 /* test for missing functionality */
256 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
258 FIXME("Flags 0x%08lx not yet implemented\n",
259 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
262 /* Create the dialog from a template */
264 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
269 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
270 !(template = LockResource( hDlgTmpl )))
272 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
288 if (fodInfos->unicode)
289 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
291 fodInfos->ofnInfos->hwndOwner,
295 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
296 (LPDLGTEMPLATEA) template,
297 fodInfos->ofnInfos->hwndOwner,
303 /* Unable to create the dialog */
310 /***********************************************************************
313 * Call GetFileName95 with this structure and clean the memory.
315 * IN : The OPENFILENAMEA initialisation structure passed to
316 * GetOpenFileNameA win api function (see filedlg.c)
318 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
321 FileOpenDlgInfos fodInfos;
322 LPSTR lpstrSavDir = NULL;
324 LPWSTR defext = NULL;
325 LPWSTR filter = NULL;
326 LPWSTR customfilter = NULL;
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);
440 MemFree(customfilter);
442 MemFree(fodInfos.initdir);
444 if(fodInfos.filename)
445 MemFree(fodInfos.filename);
447 TRACE("selected file: %s\n",ofn->lpstrFile);
452 /***********************************************************************
455 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
456 * Call GetFileName95 with this structure and clean the memory.
459 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
462 FileOpenDlgInfos fodInfos;
463 LPWSTR lpstrSavDir = NULL;
465 /* Initialize FileOpenDlgInfos structure */
466 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
468 /* Pass in the original ofn */
469 fodInfos.ofnInfos = ofn;
471 fodInfos.title = ofn->lpstrTitle;
472 fodInfos.defext = ofn->lpstrDefExt;
473 fodInfos.filter = ofn->lpstrFilter;
474 fodInfos.customfilter = ofn->lpstrCustomFilter;
476 /* convert string arguments, save others */
479 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
480 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
483 fodInfos.filename = NULL;
485 if(ofn->lpstrInitialDir)
487 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
488 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
489 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
490 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
493 fodInfos.initdir = NULL;
495 /* save current directory */
496 if (ofn->Flags & OFN_NOCHANGEDIR)
498 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
499 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
502 fodInfos.unicode = TRUE;
507 ret = GetFileName95(&fodInfos);
510 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
511 ret = GetFileName95(&fodInfos);
519 SetCurrentDirectoryW(lpstrSavDir);
520 MemFree(lpstrSavDir);
523 /* restore saved IN arguments and convert OUT arguments back */
524 MemFree(fodInfos.filename);
525 MemFree(fodInfos.initdir);
529 /******************************************************************************
530 * COMDLG32_GetDisplayNameOf [internal]
532 * Helper function to get the display name for a pidl.
534 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
535 LPSHELLFOLDER psfDesktop;
538 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
541 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
542 IShellFolder_Release(psfDesktop);
546 IShellFolder_Release(psfDesktop);
547 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
550 /***********************************************************************
551 * ArrangeCtrlPositions [internal]
553 * NOTE: Do not change anything here without a lot of testing.
555 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
557 HWND hwndChild, hwndStc32;
558 RECT rectParent, rectChild, rectStc32;
559 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
561 /* Take into account if open as read only checkbox and help button
566 RECT rectHelp, rectCancel;
567 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
568 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
569 /* subtract the height of the help button plus the space between
570 * the help button and the cancel button to the height of the dialog
572 help_fixup = rectHelp.bottom - rectCancel.bottom;
576 There are two possibilities to add components to the default file dialog box.
578 By default, all the new components are added below the standard dialog box (the else case).
580 However, if there is a static text component with the stc32 id, a special case happens.
581 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
582 in the window and the cx and cy indicate how to size the window.
583 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
584 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
588 GetClientRect(hwndParentDlg, &rectParent);
590 /* when arranging controls we have to use fixed parent size */
591 rectParent.bottom -= help_fixup;
593 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
596 GetWindowRect(hwndStc32, &rectStc32);
597 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
599 /* set the size of the stc32 control according to the size of
600 * client area of the parent dialog
602 SetWindowPos(hwndStc32, 0,
604 rectParent.right, rectParent.bottom,
605 SWP_NOMOVE | SWP_NOZORDER);
608 SetRectEmpty(&rectStc32);
610 /* this part moves controls of the child dialog */
611 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
614 if (hwndChild != hwndStc32)
616 GetWindowRect(hwndChild, &rectChild);
617 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
619 /* move only if stc32 exist */
620 if (hwndStc32 && rectChild.left > rectStc32.right)
622 LONG old_left = rectChild.left;
624 /* move to the right of visible controls of the parent dialog */
625 rectChild.left += rectParent.right;
626 rectChild.left -= rectStc32.right;
628 child_width_fixup = rectChild.left - old_left;
630 /* move even if stc32 doesn't exist */
631 if (rectChild.top >= rectStc32.bottom)
633 LONG old_top = rectChild.top;
635 /* move below visible controls of the parent dialog */
636 rectChild.top += rectParent.bottom;
637 rectChild.top -= rectStc32.bottom - rectStc32.top;
639 child_height_fixup = rectChild.top - old_top;
642 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
643 0, 0, SWP_NOSIZE | SWP_NOZORDER);
645 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
648 /* this part moves controls of the parent dialog */
649 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
652 if (hwndChild != hwndChildDlg)
654 GetWindowRect(hwndChild, &rectChild);
655 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
657 /* left,top of stc32 marks the position of controls
658 * from the parent dialog
660 rectChild.left += rectStc32.left;
661 rectChild.top += rectStc32.top;
663 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
664 0, 0, SWP_NOSIZE | SWP_NOZORDER);
666 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
669 /* calculate the size of the resulting dialog */
671 /* here we have to use original parent size */
672 GetClientRect(hwndParentDlg, &rectParent);
673 GetClientRect(hwndChildDlg, &rectChild);
677 rectChild.right += child_width_fixup;
678 rectChild.bottom += child_height_fixup;
680 if (rectParent.right > rectChild.right)
682 rectParent.right += rectChild.right;
683 rectParent.right -= rectStc32.right - rectStc32.left;
687 rectParent.right = rectChild.right;
690 if (rectParent.bottom > rectChild.bottom)
692 rectParent.bottom += rectChild.bottom;
693 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
697 /* child dialog is higher, unconditionally set new dialog
698 * height to its size (help_fixup will be subtracted below)
700 rectParent.bottom = rectChild.bottom + help_fixup;
705 rectParent.bottom += rectChild.bottom;
708 /* finally use fixed parent size */
709 rectParent.bottom -= help_fixup;
711 /* set the size of the parent dialog */
712 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
713 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
714 SetWindowPos(hwndParentDlg, 0,
716 rectParent.right - rectParent.left,
717 rectParent.bottom - rectParent.top,
718 SWP_NOMOVE | SWP_NOZORDER);
721 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
730 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
740 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
741 * structure's hInstance parameter is not a HINSTANCE, but
742 * instead a pointer to a template resource to use.
744 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
747 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
749 hinst = COMDLG32_hInstance;
750 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
752 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
758 hinst = fodInfos->ofnInfos->hInstance;
759 if(fodInfos->unicode)
761 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
762 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
766 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
767 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
771 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
774 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
775 !(template = LockResource( hDlgTmpl )))
777 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
781 if (fodInfos->unicode)
782 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
783 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
784 (LPARAM)fodInfos->ofnInfos);
786 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
787 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
788 (LPARAM)fodInfos->ofnInfos);
791 ShowWindow(hChildDlg,SW_SHOW);
795 else if( IsHooked(fodInfos))
800 WORD menu,class,title;
802 GetClientRect(hwnd,&rectHwnd);
803 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
804 temp.tmplate.dwExtendedStyle = 0;
805 temp.tmplate.cdit = 0;
810 temp.menu = temp.class = temp.title = 0;
812 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
813 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
820 /***********************************************************************
821 * SendCustomDlgNotificationMessage
823 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
826 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
828 LRESULT hook_result = 0;
830 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
832 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
834 if(!fodInfos) return 0;
836 if(fodInfos->DlgInfos.hwndCustomDlg)
838 TRACE("CALL NOTIFY for %x\n", uCode);
839 if(fodInfos->unicode)
842 ofnNotify.hdr.hwndFrom=hwndParentDlg;
843 ofnNotify.hdr.idFrom=0;
844 ofnNotify.hdr.code = uCode;
845 ofnNotify.lpOFN = fodInfos->ofnInfos;
846 ofnNotify.pszFile = NULL;
847 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
852 ofnNotify.hdr.hwndFrom=hwndParentDlg;
853 ofnNotify.hdr.idFrom=0;
854 ofnNotify.hdr.code = uCode;
855 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
856 ofnNotify.pszFile = NULL;
857 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
859 TRACE("RET NOTIFY\n");
861 TRACE("Retval: 0x%08lx\n", hook_result);
865 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
867 UINT sizeUsed = 0, n, total;
868 LPWSTR lpstrFileList = NULL;
869 WCHAR lpstrCurrentDir[MAX_PATH];
870 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
872 TRACE("CDM_GETFILEPATH:\n");
874 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
877 /* get path and filenames */
878 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
879 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
881 TRACE("path >%s< filespec >%s< %d files\n",
882 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
884 if( fodInfos->unicode )
886 LPWSTR bufW = buffer;
887 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
889 /* Prepend the current path */
890 n = strlenW(lpstrCurrentDir) + 1;
891 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
894 /* 'n' includes trailing \0 */
896 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
898 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
903 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
904 NULL, 0, NULL, NULL);
905 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
906 NULL, 0, NULL, NULL);
908 /* Prepend the current path */
909 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
910 bufA, size, NULL, NULL);
914 /* 'n' includes trailing \0 */
916 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
917 &bufA[n], size-n, NULL, NULL);
920 TRACE("returned -> %s\n",debugstr_an(bufA, total));
922 MemFree(lpstrFileList);
927 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
930 LPWSTR lpstrFileList = NULL;
931 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
933 TRACE("CDM_GETSPEC:\n");
935 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
936 if( fodInfos->unicode )
938 LPWSTR bufW = buffer;
939 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
944 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
945 NULL, 0, NULL, NULL);
946 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
947 bufA, size, NULL, NULL);
949 MemFree(lpstrFileList);
954 /***********************************************************************
955 * FILEDLG95_HandleCustomDialogMessages
957 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
959 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
961 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
962 WCHAR lpstrPath[MAX_PATH];
965 if(!fodInfos) return FALSE;
969 case CDM_GETFILEPATH:
970 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
973 case CDM_GETFOLDERPATH:
974 TRACE("CDM_GETFOLDERPATH:\n");
975 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
978 if (fodInfos->unicode)
979 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
981 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
982 (LPSTR)lParam, (int)wParam, NULL, NULL);
984 retval = strlenW(lpstrPath);
988 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
991 case CDM_SETCONTROLTEXT:
992 TRACE("CDM_SETCONTROLTEXT:\n");
995 if( fodInfos->unicode )
996 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
998 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
1003 case CDM_HIDECONTROL:
1004 /* MSDN states that it should fail for not OFN_EXPLORER case */
1005 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1007 HWND control = GetDlgItem( hwnd, wParam );
1008 if (control) ShowWindow( control, SW_HIDE );
1011 else retval = FALSE;
1015 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1016 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1019 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1023 /***********************************************************************
1026 * File open dialog procedure
1028 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1031 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1038 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1040 /* Adds the FileOpenDlgInfos in the property list of the dialog
1041 so it will be easily accessible through a GetPropA(...) */
1042 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1044 fodInfos->DlgInfos.hwndCustomDlg =
1045 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1047 FILEDLG95_InitControls(hwnd);
1049 if (fodInfos->DlgInfos.hwndCustomDlg)
1052 UINT flags = SWP_NOACTIVATE;
1054 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1055 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1057 /* resize the custom dialog to the parent size */
1058 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1059 GetClientRect(hwnd, &rc);
1062 /* our own fake template is zero sized and doesn't have
1063 * children, so there is no need to resize it.
1064 * Picasa depends on it.
1066 flags |= SWP_NOSIZE;
1069 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1070 0, 0, rc.right, rc.bottom, flags);
1073 FILEDLG95_FillControls(hwnd, wParam, lParam);
1075 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1076 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1077 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1081 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1084 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1087 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1093 case WM_GETISHELLBROWSER:
1094 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1097 RemovePropA(hwnd, FileOpenDlgInfosStr);
1102 LPNMHDR lpnmh = (LPNMHDR)lParam;
1105 /* set up the button tooltips strings */
1106 if(TTN_GETDISPINFOA == lpnmh->code )
1108 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1109 switch(lpnmh->idFrom )
1111 /* Up folder button */
1112 case FCIDM_TB_UPFOLDER:
1113 stringId = IDS_UPFOLDER;
1115 /* New folder button */
1116 case FCIDM_TB_NEWFOLDER:
1117 stringId = IDS_NEWFOLDER;
1119 /* List option button */
1120 case FCIDM_TB_SMALLICON:
1121 stringId = IDS_LISTVIEW;
1123 /* Details option button */
1124 case FCIDM_TB_REPORTVIEW:
1125 stringId = IDS_REPORTVIEW;
1127 /* Desktop button */
1128 case FCIDM_TB_DESKTOP:
1129 stringId = IDS_TODESKTOP;
1134 lpdi->hinst = COMDLG32_hInstance;
1135 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1140 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1141 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1146 /***********************************************************************
1147 * FILEDLG95_InitControls
1149 * WM_INITDIALOG message handler (before hook notification)
1151 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1153 int win2000plus = 0;
1155 int handledPath = FALSE;
1156 OSVERSIONINFOA osVi;
1157 static const WCHAR szwSlash[] = { '\\', 0 };
1158 static const WCHAR szwStar[] = { '*',0 };
1162 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1163 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1164 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1165 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1166 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1167 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1168 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1169 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1170 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1175 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1177 tba[0].hInst = HINST_COMMCTRL;
1178 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1179 tba[1].hInst = COMDLG32_hInstance;
1182 TRACE("%p\n", fodInfos);
1184 /* Get windows version emulating */
1185 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1186 GetVersionExA(&osVi);
1187 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1188 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1189 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1190 win2000plus = (osVi.dwMajorVersion > 4);
1191 if (win2000plus) win98plus = TRUE;
1193 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1195 /* Get the hwnd of the controls */
1196 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1197 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1198 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1200 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1201 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1203 /* construct the toolbar */
1204 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1205 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1207 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1208 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1209 rectTB.left = rectlook.right;
1210 rectTB.top = rectlook.top-1;
1212 if (fodInfos->unicode)
1213 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1214 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1215 rectTB.left, rectTB.top,
1216 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1217 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1219 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1220 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1221 rectTB.left, rectTB.top,
1222 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1223 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1225 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1227 /* FIXME: use TB_LOADIMAGES when implemented */
1228 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1229 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1230 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1232 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1233 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1235 /* Set the window text with the text specified in the OPENFILENAME structure */
1238 SetWindowTextW(hwnd,fodInfos->title);
1240 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1243 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1244 SetWindowTextW(hwnd, buf);
1247 /* Initialise the file name edit control */
1248 handledPath = FALSE;
1249 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1251 if(fodInfos->filename)
1253 /* 1. If win2000 or higher and filename contains a path, use it
1254 in preference over the lpstrInitialDir */
1255 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1256 WCHAR tmpBuf[MAX_PATH];
1260 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1263 /* nameBit is always shorter than the original filename */
1264 strcpyW(fodInfos->filename,nameBit);
1267 if (fodInfos->initdir == NULL)
1268 MemFree(fodInfos->initdir);
1269 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1270 strcpyW(fodInfos->initdir, tmpBuf);
1272 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1273 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1275 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1278 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1282 /* 2. (All platforms) If initdir is not null, then use it */
1283 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1284 (*fodInfos->initdir!=0x00))
1286 /* Work out the proper path as supplied one might be relative */
1287 /* (Here because supplying '.' as dir browses to My Computer) */
1288 if (handledPath==FALSE) {
1289 WCHAR tmpBuf[MAX_PATH];
1290 WCHAR tmpBuf2[MAX_PATH];
1294 strcpyW(tmpBuf, fodInfos->initdir);
1295 if( PathFileExistsW(tmpBuf) ) {
1296 /* initdir does not have to be a directory. If a file is
1297 * specified, the dir part is taken */
1298 if( PathIsDirectoryW(tmpBuf)) {
1299 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1300 strcatW(tmpBuf, szwSlash);
1302 strcatW(tmpBuf, szwStar);
1304 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1307 if (fodInfos->initdir)
1308 MemFree(fodInfos->initdir);
1309 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1310 strcpyW(fodInfos->initdir, tmpBuf2);
1312 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1315 else if (fodInfos->initdir)
1317 MemFree(fodInfos->initdir);
1318 fodInfos->initdir = NULL;
1319 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1324 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1325 (*fodInfos->initdir==0x00)))
1327 /* 3. All except w2k+: if filename contains a path use it */
1328 if (!win2000plus && fodInfos->filename &&
1329 *fodInfos->filename &&
1330 strpbrkW(fodInfos->filename, szwSlash)) {
1331 WCHAR tmpBuf[MAX_PATH];
1335 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1340 /* nameBit is always shorter than the original filename */
1341 strcpyW(fodInfos->filename, nameBit);
1344 len = strlenW(tmpBuf);
1345 if(fodInfos->initdir)
1346 MemFree(fodInfos->initdir);
1347 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1348 strcpyW(fodInfos->initdir, tmpBuf);
1351 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1352 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1354 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1357 /* 4. win98+ and win2000+ if any files of specified filter types in
1358 current directory, use it */
1359 if ( win98plus && handledPath == FALSE &&
1360 fodInfos->filter && *fodInfos->filter) {
1362 BOOL searchMore = TRUE;
1363 LPCWSTR lpstrPos = fodInfos->filter;
1364 WIN32_FIND_DATAW FindFileData;
1369 /* filter is a list... title\0ext\0......\0\0 */
1371 /* Skip the title */
1372 if(! *lpstrPos) break; /* end */
1373 lpstrPos += strlenW(lpstrPos) + 1;
1375 /* See if any files exist in the current dir with this extension */
1376 if(! *lpstrPos) break; /* end */
1378 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1380 if (hFind == INVALID_HANDLE_VALUE) {
1381 /* None found - continue search */
1382 lpstrPos += strlenW(lpstrPos) + 1;
1387 if(fodInfos->initdir)
1388 MemFree(fodInfos->initdir);
1389 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1390 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1393 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1394 debugstr_w(lpstrPos));
1400 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1402 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1403 if (handledPath == FALSE && (win2000plus || win98plus)) {
1404 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1406 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1408 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1411 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1412 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1414 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1417 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1420 } else if (handledPath==FALSE) {
1421 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1422 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1424 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1427 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1428 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1430 /* Must the open as read only check box be checked ?*/
1431 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1433 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1436 /* Must the open as read only check box be hidden? */
1437 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1439 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1440 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1443 /* Must the help button be hidden? */
1444 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1446 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1447 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1450 /* Resize the height, if open as read only checkbox ad help button
1451 are hidden and we are not using a custom template nor a customDialog
1453 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1454 (!(fodInfos->ofnInfos->Flags &
1455 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1456 (!fodInfos->DlgInfos.hwndCustomDlg ))
1458 RECT rectDlg, rectHelp, rectCancel;
1459 GetWindowRect(hwnd, &rectDlg);
1460 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1461 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1462 /* subtract the height of the help button plus the space between
1463 the help button and the cancel button to the height of the dialog */
1464 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1465 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1466 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1468 /* change Open to Save */
1469 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1472 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1473 SetDlgItemTextW(hwnd, IDOK, buf);
1474 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1475 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1480 /***********************************************************************
1481 * FILEDLG95_FillControls
1483 * WM_INITDIALOG message handler (after hook notification)
1485 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1487 LPITEMIDLIST pidlItemId = NULL;
1489 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1491 TRACE("dir=%s file=%s\n",
1492 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1494 /* Get the initial directory pidl */
1496 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1498 WCHAR path[MAX_PATH];
1500 GetCurrentDirectoryW(MAX_PATH,path);
1501 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1504 /* Initialise shell objects */
1505 FILEDLG95_SHELL_Init(hwnd);
1507 /* Initialize the Look In combo box */
1508 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1510 /* Initialize the filter combo box */
1511 FILEDLG95_FILETYPE_Init(hwnd);
1513 /* Browse to the initial directory */
1514 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1516 /* Free pidlItem memory */
1517 COMDLG32_SHFree(pidlItemId);
1521 /***********************************************************************
1524 * Regroups all the cleaning functions of the filedlg
1526 void FILEDLG95_Clean(HWND hwnd)
1528 FILEDLG95_FILETYPE_Clean(hwnd);
1529 FILEDLG95_LOOKIN_Clean(hwnd);
1530 FILEDLG95_SHELL_Clean(hwnd);
1532 /***********************************************************************
1533 * FILEDLG95_OnWMCommand
1535 * WM_COMMAND message handler
1537 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1539 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1540 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1541 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1547 FILEDLG95_OnOpen(hwnd);
1551 FILEDLG95_Clean(hwnd);
1552 EndDialog(hwnd, FALSE);
1554 /* Filetype combo box */
1556 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1558 /* LookIn combo box */
1560 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1563 /* --- toolbar --- */
1564 /* Up folder button */
1565 case FCIDM_TB_UPFOLDER:
1566 FILEDLG95_SHELL_UpFolder(hwnd);
1568 /* New folder button */
1569 case FCIDM_TB_NEWFOLDER:
1570 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1572 /* List option button */
1573 case FCIDM_TB_SMALLICON:
1574 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1576 /* Details option button */
1577 case FCIDM_TB_REPORTVIEW:
1578 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1580 /* Details option button */
1581 case FCIDM_TB_DESKTOP:
1582 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1589 /* Do not use the listview selection anymore */
1590 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1594 /***********************************************************************
1595 * FILEDLG95_OnWMGetIShellBrowser
1597 * WM_GETISHELLBROWSER message handler
1599 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1602 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1606 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1612 /***********************************************************************
1613 * FILEDLG95_SendFileOK
1615 * Sends the CDN_FILEOK notification if required
1618 * TRUE if the dialog should close
1619 * FALSE if the dialog should not be closed
1621 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1623 /* ask the hook if we can close */
1624 if(IsHooked(fodInfos))
1629 /* First send CDN_FILEOK as MSDN doc says */
1630 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1631 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1633 TRACE("canceled\n");
1634 return (retval == 0);
1637 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1638 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1639 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1640 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1642 TRACE("canceled\n");
1643 return (retval == 0);
1649 /***********************************************************************
1650 * FILEDLG95_OnOpenMultipleFiles
1652 * Handles the opening of multiple files.
1655 * check destination buffer size
1657 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1659 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1660 UINT nCount, nSizePath;
1661 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1665 if(fodInfos->unicode)
1667 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1668 ofn->lpstrFile[0] = '\0';
1672 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1673 ofn->lpstrFile[0] = '\0';
1676 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1678 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1679 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1680 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1682 LPWSTR lpstrTemp = lpstrFileList;
1684 for ( nCount = 0; nCount < nFileCount; nCount++ )
1688 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1691 WCHAR lpstrNotFound[100];
1692 WCHAR lpstrMsg[100];
1694 static const WCHAR nl[] = {'\n',0};
1696 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1697 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1699 strcpyW(tmp, lpstrTemp);
1701 strcatW(tmp, lpstrNotFound);
1703 strcatW(tmp, lpstrMsg);
1705 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1709 /* move to the next file in the list of files */
1710 lpstrTemp += strlenW(lpstrTemp) + 1;
1711 COMDLG32_SHFree(pidl);
1715 nSizePath = strlenW(lpstrPathSpec) + 1;
1716 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1718 /* For "oldstyle" dialog the components have to
1719 be separated by blanks (not '\0'!) and short
1720 filenames have to be used! */
1721 FIXME("Components have to be separated by blanks\n");
1723 if(fodInfos->unicode)
1725 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1726 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1727 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1731 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1733 if (ofn->lpstrFile != NULL)
1735 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1736 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1737 if (ofn->nMaxFile > nSizePath)
1739 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1740 ofn->lpstrFile + nSizePath,
1741 ofn->nMaxFile - nSizePath, NULL, NULL);
1746 fodInfos->ofnInfos->nFileOffset = nSizePath;
1747 fodInfos->ofnInfos->nFileExtension = 0;
1749 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1752 /* clean and exit */
1753 FILEDLG95_Clean(hwnd);
1754 return EndDialog(hwnd,TRUE);
1757 /***********************************************************************
1760 * Ok button WM_COMMAND message handler
1762 * If the function succeeds, the return value is nonzero.
1764 #define ONOPEN_BROWSE 1
1765 #define ONOPEN_OPEN 2
1766 #define ONOPEN_SEARCH 3
1767 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1769 WCHAR strMsgTitle[MAX_PATH];
1770 WCHAR strMsgText [MAX_PATH];
1772 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1774 strMsgTitle[0] = '\0';
1775 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1776 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1779 BOOL FILEDLG95_OnOpen(HWND hwnd)
1781 LPWSTR lpstrFileList;
1782 UINT nFileCount = 0;
1785 WCHAR lpstrPathAndFile[MAX_PATH];
1786 WCHAR lpstrTemp[MAX_PATH];
1787 LPSHELLFOLDER lpsf = NULL;
1789 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1791 TRACE("hwnd=%p\n", hwnd);
1793 /* get the files from the edit control */
1794 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1796 /* try if the user selected a folder in the shellview */
1799 BrowseSelectedFolder(hwnd);
1805 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1809 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1812 Step 1: Build a complete path name from the current folder and
1813 the filename or path in the edit box.
1815 - the path in the edit box is a root path
1816 (with or without drive letter)
1817 - the edit box contains ".." (or a path with ".." in it)
1820 /* Get the current directory name */
1821 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1824 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1826 PathAddBackslashW(lpstrPathAndFile);
1828 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1830 /* if the user specifyed a fully qualified path use it */
1831 if(PathIsRelativeW(lpstrFileList))
1833 strcatW(lpstrPathAndFile, lpstrFileList);
1837 /* does the path have a drive letter? */
1838 if (PathGetDriveNumberW(lpstrFileList) == -1)
1839 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1841 strcpyW(lpstrPathAndFile, lpstrFileList);
1844 /* resolve "." and ".." */
1845 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1846 strcpyW(lpstrPathAndFile, lpstrTemp);
1847 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1849 MemFree(lpstrFileList);
1852 Step 2: here we have a cleaned up path
1854 We have to parse the path step by step to see if we have to browse
1855 to a folder if the path points to a directory or the last
1856 valid element is a directory.
1859 lpstrPathAndFile: cleaned up path
1863 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1864 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1865 nOpenAction = ONOPEN_OPEN;
1867 nOpenAction = ONOPEN_BROWSE;
1869 /* don't apply any checks with OFN_NOVALIDATE */
1871 LPWSTR lpszTemp, lpszTemp1;
1872 LPITEMIDLIST pidl = NULL;
1873 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1875 /* check for invalid chars */
1876 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1878 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1883 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1885 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1888 LPSHELLFOLDER lpsfChild;
1889 WCHAR lpwstrTemp[MAX_PATH];
1890 DWORD dwEaten, dwAttributes;
1893 strcpyW(lpwstrTemp, lpszTemp);
1894 p = PathFindNextComponentW(lpwstrTemp);
1896 if (!p) break; /* end of path */
1899 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1901 /* There are no wildcards when OFN_NOVALIDATE is set */
1902 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1904 static const WCHAR wszWild[] = { '*', '?', 0 };
1905 /* if the last element is a wildcard do a search */
1906 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1908 nOpenAction = ONOPEN_SEARCH;
1912 lpszTemp1 = lpszTemp;
1914 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1916 /* append a backslash to drive letters */
1917 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1918 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1919 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1921 PathAddBackslashW(lpwstrTemp);
1924 dwAttributes = SFGAO_FOLDER;
1925 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1927 /* the path component is valid, we have a pidl of the next path component */
1928 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1929 if(dwAttributes & SFGAO_FOLDER)
1931 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1933 ERR("bind to failed\n"); /* should not fail */
1936 IShellFolder_Release(lpsf);
1944 /* end dialog, return value */
1945 nOpenAction = ONOPEN_OPEN;
1948 COMDLG32_SHFree(pidl);
1951 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1953 if(*lpszTemp) /* points to trailing null for last path element */
1955 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1957 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1963 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1964 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1966 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1970 /* change to the current folder */
1971 nOpenAction = ONOPEN_OPEN;
1976 nOpenAction = ONOPEN_OPEN;
1980 if(pidl) COMDLG32_SHFree(pidl);
1984 Step 3: here we have a cleaned up and validated path
1987 lpsf: ShellFolder bound to the rightmost valid path component
1988 lpstrPathAndFile: cleaned up path
1989 nOpenAction: action to do
1991 TRACE("end validate sf=%p\n", lpsf);
1995 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1996 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1999 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2002 /* replace the current filter */
2003 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2004 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2005 len = strlenW(lpszTemp)+1;
2006 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2007 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2009 /* set the filter cb to the extension when possible */
2010 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2011 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2014 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2015 TRACE("ONOPEN_BROWSE\n");
2017 IPersistFolder2 * ppf2;
2018 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2020 LPITEMIDLIST pidlCurrent;
2021 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2022 IPersistFolder2_Release(ppf2);
2023 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2025 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
2027 else if( nOpenAction == ONOPEN_SEARCH )
2029 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2031 COMDLG32_SHFree(pidlCurrent);
2036 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2037 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2041 /* update READONLY check box flag */
2042 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2043 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2045 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2047 /* Attach the file extension with file name*/
2048 ext = PathFindExtensionW(lpstrPathAndFile);
2051 /* if no extension is specified with file name, then */
2052 /* attach the extension from file filter or default one */
2054 WCHAR *filterExt = NULL;
2055 LPWSTR lpstrFilter = NULL;
2056 static const WCHAR szwDot[] = {'.',0};
2057 int PathLength = strlenW(lpstrPathAndFile);
2060 strcatW(lpstrPathAndFile, szwDot);
2062 /*Get the file extension from file type filter*/
2063 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2064 fodInfos->ofnInfos->nFilterIndex-1);
2066 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2067 filterExt = PathFindExtensionW(lpstrFilter);
2069 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2070 strcatW(lpstrPathAndFile, filterExt + 1);
2071 else if ( fodInfos->defext ) /* attach the default file extension*/
2072 strcatW(lpstrPathAndFile, fodInfos->defext);
2074 /* In Open dialog: if file does not exist try without extension */
2075 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2076 lpstrPathAndFile[PathLength] = '\0';
2079 if (fodInfos->defext) /* add default extension */
2081 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2084 if (!lstrcmpiW(fodInfos->defext, ext))
2085 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2087 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2090 /* In Save dialog: check if the file already exists */
2091 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2092 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2093 && PathFileExistsW(lpstrPathAndFile))
2095 WCHAR lpstrOverwrite[100];
2098 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2099 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2100 MB_YESNO | MB_ICONEXCLAMATION);
2108 /* Check that the size of the file does not exceed buffer size.
2109 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2110 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2111 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2115 /* fill destination buffer */
2116 if (fodInfos->ofnInfos->lpstrFile)
2118 if(fodInfos->unicode)
2120 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2122 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2123 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2124 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2128 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2130 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2131 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2132 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2133 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2137 /* set filename offset */
2138 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2139 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2141 /* set extension offset */
2142 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2143 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2145 /* set the lpstrFileTitle */
2146 if(fodInfos->ofnInfos->lpstrFileTitle)
2148 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2149 if(fodInfos->unicode)
2151 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2152 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2156 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2157 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2158 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2162 /* copy currently selected filter to lpstrCustomFilter */
2163 if (fodInfos->ofnInfos->lpstrCustomFilter)
2165 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2166 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2167 NULL, 0, NULL, NULL);
2168 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2170 LPSTR s = ofn->lpstrCustomFilter;
2171 s += strlen(ofn->lpstrCustomFilter)+1;
2172 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2173 s, len, NULL, NULL);
2178 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2182 FILEDLG95_Clean(hwnd);
2183 ret = EndDialog(hwnd, TRUE);
2189 size = strlenW(lpstrPathAndFile) + 1;
2190 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2192 /* return needed size in first two bytes of lpstrFile */
2193 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2194 FILEDLG95_Clean(hwnd);
2195 ret = EndDialog(hwnd, FALSE);
2196 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2204 if(lpsf) IShellFolder_Release(lpsf);
2208 /***********************************************************************
2209 * FILEDLG95_SHELL_Init
2211 * Initialisation of the shell objects
2213 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2215 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2220 * Initialisation of the FileOpenDialogInfos structure
2226 fodInfos->ShellInfos.hwndOwner = hwnd;
2228 /* Disable multi-select if flag not set */
2229 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2231 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2233 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2234 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2236 /* Construct the IShellBrowser interface */
2237 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2242 /***********************************************************************
2243 * FILEDLG95_SHELL_ExecuteCommand
2245 * Change the folder option and refresh the view
2246 * If the function succeeds, the return value is nonzero.
2248 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2250 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2253 TRACE("(%p,%p)\n", hwnd, lpVerb);
2255 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2260 CMINVOKECOMMANDINFO ci;
2261 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2262 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2266 IContextMenu_InvokeCommand(pcm, &ci);
2267 IContextMenu_Release(pcm);
2273 /***********************************************************************
2274 * FILEDLG95_SHELL_UpFolder
2276 * Browse to the specified object
2277 * If the function succeeds, the return value is nonzero.
2279 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2281 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2285 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2289 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2295 /***********************************************************************
2296 * FILEDLG95_SHELL_BrowseToDesktop
2298 * Browse to the Desktop
2299 * If the function succeeds, the return value is nonzero.
2301 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2303 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2309 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2310 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2311 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2312 COMDLG32_SHFree(pidl);
2313 return SUCCEEDED(hres);
2315 /***********************************************************************
2316 * FILEDLG95_SHELL_Clean
2318 * Cleans the memory used by shell objects
2320 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2322 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2326 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2328 /* clean Shell interfaces */
2329 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2330 IShellView_Release(fodInfos->Shell.FOIShellView);
2331 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2332 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2333 if (fodInfos->Shell.FOIDataObject)
2334 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2337 /***********************************************************************
2338 * FILEDLG95_FILETYPE_Init
2340 * Initialisation of the file type combo box
2342 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2344 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2345 int nFilters = 0; /* number of filters */
2350 if(fodInfos->customfilter)
2352 /* customfilter has one entry... title\0ext\0
2353 * Set first entry of combo box item with customfilter
2356 LPCWSTR lpstrPos = fodInfos->customfilter;
2359 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2361 /* Copy the extensions */
2362 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2363 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2364 strcpyW(lpstrExt,lpstrPos);
2366 /* Add the item at the end of the combo */
2367 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2368 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2371 if(fodInfos->filter)
2373 LPCWSTR lpstrPos = fodInfos->filter;
2377 /* filter is a list... title\0ext\0......\0\0
2378 * Set the combo item text to the title and the item data
2381 LPCWSTR lpstrDisplay;
2385 if(! *lpstrPos) break; /* end */
2386 lpstrDisplay = lpstrPos;
2387 lpstrPos += strlenW(lpstrPos) + 1;
2389 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2393 /* Copy the extensions */
2394 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2395 strcpyW(lpstrExt,lpstrPos);
2396 lpstrPos += strlenW(lpstrPos) + 1;
2398 /* Add the item at the end of the combo */
2399 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2401 /* malformed filters are added anyway... */
2402 if (!*lpstrExt) break;
2407 * Set the current filter to the one specified
2408 * in the initialisation structure
2410 if (fodInfos->filter || fodInfos->customfilter)
2414 /* Check to make sure our index isn't out of bounds. */
2415 if ( fodInfos->ofnInfos->nFilterIndex >
2416 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2417 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2419 /* set default filter index */
2420 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2421 fodInfos->ofnInfos->nFilterIndex = 1;
2423 /* calculate index of Combo Box item */
2424 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2425 if (fodInfos->customfilter == NULL)
2428 /* Set the current index selection. */
2429 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2431 /* Get the corresponding text string from the combo box. */
2432 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2435 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2441 CharLowerW(lpstrFilter); /* lowercase */
2442 len = strlenW(lpstrFilter)+1;
2443 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2444 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2447 fodInfos->ofnInfos->nFilterIndex = 0;
2451 /***********************************************************************
2452 * FILEDLG95_FILETYPE_OnCommand
2454 * WM_COMMAND of the file type combo box
2455 * If the function succeeds, the return value is nonzero.
2457 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2459 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2467 /* Get the current item of the filetype combo box */
2468 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2470 /* set the current filter index */
2471 fodInfos->ofnInfos->nFilterIndex = iItem +
2472 (fodInfos->customfilter == NULL ? 1 : 0);
2474 /* Set the current filter with the current selection */
2475 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2476 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2478 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2480 if((INT_PTR)lpstrFilter != CB_ERR)
2483 CharLowerW(lpstrFilter); /* lowercase */
2484 len = strlenW(lpstrFilter)+1;
2485 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2486 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2487 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2490 /* Refresh the actual view to display the included items*/
2491 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2496 /***********************************************************************
2497 * FILEDLG95_FILETYPE_SearchExt
2499 * searches for an extension in the filetype box
2501 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2503 int i, iCount = CBGetCount(hwnd);
2505 TRACE("%s\n", debugstr_w(lpstrExt));
2507 if(iCount != CB_ERR)
2509 for(i=0;i<iCount;i++)
2511 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2518 /***********************************************************************
2519 * FILEDLG95_FILETYPE_Clean
2521 * Clean the memory used by the filetype combo box
2523 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2525 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2527 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2531 /* Delete each string of the combo and their associated data */
2532 if(iCount != CB_ERR)
2534 for(iPos = iCount-1;iPos>=0;iPos--)
2536 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2537 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2540 /* Current filter */
2541 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2542 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2546 /***********************************************************************
2547 * FILEDLG95_LOOKIN_Init
2549 * Initialisation of the look in combo box
2552 /* Small helper function, to determine if the unixfs shell extension is rooted
2553 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2555 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2557 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2558 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2559 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2560 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2561 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2562 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2563 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2565 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2572 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2574 IShellFolder *psfRoot, *psfDrives;
2575 IEnumIDList *lpeRoot, *lpeDrives;
2576 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2578 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2582 liInfos->iMaxIndentation = 0;
2584 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2586 /* set item height for both text field and listbox */
2587 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2588 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2590 /* Turn on the extended UI for the combo box like Windows does */
2591 CBSetExtendedUI(hwndCombo, TRUE);
2593 /* Initialise data of Desktop folder */
2594 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2595 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2596 COMDLG32_SHFree(pidlTmp);
2598 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2600 SHGetDesktopFolder(&psfRoot);
2604 /* enumerate the contents of the desktop */
2605 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2607 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2609 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2611 /* If the unixfs extension is rooted, we don't expand the drives by default */
2612 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2614 /* special handling for CSIDL_DRIVES */
2615 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2617 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2619 /* enumerate the drives */
2620 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2622 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2624 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2625 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2626 COMDLG32_SHFree(pidlAbsTmp);
2627 COMDLG32_SHFree(pidlTmp1);
2629 IEnumIDList_Release(lpeDrives);
2631 IShellFolder_Release(psfDrives);
2636 COMDLG32_SHFree(pidlTmp);
2638 IEnumIDList_Release(lpeRoot);
2640 IShellFolder_Release(psfRoot);
2643 COMDLG32_SHFree(pidlDrives);
2646 /***********************************************************************
2647 * FILEDLG95_LOOKIN_DrawItem
2649 * WM_DRAWITEM message handler
2651 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2653 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2654 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2655 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2659 HIMAGELIST ilItemImage;
2662 LPSFOLDER tmpFolder;
2665 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2669 if(pDIStruct->itemID == -1)
2672 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2673 pDIStruct->itemID)))
2677 if(pDIStruct->itemID == liInfos->uSelectedItem)
2679 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2682 sizeof (SHFILEINFOA),
2683 SHGFI_PIDL | SHGFI_SMALLICON |
2684 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2685 SHGFI_DISPLAYNAME );
2689 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2692 sizeof (SHFILEINFOA),
2693 SHGFI_PIDL | SHGFI_SMALLICON |
2694 SHGFI_SYSICONINDEX |
2698 /* Is this item selected ? */
2699 if(pDIStruct->itemState & ODS_SELECTED)
2701 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2702 SetBkColor(pDIStruct->hDC,crHighLight);
2703 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2707 SetTextColor(pDIStruct->hDC,crText);
2708 SetBkColor(pDIStruct->hDC,crWin);
2709 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2712 /* Do not indent item if drawing in the edit of the combo */
2713 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2716 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2719 sizeof (SHFILEINFOA),
2720 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2721 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2726 iIndentation = tmpFolder->m_iIndent;
2728 /* Draw text and icon */
2730 /* Initialise the icon display area */
2731 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2732 rectIcon.top = pDIStruct->rcItem.top;
2733 rectIcon.right = rectIcon.left + ICONWIDTH;
2734 rectIcon.bottom = pDIStruct->rcItem.bottom;
2736 /* Initialise the text display area */
2737 GetTextMetricsA(pDIStruct->hDC, &tm);
2738 rectText.left = rectIcon.right;
2740 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2741 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2743 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2745 /* Draw the icon from the image list */
2746 ImageList_Draw(ilItemImage,
2753 /* Draw the associated text */
2754 if(sfi.szDisplayName)
2755 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2761 /***********************************************************************
2762 * FILEDLG95_LOOKIN_OnCommand
2764 * LookIn combo box WM_COMMAND message handler
2765 * If the function succeeds, the return value is nonzero.
2767 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2769 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2771 TRACE("%p\n", fodInfos);
2777 LPSFOLDER tmpFolder;
2780 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2782 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2787 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2788 tmpFolder->pidlItem,
2791 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2801 /***********************************************************************
2802 * FILEDLG95_LOOKIN_AddItem
2804 * Adds an absolute pidl item to the lookin combo box
2805 * returns the index of the inserted item
2807 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2809 LPITEMIDLIST pidlNext;
2812 LookInInfos *liInfos;
2814 TRACE("%08x\n", iInsertId);
2819 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2822 tmpFolder = MemAlloc(sizeof(SFOLDER));
2823 tmpFolder->m_iIndent = 0;
2825 /* Calculate the indentation of the item in the lookin*/
2827 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2829 tmpFolder->m_iIndent++;
2832 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2834 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2835 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2837 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2838 SHGetFileInfoA((LPSTR)pidl,
2842 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2843 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2845 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2847 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2851 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2853 /* Add the item at the end of the list */
2856 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2858 /* Insert the item at the iInsertId position*/
2861 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2864 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2868 COMDLG32_SHFree( tmpFolder->pidlItem );
2869 MemFree( tmpFolder );
2874 /***********************************************************************
2875 * FILEDLG95_LOOKIN_InsertItemAfterParent
2877 * Insert an item below its parent
2879 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2882 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2887 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2891 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2894 /* Free pidlParent memory */
2895 COMDLG32_SHFree((LPVOID)pidlParent);
2897 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2900 /***********************************************************************
2901 * FILEDLG95_LOOKIN_SelectItem
2903 * Adds an absolute pidl item to the lookin combo box
2904 * returns the index of the inserted item
2906 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2909 LookInInfos *liInfos;
2913 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2915 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2919 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2920 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2925 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2926 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2930 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2932 if(iRemovedItem < iItemPos)
2937 CBSetCurSel(hwnd,iItemPos);
2938 liInfos->uSelectedItem = iItemPos;
2944 /***********************************************************************
2945 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2947 * Remove the item with an expansion level over iExpansionLevel
2949 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2953 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2957 if(liInfos->iMaxIndentation <= 2)
2960 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2962 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2963 COMDLG32_SHFree(tmpFolder->pidlItem);
2965 CBDeleteString(hwnd,iItemPos);
2966 liInfos->iMaxIndentation--;
2974 /***********************************************************************
2975 * FILEDLG95_LOOKIN_SearchItem
2977 * Search for pidl in the lookin combo box
2978 * returns the index of the found item
2980 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2983 int iCount = CBGetCount(hwnd);
2985 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2987 if (iCount != CB_ERR)
2991 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2993 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2995 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3003 /***********************************************************************
3004 * FILEDLG95_LOOKIN_Clean
3006 * Clean the memory used by the lookin combo box
3008 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3010 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3012 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3016 /* Delete each string of the combo and their associated data */
3017 if (iCount != CB_ERR)
3019 for(iPos = iCount-1;iPos>=0;iPos--)
3021 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3022 COMDLG32_SHFree(tmpFolder->pidlItem);
3024 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3028 /* LookInInfos structure */
3029 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3032 /***********************************************************************
3033 * FILEDLG95_FILENAME_FillFromSelection
3035 * fills the edit box from the cached DataObject
3037 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3039 FileOpenDlgInfos *fodInfos;
3041 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3042 char lpstrTemp[MAX_PATH];
3043 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3046 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3048 /* Count how many files we have */
3049 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3051 /* calculate the string length, count files */
3052 if (nFileSelected >= 1)
3054 nLength += 3; /* first and last quotes, trailing \0 */
3055 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3057 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3061 /* get the total length of the selected file names */
3062 lpstrTemp[0] = '\0';
3063 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3065 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3067 nLength += strlen( lpstrTemp ) + 3;
3070 COMDLG32_SHFree( pidl );
3075 /* allocate the buffer */
3076 if (nFiles <= 1) nLength = MAX_PATH;
3077 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3078 lpstrAllFile[0] = '\0';
3080 /* Generate the string for the edit control */
3083 lpstrCurrFile = lpstrAllFile;
3084 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3086 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3090 /* get the file name */
3091 lpstrTemp[0] = '\0';
3092 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3094 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3098 *lpstrCurrFile++ = '\"';
3099 strcpy( lpstrCurrFile, lpstrTemp );
3100 lpstrCurrFile += strlen( lpstrTemp );
3101 strcpy( lpstrCurrFile, "\" " );
3106 strcpy( lpstrAllFile, lpstrTemp );
3109 COMDLG32_SHFree( (LPVOID) pidl );
3112 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3114 /* Select the file name like Windows does */
3115 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3117 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3121 /* copied from shell32 to avoid linking to it
3122 * FIXME: why? shell32 is already linked
3124 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3129 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3130 COMDLG32_SHFree(src->u.pOleStr);
3134 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3138 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3142 FIXME("unknown type!\n");
3145 *(LPSTR)dest = '\0';
3152 /***********************************************************************
3153 * FILEDLG95_FILENAME_GetFileNames
3155 * Copies the filenames to a delimited string list.
3156 * The delimiter is specified by the parameter 'separator',
3157 * usually either a space or a nul
3159 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3161 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3162 UINT nStrCharCount = 0; /* index in src buffer */
3163 UINT nFileIndex = 0; /* index in dest buffer */
3164 UINT nFileCount = 0; /* number of files */
3165 UINT nStrLen = 0; /* length of string in edit control */
3166 LPWSTR lpstrEdit; /* buffer for string from edit control */
3170 /* get the filenames from the edit control */
3171 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3172 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3173 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3175 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3177 /* we might get single filename without any '"',
3178 * so we need nStrLen + terminating \0 + end-of-list \0 */
3179 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3182 /* build delimited file list from filenames */
3183 while ( nStrCharCount <= nStrLen )
3185 if ( lpstrEdit[nStrCharCount]=='"' )
3188 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3190 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3194 (*lpstrFileList)[nFileIndex++] = separator;
3201 /* single, unquoted string */
3202 if ((nStrLen > 0) && (*sizeUsed == 0) )
3204 strcpyW(*lpstrFileList, lpstrEdit);
3205 nFileIndex = strlenW(lpstrEdit) + 1;
3206 (*sizeUsed) = nFileIndex;
3211 (*lpstrFileList)[nFileIndex] = '\0';
3218 #define SETDefFormatEtc(fe,cf,med) \
3220 (fe).cfFormat = cf;\
3221 (fe).dwAspect = DVASPECT_CONTENT; \
3228 * DATAOBJECT Helper functions
3231 /***********************************************************************
3232 * COMCTL32_ReleaseStgMedium
3234 * like ReleaseStgMedium from ole32
3236 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3238 if(medium.pUnkForRelease)
3240 IUnknown_Release(medium.pUnkForRelease);
3244 GlobalUnlock(medium.u.hGlobal);
3245 GlobalFree(medium.u.hGlobal);
3249 /***********************************************************************
3250 * GetPidlFromDataObject
3252 * Return pidl(s) by number from the cached DataObject
3254 * nPidlIndex=0 gets the fully qualified root path
3256 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3260 FORMATETC formatetc;
3261 LPITEMIDLIST pidl = NULL;
3263 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3268 /* Set the FORMATETC structure*/
3269 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3271 /* Get the pidls from IDataObject */
3272 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3274 LPIDA cida = GlobalLock(medium.u.hGlobal);
3275 if(nPidlIndex <= cida->cidl)
3277 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3279 COMCTL32_ReleaseStgMedium(medium);
3284 /***********************************************************************
3287 * Return the number of selected items in the DataObject.
3290 UINT GetNumSelected( IDataObject *doSelected )
3294 FORMATETC formatetc;
3296 TRACE("sv=%p\n", doSelected);
3298 if (!doSelected) return 0;
3300 /* Set the FORMATETC structure*/
3301 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3303 /* Get the pidls from IDataObject */
3304 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3306 LPIDA cida = GlobalLock(medium.u.hGlobal);
3307 retVal = cida->cidl;
3308 COMCTL32_ReleaseStgMedium(medium);
3318 /***********************************************************************
3321 * Get the pidl's display name (relative to folder) and
3322 * put it in lpstrFileName.
3324 * Return NOERROR on success,
3328 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3333 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3337 SHGetDesktopFolder(&lpsf);
3338 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3339 IShellFolder_Release(lpsf);
3343 /* Get the display name of the pidl relative to the folder */
3344 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3346 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3351 /***********************************************************************
3352 * GetShellFolderFromPidl
3354 * pidlRel is the item pidl relative
3355 * Return the IShellFolder of the absolute pidl
3357 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3359 IShellFolder *psf = NULL,*psfParent;
3361 TRACE("%p\n", pidlAbs);
3363 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3366 if(pidlAbs && pidlAbs->mkid.cb)
3368 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3370 IShellFolder_Release(psfParent);
3374 /* return the desktop */
3380 /***********************************************************************
3383 * Return the LPITEMIDLIST to the parent of the pidl in the list
3385 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3387 LPITEMIDLIST pidlParent;
3389 TRACE("%p\n", pidl);
3391 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3392 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3397 /***********************************************************************
3400 * returns the pidl of the file name relative to folder
3401 * NULL if an error occurred
3403 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3405 LPITEMIDLIST pidl = NULL;
3408 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3410 if(!lpcstrFileName) return NULL;
3411 if(!*lpcstrFileName) return NULL;
3415 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3416 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3417 IShellFolder_Release(lpsf);
3422 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3429 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3431 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3434 TRACE("%p, %p\n", psf, pidl);
3436 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3438 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3439 /* see documentation shell 4.1*/
3440 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3443 /***********************************************************************
3444 * BrowseSelectedFolder
3446 static BOOL BrowseSelectedFolder(HWND hwnd)
3448 BOOL bBrowseSelFolder = FALSE;
3449 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3453 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3455 LPITEMIDLIST pidlSelection;
3457 /* get the file selected */
3458 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3459 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3461 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3462 pidlSelection, SBSP_RELATIVE ) ) )
3464 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3465 ' ','n','o','t',' ','e','x','i','s','t',0};
3466 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3468 bBrowseSelFolder = TRUE;
3469 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3471 COMDLG32_SHFree( pidlSelection );
3474 return bBrowseSelFolder;
3478 * Memory allocation methods */
3479 static void *MemAlloc(UINT size)
3481 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3484 static void MemFree(void *mem)
3486 HeapFree(GetProcessHeap(),0,mem);
3490 * Old-style (win3.1) dialogs */
3492 /***********************************************************************
3493 * FD32_GetTemplate [internal]
3495 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3496 * by a 32 bits application
3499 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3501 LPOPENFILENAMEW ofnW = lfs->ofnW;
3502 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3505 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3507 if (!(lfs->template = LockResource( ofnW->hInstance )))
3509 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3513 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3517 hResInfo = FindResourceA(priv->ofnA->hInstance,
3518 priv->ofnA->lpTemplateName,
3521 hResInfo = FindResourceW(ofnW->hInstance,
3522 ofnW->lpTemplateName,
3526 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3529 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3531 !(lfs->template = LockResource(hDlgTmpl)))
3533 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3536 } else { /* get it from internal Wine resource */
3538 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3539 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3541 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3544 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3545 !(lfs->template = LockResource( hDlgTmpl )))
3547 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3555 /************************************************************************
3556 * FD32_Init [internal]
3557 * called from the common 16/32 code to initialize 32 bit data
3559 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3561 BOOL IsUnicode = (BOOL) data;
3564 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3565 lfs->private1632 = priv;
3566 if (NULL == lfs->private1632) return FALSE;
3569 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3570 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3571 if (lfs->ofnW->lpfnHook)
3576 priv->ofnA = (LPOPENFILENAMEA) lParam;
3577 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3578 if (priv->ofnA->lpfnHook)
3580 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3581 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3584 if (! FD32_GetTemplate(lfs)) return FALSE;
3589 /***********************************************************************
3590 * FD32_CallWindowProc [internal]
3592 * called from the common 16/32 code to call the appropriate hook
3594 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3598 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3602 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3603 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3604 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3605 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3606 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3610 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3611 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3612 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3613 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3614 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3618 /***********************************************************************
3619 * FD32_UpdateResult [internal]
3620 * update the real client structures if any
3622 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3624 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3625 LPOPENFILENAMEW ofnW = lfs->ofnW;
3629 if (ofnW->nMaxFile &&
3630 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3631 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3632 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3633 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3634 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3638 /***********************************************************************
3639 * FD32_UpdateFileTitle [internal]
3640 * update the real client structures if any
3642 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3644 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3645 LPOPENFILENAMEW ofnW = lfs->ofnW;
3649 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3650 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3651 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3656 /***********************************************************************
3657 * FD32_SendLbGetCurSel [internal]
3658 * retrieve selected listbox item
3660 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3662 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3666 /************************************************************************
3667 * FD32_Destroy [internal]
3668 * called from the common 16/32 code to cleanup 32 bit data
3670 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3672 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3674 /* if ofnW has been allocated, have to free everything in it */
3675 if (NULL != priv && NULL != priv->ofnA)
3677 FD31_FreeOfnW(lfs->ofnW);
3678 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3682 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3684 callbacks->Init = FD32_Init;
3685 callbacks->CWP = FD32_CallWindowProc;
3686 callbacks->UpdateResult = FD32_UpdateResult;
3687 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3688 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3689 callbacks->Destroy = FD32_Destroy;
3692 /***********************************************************************
3693 * FD32_WMMeasureItem [internal]
3695 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3697 LPMEASUREITEMSTRUCT lpmeasure;
3699 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3700 lpmeasure->itemHeight = FD31_GetFldrHeight();
3705 /***********************************************************************
3706 * FileOpenDlgProc [internal]
3707 * Used for open and save, in fact.
3709 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3710 WPARAM wParam, LPARAM lParam)
3712 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3714 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3715 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3718 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3720 return lRet; /* else continue message processing */
3725 return FD31_WMInitDialog(hWnd, wParam, lParam);
3727 case WM_MEASUREITEM:
3728 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3731 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3734 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3737 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3738 switch (HIWORD(lParam))
3741 SetTextColor((HDC16)wParam, 0x00000000);
3743 case CTLCOLOR_STATIC:
3744 SetTextColor((HDC16)wParam, 0x00000000);
3754 /***********************************************************************
3755 * GetFileName31A [internal]
3757 * Creates a win31 style dialog box for the user to select a file to open/save.
3759 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3760 UINT dlgType /* type dialogue : open/save */
3766 FD31_CALLBACKS callbacks;
3768 if (!lpofn || !FD31_Init()) return FALSE;
3770 TRACE("ofn flags %08lx\n", lpofn->Flags);
3771 FD32_SetupCallbacks(&callbacks);
3772 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3775 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3776 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3777 FD32_FileOpenDlgProc, (LPARAM)lfs);
3778 FD31_DestroyPrivate(lfs);
3781 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3785 /***********************************************************************
3786 * GetFileName31W [internal]
3788 * Creates a win31 style dialog box for the user to select a file to open/save
3790 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3791 UINT dlgType /* type dialogue : open/save */
3797 FD31_CALLBACKS callbacks;
3799 if (!lpofn || !FD31_Init()) return FALSE;
3801 FD32_SetupCallbacks(&callbacks);
3802 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3805 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3806 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3807 FD32_FileOpenDlgProc, (LPARAM)lfs);
3808 FD31_DestroyPrivate(lfs);
3811 TRACE("file %s, file offset %d, ext offset %d\n",
3812 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3816 /* ------------------ APIs ---------------------- */
3818 /***********************************************************************
3819 * GetOpenFileNameA (COMDLG32.@)
3821 * Creates a dialog box for the user to select a file to open.
3824 * TRUE on success: user enters a valid file
3825 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3828 BOOL WINAPI GetOpenFileNameA(
3829 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3831 BOOL win16look = FALSE;
3833 TRACE("flags %08lx\n", ofn->Flags);
3835 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3836 if (ofn->Flags & OFN_FILEMUSTEXIST)
3837 ofn->Flags |= OFN_PATHMUSTEXIST;
3839 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3840 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3843 return GetFileName31A(ofn, OPEN_DIALOG);
3845 return GetFileDialog95A(ofn, OPEN_DIALOG);
3848 /***********************************************************************
3849 * GetOpenFileNameW (COMDLG32.@)
3851 * Creates a dialog box for the user to select a file to open.
3854 * TRUE on success: user enters a valid file
3855 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3858 BOOL WINAPI GetOpenFileNameW(
3859 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3861 BOOL win16look = FALSE;
3863 TRACE("flags %08lx\n", ofn->Flags);
3865 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3866 if (ofn->Flags & OFN_FILEMUSTEXIST)
3867 ofn->Flags |= OFN_PATHMUSTEXIST;
3869 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3870 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3873 return GetFileName31W(ofn, OPEN_DIALOG);
3875 return GetFileDialog95W(ofn, OPEN_DIALOG);
3879 /***********************************************************************
3880 * GetSaveFileNameA (COMDLG32.@)
3882 * Creates a dialog box for the user to select a file to save.
3885 * TRUE on success: user enters a valid file
3886 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3889 BOOL WINAPI GetSaveFileNameA(
3890 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3892 BOOL win16look = FALSE;
3894 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3895 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3898 return GetFileName31A(ofn, SAVE_DIALOG);
3900 return GetFileDialog95A(ofn, SAVE_DIALOG);
3903 /***********************************************************************
3904 * GetSaveFileNameW (COMDLG32.@)
3906 * Creates a dialog box for the user to select a file to save.
3909 * TRUE on success: user enters a valid file
3910 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3913 BOOL WINAPI GetSaveFileNameW(
3914 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3916 BOOL win16look = FALSE;
3918 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3919 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3922 return GetFileName31W(ofn, SAVE_DIALOG);
3924 return GetFileDialog95W(ofn, SAVE_DIALOG);