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
73 #include "filedlg31.h"
78 #include "filedlgbrowser.h"
81 #include "wine/unicode.h"
82 #include "wine/debug.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
86 #define UNIMPLEMENTED_FLAGS \
87 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
88 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
89 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
90 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
92 #define IsHooked(fodInfos) \
93 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
94 /***********************************************************************
95 * Data structure and global variables
97 typedef struct SFolder
99 int m_iImageIndex; /* Index of picture in image list */
101 int m_iIndent; /* Indentation index */
102 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
104 } SFOLDER,*LPSFOLDER;
106 typedef struct tagLookInInfo
112 typedef struct tagFD32_PRIVATE
114 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
115 } FD32_PRIVATE, *PFD32_PRIVATE;
118 /***********************************************************************
119 * Defines and global variables
122 /* Draw item constant */
124 #define XTEXTOFFSET 3
129 /* SearchItem methods */
130 #define SEARCH_PIDL 1
132 #define ITEM_NOTFOUND -1
134 /* Undefined windows message sent by CreateViewObject*/
135 #define WM_GETISHELLBROWSER WM_USER+7
138 * Those macros exist in windowsx.h. However, you can't really use them since
139 * they rely on the UNICODE defines and can't be used inside Wine itself.
142 /* Combo box macros */
143 #define CBAddString(hwnd,str) \
144 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
146 #define CBInsertString(hwnd,str,pos) \
147 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
149 #define CBDeleteString(hwnd,pos) \
150 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
152 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
153 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
155 #define CBGetItemDataPtr(hwnd,iItemId) \
156 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
158 #define CBGetLBText(hwnd,iItemId,str) \
159 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
161 #define CBGetCurSel(hwnd) \
162 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
164 #define CBSetCurSel(hwnd,pos) \
165 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
167 #define CBGetCount(hwnd) \
168 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
169 #define CBShowDropDown(hwnd,show) \
170 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
171 #define CBSetItemHeight(hwnd,index,height) \
172 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
174 #define CBSetExtendedUI(hwnd,flag) \
175 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
177 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
178 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
180 /***********************************************************************
184 /* Internal functions used by the dialog */
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 static BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
202 /* Functions used by the filetype combo box */
203 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
204 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
210 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
211 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
219 /* Miscellaneous tool functions */
220 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
221 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
222 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
223 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size);
227 static void MemFree(void *mem);
229 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
253 /* test for missing functionality */
254 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 FIXME("Flags 0x%08x not yet implemented\n",
257 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
260 /* Create the dialog from a template */
262 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268 !(template = LockResource( hDlgTmpl )))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
274 /* old style hook messages */
275 if (IsHooked(fodInfos))
277 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
278 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
279 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
280 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
283 /* Some shell namespace extensions depend on COM being initialized. */
284 hr = OleInitialize(NULL);
286 if (fodInfos->unicode)
287 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
289 fodInfos->ofnInfos->hwndOwner,
293 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
294 (LPCDLGTEMPLATEA) template,
295 fodInfos->ofnInfos->hwndOwner,
301 /* Unable to create the dialog */
308 /***********************************************************************
311 * Call GetFileName95 with this structure and clean the memory.
313 * IN : The OPENFILENAMEA initialisation structure passed to
314 * GetOpenFileNameA win api function (see filedlg.c)
316 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
319 FileOpenDlgInfos fodInfos;
320 LPSTR lpstrSavDir = NULL;
322 LPWSTR defext = NULL;
323 LPWSTR filter = NULL;
324 LPWSTR customfilter = NULL;
326 /* Initialize FileOpenDlgInfos structure */
327 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
329 /* Pass in the original ofn */
330 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
332 /* save current directory */
333 if (ofn->Flags & OFN_NOCHANGEDIR)
335 lpstrSavDir = MemAlloc(MAX_PATH);
336 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
339 fodInfos.unicode = FALSE;
341 /* convert all the input strings to unicode */
342 if(ofn->lpstrInitialDir)
344 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
345 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
346 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
349 fodInfos.initdir = NULL;
353 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
354 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
357 fodInfos.filename = NULL;
361 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
362 defext = MemAlloc((len+1)*sizeof(WCHAR));
363 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
365 fodInfos.defext = defext;
369 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
370 title = MemAlloc((len+1)*sizeof(WCHAR));
371 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
373 fodInfos.title = title;
375 if (ofn->lpstrFilter)
380 /* filter is a list... title\0ext\0......\0\0 */
381 s = ofn->lpstrFilter;
382 while (*s) s = s+strlen(s)+1;
384 n = s - ofn->lpstrFilter;
385 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
386 filter = MemAlloc(len*sizeof(WCHAR));
387 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
389 fodInfos.filter = filter;
391 /* convert lpstrCustomFilter */
392 if (ofn->lpstrCustomFilter)
397 /* customfilter contains a pair of strings... title\0ext\0 */
398 s = ofn->lpstrCustomFilter;
399 if (*s) s = s+strlen(s)+1;
400 if (*s) s = s+strlen(s)+1;
401 n = s - ofn->lpstrCustomFilter;
402 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
403 customfilter = MemAlloc(len*sizeof(WCHAR));
404 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
406 fodInfos.customfilter = customfilter;
408 /* Initialize the dialog property */
409 fodInfos.DlgInfos.dwDlgProp = 0;
410 fodInfos.DlgInfos.hwndCustomDlg = NULL;
415 ret = GetFileName95(&fodInfos);
418 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
419 ret = GetFileName95(&fodInfos);
427 SetCurrentDirectoryA(lpstrSavDir);
428 MemFree(lpstrSavDir);
434 MemFree(customfilter);
435 MemFree(fodInfos.initdir);
436 MemFree(fodInfos.filename);
438 TRACE("selected file: %s\n",ofn->lpstrFile);
443 /***********************************************************************
446 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
447 * Call GetFileName95 with this structure and clean the memory.
450 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
453 FileOpenDlgInfos fodInfos;
454 LPWSTR lpstrSavDir = NULL;
456 /* Initialize FileOpenDlgInfos structure */
457 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
459 /* Pass in the original ofn */
460 fodInfos.ofnInfos = ofn;
462 fodInfos.title = ofn->lpstrTitle;
463 fodInfos.defext = ofn->lpstrDefExt;
464 fodInfos.filter = ofn->lpstrFilter;
465 fodInfos.customfilter = ofn->lpstrCustomFilter;
467 /* convert string arguments, save others */
470 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
471 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
474 fodInfos.filename = NULL;
476 if(ofn->lpstrInitialDir)
478 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
479 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
480 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
481 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
484 fodInfos.initdir = NULL;
486 /* save current directory */
487 if (ofn->Flags & OFN_NOCHANGEDIR)
489 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
490 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
493 fodInfos.unicode = TRUE;
498 ret = GetFileName95(&fodInfos);
501 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
502 ret = GetFileName95(&fodInfos);
510 SetCurrentDirectoryW(lpstrSavDir);
511 MemFree(lpstrSavDir);
514 /* restore saved IN arguments and convert OUT arguments back */
515 MemFree(fodInfos.filename);
516 MemFree(fodInfos.initdir);
520 /******************************************************************************
521 * COMDLG32_GetDisplayNameOf [internal]
523 * Helper function to get the display name for a pidl.
525 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
526 LPSHELLFOLDER psfDesktop;
529 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
532 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
533 IShellFolder_Release(psfDesktop);
537 IShellFolder_Release(psfDesktop);
538 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
541 /***********************************************************************
542 * ArrangeCtrlPositions [internal]
544 * NOTE: Do not change anything here without a lot of testing.
546 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
548 HWND hwndChild, hwndStc32;
549 RECT rectParent, rectChild, rectStc32;
550 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
552 /* Take into account if open as read only checkbox and help button
557 RECT rectHelp, rectCancel;
558 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
559 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
560 /* subtract the height of the help button plus the space between
561 * the help button and the cancel button to the height of the dialog
563 help_fixup = rectHelp.bottom - rectCancel.bottom;
567 There are two possibilities to add components to the default file dialog box.
569 By default, all the new components are added below the standard dialog box (the else case).
571 However, if there is a static text component with the stc32 id, a special case happens.
572 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
573 in the window and the cx and cy indicate how to size the window.
574 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
575 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
579 GetClientRect(hwndParentDlg, &rectParent);
581 /* when arranging controls we have to use fixed parent size */
582 rectParent.bottom -= help_fixup;
584 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
587 GetWindowRect(hwndStc32, &rectStc32);
588 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
590 /* set the size of the stc32 control according to the size of
591 * client area of the parent dialog
593 SetWindowPos(hwndStc32, 0,
595 rectParent.right, rectParent.bottom,
596 SWP_NOMOVE | SWP_NOZORDER);
599 SetRectEmpty(&rectStc32);
601 /* this part moves controls of the child dialog */
602 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
605 if (hwndChild != hwndStc32)
607 GetWindowRect(hwndChild, &rectChild);
608 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
610 /* move only if stc32 exist */
611 if (hwndStc32 && rectChild.left > rectStc32.right)
613 LONG old_left = rectChild.left;
615 /* move to the right of visible controls of the parent dialog */
616 rectChild.left += rectParent.right;
617 rectChild.left -= rectStc32.right;
619 child_width_fixup = rectChild.left - old_left;
621 /* move even if stc32 doesn't exist */
622 if (rectChild.top >= rectStc32.bottom)
624 LONG old_top = rectChild.top;
626 /* move below visible controls of the parent dialog */
627 rectChild.top += rectParent.bottom;
628 rectChild.top -= rectStc32.bottom - rectStc32.top;
630 child_height_fixup = rectChild.top - old_top;
633 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
634 0, 0, SWP_NOSIZE | SWP_NOZORDER);
636 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
639 /* this part moves controls of the parent dialog */
640 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
643 if (hwndChild != hwndChildDlg)
645 GetWindowRect(hwndChild, &rectChild);
646 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
648 /* left,top of stc32 marks the position of controls
649 * from the parent dialog
651 rectChild.left += rectStc32.left;
652 rectChild.top += rectStc32.top;
654 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
655 0, 0, SWP_NOSIZE | SWP_NOZORDER);
657 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
660 /* calculate the size of the resulting dialog */
662 /* here we have to use original parent size */
663 GetClientRect(hwndParentDlg, &rectParent);
664 GetClientRect(hwndChildDlg, &rectChild);
668 rectChild.right += child_width_fixup;
669 rectChild.bottom += child_height_fixup;
671 if (rectParent.right > rectChild.right)
673 rectParent.right += rectChild.right;
674 rectParent.right -= rectStc32.right - rectStc32.left;
678 rectParent.right = rectChild.right;
681 if (rectParent.bottom > rectChild.bottom)
683 rectParent.bottom += rectChild.bottom;
684 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
688 /* child dialog is higher, unconditionally set new dialog
689 * height to its size (help_fixup will be subtracted below)
691 rectParent.bottom = rectChild.bottom + help_fixup;
696 rectParent.bottom += rectChild.bottom;
699 /* finally use fixed parent size */
700 rectParent.bottom -= help_fixup;
702 /* set the size of the parent dialog */
703 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
704 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
705 SetWindowPos(hwndParentDlg, 0,
707 rectParent.right - rectParent.left,
708 rectParent.bottom - rectParent.top,
709 SWP_NOMOVE | SWP_NOZORDER);
712 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
721 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
731 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
732 * structure's hInstance parameter is not a HINSTANCE, but
733 * instead a pointer to a template resource to use.
735 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
738 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
740 hinst = COMDLG32_hInstance;
741 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
743 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
749 hinst = fodInfos->ofnInfos->hInstance;
750 if(fodInfos->unicode)
752 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
753 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
757 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
758 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
762 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
765 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
766 !(template = LockResource( hDlgTmpl )))
768 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
772 if (fodInfos->unicode)
773 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
774 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
775 (LPARAM)fodInfos->ofnInfos);
777 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
778 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
779 (LPARAM)fodInfos->ofnInfos);
782 ShowWindow(hChildDlg,SW_SHOW);
786 else if( IsHooked(fodInfos))
791 WORD menu,class,title;
793 GetClientRect(hwnd,&rectHwnd);
794 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
795 temp.tmplate.dwExtendedStyle = 0;
796 temp.tmplate.cdit = 0;
801 temp.menu = temp.class = temp.title = 0;
803 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
804 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
811 /***********************************************************************
812 * SendCustomDlgNotificationMessage
814 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
817 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
819 LRESULT hook_result = 0;
821 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
823 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
825 if(!fodInfos) return 0;
827 if(fodInfos->DlgInfos.hwndCustomDlg)
829 TRACE("CALL NOTIFY for %x\n", uCode);
830 if(fodInfos->unicode)
833 ofnNotify.hdr.hwndFrom=hwndParentDlg;
834 ofnNotify.hdr.idFrom=0;
835 ofnNotify.hdr.code = uCode;
836 ofnNotify.lpOFN = fodInfos->ofnInfos;
837 ofnNotify.pszFile = NULL;
838 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
843 ofnNotify.hdr.hwndFrom=hwndParentDlg;
844 ofnNotify.hdr.idFrom=0;
845 ofnNotify.hdr.code = uCode;
846 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
847 ofnNotify.pszFile = NULL;
848 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
850 TRACE("RET NOTIFY\n");
852 TRACE("Retval: 0x%08lx\n", hook_result);
856 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
858 UINT sizeUsed = 0, n, total;
859 LPWSTR lpstrFileList = NULL;
860 WCHAR lpstrCurrentDir[MAX_PATH];
861 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
863 TRACE("CDM_GETFILEPATH:\n");
865 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
868 /* get path and filenames */
869 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
870 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
872 TRACE("path >%s< filespec >%s< %d files\n",
873 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
875 if( fodInfos->unicode )
877 LPWSTR bufW = buffer;
878 total = lstrlenW(lpstrCurrentDir) + 1 + sizeUsed;
880 /* Prepend the current path */
881 n = lstrlenW(lpstrCurrentDir) + 1;
882 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
885 /* 'n' includes trailing \0 */
887 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
889 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
894 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
895 NULL, 0, NULL, NULL);
896 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
897 NULL, 0, NULL, NULL);
899 /* Prepend the current path */
900 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
901 bufA, size, NULL, NULL);
905 /* 'n' includes trailing \0 */
907 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
908 &bufA[n], size-n, NULL, NULL);
911 TRACE("returned -> %s\n",debugstr_an(bufA, total));
913 MemFree(lpstrFileList);
918 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
921 LPWSTR lpstrFileList = NULL;
922 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
924 TRACE("CDM_GETSPEC:\n");
926 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
927 if( fodInfos->unicode )
929 LPWSTR bufW = buffer;
930 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
935 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
936 NULL, 0, NULL, NULL);
937 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
938 bufA, size, NULL, NULL);
940 MemFree(lpstrFileList);
945 /***********************************************************************
946 * FILEDLG95_HandleCustomDialogMessages
948 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
950 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
952 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
953 WCHAR lpstrPath[MAX_PATH];
956 if(!fodInfos) return FALSE;
960 case CDM_GETFILEPATH:
961 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
964 case CDM_GETFOLDERPATH:
965 TRACE("CDM_GETFOLDERPATH:\n");
966 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
969 if (fodInfos->unicode)
970 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
972 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
973 (LPSTR)lParam, (int)wParam, NULL, NULL);
975 retval = lstrlenW(lpstrPath);
979 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
982 case CDM_SETCONTROLTEXT:
983 TRACE("CDM_SETCONTROLTEXT:\n");
986 if( fodInfos->unicode )
987 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
989 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
994 case CDM_HIDECONTROL:
995 /* MSDN states that it should fail for not OFN_EXPLORER case */
996 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
998 HWND control = GetDlgItem( hwnd, wParam );
999 if (control) ShowWindow( control, SW_HIDE );
1002 else retval = FALSE;
1006 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1007 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1010 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1014 /***********************************************************************
1017 * File open dialog procedure
1019 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1022 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1029 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1031 /* Adds the FileOpenDlgInfos in the property list of the dialog
1032 so it will be easily accessible through a GetPropA(...) */
1033 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1035 fodInfos->DlgInfos.hwndCustomDlg =
1036 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1038 FILEDLG95_InitControls(hwnd);
1040 if (fodInfos->DlgInfos.hwndCustomDlg)
1043 UINT flags = SWP_NOACTIVATE;
1045 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1046 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1048 /* resize the custom dialog to the parent size */
1049 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1050 GetClientRect(hwnd, &rc);
1053 /* our own fake template is zero sized and doesn't have
1054 * children, so there is no need to resize it.
1055 * Picasa depends on it.
1057 flags |= SWP_NOSIZE;
1060 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1061 0, 0, rc.right, rc.bottom, flags);
1064 FILEDLG95_FillControls(hwnd, wParam, lParam);
1066 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1067 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1068 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1072 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1075 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1078 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1084 case WM_GETISHELLBROWSER:
1085 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1088 RemovePropA(hwnd, FileOpenDlgInfosStr);
1093 LPNMHDR lpnmh = (LPNMHDR)lParam;
1096 /* set up the button tooltips strings */
1097 if(TTN_GETDISPINFOA == lpnmh->code )
1099 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1100 switch(lpnmh->idFrom )
1102 /* Up folder button */
1103 case FCIDM_TB_UPFOLDER:
1104 stringId = IDS_UPFOLDER;
1106 /* New folder button */
1107 case FCIDM_TB_NEWFOLDER:
1108 stringId = IDS_NEWFOLDER;
1110 /* List option button */
1111 case FCIDM_TB_SMALLICON:
1112 stringId = IDS_LISTVIEW;
1114 /* Details option button */
1115 case FCIDM_TB_REPORTVIEW:
1116 stringId = IDS_REPORTVIEW;
1118 /* Desktop button */
1119 case FCIDM_TB_DESKTOP:
1120 stringId = IDS_TODESKTOP;
1125 lpdi->hinst = COMDLG32_hInstance;
1126 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1131 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1132 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1137 /***********************************************************************
1138 * FILEDLG95_InitControls
1140 * WM_INITDIALOG message handler (before hook notification)
1142 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1144 int win2000plus = 0;
1146 int handledPath = FALSE;
1147 OSVERSIONINFOW osVi;
1148 static const WCHAR szwSlash[] = { '\\', 0 };
1149 static const WCHAR szwStar[] = { '*',0 };
1151 static const TBBUTTON tbb[] =
1153 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1154 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1155 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1156 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1157 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1158 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1159 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1160 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1161 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1166 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1168 tba[0].hInst = HINST_COMMCTRL;
1169 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1170 tba[1].hInst = COMDLG32_hInstance;
1173 TRACE("%p\n", fodInfos);
1175 /* Get windows version emulating */
1176 osVi.dwOSVersionInfoSize = sizeof(osVi);
1177 GetVersionExW(&osVi);
1178 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1179 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1180 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1181 win2000plus = (osVi.dwMajorVersion > 4);
1182 if (win2000plus) win98plus = TRUE;
1184 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1186 /* Get the hwnd of the controls */
1187 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1188 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1189 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1191 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1192 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1194 /* construct the toolbar */
1195 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1196 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1198 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1199 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1200 rectTB.left = rectlook.right;
1201 rectTB.top = rectlook.top-1;
1203 if (fodInfos->unicode)
1204 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1205 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1206 rectTB.left, rectTB.top,
1207 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1208 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1210 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1211 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1212 rectTB.left, rectTB.top,
1213 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1214 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1216 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1218 /* FIXME: use TB_LOADIMAGES when implemented */
1219 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1220 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1221 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1223 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1224 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1226 /* Set the window text with the text specified in the OPENFILENAME structure */
1229 SetWindowTextW(hwnd,fodInfos->title);
1231 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1234 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1235 SetWindowTextW(hwnd, buf);
1238 /* Initialise the file name edit control */
1239 handledPath = FALSE;
1240 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1242 if(fodInfos->filename)
1244 /* 1. If win2000 or higher and filename contains a path, use it
1245 in preference over the lpstrInitialDir */
1246 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1247 WCHAR tmpBuf[MAX_PATH];
1251 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1254 /* nameBit is always shorter than the original filename */
1255 lstrcpyW(fodInfos->filename,nameBit);
1258 if (fodInfos->initdir == NULL)
1259 MemFree(fodInfos->initdir);
1260 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1261 lstrcpyW(fodInfos->initdir, tmpBuf);
1263 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1264 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1266 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1269 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1273 /* 2. (All platforms) If initdir is not null, then use it */
1274 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1275 (*fodInfos->initdir!=0x00))
1277 /* Work out the proper path as supplied one might be relative */
1278 /* (Here because supplying '.' as dir browses to My Computer) */
1279 if (handledPath==FALSE) {
1280 WCHAR tmpBuf[MAX_PATH];
1281 WCHAR tmpBuf2[MAX_PATH];
1285 lstrcpyW(tmpBuf, fodInfos->initdir);
1286 if( PathFileExistsW(tmpBuf) ) {
1287 /* initdir does not have to be a directory. If a file is
1288 * specified, the dir part is taken */
1289 if( PathIsDirectoryW(tmpBuf)) {
1290 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1291 lstrcatW(tmpBuf, szwSlash);
1293 lstrcatW(tmpBuf, szwStar);
1295 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1298 MemFree(fodInfos->initdir);
1299 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1300 lstrcpyW(fodInfos->initdir, tmpBuf2);
1302 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1305 else if (fodInfos->initdir)
1307 MemFree(fodInfos->initdir);
1308 fodInfos->initdir = NULL;
1309 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1314 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1315 (*fodInfos->initdir==0x00)))
1317 /* 3. All except w2k+: if filename contains a path use it */
1318 if (!win2000plus && fodInfos->filename &&
1319 *fodInfos->filename &&
1320 strpbrkW(fodInfos->filename, szwSlash)) {
1321 WCHAR tmpBuf[MAX_PATH];
1325 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1330 /* nameBit is always shorter than the original filename */
1331 lstrcpyW(fodInfos->filename, nameBit);
1334 len = lstrlenW(tmpBuf);
1335 MemFree(fodInfos->initdir);
1336 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1337 lstrcpyW(fodInfos->initdir, tmpBuf);
1340 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1341 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1343 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1346 /* 4. win98+ and win2000+ if any files of specified filter types in
1347 current directory, use it */
1348 if ( win98plus && handledPath == FALSE &&
1349 fodInfos->filter && *fodInfos->filter) {
1351 BOOL searchMore = TRUE;
1352 LPCWSTR lpstrPos = fodInfos->filter;
1353 WIN32_FIND_DATAW FindFileData;
1358 /* filter is a list... title\0ext\0......\0\0 */
1360 /* Skip the title */
1361 if(! *lpstrPos) break; /* end */
1362 lpstrPos += lstrlenW(lpstrPos) + 1;
1364 /* See if any files exist in the current dir with this extension */
1365 if(! *lpstrPos) break; /* end */
1367 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1369 if (hFind == INVALID_HANDLE_VALUE) {
1370 /* None found - continue search */
1371 lpstrPos += lstrlenW(lpstrPos) + 1;
1376 MemFree(fodInfos->initdir);
1377 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1378 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1381 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1382 debugstr_w(lpstrPos));
1388 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1390 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1391 if (handledPath == FALSE && (win2000plus || win98plus)) {
1392 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1394 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1396 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1399 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1400 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1402 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1405 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1408 } else if (handledPath==FALSE) {
1409 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1410 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1412 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1415 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1416 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1418 /* Must the open as read only check box be checked ?*/
1419 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1421 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1424 /* Must the open as read only check box be hidden? */
1425 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1427 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1428 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1431 /* Must the help button be hidden? */
1432 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1434 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1435 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1438 /* Resize the height, if open as read only checkbox ad help button
1439 are hidden and we are not using a custom template nor a customDialog
1441 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1442 (!(fodInfos->ofnInfos->Flags &
1443 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1444 (!fodInfos->DlgInfos.hwndCustomDlg ))
1446 RECT rectDlg, rectHelp, rectCancel;
1447 GetWindowRect(hwnd, &rectDlg);
1448 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1449 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1450 /* subtract the height of the help button plus the space between
1451 the help button and the cancel button to the height of the dialog */
1452 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1453 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1454 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1456 /* change Open to Save */
1457 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1460 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1461 SetDlgItemTextW(hwnd, IDOK, buf);
1462 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1463 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1468 /***********************************************************************
1469 * FILEDLG95_FillControls
1471 * WM_INITDIALOG message handler (after hook notification)
1473 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1475 LPITEMIDLIST pidlItemId = NULL;
1477 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1479 TRACE("dir=%s file=%s\n",
1480 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1482 /* Get the initial directory pidl */
1484 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1486 WCHAR path[MAX_PATH];
1488 GetCurrentDirectoryW(MAX_PATH,path);
1489 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1492 /* Initialise shell objects */
1493 FILEDLG95_SHELL_Init(hwnd);
1495 /* Initialize the Look In combo box */
1496 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1498 /* Initialize the filter combo box */
1499 FILEDLG95_FILETYPE_Init(hwnd);
1501 /* Browse to the initial directory */
1502 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1504 /* Free pidlItem memory */
1505 COMDLG32_SHFree(pidlItemId);
1509 /***********************************************************************
1512 * Regroups all the cleaning functions of the filedlg
1514 void FILEDLG95_Clean(HWND hwnd)
1516 FILEDLG95_FILETYPE_Clean(hwnd);
1517 FILEDLG95_LOOKIN_Clean(hwnd);
1518 FILEDLG95_SHELL_Clean(hwnd);
1520 /***********************************************************************
1521 * FILEDLG95_OnWMCommand
1523 * WM_COMMAND message handler
1525 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1527 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1528 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1529 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1535 FILEDLG95_OnOpen(hwnd);
1539 FILEDLG95_Clean(hwnd);
1540 EndDialog(hwnd, FALSE);
1542 /* Filetype combo box */
1544 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1546 /* LookIn combo box */
1548 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1551 /* --- toolbar --- */
1552 /* Up folder button */
1553 case FCIDM_TB_UPFOLDER:
1554 FILEDLG95_SHELL_UpFolder(hwnd);
1556 /* New folder button */
1557 case FCIDM_TB_NEWFOLDER:
1558 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1560 /* List option button */
1561 case FCIDM_TB_SMALLICON:
1562 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1564 /* Details option button */
1565 case FCIDM_TB_REPORTVIEW:
1566 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1568 /* Details option button */
1569 case FCIDM_TB_DESKTOP:
1570 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1577 /* Do not use the listview selection anymore */
1578 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1582 /***********************************************************************
1583 * FILEDLG95_OnWMGetIShellBrowser
1585 * WM_GETISHELLBROWSER message handler
1587 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1590 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1594 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1600 /***********************************************************************
1601 * FILEDLG95_SendFileOK
1603 * Sends the CDN_FILEOK notification if required
1606 * TRUE if the dialog should close
1607 * FALSE if the dialog should not be closed
1609 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1611 /* ask the hook if we can close */
1612 if(IsHooked(fodInfos))
1617 /* First send CDN_FILEOK as MSDN doc says */
1618 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1619 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1621 TRACE("canceled\n");
1622 return (retval == 0);
1625 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1626 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1627 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1628 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1630 TRACE("canceled\n");
1631 return (retval == 0);
1637 /***********************************************************************
1638 * FILEDLG95_OnOpenMultipleFiles
1640 * Handles the opening of multiple files.
1643 * check destination buffer size
1645 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1647 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1648 UINT nCount, nSizePath;
1649 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1653 if(fodInfos->unicode)
1655 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1656 ofn->lpstrFile[0] = '\0';
1660 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1661 ofn->lpstrFile[0] = '\0';
1664 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1666 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1667 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1668 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1670 LPWSTR lpstrTemp = lpstrFileList;
1672 for ( nCount = 0; nCount < nFileCount; nCount++ )
1676 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1679 WCHAR lpstrNotFound[100];
1680 WCHAR lpstrMsg[100];
1682 static const WCHAR nl[] = {'\n',0};
1684 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1685 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1687 lstrcpyW(tmp, lpstrTemp);
1689 lstrcatW(tmp, lpstrNotFound);
1691 lstrcatW(tmp, lpstrMsg);
1693 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1697 /* move to the next file in the list of files */
1698 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1699 COMDLG32_SHFree(pidl);
1703 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1704 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1706 /* For "oldstyle" dialog the components have to
1707 be separated by blanks (not '\0'!) and short
1708 filenames have to be used! */
1709 FIXME("Components have to be separated by blanks\n");
1711 if(fodInfos->unicode)
1713 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1714 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1715 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1719 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1721 if (ofn->lpstrFile != NULL)
1723 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1724 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1725 if (ofn->nMaxFile > nSizePath)
1727 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1728 ofn->lpstrFile + nSizePath,
1729 ofn->nMaxFile - nSizePath, NULL, NULL);
1734 fodInfos->ofnInfos->nFileOffset = nSizePath;
1735 fodInfos->ofnInfos->nFileExtension = 0;
1737 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1740 /* clean and exit */
1741 FILEDLG95_Clean(hwnd);
1742 return EndDialog(hwnd,TRUE);
1745 /***********************************************************************
1748 * Ok button WM_COMMAND message handler
1750 * If the function succeeds, the return value is nonzero.
1752 #define ONOPEN_BROWSE 1
1753 #define ONOPEN_OPEN 2
1754 #define ONOPEN_SEARCH 3
1755 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1757 WCHAR strMsgTitle[MAX_PATH];
1758 WCHAR strMsgText [MAX_PATH];
1760 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1762 strMsgTitle[0] = '\0';
1763 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1764 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1767 BOOL FILEDLG95_OnOpen(HWND hwnd)
1769 LPWSTR lpstrFileList;
1770 UINT nFileCount = 0;
1773 WCHAR lpstrPathAndFile[MAX_PATH];
1774 WCHAR lpstrTemp[MAX_PATH];
1775 LPSHELLFOLDER lpsf = NULL;
1777 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1779 TRACE("hwnd=%p\n", hwnd);
1781 /* get the files from the edit control */
1782 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1784 /* try if the user selected a folder in the shellview */
1787 BrowseSelectedFolder(hwnd);
1793 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1797 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1800 Step 1: Build a complete path name from the current folder and
1801 the filename or path in the edit box.
1803 - the path in the edit box is a root path
1804 (with or without drive letter)
1805 - the edit box contains ".." (or a path with ".." in it)
1808 /* Get the current directory name */
1809 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1812 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1814 PathAddBackslashW(lpstrPathAndFile);
1816 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1818 /* if the user specifyed a fully qualified path use it */
1819 if(PathIsRelativeW(lpstrFileList))
1821 lstrcatW(lpstrPathAndFile, lpstrFileList);
1825 /* does the path have a drive letter? */
1826 if (PathGetDriveNumberW(lpstrFileList) == -1)
1827 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1829 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1832 /* resolve "." and ".." */
1833 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1834 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1835 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1837 MemFree(lpstrFileList);
1840 Step 2: here we have a cleaned up path
1842 We have to parse the path step by step to see if we have to browse
1843 to a folder if the path points to a directory or the last
1844 valid element is a directory.
1847 lpstrPathAndFile: cleaned up path
1851 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1852 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1853 nOpenAction = ONOPEN_OPEN;
1855 nOpenAction = ONOPEN_BROWSE;
1857 /* don't apply any checks with OFN_NOVALIDATE */
1859 LPWSTR lpszTemp, lpszTemp1;
1860 LPITEMIDLIST pidl = NULL;
1861 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1863 /* check for invalid chars */
1864 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1866 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1871 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1873 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1876 LPSHELLFOLDER lpsfChild;
1877 WCHAR lpwstrTemp[MAX_PATH];
1878 DWORD dwEaten, dwAttributes;
1881 lstrcpyW(lpwstrTemp, lpszTemp);
1882 p = PathFindNextComponentW(lpwstrTemp);
1884 if (!p) break; /* end of path */
1887 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1889 /* There are no wildcards when OFN_NOVALIDATE is set */
1890 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1892 static const WCHAR wszWild[] = { '*', '?', 0 };
1893 /* if the last element is a wildcard do a search */
1894 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1896 nOpenAction = ONOPEN_SEARCH;
1900 lpszTemp1 = lpszTemp;
1902 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1904 /* append a backslash to drive letters */
1905 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1906 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1907 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1909 PathAddBackslashW(lpwstrTemp);
1912 dwAttributes = SFGAO_FOLDER;
1913 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1915 /* the path component is valid, we have a pidl of the next path component */
1916 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1917 if(dwAttributes & SFGAO_FOLDER)
1919 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1921 ERR("bind to failed\n"); /* should not fail */
1924 IShellFolder_Release(lpsf);
1932 /* end dialog, return value */
1933 nOpenAction = ONOPEN_OPEN;
1936 COMDLG32_SHFree(pidl);
1939 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1941 if(*lpszTemp) /* points to trailing null for last path element */
1943 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1945 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1951 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1952 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1954 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1958 /* change to the current folder */
1959 nOpenAction = ONOPEN_OPEN;
1964 nOpenAction = ONOPEN_OPEN;
1968 if(pidl) COMDLG32_SHFree(pidl);
1972 Step 3: here we have a cleaned up and validated path
1975 lpsf: ShellFolder bound to the rightmost valid path component
1976 lpstrPathAndFile: cleaned up path
1977 nOpenAction: action to do
1979 TRACE("end validate sf=%p\n", lpsf);
1983 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1984 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1987 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1990 /* replace the current filter */
1991 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1992 len = lstrlenW(lpszTemp)+1;
1993 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1994 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1996 /* set the filter cb to the extension when possible */
1997 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1998 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2001 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2002 TRACE("ONOPEN_BROWSE\n");
2004 IPersistFolder2 * ppf2;
2005 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2007 LPITEMIDLIST pidlCurrent;
2008 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2009 IPersistFolder2_Release(ppf2);
2010 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2012 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2014 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2017 else if( nOpenAction == ONOPEN_SEARCH )
2019 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2021 COMDLG32_SHFree(pidlCurrent);
2022 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2027 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2028 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2032 /* update READONLY check box flag */
2033 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2034 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2036 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2038 /* Attach the file extension with file name*/
2039 ext = PathFindExtensionW(lpstrPathAndFile);
2042 /* if no extension is specified with file name, then */
2043 /* attach the extension from file filter or default one */
2045 WCHAR *filterExt = NULL;
2046 LPWSTR lpstrFilter = NULL;
2047 static const WCHAR szwDot[] = {'.',0};
2048 int PathLength = lstrlenW(lpstrPathAndFile);
2051 lstrcatW(lpstrPathAndFile, szwDot);
2053 /*Get the file extension from file type filter*/
2054 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2055 fodInfos->ofnInfos->nFilterIndex-1);
2057 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2058 filterExt = PathFindExtensionW(lpstrFilter);
2060 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2061 lstrcatW(lpstrPathAndFile, filterExt + 1);
2062 else if ( fodInfos->defext ) /* attach the default file extension*/
2063 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2065 /* In Open dialog: if file does not exist try without extension */
2066 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2067 lpstrPathAndFile[PathLength] = '\0';
2070 if (fodInfos->defext) /* add default extension */
2072 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2075 if (!lstrcmpiW(fodInfos->defext, ext))
2076 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2078 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2081 /* In Save dialog: check if the file already exists */
2082 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2083 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2084 && PathFileExistsW(lpstrPathAndFile))
2086 WCHAR lpstrOverwrite[100];
2089 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2090 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2091 MB_YESNO | MB_ICONEXCLAMATION);
2099 /* Check that the size of the file does not exceed buffer size.
2100 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2101 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2102 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2106 /* fill destination buffer */
2107 if (fodInfos->ofnInfos->lpstrFile)
2109 if(fodInfos->unicode)
2111 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2113 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2114 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2115 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2119 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2121 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2122 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2123 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2124 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2128 /* set filename offset */
2129 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2130 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2132 /* set extension offset */
2133 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2134 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2136 /* set the lpstrFileTitle */
2137 if(fodInfos->ofnInfos->lpstrFileTitle)
2139 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2140 if(fodInfos->unicode)
2142 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2143 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2147 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2148 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2149 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2153 /* copy currently selected filter to lpstrCustomFilter */
2154 if (fodInfos->ofnInfos->lpstrCustomFilter)
2156 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2157 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2158 NULL, 0, NULL, NULL);
2159 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2161 LPSTR s = ofn->lpstrCustomFilter;
2162 s += strlen(ofn->lpstrCustomFilter)+1;
2163 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2164 s, len, NULL, NULL);
2169 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2173 FILEDLG95_Clean(hwnd);
2174 ret = EndDialog(hwnd, TRUE);
2180 size = lstrlenW(lpstrPathAndFile) + 1;
2181 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2183 /* return needed size in first two bytes of lpstrFile */
2184 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2185 FILEDLG95_Clean(hwnd);
2186 ret = EndDialog(hwnd, FALSE);
2187 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2195 if(lpsf) IShellFolder_Release(lpsf);
2199 /***********************************************************************
2200 * FILEDLG95_SHELL_Init
2202 * Initialisation of the shell objects
2204 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2206 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2211 * Initialisation of the FileOpenDialogInfos structure
2217 fodInfos->ShellInfos.hwndOwner = hwnd;
2219 /* Disable multi-select if flag not set */
2220 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2222 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2224 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2225 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2227 /* Construct the IShellBrowser interface */
2228 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2233 /***********************************************************************
2234 * FILEDLG95_SHELL_ExecuteCommand
2236 * Change the folder option and refresh the view
2237 * If the function succeeds, the return value is nonzero.
2239 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2241 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2244 TRACE("(%p,%p)\n", hwnd, lpVerb);
2246 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2251 CMINVOKECOMMANDINFO ci;
2252 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2253 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2257 IContextMenu_InvokeCommand(pcm, &ci);
2258 IContextMenu_Release(pcm);
2264 /***********************************************************************
2265 * FILEDLG95_SHELL_UpFolder
2267 * Browse to the specified object
2268 * If the function succeeds, the return value is nonzero.
2270 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2272 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2276 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2280 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2286 /***********************************************************************
2287 * FILEDLG95_SHELL_BrowseToDesktop
2289 * Browse to the Desktop
2290 * If the function succeeds, the return value is nonzero.
2292 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2294 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2300 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2301 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2302 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2303 COMDLG32_SHFree(pidl);
2304 return SUCCEEDED(hres);
2306 /***********************************************************************
2307 * FILEDLG95_SHELL_Clean
2309 * Cleans the memory used by shell objects
2311 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2313 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2317 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2319 /* clean Shell interfaces */
2320 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2321 IShellView_Release(fodInfos->Shell.FOIShellView);
2322 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2323 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2324 if (fodInfos->Shell.FOIDataObject)
2325 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2328 /***********************************************************************
2329 * FILEDLG95_FILETYPE_Init
2331 * Initialisation of the file type combo box
2333 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2335 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2336 int nFilters = 0; /* number of filters */
2341 if(fodInfos->customfilter)
2343 /* customfilter has one entry... title\0ext\0
2344 * Set first entry of combo box item with customfilter
2347 LPCWSTR lpstrPos = fodInfos->customfilter;
2350 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2352 /* Copy the extensions */
2353 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2354 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2355 lstrcpyW(lpstrExt,lpstrPos);
2357 /* Add the item at the end of the combo */
2358 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2359 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2362 if(fodInfos->filter)
2364 LPCWSTR lpstrPos = fodInfos->filter;
2368 /* filter is a list... title\0ext\0......\0\0
2369 * Set the combo item text to the title and the item data
2372 LPCWSTR lpstrDisplay;
2376 if(! *lpstrPos) break; /* end */
2377 lpstrDisplay = lpstrPos;
2378 lpstrPos += lstrlenW(lpstrPos) + 1;
2380 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2384 /* Copy the extensions */
2385 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2386 lstrcpyW(lpstrExt,lpstrPos);
2387 lpstrPos += lstrlenW(lpstrPos) + 1;
2389 /* Add the item at the end of the combo */
2390 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2392 /* malformed filters are added anyway... */
2393 if (!*lpstrExt) break;
2398 * Set the current filter to the one specified
2399 * in the initialisation structure
2401 if (fodInfos->filter || fodInfos->customfilter)
2405 /* Check to make sure our index isn't out of bounds. */
2406 if ( fodInfos->ofnInfos->nFilterIndex >
2407 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2408 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2410 /* set default filter index */
2411 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2412 fodInfos->ofnInfos->nFilterIndex = 1;
2414 /* calculate index of Combo Box item */
2415 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2416 if (fodInfos->customfilter == NULL)
2419 /* Set the current index selection. */
2420 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2422 /* Get the corresponding text string from the combo box. */
2423 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2426 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2432 CharLowerW(lpstrFilter); /* lowercase */
2433 len = lstrlenW(lpstrFilter)+1;
2434 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2435 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2438 fodInfos->ofnInfos->nFilterIndex = 0;
2442 /***********************************************************************
2443 * FILEDLG95_FILETYPE_OnCommand
2445 * WM_COMMAND of the file type combo box
2446 * If the function succeeds, the return value is nonzero.
2448 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2450 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2458 /* Get the current item of the filetype combo box */
2459 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2461 /* set the current filter index */
2462 fodInfos->ofnInfos->nFilterIndex = iItem +
2463 (fodInfos->customfilter == NULL ? 1 : 0);
2465 /* Set the current filter with the current selection */
2466 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2468 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2470 if((INT_PTR)lpstrFilter != CB_ERR)
2473 CharLowerW(lpstrFilter); /* lowercase */
2474 len = lstrlenW(lpstrFilter)+1;
2475 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2476 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2477 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2480 /* Refresh the actual view to display the included items*/
2481 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2486 /***********************************************************************
2487 * FILEDLG95_FILETYPE_SearchExt
2489 * searches for an extension in the filetype box
2491 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2493 int i, iCount = CBGetCount(hwnd);
2495 TRACE("%s\n", debugstr_w(lpstrExt));
2497 if(iCount != CB_ERR)
2499 for(i=0;i<iCount;i++)
2501 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2508 /***********************************************************************
2509 * FILEDLG95_FILETYPE_Clean
2511 * Clean the memory used by the filetype combo box
2513 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2515 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2517 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2521 /* Delete each string of the combo and their associated data */
2522 if(iCount != CB_ERR)
2524 for(iPos = iCount-1;iPos>=0;iPos--)
2526 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2527 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2530 /* Current filter */
2531 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2535 /***********************************************************************
2536 * FILEDLG95_LOOKIN_Init
2538 * Initialisation of the look in combo box
2541 /* Small helper function, to determine if the unixfs shell extension is rooted
2542 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2544 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2546 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2547 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2548 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2549 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2550 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2551 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2552 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2554 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2561 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2563 IShellFolder *psfRoot, *psfDrives;
2564 IEnumIDList *lpeRoot, *lpeDrives;
2565 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2567 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2571 liInfos->iMaxIndentation = 0;
2573 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2575 /* set item height for both text field and listbox */
2576 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2577 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2579 /* Turn on the extended UI for the combo box like Windows does */
2580 CBSetExtendedUI(hwndCombo, TRUE);
2582 /* Initialise data of Desktop folder */
2583 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2584 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2585 COMDLG32_SHFree(pidlTmp);
2587 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2589 SHGetDesktopFolder(&psfRoot);
2593 /* enumerate the contents of the desktop */
2594 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2596 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2598 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2600 /* If the unixfs extension is rooted, we don't expand the drives by default */
2601 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2603 /* special handling for CSIDL_DRIVES */
2604 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2606 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2608 /* enumerate the drives */
2609 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2611 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2613 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2614 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2615 COMDLG32_SHFree(pidlAbsTmp);
2616 COMDLG32_SHFree(pidlTmp1);
2618 IEnumIDList_Release(lpeDrives);
2620 IShellFolder_Release(psfDrives);
2625 COMDLG32_SHFree(pidlTmp);
2627 IEnumIDList_Release(lpeRoot);
2629 IShellFolder_Release(psfRoot);
2632 COMDLG32_SHFree(pidlDrives);
2635 /***********************************************************************
2636 * FILEDLG95_LOOKIN_DrawItem
2638 * WM_DRAWITEM message handler
2640 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2642 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2643 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2644 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2648 HIMAGELIST ilItemImage;
2651 LPSFOLDER tmpFolder;
2654 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2658 if(pDIStruct->itemID == -1)
2661 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2662 pDIStruct->itemID)))
2666 if(pDIStruct->itemID == liInfos->uSelectedItem)
2668 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2672 SHGFI_PIDL | SHGFI_SMALLICON |
2673 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2674 SHGFI_DISPLAYNAME );
2678 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2682 SHGFI_PIDL | SHGFI_SMALLICON |
2683 SHGFI_SYSICONINDEX |
2687 /* Is this item selected ? */
2688 if(pDIStruct->itemState & ODS_SELECTED)
2690 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2691 SetBkColor(pDIStruct->hDC,crHighLight);
2692 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2696 SetTextColor(pDIStruct->hDC,crText);
2697 SetBkColor(pDIStruct->hDC,crWin);
2698 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2701 /* Do not indent item if drawing in the edit of the combo */
2702 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2705 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2709 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2710 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2715 iIndentation = tmpFolder->m_iIndent;
2717 /* Draw text and icon */
2719 /* Initialise the icon display area */
2720 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2721 rectIcon.top = pDIStruct->rcItem.top;
2722 rectIcon.right = rectIcon.left + ICONWIDTH;
2723 rectIcon.bottom = pDIStruct->rcItem.bottom;
2725 /* Initialise the text display area */
2726 GetTextMetricsW(pDIStruct->hDC, &tm);
2727 rectText.left = rectIcon.right;
2729 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2730 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2732 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2734 /* Draw the icon from the image list */
2735 ImageList_Draw(ilItemImage,
2742 /* Draw the associated text */
2743 if(sfi.szDisplayName)
2744 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2750 /***********************************************************************
2751 * FILEDLG95_LOOKIN_OnCommand
2753 * LookIn combo box WM_COMMAND message handler
2754 * If the function succeeds, the return value is nonzero.
2756 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2758 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2760 TRACE("%p\n", fodInfos);
2766 LPSFOLDER tmpFolder;
2769 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2771 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2776 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2777 tmpFolder->pidlItem,
2780 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2790 /***********************************************************************
2791 * FILEDLG95_LOOKIN_AddItem
2793 * Adds an absolute pidl item to the lookin combo box
2794 * returns the index of the inserted item
2796 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2798 LPITEMIDLIST pidlNext;
2801 LookInInfos *liInfos;
2803 TRACE("%08x\n", iInsertId);
2808 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2811 tmpFolder = MemAlloc(sizeof(SFOLDER));
2812 tmpFolder->m_iIndent = 0;
2814 /* Calculate the indentation of the item in the lookin*/
2816 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2818 tmpFolder->m_iIndent++;
2821 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2823 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2824 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2826 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2827 SHGetFileInfoW((LPCWSTR)pidl,
2831 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2832 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2834 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2836 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2840 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2842 /* Add the item at the end of the list */
2845 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2847 /* Insert the item at the iInsertId position*/
2850 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2853 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2857 COMDLG32_SHFree( tmpFolder->pidlItem );
2858 MemFree( tmpFolder );
2863 /***********************************************************************
2864 * FILEDLG95_LOOKIN_InsertItemAfterParent
2866 * Insert an item below its parent
2868 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2871 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2876 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2880 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2883 /* Free pidlParent memory */
2884 COMDLG32_SHFree((LPVOID)pidlParent);
2886 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2889 /***********************************************************************
2890 * FILEDLG95_LOOKIN_SelectItem
2892 * Adds an absolute pidl item to the lookin combo box
2893 * returns the index of the inserted item
2895 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2898 LookInInfos *liInfos;
2902 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2904 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2908 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2909 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2914 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2915 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2919 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2921 if(iRemovedItem < iItemPos)
2926 CBSetCurSel(hwnd,iItemPos);
2927 liInfos->uSelectedItem = iItemPos;
2933 /***********************************************************************
2934 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2936 * Remove the item with an expansion level over iExpansionLevel
2938 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2942 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2946 if(liInfos->iMaxIndentation <= 2)
2949 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2951 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2952 COMDLG32_SHFree(tmpFolder->pidlItem);
2954 CBDeleteString(hwnd,iItemPos);
2955 liInfos->iMaxIndentation--;
2963 /***********************************************************************
2964 * FILEDLG95_LOOKIN_SearchItem
2966 * Search for pidl in the lookin combo box
2967 * returns the index of the found item
2969 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2972 int iCount = CBGetCount(hwnd);
2974 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2976 if (iCount != CB_ERR)
2980 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2982 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2984 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2992 /***********************************************************************
2993 * FILEDLG95_LOOKIN_Clean
2995 * Clean the memory used by the lookin combo box
2997 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2999 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3001 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3005 /* Delete each string of the combo and their associated data */
3006 if (iCount != CB_ERR)
3008 for(iPos = iCount-1;iPos>=0;iPos--)
3010 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3011 COMDLG32_SHFree(tmpFolder->pidlItem);
3013 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3017 /* LookInInfos structure */
3018 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3021 /***********************************************************************
3022 * FILEDLG95_FILENAME_FillFromSelection
3024 * fills the edit box from the cached DataObject
3026 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3028 FileOpenDlgInfos *fodInfos;
3030 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3031 WCHAR lpstrTemp[MAX_PATH];
3032 LPWSTR lpstrAllFile, lpstrCurrFile;
3035 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3037 /* Count how many files we have */
3038 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3040 /* calculate the string length, count files */
3041 if (nFileSelected >= 1)
3043 nLength += 3; /* first and last quotes, trailing \0 */
3044 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3046 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3050 /* get the total length of the selected file names */
3051 lpstrTemp[0] = '\0';
3052 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3054 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3056 nLength += lstrlenW( lpstrTemp ) + 3;
3059 COMDLG32_SHFree( pidl );
3064 /* allocate the buffer */
3065 if (nFiles <= 1) nLength = MAX_PATH;
3066 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3068 /* Generate the string for the edit control */
3071 lpstrCurrFile = lpstrAllFile;
3072 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3074 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3078 /* get the file name */
3079 lpstrTemp[0] = '\0';
3080 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3082 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3086 *lpstrCurrFile++ = '\"';
3087 lstrcpyW( lpstrCurrFile, lpstrTemp );
3088 lpstrCurrFile += lstrlenW( lpstrTemp );
3089 *lpstrCurrFile++ = '\"';
3090 *lpstrCurrFile++ = ' ';
3095 lstrcpyW( lpstrAllFile, lpstrTemp );
3098 COMDLG32_SHFree( (LPVOID) pidl );
3101 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3103 /* Select the file name like Windows does */
3104 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3106 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3110 /* copied from shell32 to avoid linking to it
3111 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3112 * is dependent on whether emulated OS is unicode or not.
3114 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3119 lstrcpynW(dest, src->u.pOleStr, len);
3120 COMDLG32_SHFree(src->u.pOleStr);
3124 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3129 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3134 FIXME("unknown type %x!\n", src->uType);
3135 if (len) *dest = '\0';
3141 /***********************************************************************
3142 * FILEDLG95_FILENAME_GetFileNames
3144 * Copies the filenames to a delimited string list.
3145 * The delimiter is specified by the parameter 'separator',
3146 * usually either a space or a nul
3148 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3150 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3151 UINT nStrCharCount = 0; /* index in src buffer */
3152 UINT nFileIndex = 0; /* index in dest buffer */
3153 UINT nFileCount = 0; /* number of files */
3154 UINT nStrLen = 0; /* length of string in edit control */
3155 LPWSTR lpstrEdit; /* buffer for string from edit control */
3159 /* get the filenames from the edit control */
3160 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3161 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3162 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3164 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3166 /* we might get single filename without any '"',
3167 * so we need nStrLen + terminating \0 + end-of-list \0 */
3168 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3171 /* build delimited file list from filenames */
3172 while ( nStrCharCount <= nStrLen )
3174 if ( lpstrEdit[nStrCharCount]=='"' )
3177 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3179 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3183 (*lpstrFileList)[nFileIndex++] = separator;
3190 /* single, unquoted string */
3191 if ((nStrLen > 0) && (*sizeUsed == 0) )
3193 lstrcpyW(*lpstrFileList, lpstrEdit);
3194 nFileIndex = lstrlenW(lpstrEdit) + 1;
3195 (*sizeUsed) = nFileIndex;
3200 (*lpstrFileList)[nFileIndex] = '\0';
3207 #define SETDefFormatEtc(fe,cf,med) \
3209 (fe).cfFormat = cf;\
3210 (fe).dwAspect = DVASPECT_CONTENT; \
3217 * DATAOBJECT Helper functions
3220 /***********************************************************************
3221 * COMCTL32_ReleaseStgMedium
3223 * like ReleaseStgMedium from ole32
3225 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3227 if(medium.pUnkForRelease)
3229 IUnknown_Release(medium.pUnkForRelease);
3233 GlobalUnlock(medium.u.hGlobal);
3234 GlobalFree(medium.u.hGlobal);
3238 /***********************************************************************
3239 * GetPidlFromDataObject
3241 * Return pidl(s) by number from the cached DataObject
3243 * nPidlIndex=0 gets the fully qualified root path
3245 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3249 FORMATETC formatetc;
3250 LPITEMIDLIST pidl = NULL;
3252 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3257 /* Set the FORMATETC structure*/
3258 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3260 /* Get the pidls from IDataObject */
3261 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3263 LPIDA cida = GlobalLock(medium.u.hGlobal);
3264 if(nPidlIndex <= cida->cidl)
3266 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3268 COMCTL32_ReleaseStgMedium(medium);
3273 /***********************************************************************
3276 * Return the number of selected items in the DataObject.
3279 UINT GetNumSelected( IDataObject *doSelected )
3283 FORMATETC formatetc;
3285 TRACE("sv=%p\n", doSelected);
3287 if (!doSelected) return 0;
3289 /* Set the FORMATETC structure*/
3290 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3292 /* Get the pidls from IDataObject */
3293 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3295 LPIDA cida = GlobalLock(medium.u.hGlobal);
3296 retVal = cida->cidl;
3297 COMCTL32_ReleaseStgMedium(medium);
3307 /***********************************************************************
3310 * Get the pidl's display name (relative to folder) and
3311 * put it in lpstrFileName.
3313 * Return NOERROR on success,
3317 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3322 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3326 SHGetDesktopFolder(&lpsf);
3327 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3328 IShellFolder_Release(lpsf);
3332 /* Get the display name of the pidl relative to the folder */
3333 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3335 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3340 /***********************************************************************
3341 * GetShellFolderFromPidl
3343 * pidlRel is the item pidl relative
3344 * Return the IShellFolder of the absolute pidl
3346 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3348 IShellFolder *psf = NULL,*psfParent;
3350 TRACE("%p\n", pidlAbs);
3352 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3355 if(pidlAbs && pidlAbs->mkid.cb)
3357 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3359 IShellFolder_Release(psfParent);
3363 /* return the desktop */
3369 /***********************************************************************
3372 * Return the LPITEMIDLIST to the parent of the pidl in the list
3374 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3376 LPITEMIDLIST pidlParent;
3378 TRACE("%p\n", pidl);
3380 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3381 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3386 /***********************************************************************
3389 * returns the pidl of the file name relative to folder
3390 * NULL if an error occurred
3392 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3394 LPITEMIDLIST pidl = NULL;
3397 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3399 if(!lpcstrFileName) return NULL;
3400 if(!*lpcstrFileName) return NULL;
3404 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3405 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3406 IShellFolder_Release(lpsf);
3411 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3418 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3420 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3423 TRACE("%p, %p\n", psf, pidl);
3425 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3427 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3428 /* see documentation shell 4.1*/
3429 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3432 /***********************************************************************
3433 * BrowseSelectedFolder
3435 static BOOL BrowseSelectedFolder(HWND hwnd)
3437 BOOL bBrowseSelFolder = FALSE;
3438 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3442 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3444 LPITEMIDLIST pidlSelection;
3446 /* get the file selected */
3447 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3448 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3450 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3451 pidlSelection, SBSP_RELATIVE ) ) )
3453 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3454 ' ','n','o','t',' ','e','x','i','s','t',0};
3455 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3457 bBrowseSelFolder = TRUE;
3458 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3460 COMDLG32_SHFree( pidlSelection );
3463 return bBrowseSelFolder;
3467 * Memory allocation methods */
3468 static void *MemAlloc(UINT size)
3470 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3473 static void MemFree(void *mem)
3475 HeapFree(GetProcessHeap(),0,mem);
3479 * Old-style (win3.1) dialogs */
3481 /***********************************************************************
3482 * FD32_GetTemplate [internal]
3484 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3485 * by a 32 bits application
3488 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3490 LPOPENFILENAMEW ofnW = lfs->ofnW;
3491 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3494 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3496 if (!(lfs->template = LockResource( ofnW->hInstance )))
3498 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3502 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3506 hResInfo = FindResourceA(priv->ofnA->hInstance,
3507 priv->ofnA->lpTemplateName,
3510 hResInfo = FindResourceW(ofnW->hInstance,
3511 ofnW->lpTemplateName,
3515 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3518 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3520 !(lfs->template = LockResource(hDlgTmpl)))
3522 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3525 } else { /* get it from internal Wine resource */
3527 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3528 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3530 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3533 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3534 !(lfs->template = LockResource( hDlgTmpl )))
3536 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3544 /************************************************************************
3545 * FD32_Init [internal]
3546 * called from the common 16/32 code to initialize 32 bit data
3548 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3550 BOOL IsUnicode = (BOOL) data;
3553 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3554 lfs->private1632 = priv;
3555 if (NULL == lfs->private1632) return FALSE;
3558 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3559 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3560 if (lfs->ofnW->lpfnHook)
3565 priv->ofnA = (LPOPENFILENAMEA) lParam;
3566 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3567 if (priv->ofnA->lpfnHook)
3569 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3570 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3573 if (! FD32_GetTemplate(lfs)) return FALSE;
3578 /***********************************************************************
3579 * FD32_CallWindowProc [internal]
3581 * called from the common 16/32 code to call the appropriate hook
3583 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3587 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3591 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3592 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3593 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3594 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3595 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3599 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3600 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3601 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3602 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3603 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3607 /***********************************************************************
3608 * FD32_UpdateResult [internal]
3609 * update the real client structures if any
3611 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3613 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3614 LPOPENFILENAMEW ofnW = lfs->ofnW;
3618 if (ofnW->nMaxFile &&
3619 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3620 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3621 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3622 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3623 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3627 /***********************************************************************
3628 * FD32_UpdateFileTitle [internal]
3629 * update the real client structures if any
3631 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3633 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3634 LPOPENFILENAMEW ofnW = lfs->ofnW;
3638 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3639 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3640 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3645 /***********************************************************************
3646 * FD32_SendLbGetCurSel [internal]
3647 * retrieve selected listbox item
3649 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3651 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3655 /************************************************************************
3656 * FD32_Destroy [internal]
3657 * called from the common 16/32 code to cleanup 32 bit data
3659 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3661 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3663 /* if ofnW has been allocated, have to free everything in it */
3664 if (NULL != priv && NULL != priv->ofnA)
3666 FD31_FreeOfnW(lfs->ofnW);
3667 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3671 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3673 callbacks->Init = FD32_Init;
3674 callbacks->CWP = FD32_CallWindowProc;
3675 callbacks->UpdateResult = FD32_UpdateResult;
3676 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3677 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3678 callbacks->Destroy = FD32_Destroy;
3681 /***********************************************************************
3682 * FD32_WMMeasureItem [internal]
3684 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3686 LPMEASUREITEMSTRUCT lpmeasure;
3688 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3689 lpmeasure->itemHeight = FD31_GetFldrHeight();
3694 /***********************************************************************
3695 * FileOpenDlgProc [internal]
3696 * Used for open and save, in fact.
3698 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3699 WPARAM wParam, LPARAM lParam)
3701 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3703 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3704 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3707 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3709 return lRet; /* else continue message processing */
3714 return FD31_WMInitDialog(hWnd, wParam, lParam);
3716 case WM_MEASUREITEM:
3717 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3720 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3723 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3726 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3727 switch (HIWORD(lParam))
3730 SetTextColor((HDC16)wParam, 0x00000000);
3732 case CTLCOLOR_STATIC:
3733 SetTextColor((HDC16)wParam, 0x00000000);
3743 /***********************************************************************
3744 * GetFileName31A [internal]
3746 * Creates a win31 style dialog box for the user to select a file to open/save.
3748 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3749 UINT dlgType /* type dialogue : open/save */
3755 FD31_CALLBACKS callbacks;
3757 if (!lpofn || !FD31_Init()) return FALSE;
3759 TRACE("ofn flags %08x\n", lpofn->Flags);
3760 FD32_SetupCallbacks(&callbacks);
3761 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3764 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3765 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3766 FD32_FileOpenDlgProc, (LPARAM)lfs);
3767 FD31_DestroyPrivate(lfs);
3770 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3774 /***********************************************************************
3775 * GetFileName31W [internal]
3777 * Creates a win31 style dialog box for the user to select a file to open/save
3779 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3780 UINT dlgType /* type dialogue : open/save */
3786 FD31_CALLBACKS callbacks;
3788 if (!lpofn || !FD31_Init()) return FALSE;
3790 FD32_SetupCallbacks(&callbacks);
3791 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3794 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3795 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3796 FD32_FileOpenDlgProc, (LPARAM)lfs);
3797 FD31_DestroyPrivate(lfs);
3800 TRACE("file %s, file offset %d, ext offset %d\n",
3801 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3805 /* ------------------ APIs ---------------------- */
3807 /***********************************************************************
3808 * GetOpenFileNameA (COMDLG32.@)
3810 * Creates a dialog box for the user to select a file to open.
3813 * TRUE on success: user enters a valid file
3814 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3817 BOOL WINAPI GetOpenFileNameA(
3818 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3820 BOOL win16look = FALSE;
3822 TRACE("flags %08x\n", ofn->Flags);
3824 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3825 if (ofn->Flags & OFN_FILEMUSTEXIST)
3826 ofn->Flags |= OFN_PATHMUSTEXIST;
3828 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3829 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3832 return GetFileName31A(ofn, OPEN_DIALOG);
3834 return GetFileDialog95A(ofn, OPEN_DIALOG);
3837 /***********************************************************************
3838 * GetOpenFileNameW (COMDLG32.@)
3840 * Creates a dialog box for the user to select a file to open.
3843 * TRUE on success: user enters a valid file
3844 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3847 BOOL WINAPI GetOpenFileNameW(
3848 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3850 BOOL win16look = FALSE;
3852 TRACE("flags %08x\n", ofn->Flags);
3854 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3855 if (ofn->Flags & OFN_FILEMUSTEXIST)
3856 ofn->Flags |= OFN_PATHMUSTEXIST;
3858 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3859 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3862 return GetFileName31W(ofn, OPEN_DIALOG);
3864 return GetFileDialog95W(ofn, OPEN_DIALOG);
3868 /***********************************************************************
3869 * GetSaveFileNameA (COMDLG32.@)
3871 * Creates a dialog box for the user to select a file to save.
3874 * TRUE on success: user enters a valid file
3875 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3878 BOOL WINAPI GetSaveFileNameA(
3879 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3881 BOOL win16look = FALSE;
3883 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3884 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3887 return GetFileName31A(ofn, SAVE_DIALOG);
3889 return GetFileDialog95A(ofn, SAVE_DIALOG);
3892 /***********************************************************************
3893 * GetSaveFileNameW (COMDLG32.@)
3895 * Creates a dialog box for the user to select a file to save.
3898 * TRUE on success: user enters a valid file
3899 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3902 BOOL WINAPI GetSaveFileNameW(
3903 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3905 BOOL win16look = FALSE;
3907 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3908 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3911 return GetFileName31W(ofn, SAVE_DIALOG);
3913 return GetFileDialog95W(ofn, SAVE_DIALOG);
3916 /***********************************************************************
3917 * GetFileTitleA (COMDLG32.@)
3919 * See GetFileTitleW.
3921 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3924 UNICODE_STRING strWFile;
3927 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3928 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3929 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3930 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3931 RtlFreeUnicodeString( &strWFile );
3932 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3937 /***********************************************************************
3938 * GetFileTitleW (COMDLG32.@)
3940 * Get the name of a file.
3943 * lpFile [I] name and location of file
3944 * lpTitle [O] returned file name
3945 * cbBuf [I] buffer size of lpTitle
3949 * Failure: negative number.
3951 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3954 static const WCHAR brkpoint[] = {'*','[',']',0};
3955 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3957 if(lpFile == NULL || lpTitle == NULL)
3960 len = lstrlenW(lpFile);
3965 if(strpbrkW(lpFile, brkpoint))
3970 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3973 for(i = len; i >= 0; i--)
3975 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
3985 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
3987 len = lstrlenW(lpFile+i)+1;
3991 lstrcpyW(lpTitle, &lpFile[i]);