2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/unicode.h"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
80 #include "filedlgbrowser.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
123 #define XTEXTOFFSET 3
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
179 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
185 /* Internal functions used by the dialog */
186 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
189 BOOL FILEDLG95_OnOpen(HWND hwnd);
190 static LRESULT FILEDLG95_InitControls(HWND hwnd);
191 static void FILEDLG95_Clean(HWND hwnd);
193 /* Functions used by the shell navigation */
194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
203 /* Functions used by the filetype combo box */
204 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
205 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
211 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
212 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
220 /* Miscellaneous tool functions */
221 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
222 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
223 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
224 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
230 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
232 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
233 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
234 static BOOL BrowseSelectedFolder(HWND hwnd);
236 /***********************************************************************
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
255 /* test for missing functionality */
256 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
258 FIXME("Flags 0x%08x not yet implemented\n",
259 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
262 /* Create the dialog from a template */
264 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
269 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
270 !(template = LockResource( hDlgTmpl )))
272 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
288 if (fodInfos->unicode)
289 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
291 fodInfos->ofnInfos->hwndOwner,
295 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
296 (LPCDLGTEMPLATEA) template,
297 fodInfos->ofnInfos->hwndOwner,
303 /* Unable to create the dialog */
310 /***********************************************************************
313 * Call GetFileName95 with this structure and clean the memory.
315 * IN : The OPENFILENAMEA initialisation structure passed to
316 * GetOpenFileNameA win api function (see filedlg.c)
318 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
321 FileOpenDlgInfos fodInfos;
322 LPSTR lpstrSavDir = NULL;
324 LPWSTR defext = NULL;
325 LPWSTR filter = NULL;
326 LPWSTR customfilter = NULL;
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
351 fodInfos.initdir = NULL;
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
359 fodInfos.filename = NULL;
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
417 ret = GetFileName95(&fodInfos);
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
445 /***********************************************************************
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize FileOpenDlgInfos structure */
459 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
461 /* Pass in the original ofn */
462 fodInfos.ofnInfos = ofn;
464 fodInfos.title = ofn->lpstrTitle;
465 fodInfos.defext = ofn->lpstrDefExt;
466 fodInfos.filter = ofn->lpstrFilter;
467 fodInfos.customfilter = ofn->lpstrCustomFilter;
469 /* convert string arguments, save others */
472 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
473 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
476 fodInfos.filename = NULL;
478 if(ofn->lpstrInitialDir)
480 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
481 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
482 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
483 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
486 fodInfos.initdir = NULL;
488 /* save current directory */
489 if (ofn->Flags & OFN_NOCHANGEDIR)
491 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
492 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
495 fodInfos.unicode = TRUE;
500 ret = GetFileName95(&fodInfos);
503 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
504 ret = GetFileName95(&fodInfos);
512 SetCurrentDirectoryW(lpstrSavDir);
513 MemFree(lpstrSavDir);
516 /* restore saved IN arguments and convert OUT arguments back */
517 MemFree(fodInfos.filename);
518 MemFree(fodInfos.initdir);
522 /******************************************************************************
523 * COMDLG32_GetDisplayNameOf [internal]
525 * Helper function to get the display name for a pidl.
527 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
528 LPSHELLFOLDER psfDesktop;
531 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
534 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
535 IShellFolder_Release(psfDesktop);
539 IShellFolder_Release(psfDesktop);
540 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
543 /***********************************************************************
544 * ArrangeCtrlPositions [internal]
546 * NOTE: Do not change anything here without a lot of testing.
548 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
550 HWND hwndChild, hwndStc32;
551 RECT rectParent, rectChild, rectStc32;
552 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
554 /* Take into account if open as read only checkbox and help button
559 RECT rectHelp, rectCancel;
560 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
561 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
562 /* subtract the height of the help button plus the space between
563 * the help button and the cancel button to the height of the dialog
565 help_fixup = rectHelp.bottom - rectCancel.bottom;
569 There are two possibilities to add components to the default file dialog box.
571 By default, all the new components are added below the standard dialog box (the else case).
573 However, if there is a static text component with the stc32 id, a special case happens.
574 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
575 in the window and the cx and cy indicate how to size the window.
576 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
577 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
581 GetClientRect(hwndParentDlg, &rectParent);
583 /* when arranging controls we have to use fixed parent size */
584 rectParent.bottom -= help_fixup;
586 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
589 GetWindowRect(hwndStc32, &rectStc32);
590 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
592 /* set the size of the stc32 control according to the size of
593 * client area of the parent dialog
595 SetWindowPos(hwndStc32, 0,
597 rectParent.right, rectParent.bottom,
598 SWP_NOMOVE | SWP_NOZORDER);
601 SetRectEmpty(&rectStc32);
603 /* this part moves controls of the child dialog */
604 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
607 if (hwndChild != hwndStc32)
609 GetWindowRect(hwndChild, &rectChild);
610 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
612 /* move only if stc32 exist */
613 if (hwndStc32 && rectChild.left > rectStc32.right)
615 LONG old_left = rectChild.left;
617 /* move to the right of visible controls of the parent dialog */
618 rectChild.left += rectParent.right;
619 rectChild.left -= rectStc32.right;
621 child_width_fixup = rectChild.left - old_left;
623 /* move even if stc32 doesn't exist */
624 if (rectChild.top >= rectStc32.bottom)
626 LONG old_top = rectChild.top;
628 /* move below visible controls of the parent dialog */
629 rectChild.top += rectParent.bottom;
630 rectChild.top -= rectStc32.bottom - rectStc32.top;
632 child_height_fixup = rectChild.top - old_top;
635 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
636 0, 0, SWP_NOSIZE | SWP_NOZORDER);
638 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
641 /* this part moves controls of the parent dialog */
642 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
645 if (hwndChild != hwndChildDlg)
647 GetWindowRect(hwndChild, &rectChild);
648 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
650 /* left,top of stc32 marks the position of controls
651 * from the parent dialog
653 rectChild.left += rectStc32.left;
654 rectChild.top += rectStc32.top;
656 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
657 0, 0, SWP_NOSIZE | SWP_NOZORDER);
659 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
662 /* calculate the size of the resulting dialog */
664 /* here we have to use original parent size */
665 GetClientRect(hwndParentDlg, &rectParent);
666 GetClientRect(hwndChildDlg, &rectChild);
670 rectChild.right += child_width_fixup;
671 rectChild.bottom += child_height_fixup;
673 if (rectParent.right > rectChild.right)
675 rectParent.right += rectChild.right;
676 rectParent.right -= rectStc32.right - rectStc32.left;
680 rectParent.right = rectChild.right;
683 if (rectParent.bottom > rectChild.bottom)
685 rectParent.bottom += rectChild.bottom;
686 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
690 /* child dialog is higher, unconditionally set new dialog
691 * height to its size (help_fixup will be subtracted below)
693 rectParent.bottom = rectChild.bottom + help_fixup;
698 rectParent.bottom += rectChild.bottom;
701 /* finally use fixed parent size */
702 rectParent.bottom -= help_fixup;
704 /* set the size of the parent dialog */
705 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
706 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
707 SetWindowPos(hwndParentDlg, 0,
709 rectParent.right - rectParent.left,
710 rectParent.bottom - rectParent.top,
711 SWP_NOMOVE | SWP_NOZORDER);
714 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
723 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
742 hinst = COMDLG32_hInstance;
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
774 if (fodInfos->unicode)
775 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
776 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
777 (LPARAM)fodInfos->ofnInfos);
779 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
780 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
781 (LPARAM)fodInfos->ofnInfos);
784 ShowWindow(hChildDlg,SW_SHOW);
788 else if( IsHooked(fodInfos))
793 WORD menu,class,title;
795 GetClientRect(hwnd,&rectHwnd);
796 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
797 temp.tmplate.dwExtendedStyle = 0;
798 temp.tmplate.cdit = 0;
803 temp.menu = temp.class = temp.title = 0;
805 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
806 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
813 /***********************************************************************
814 * SendCustomDlgNotificationMessage
816 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
819 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
821 LRESULT hook_result = 0;
823 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
825 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
827 if(!fodInfos) return 0;
829 if(fodInfos->DlgInfos.hwndCustomDlg)
831 TRACE("CALL NOTIFY for %x\n", uCode);
832 if(fodInfos->unicode)
835 ofnNotify.hdr.hwndFrom=hwndParentDlg;
836 ofnNotify.hdr.idFrom=0;
837 ofnNotify.hdr.code = uCode;
838 ofnNotify.lpOFN = fodInfos->ofnInfos;
839 ofnNotify.pszFile = NULL;
840 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
845 ofnNotify.hdr.hwndFrom=hwndParentDlg;
846 ofnNotify.hdr.idFrom=0;
847 ofnNotify.hdr.code = uCode;
848 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
849 ofnNotify.pszFile = NULL;
850 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
852 TRACE("RET NOTIFY\n");
854 TRACE("Retval: 0x%08lx\n", hook_result);
858 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
860 UINT sizeUsed = 0, n, total;
861 LPWSTR lpstrFileList = NULL;
862 WCHAR lpstrCurrentDir[MAX_PATH];
863 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
865 TRACE("CDM_GETFILEPATH:\n");
867 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
870 /* get path and filenames */
871 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
872 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
874 TRACE("path >%s< filespec >%s< %d files\n",
875 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
877 if( fodInfos->unicode )
879 LPWSTR bufW = buffer;
880 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
882 /* Prepend the current path */
883 n = strlenW(lpstrCurrentDir) + 1;
884 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
887 /* 'n' includes trailing \0 */
889 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
891 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
896 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
897 NULL, 0, NULL, NULL);
898 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
899 NULL, 0, NULL, NULL);
901 /* Prepend the current path */
902 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
903 bufA, size, NULL, NULL);
907 /* 'n' includes trailing \0 */
909 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
910 &bufA[n], size-n, NULL, NULL);
913 TRACE("returned -> %s\n",debugstr_an(bufA, total));
915 MemFree(lpstrFileList);
920 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
923 LPWSTR lpstrFileList = NULL;
924 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
926 TRACE("CDM_GETSPEC:\n");
928 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
929 if( fodInfos->unicode )
931 LPWSTR bufW = buffer;
932 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
937 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
938 NULL, 0, NULL, NULL);
939 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
940 bufA, size, NULL, NULL);
942 MemFree(lpstrFileList);
947 /***********************************************************************
948 * FILEDLG95_HandleCustomDialogMessages
950 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
952 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
954 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
955 WCHAR lpstrPath[MAX_PATH];
958 if(!fodInfos) return FALSE;
962 case CDM_GETFILEPATH:
963 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
966 case CDM_GETFOLDERPATH:
967 TRACE("CDM_GETFOLDERPATH:\n");
968 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
971 if (fodInfos->unicode)
972 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
974 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
975 (LPSTR)lParam, (int)wParam, NULL, NULL);
977 retval = strlenW(lpstrPath);
981 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
984 case CDM_SETCONTROLTEXT:
985 TRACE("CDM_SETCONTROLTEXT:\n");
988 if( fodInfos->unicode )
989 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
991 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
996 case CDM_HIDECONTROL:
997 /* MSDN states that it should fail for not OFN_EXPLORER case */
998 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1000 HWND control = GetDlgItem( hwnd, wParam );
1001 if (control) ShowWindow( control, SW_HIDE );
1004 else retval = FALSE;
1008 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1009 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1012 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1016 /***********************************************************************
1019 * File open dialog procedure
1021 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1024 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1031 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1033 /* Adds the FileOpenDlgInfos in the property list of the dialog
1034 so it will be easily accessible through a GetPropA(...) */
1035 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1037 fodInfos->DlgInfos.hwndCustomDlg =
1038 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1040 FILEDLG95_InitControls(hwnd);
1042 if (fodInfos->DlgInfos.hwndCustomDlg)
1045 UINT flags = SWP_NOACTIVATE;
1047 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1048 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1050 /* resize the custom dialog to the parent size */
1051 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1052 GetClientRect(hwnd, &rc);
1055 /* our own fake template is zero sized and doesn't have
1056 * children, so there is no need to resize it.
1057 * Picasa depends on it.
1059 flags |= SWP_NOSIZE;
1062 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1063 0, 0, rc.right, rc.bottom, flags);
1066 FILEDLG95_FillControls(hwnd, wParam, lParam);
1068 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1069 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1070 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1074 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1077 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1080 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1086 case WM_GETISHELLBROWSER:
1087 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1090 RemovePropA(hwnd, FileOpenDlgInfosStr);
1095 LPNMHDR lpnmh = (LPNMHDR)lParam;
1098 /* set up the button tooltips strings */
1099 if(TTN_GETDISPINFOA == lpnmh->code )
1101 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1102 switch(lpnmh->idFrom )
1104 /* Up folder button */
1105 case FCIDM_TB_UPFOLDER:
1106 stringId = IDS_UPFOLDER;
1108 /* New folder button */
1109 case FCIDM_TB_NEWFOLDER:
1110 stringId = IDS_NEWFOLDER;
1112 /* List option button */
1113 case FCIDM_TB_SMALLICON:
1114 stringId = IDS_LISTVIEW;
1116 /* Details option button */
1117 case FCIDM_TB_REPORTVIEW:
1118 stringId = IDS_REPORTVIEW;
1120 /* Desktop button */
1121 case FCIDM_TB_DESKTOP:
1122 stringId = IDS_TODESKTOP;
1127 lpdi->hinst = COMDLG32_hInstance;
1128 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1133 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1134 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1139 /***********************************************************************
1140 * FILEDLG95_InitControls
1142 * WM_INITDIALOG message handler (before hook notification)
1144 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1146 int win2000plus = 0;
1148 int handledPath = FALSE;
1149 OSVERSIONINFOA osVi;
1150 static const WCHAR szwSlash[] = { '\\', 0 };
1151 static const WCHAR szwStar[] = { '*',0 };
1155 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1156 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1157 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1158 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1159 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1160 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1161 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1162 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1163 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1168 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1170 tba[0].hInst = HINST_COMMCTRL;
1171 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1172 tba[1].hInst = COMDLG32_hInstance;
1175 TRACE("%p\n", fodInfos);
1177 /* Get windows version emulating */
1178 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1179 GetVersionExA(&osVi);
1180 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1181 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1182 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1183 win2000plus = (osVi.dwMajorVersion > 4);
1184 if (win2000plus) win98plus = TRUE;
1186 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1188 /* Get the hwnd of the controls */
1189 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1190 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1191 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1193 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1194 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1196 /* construct the toolbar */
1197 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1198 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1200 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1201 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1202 rectTB.left = rectlook.right;
1203 rectTB.top = rectlook.top-1;
1205 if (fodInfos->unicode)
1206 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1207 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1208 rectTB.left, rectTB.top,
1209 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1210 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1212 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1213 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1214 rectTB.left, rectTB.top,
1215 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1216 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1218 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1220 /* FIXME: use TB_LOADIMAGES when implemented */
1221 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1222 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1223 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1225 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1226 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1228 /* Set the window text with the text specified in the OPENFILENAME structure */
1231 SetWindowTextW(hwnd,fodInfos->title);
1233 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1236 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1237 SetWindowTextW(hwnd, buf);
1240 /* Initialise the file name edit control */
1241 handledPath = FALSE;
1242 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1244 if(fodInfos->filename)
1246 /* 1. If win2000 or higher and filename contains a path, use it
1247 in preference over the lpstrInitialDir */
1248 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1249 WCHAR tmpBuf[MAX_PATH];
1253 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1256 /* nameBit is always shorter than the original filename */
1257 strcpyW(fodInfos->filename,nameBit);
1260 if (fodInfos->initdir == NULL)
1261 MemFree(fodInfos->initdir);
1262 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1263 strcpyW(fodInfos->initdir, tmpBuf);
1265 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1266 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1268 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1271 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1275 /* 2. (All platforms) If initdir is not null, then use it */
1276 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1277 (*fodInfos->initdir!=0x00))
1279 /* Work out the proper path as supplied one might be relative */
1280 /* (Here because supplying '.' as dir browses to My Computer) */
1281 if (handledPath==FALSE) {
1282 WCHAR tmpBuf[MAX_PATH];
1283 WCHAR tmpBuf2[MAX_PATH];
1287 strcpyW(tmpBuf, fodInfos->initdir);
1288 if( PathFileExistsW(tmpBuf) ) {
1289 /* initdir does not have to be a directory. If a file is
1290 * specified, the dir part is taken */
1291 if( PathIsDirectoryW(tmpBuf)) {
1292 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1293 strcatW(tmpBuf, szwSlash);
1295 strcatW(tmpBuf, szwStar);
1297 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1300 MemFree(fodInfos->initdir);
1301 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1302 strcpyW(fodInfos->initdir, tmpBuf2);
1304 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1307 else if (fodInfos->initdir)
1309 MemFree(fodInfos->initdir);
1310 fodInfos->initdir = NULL;
1311 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1316 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1317 (*fodInfos->initdir==0x00)))
1319 /* 3. All except w2k+: if filename contains a path use it */
1320 if (!win2000plus && fodInfos->filename &&
1321 *fodInfos->filename &&
1322 strpbrkW(fodInfos->filename, szwSlash)) {
1323 WCHAR tmpBuf[MAX_PATH];
1327 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1332 /* nameBit is always shorter than the original filename */
1333 strcpyW(fodInfos->filename, nameBit);
1336 len = strlenW(tmpBuf);
1337 MemFree(fodInfos->initdir);
1338 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1339 strcpyW(fodInfos->initdir, tmpBuf);
1342 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1343 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1345 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1348 /* 4. win98+ and win2000+ if any files of specified filter types in
1349 current directory, use it */
1350 if ( win98plus && handledPath == FALSE &&
1351 fodInfos->filter && *fodInfos->filter) {
1353 BOOL searchMore = TRUE;
1354 LPCWSTR lpstrPos = fodInfos->filter;
1355 WIN32_FIND_DATAW FindFileData;
1360 /* filter is a list... title\0ext\0......\0\0 */
1362 /* Skip the title */
1363 if(! *lpstrPos) break; /* end */
1364 lpstrPos += strlenW(lpstrPos) + 1;
1366 /* See if any files exist in the current dir with this extension */
1367 if(! *lpstrPos) break; /* end */
1369 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1371 if (hFind == INVALID_HANDLE_VALUE) {
1372 /* None found - continue search */
1373 lpstrPos += strlenW(lpstrPos) + 1;
1378 MemFree(fodInfos->initdir);
1379 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1380 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1383 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1384 debugstr_w(lpstrPos));
1390 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1392 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1393 if (handledPath == FALSE && (win2000plus || win98plus)) {
1394 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1396 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1398 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1401 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1402 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1404 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1407 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1410 } else if (handledPath==FALSE) {
1411 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1412 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1414 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1417 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1418 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1420 /* Must the open as read only check box be checked ?*/
1421 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1423 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1426 /* Must the open as read only check box be hidden? */
1427 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1429 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1430 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1433 /* Must the help button be hidden? */
1434 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1436 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1437 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1440 /* Resize the height, if open as read only checkbox ad help button
1441 are hidden and we are not using a custom template nor a customDialog
1443 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1444 (!(fodInfos->ofnInfos->Flags &
1445 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1446 (!fodInfos->DlgInfos.hwndCustomDlg ))
1448 RECT rectDlg, rectHelp, rectCancel;
1449 GetWindowRect(hwnd, &rectDlg);
1450 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1451 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1452 /* subtract the height of the help button plus the space between
1453 the help button and the cancel button to the height of the dialog */
1454 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1455 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1456 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1458 /* change Open to Save */
1459 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1462 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1463 SetDlgItemTextW(hwnd, IDOK, buf);
1464 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1465 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1470 /***********************************************************************
1471 * FILEDLG95_FillControls
1473 * WM_INITDIALOG message handler (after hook notification)
1475 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1477 LPITEMIDLIST pidlItemId = NULL;
1479 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1481 TRACE("dir=%s file=%s\n",
1482 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1484 /* Get the initial directory pidl */
1486 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1488 WCHAR path[MAX_PATH];
1490 GetCurrentDirectoryW(MAX_PATH,path);
1491 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1494 /* Initialise shell objects */
1495 FILEDLG95_SHELL_Init(hwnd);
1497 /* Initialize the Look In combo box */
1498 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1500 /* Initialize the filter combo box */
1501 FILEDLG95_FILETYPE_Init(hwnd);
1503 /* Browse to the initial directory */
1504 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1506 /* Free pidlItem memory */
1507 COMDLG32_SHFree(pidlItemId);
1511 /***********************************************************************
1514 * Regroups all the cleaning functions of the filedlg
1516 void FILEDLG95_Clean(HWND hwnd)
1518 FILEDLG95_FILETYPE_Clean(hwnd);
1519 FILEDLG95_LOOKIN_Clean(hwnd);
1520 FILEDLG95_SHELL_Clean(hwnd);
1522 /***********************************************************************
1523 * FILEDLG95_OnWMCommand
1525 * WM_COMMAND message handler
1527 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1529 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1530 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1531 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1537 FILEDLG95_OnOpen(hwnd);
1541 FILEDLG95_Clean(hwnd);
1542 EndDialog(hwnd, FALSE);
1544 /* Filetype combo box */
1546 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1548 /* LookIn combo box */
1550 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1553 /* --- toolbar --- */
1554 /* Up folder button */
1555 case FCIDM_TB_UPFOLDER:
1556 FILEDLG95_SHELL_UpFolder(hwnd);
1558 /* New folder button */
1559 case FCIDM_TB_NEWFOLDER:
1560 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1562 /* List option button */
1563 case FCIDM_TB_SMALLICON:
1564 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1566 /* Details option button */
1567 case FCIDM_TB_REPORTVIEW:
1568 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1570 /* Details option button */
1571 case FCIDM_TB_DESKTOP:
1572 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1579 /* Do not use the listview selection anymore */
1580 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1584 /***********************************************************************
1585 * FILEDLG95_OnWMGetIShellBrowser
1587 * WM_GETISHELLBROWSER message handler
1589 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1592 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1596 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1602 /***********************************************************************
1603 * FILEDLG95_SendFileOK
1605 * Sends the CDN_FILEOK notification if required
1608 * TRUE if the dialog should close
1609 * FALSE if the dialog should not be closed
1611 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1613 /* ask the hook if we can close */
1614 if(IsHooked(fodInfos))
1619 /* First send CDN_FILEOK as MSDN doc says */
1620 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1621 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1623 TRACE("canceled\n");
1624 return (retval == 0);
1627 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1628 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1629 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1630 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1632 TRACE("canceled\n");
1633 return (retval == 0);
1639 /***********************************************************************
1640 * FILEDLG95_OnOpenMultipleFiles
1642 * Handles the opening of multiple files.
1645 * check destination buffer size
1647 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1649 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1650 UINT nCount, nSizePath;
1651 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1655 if(fodInfos->unicode)
1657 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1658 ofn->lpstrFile[0] = '\0';
1662 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1663 ofn->lpstrFile[0] = '\0';
1666 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1668 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1669 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1670 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1672 LPWSTR lpstrTemp = lpstrFileList;
1674 for ( nCount = 0; nCount < nFileCount; nCount++ )
1678 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1681 WCHAR lpstrNotFound[100];
1682 WCHAR lpstrMsg[100];
1684 static const WCHAR nl[] = {'\n',0};
1686 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1687 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1689 strcpyW(tmp, lpstrTemp);
1691 strcatW(tmp, lpstrNotFound);
1693 strcatW(tmp, lpstrMsg);
1695 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1699 /* move to the next file in the list of files */
1700 lpstrTemp += strlenW(lpstrTemp) + 1;
1701 COMDLG32_SHFree(pidl);
1705 nSizePath = strlenW(lpstrPathSpec) + 1;
1706 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1708 /* For "oldstyle" dialog the components have to
1709 be separated by blanks (not '\0'!) and short
1710 filenames have to be used! */
1711 FIXME("Components have to be separated by blanks\n");
1713 if(fodInfos->unicode)
1715 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1716 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1717 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1721 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1723 if (ofn->lpstrFile != NULL)
1725 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1726 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1727 if (ofn->nMaxFile > nSizePath)
1729 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1730 ofn->lpstrFile + nSizePath,
1731 ofn->nMaxFile - nSizePath, NULL, NULL);
1736 fodInfos->ofnInfos->nFileOffset = nSizePath;
1737 fodInfos->ofnInfos->nFileExtension = 0;
1739 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1742 /* clean and exit */
1743 FILEDLG95_Clean(hwnd);
1744 return EndDialog(hwnd,TRUE);
1747 /***********************************************************************
1750 * Ok button WM_COMMAND message handler
1752 * If the function succeeds, the return value is nonzero.
1754 #define ONOPEN_BROWSE 1
1755 #define ONOPEN_OPEN 2
1756 #define ONOPEN_SEARCH 3
1757 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1759 WCHAR strMsgTitle[MAX_PATH];
1760 WCHAR strMsgText [MAX_PATH];
1762 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1764 strMsgTitle[0] = '\0';
1765 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1766 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1769 BOOL FILEDLG95_OnOpen(HWND hwnd)
1771 LPWSTR lpstrFileList;
1772 UINT nFileCount = 0;
1775 WCHAR lpstrPathAndFile[MAX_PATH];
1776 WCHAR lpstrTemp[MAX_PATH];
1777 LPSHELLFOLDER lpsf = NULL;
1779 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1781 TRACE("hwnd=%p\n", hwnd);
1783 /* get the files from the edit control */
1784 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1786 /* try if the user selected a folder in the shellview */
1789 BrowseSelectedFolder(hwnd);
1795 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1799 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1802 Step 1: Build a complete path name from the current folder and
1803 the filename or path in the edit box.
1805 - the path in the edit box is a root path
1806 (with or without drive letter)
1807 - the edit box contains ".." (or a path with ".." in it)
1810 /* Get the current directory name */
1811 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1814 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1816 PathAddBackslashW(lpstrPathAndFile);
1818 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1820 /* if the user specifyed a fully qualified path use it */
1821 if(PathIsRelativeW(lpstrFileList))
1823 strcatW(lpstrPathAndFile, lpstrFileList);
1827 /* does the path have a drive letter? */
1828 if (PathGetDriveNumberW(lpstrFileList) == -1)
1829 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1831 strcpyW(lpstrPathAndFile, lpstrFileList);
1834 /* resolve "." and ".." */
1835 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1836 strcpyW(lpstrPathAndFile, lpstrTemp);
1837 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1839 MemFree(lpstrFileList);
1842 Step 2: here we have a cleaned up path
1844 We have to parse the path step by step to see if we have to browse
1845 to a folder if the path points to a directory or the last
1846 valid element is a directory.
1849 lpstrPathAndFile: cleaned up path
1853 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1854 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1855 nOpenAction = ONOPEN_OPEN;
1857 nOpenAction = ONOPEN_BROWSE;
1859 /* don't apply any checks with OFN_NOVALIDATE */
1861 LPWSTR lpszTemp, lpszTemp1;
1862 LPITEMIDLIST pidl = NULL;
1863 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1865 /* check for invalid chars */
1866 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1868 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1873 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1875 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1878 LPSHELLFOLDER lpsfChild;
1879 WCHAR lpwstrTemp[MAX_PATH];
1880 DWORD dwEaten, dwAttributes;
1883 strcpyW(lpwstrTemp, lpszTemp);
1884 p = PathFindNextComponentW(lpwstrTemp);
1886 if (!p) break; /* end of path */
1889 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1891 /* There are no wildcards when OFN_NOVALIDATE is set */
1892 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1894 static const WCHAR wszWild[] = { '*', '?', 0 };
1895 /* if the last element is a wildcard do a search */
1896 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1898 nOpenAction = ONOPEN_SEARCH;
1902 lpszTemp1 = lpszTemp;
1904 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1906 /* append a backslash to drive letters */
1907 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1908 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1909 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1911 PathAddBackslashW(lpwstrTemp);
1914 dwAttributes = SFGAO_FOLDER;
1915 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1917 /* the path component is valid, we have a pidl of the next path component */
1918 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1919 if(dwAttributes & SFGAO_FOLDER)
1921 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1923 ERR("bind to failed\n"); /* should not fail */
1926 IShellFolder_Release(lpsf);
1934 /* end dialog, return value */
1935 nOpenAction = ONOPEN_OPEN;
1938 COMDLG32_SHFree(pidl);
1941 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1943 if(*lpszTemp) /* points to trailing null for last path element */
1945 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1947 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1953 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1954 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1956 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1960 /* change to the current folder */
1961 nOpenAction = ONOPEN_OPEN;
1966 nOpenAction = ONOPEN_OPEN;
1970 if(pidl) COMDLG32_SHFree(pidl);
1974 Step 3: here we have a cleaned up and validated path
1977 lpsf: ShellFolder bound to the rightmost valid path component
1978 lpstrPathAndFile: cleaned up path
1979 nOpenAction: action to do
1981 TRACE("end validate sf=%p\n", lpsf);
1985 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1986 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1989 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1992 /* replace the current filter */
1993 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1994 len = strlenW(lpszTemp)+1;
1995 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1996 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1998 /* set the filter cb to the extension when possible */
1999 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2000 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2003 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2004 TRACE("ONOPEN_BROWSE\n");
2006 IPersistFolder2 * ppf2;
2007 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2009 LPITEMIDLIST pidlCurrent;
2010 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2011 IPersistFolder2_Release(ppf2);
2012 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2014 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2016 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2019 else if( nOpenAction == ONOPEN_SEARCH )
2021 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2023 COMDLG32_SHFree(pidlCurrent);
2024 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2029 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2030 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2034 /* update READONLY check box flag */
2035 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2036 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2038 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2040 /* Attach the file extension with file name*/
2041 ext = PathFindExtensionW(lpstrPathAndFile);
2044 /* if no extension is specified with file name, then */
2045 /* attach the extension from file filter or default one */
2047 WCHAR *filterExt = NULL;
2048 LPWSTR lpstrFilter = NULL;
2049 static const WCHAR szwDot[] = {'.',0};
2050 int PathLength = strlenW(lpstrPathAndFile);
2053 strcatW(lpstrPathAndFile, szwDot);
2055 /*Get the file extension from file type filter*/
2056 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2057 fodInfos->ofnInfos->nFilterIndex-1);
2059 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2060 filterExt = PathFindExtensionW(lpstrFilter);
2062 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2063 strcatW(lpstrPathAndFile, filterExt + 1);
2064 else if ( fodInfos->defext ) /* attach the default file extension*/
2065 strcatW(lpstrPathAndFile, fodInfos->defext);
2067 /* In Open dialog: if file does not exist try without extension */
2068 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2069 lpstrPathAndFile[PathLength] = '\0';
2072 if (fodInfos->defext) /* add default extension */
2074 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2077 if (!lstrcmpiW(fodInfos->defext, ext))
2078 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2080 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2083 /* In Save dialog: check if the file already exists */
2084 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2085 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2086 && PathFileExistsW(lpstrPathAndFile))
2088 WCHAR lpstrOverwrite[100];
2091 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2092 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2093 MB_YESNO | MB_ICONEXCLAMATION);
2101 /* Check that the size of the file does not exceed buffer size.
2102 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2103 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2104 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2108 /* fill destination buffer */
2109 if (fodInfos->ofnInfos->lpstrFile)
2111 if(fodInfos->unicode)
2113 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2115 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2116 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2117 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2121 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2123 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2124 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2125 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2126 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2130 /* set filename offset */
2131 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2132 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2134 /* set extension offset */
2135 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2136 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2138 /* set the lpstrFileTitle */
2139 if(fodInfos->ofnInfos->lpstrFileTitle)
2141 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2142 if(fodInfos->unicode)
2144 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2145 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2149 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2150 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2151 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2155 /* copy currently selected filter to lpstrCustomFilter */
2156 if (fodInfos->ofnInfos->lpstrCustomFilter)
2158 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2159 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2160 NULL, 0, NULL, NULL);
2161 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2163 LPSTR s = ofn->lpstrCustomFilter;
2164 s += strlen(ofn->lpstrCustomFilter)+1;
2165 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2166 s, len, NULL, NULL);
2171 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2175 FILEDLG95_Clean(hwnd);
2176 ret = EndDialog(hwnd, TRUE);
2182 size = strlenW(lpstrPathAndFile) + 1;
2183 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2185 /* return needed size in first two bytes of lpstrFile */
2186 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2187 FILEDLG95_Clean(hwnd);
2188 ret = EndDialog(hwnd, FALSE);
2189 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2197 if(lpsf) IShellFolder_Release(lpsf);
2201 /***********************************************************************
2202 * FILEDLG95_SHELL_Init
2204 * Initialisation of the shell objects
2206 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2208 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2213 * Initialisation of the FileOpenDialogInfos structure
2219 fodInfos->ShellInfos.hwndOwner = hwnd;
2221 /* Disable multi-select if flag not set */
2222 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2224 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2226 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2227 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2229 /* Construct the IShellBrowser interface */
2230 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2235 /***********************************************************************
2236 * FILEDLG95_SHELL_ExecuteCommand
2238 * Change the folder option and refresh the view
2239 * If the function succeeds, the return value is nonzero.
2241 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2243 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2246 TRACE("(%p,%p)\n", hwnd, lpVerb);
2248 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2253 CMINVOKECOMMANDINFO ci;
2254 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2255 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2259 IContextMenu_InvokeCommand(pcm, &ci);
2260 IContextMenu_Release(pcm);
2266 /***********************************************************************
2267 * FILEDLG95_SHELL_UpFolder
2269 * Browse to the specified object
2270 * If the function succeeds, the return value is nonzero.
2272 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2274 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2278 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2282 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2288 /***********************************************************************
2289 * FILEDLG95_SHELL_BrowseToDesktop
2291 * Browse to the Desktop
2292 * If the function succeeds, the return value is nonzero.
2294 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2296 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2302 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2303 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2304 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2305 COMDLG32_SHFree(pidl);
2306 return SUCCEEDED(hres);
2308 /***********************************************************************
2309 * FILEDLG95_SHELL_Clean
2311 * Cleans the memory used by shell objects
2313 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2315 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2319 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2321 /* clean Shell interfaces */
2322 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2323 IShellView_Release(fodInfos->Shell.FOIShellView);
2324 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2325 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2326 if (fodInfos->Shell.FOIDataObject)
2327 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2330 /***********************************************************************
2331 * FILEDLG95_FILETYPE_Init
2333 * Initialisation of the file type combo box
2335 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2337 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2338 int nFilters = 0; /* number of filters */
2343 if(fodInfos->customfilter)
2345 /* customfilter has one entry... title\0ext\0
2346 * Set first entry of combo box item with customfilter
2349 LPCWSTR lpstrPos = fodInfos->customfilter;
2352 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2354 /* Copy the extensions */
2355 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2356 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2357 strcpyW(lpstrExt,lpstrPos);
2359 /* Add the item at the end of the combo */
2360 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2361 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2364 if(fodInfos->filter)
2366 LPCWSTR lpstrPos = fodInfos->filter;
2370 /* filter is a list... title\0ext\0......\0\0
2371 * Set the combo item text to the title and the item data
2374 LPCWSTR lpstrDisplay;
2378 if(! *lpstrPos) break; /* end */
2379 lpstrDisplay = lpstrPos;
2380 lpstrPos += strlenW(lpstrPos) + 1;
2382 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2386 /* Copy the extensions */
2387 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2388 strcpyW(lpstrExt,lpstrPos);
2389 lpstrPos += strlenW(lpstrPos) + 1;
2391 /* Add the item at the end of the combo */
2392 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2394 /* malformed filters are added anyway... */
2395 if (!*lpstrExt) break;
2400 * Set the current filter to the one specified
2401 * in the initialisation structure
2403 if (fodInfos->filter || fodInfos->customfilter)
2407 /* Check to make sure our index isn't out of bounds. */
2408 if ( fodInfos->ofnInfos->nFilterIndex >
2409 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2410 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2412 /* set default filter index */
2413 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2414 fodInfos->ofnInfos->nFilterIndex = 1;
2416 /* calculate index of Combo Box item */
2417 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2418 if (fodInfos->customfilter == NULL)
2421 /* Set the current index selection. */
2422 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2424 /* Get the corresponding text string from the combo box. */
2425 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2428 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2434 CharLowerW(lpstrFilter); /* lowercase */
2435 len = strlenW(lpstrFilter)+1;
2436 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2437 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2440 fodInfos->ofnInfos->nFilterIndex = 0;
2444 /***********************************************************************
2445 * FILEDLG95_FILETYPE_OnCommand
2447 * WM_COMMAND of the file type combo box
2448 * If the function succeeds, the return value is nonzero.
2450 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2452 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2460 /* Get the current item of the filetype combo box */
2461 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2463 /* set the current filter index */
2464 fodInfos->ofnInfos->nFilterIndex = iItem +
2465 (fodInfos->customfilter == NULL ? 1 : 0);
2467 /* Set the current filter with the current selection */
2468 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2470 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2472 if((INT_PTR)lpstrFilter != CB_ERR)
2475 CharLowerW(lpstrFilter); /* lowercase */
2476 len = strlenW(lpstrFilter)+1;
2477 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2478 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2479 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2482 /* Refresh the actual view to display the included items*/
2483 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2488 /***********************************************************************
2489 * FILEDLG95_FILETYPE_SearchExt
2491 * searches for an extension in the filetype box
2493 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2495 int i, iCount = CBGetCount(hwnd);
2497 TRACE("%s\n", debugstr_w(lpstrExt));
2499 if(iCount != CB_ERR)
2501 for(i=0;i<iCount;i++)
2503 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2510 /***********************************************************************
2511 * FILEDLG95_FILETYPE_Clean
2513 * Clean the memory used by the filetype combo box
2515 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2517 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2519 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2523 /* Delete each string of the combo and their associated data */
2524 if(iCount != CB_ERR)
2526 for(iPos = iCount-1;iPos>=0;iPos--)
2528 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2529 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2532 /* Current filter */
2533 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2537 /***********************************************************************
2538 * FILEDLG95_LOOKIN_Init
2540 * Initialisation of the look in combo box
2543 /* Small helper function, to determine if the unixfs shell extension is rooted
2544 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2546 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2548 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2549 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2550 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2551 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2552 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2553 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2554 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2556 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2563 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2565 IShellFolder *psfRoot, *psfDrives;
2566 IEnumIDList *lpeRoot, *lpeDrives;
2567 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2569 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2573 liInfos->iMaxIndentation = 0;
2575 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2577 /* set item height for both text field and listbox */
2578 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2579 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2581 /* Turn on the extended UI for the combo box like Windows does */
2582 CBSetExtendedUI(hwndCombo, TRUE);
2584 /* Initialise data of Desktop folder */
2585 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2586 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2587 COMDLG32_SHFree(pidlTmp);
2589 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2591 SHGetDesktopFolder(&psfRoot);
2595 /* enumerate the contents of the desktop */
2596 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2598 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2600 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2602 /* If the unixfs extension is rooted, we don't expand the drives by default */
2603 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2605 /* special handling for CSIDL_DRIVES */
2606 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2608 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2610 /* enumerate the drives */
2611 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2613 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2615 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2616 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2617 COMDLG32_SHFree(pidlAbsTmp);
2618 COMDLG32_SHFree(pidlTmp1);
2620 IEnumIDList_Release(lpeDrives);
2622 IShellFolder_Release(psfDrives);
2627 COMDLG32_SHFree(pidlTmp);
2629 IEnumIDList_Release(lpeRoot);
2631 IShellFolder_Release(psfRoot);
2634 COMDLG32_SHFree(pidlDrives);
2637 /***********************************************************************
2638 * FILEDLG95_LOOKIN_DrawItem
2640 * WM_DRAWITEM message handler
2642 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2644 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2645 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2646 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2650 HIMAGELIST ilItemImage;
2653 LPSFOLDER tmpFolder;
2656 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2660 if(pDIStruct->itemID == -1)
2663 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2664 pDIStruct->itemID)))
2668 if(pDIStruct->itemID == liInfos->uSelectedItem)
2670 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2673 sizeof (SHFILEINFOA),
2674 SHGFI_PIDL | SHGFI_SMALLICON |
2675 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2676 SHGFI_DISPLAYNAME );
2680 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2683 sizeof (SHFILEINFOA),
2684 SHGFI_PIDL | SHGFI_SMALLICON |
2685 SHGFI_SYSICONINDEX |
2689 /* Is this item selected ? */
2690 if(pDIStruct->itemState & ODS_SELECTED)
2692 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2693 SetBkColor(pDIStruct->hDC,crHighLight);
2694 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2698 SetTextColor(pDIStruct->hDC,crText);
2699 SetBkColor(pDIStruct->hDC,crWin);
2700 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2703 /* Do not indent item if drawing in the edit of the combo */
2704 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2707 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2710 sizeof (SHFILEINFOA),
2711 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2712 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2717 iIndentation = tmpFolder->m_iIndent;
2719 /* Draw text and icon */
2721 /* Initialise the icon display area */
2722 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2723 rectIcon.top = pDIStruct->rcItem.top;
2724 rectIcon.right = rectIcon.left + ICONWIDTH;
2725 rectIcon.bottom = pDIStruct->rcItem.bottom;
2727 /* Initialise the text display area */
2728 GetTextMetricsA(pDIStruct->hDC, &tm);
2729 rectText.left = rectIcon.right;
2731 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2732 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2734 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2736 /* Draw the icon from the image list */
2737 ImageList_Draw(ilItemImage,
2744 /* Draw the associated text */
2745 if(sfi.szDisplayName)
2746 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2752 /***********************************************************************
2753 * FILEDLG95_LOOKIN_OnCommand
2755 * LookIn combo box WM_COMMAND message handler
2756 * If the function succeeds, the return value is nonzero.
2758 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2760 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2762 TRACE("%p\n", fodInfos);
2768 LPSFOLDER tmpFolder;
2771 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2773 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2778 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2779 tmpFolder->pidlItem,
2782 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2792 /***********************************************************************
2793 * FILEDLG95_LOOKIN_AddItem
2795 * Adds an absolute pidl item to the lookin combo box
2796 * returns the index of the inserted item
2798 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2800 LPITEMIDLIST pidlNext;
2803 LookInInfos *liInfos;
2805 TRACE("%08x\n", iInsertId);
2810 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2813 tmpFolder = MemAlloc(sizeof(SFOLDER));
2814 tmpFolder->m_iIndent = 0;
2816 /* Calculate the indentation of the item in the lookin*/
2818 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2820 tmpFolder->m_iIndent++;
2823 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2825 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2826 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2828 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2829 SHGetFileInfoA((LPSTR)pidl,
2833 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2834 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2836 TRACE("-- Add %s attr=%08x\n", sfi.szDisplayName, sfi.dwAttributes);
2838 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2842 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2844 /* Add the item at the end of the list */
2847 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2849 /* Insert the item at the iInsertId position*/
2852 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2855 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2859 COMDLG32_SHFree( tmpFolder->pidlItem );
2860 MemFree( tmpFolder );
2865 /***********************************************************************
2866 * FILEDLG95_LOOKIN_InsertItemAfterParent
2868 * Insert an item below its parent
2870 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2873 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2878 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2882 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2885 /* Free pidlParent memory */
2886 COMDLG32_SHFree((LPVOID)pidlParent);
2888 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2891 /***********************************************************************
2892 * FILEDLG95_LOOKIN_SelectItem
2894 * Adds an absolute pidl item to the lookin combo box
2895 * returns the index of the inserted item
2897 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2900 LookInInfos *liInfos;
2904 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2906 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2910 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2911 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2916 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2917 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2921 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2923 if(iRemovedItem < iItemPos)
2928 CBSetCurSel(hwnd,iItemPos);
2929 liInfos->uSelectedItem = iItemPos;
2935 /***********************************************************************
2936 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2938 * Remove the item with an expansion level over iExpansionLevel
2940 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2944 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2948 if(liInfos->iMaxIndentation <= 2)
2951 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2953 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2954 COMDLG32_SHFree(tmpFolder->pidlItem);
2956 CBDeleteString(hwnd,iItemPos);
2957 liInfos->iMaxIndentation--;
2965 /***********************************************************************
2966 * FILEDLG95_LOOKIN_SearchItem
2968 * Search for pidl in the lookin combo box
2969 * returns the index of the found item
2971 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2974 int iCount = CBGetCount(hwnd);
2976 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2978 if (iCount != CB_ERR)
2982 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2984 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2986 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2994 /***********************************************************************
2995 * FILEDLG95_LOOKIN_Clean
2997 * Clean the memory used by the lookin combo box
2999 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3001 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3003 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3007 /* Delete each string of the combo and their associated data */
3008 if (iCount != CB_ERR)
3010 for(iPos = iCount-1;iPos>=0;iPos--)
3012 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3013 COMDLG32_SHFree(tmpFolder->pidlItem);
3015 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3019 /* LookInInfos structure */
3020 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3023 /***********************************************************************
3024 * FILEDLG95_FILENAME_FillFromSelection
3026 * fills the edit box from the cached DataObject
3028 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3030 FileOpenDlgInfos *fodInfos;
3032 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3033 char lpstrTemp[MAX_PATH];
3034 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3037 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3039 /* Count how many files we have */
3040 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3042 /* calculate the string length, count files */
3043 if (nFileSelected >= 1)
3045 nLength += 3; /* first and last quotes, trailing \0 */
3046 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3048 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3052 /* get the total length of the selected file names */
3053 lpstrTemp[0] = '\0';
3054 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3056 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3058 nLength += strlen( lpstrTemp ) + 3;
3061 COMDLG32_SHFree( pidl );
3066 /* allocate the buffer */
3067 if (nFiles <= 1) nLength = MAX_PATH;
3068 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3069 lpstrAllFile[0] = '\0';
3071 /* Generate the string for the edit control */
3074 lpstrCurrFile = lpstrAllFile;
3075 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3077 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3081 /* get the file name */
3082 lpstrTemp[0] = '\0';
3083 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3085 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3089 *lpstrCurrFile++ = '\"';
3090 strcpy( lpstrCurrFile, lpstrTemp );
3091 lpstrCurrFile += strlen( lpstrTemp );
3092 strcpy( lpstrCurrFile, "\" " );
3097 strcpy( lpstrAllFile, lpstrTemp );
3100 COMDLG32_SHFree( (LPVOID) pidl );
3103 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3105 /* Select the file name like Windows does */
3106 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3108 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3112 /* copied from shell32 to avoid linking to it
3113 * FIXME: why? shell32 is already linked
3115 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3120 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3121 COMDLG32_SHFree(src->u.pOleStr);
3125 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3129 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3133 FIXME("unknown type!\n");
3136 *(LPSTR)dest = '\0';
3143 /***********************************************************************
3144 * FILEDLG95_FILENAME_GetFileNames
3146 * Copies the filenames to a delimited string list.
3147 * The delimiter is specified by the parameter 'separator',
3148 * usually either a space or a nul
3150 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3152 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3153 UINT nStrCharCount = 0; /* index in src buffer */
3154 UINT nFileIndex = 0; /* index in dest buffer */
3155 UINT nFileCount = 0; /* number of files */
3156 UINT nStrLen = 0; /* length of string in edit control */
3157 LPWSTR lpstrEdit; /* buffer for string from edit control */
3161 /* get the filenames from the edit control */
3162 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3163 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3164 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3166 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3168 /* we might get single filename without any '"',
3169 * so we need nStrLen + terminating \0 + end-of-list \0 */
3170 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3173 /* build delimited file list from filenames */
3174 while ( nStrCharCount <= nStrLen )
3176 if ( lpstrEdit[nStrCharCount]=='"' )
3179 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3181 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3185 (*lpstrFileList)[nFileIndex++] = separator;
3192 /* single, unquoted string */
3193 if ((nStrLen > 0) && (*sizeUsed == 0) )
3195 strcpyW(*lpstrFileList, lpstrEdit);
3196 nFileIndex = strlenW(lpstrEdit) + 1;
3197 (*sizeUsed) = nFileIndex;
3202 (*lpstrFileList)[nFileIndex] = '\0';
3209 #define SETDefFormatEtc(fe,cf,med) \
3211 (fe).cfFormat = cf;\
3212 (fe).dwAspect = DVASPECT_CONTENT; \
3219 * DATAOBJECT Helper functions
3222 /***********************************************************************
3223 * COMCTL32_ReleaseStgMedium
3225 * like ReleaseStgMedium from ole32
3227 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3229 if(medium.pUnkForRelease)
3231 IUnknown_Release(medium.pUnkForRelease);
3235 GlobalUnlock(medium.u.hGlobal);
3236 GlobalFree(medium.u.hGlobal);
3240 /***********************************************************************
3241 * GetPidlFromDataObject
3243 * Return pidl(s) by number from the cached DataObject
3245 * nPidlIndex=0 gets the fully qualified root path
3247 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3251 FORMATETC formatetc;
3252 LPITEMIDLIST pidl = NULL;
3254 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3259 /* Set the FORMATETC structure*/
3260 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3262 /* Get the pidls from IDataObject */
3263 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3265 LPIDA cida = GlobalLock(medium.u.hGlobal);
3266 if(nPidlIndex <= cida->cidl)
3268 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3270 COMCTL32_ReleaseStgMedium(medium);
3275 /***********************************************************************
3278 * Return the number of selected items in the DataObject.
3281 UINT GetNumSelected( IDataObject *doSelected )
3285 FORMATETC formatetc;
3287 TRACE("sv=%p\n", doSelected);
3289 if (!doSelected) return 0;
3291 /* Set the FORMATETC structure*/
3292 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3294 /* Get the pidls from IDataObject */
3295 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3297 LPIDA cida = GlobalLock(medium.u.hGlobal);
3298 retVal = cida->cidl;
3299 COMCTL32_ReleaseStgMedium(medium);
3309 /***********************************************************************
3312 * Get the pidl's display name (relative to folder) and
3313 * put it in lpstrFileName.
3315 * Return NOERROR on success,
3319 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3324 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3328 SHGetDesktopFolder(&lpsf);
3329 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3330 IShellFolder_Release(lpsf);
3334 /* Get the display name of the pidl relative to the folder */
3335 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3337 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3342 /***********************************************************************
3343 * GetShellFolderFromPidl
3345 * pidlRel is the item pidl relative
3346 * Return the IShellFolder of the absolute pidl
3348 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3350 IShellFolder *psf = NULL,*psfParent;
3352 TRACE("%p\n", pidlAbs);
3354 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3357 if(pidlAbs && pidlAbs->mkid.cb)
3359 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3361 IShellFolder_Release(psfParent);
3365 /* return the desktop */
3371 /***********************************************************************
3374 * Return the LPITEMIDLIST to the parent of the pidl in the list
3376 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3378 LPITEMIDLIST pidlParent;
3380 TRACE("%p\n", pidl);
3382 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3383 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3388 /***********************************************************************
3391 * returns the pidl of the file name relative to folder
3392 * NULL if an error occurred
3394 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3396 LPITEMIDLIST pidl = NULL;
3399 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3401 if(!lpcstrFileName) return NULL;
3402 if(!*lpcstrFileName) return NULL;
3406 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3407 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3408 IShellFolder_Release(lpsf);
3413 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3420 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3422 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3425 TRACE("%p, %p\n", psf, pidl);
3427 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3429 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3430 /* see documentation shell 4.1*/
3431 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3434 /***********************************************************************
3435 * BrowseSelectedFolder
3437 static BOOL BrowseSelectedFolder(HWND hwnd)
3439 BOOL bBrowseSelFolder = FALSE;
3440 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3444 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3446 LPITEMIDLIST pidlSelection;
3448 /* get the file selected */
3449 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3450 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3452 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3453 pidlSelection, SBSP_RELATIVE ) ) )
3455 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3456 ' ','n','o','t',' ','e','x','i','s','t',0};
3457 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3459 bBrowseSelFolder = TRUE;
3460 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3462 COMDLG32_SHFree( pidlSelection );
3465 return bBrowseSelFolder;
3469 * Memory allocation methods */
3470 static void *MemAlloc(UINT size)
3472 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3475 static void MemFree(void *mem)
3477 HeapFree(GetProcessHeap(),0,mem);
3481 * Old-style (win3.1) dialogs */
3483 /***********************************************************************
3484 * FD32_GetTemplate [internal]
3486 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3487 * by a 32 bits application
3490 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3492 LPOPENFILENAMEW ofnW = lfs->ofnW;
3493 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3496 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3498 if (!(lfs->template = LockResource( ofnW->hInstance )))
3500 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3504 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3508 hResInfo = FindResourceA(priv->ofnA->hInstance,
3509 priv->ofnA->lpTemplateName,
3512 hResInfo = FindResourceW(ofnW->hInstance,
3513 ofnW->lpTemplateName,
3517 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3520 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3522 !(lfs->template = LockResource(hDlgTmpl)))
3524 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3527 } else { /* get it from internal Wine resource */
3529 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3530 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3532 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3535 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3536 !(lfs->template = LockResource( hDlgTmpl )))
3538 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3546 /************************************************************************
3547 * FD32_Init [internal]
3548 * called from the common 16/32 code to initialize 32 bit data
3550 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3552 BOOL IsUnicode = (BOOL) data;
3555 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3556 lfs->private1632 = priv;
3557 if (NULL == lfs->private1632) return FALSE;
3560 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3561 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3562 if (lfs->ofnW->lpfnHook)
3567 priv->ofnA = (LPOPENFILENAMEA) lParam;
3568 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3569 if (priv->ofnA->lpfnHook)
3571 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3572 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3575 if (! FD32_GetTemplate(lfs)) return FALSE;
3580 /***********************************************************************
3581 * FD32_CallWindowProc [internal]
3583 * called from the common 16/32 code to call the appropriate hook
3585 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3589 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3593 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3594 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3595 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3596 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3597 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3601 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3602 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3603 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3604 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3605 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3609 /***********************************************************************
3610 * FD32_UpdateResult [internal]
3611 * update the real client structures if any
3613 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3615 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3616 LPOPENFILENAMEW ofnW = lfs->ofnW;
3620 if (ofnW->nMaxFile &&
3621 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3622 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3623 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3624 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3625 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3629 /***********************************************************************
3630 * FD32_UpdateFileTitle [internal]
3631 * update the real client structures if any
3633 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3635 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3636 LPOPENFILENAMEW ofnW = lfs->ofnW;
3640 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3641 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3642 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3647 /***********************************************************************
3648 * FD32_SendLbGetCurSel [internal]
3649 * retrieve selected listbox item
3651 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3653 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3657 /************************************************************************
3658 * FD32_Destroy [internal]
3659 * called from the common 16/32 code to cleanup 32 bit data
3661 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3663 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3665 /* if ofnW has been allocated, have to free everything in it */
3666 if (NULL != priv && NULL != priv->ofnA)
3668 FD31_FreeOfnW(lfs->ofnW);
3669 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3673 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3675 callbacks->Init = FD32_Init;
3676 callbacks->CWP = FD32_CallWindowProc;
3677 callbacks->UpdateResult = FD32_UpdateResult;
3678 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3679 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3680 callbacks->Destroy = FD32_Destroy;
3683 /***********************************************************************
3684 * FD32_WMMeasureItem [internal]
3686 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3688 LPMEASUREITEMSTRUCT lpmeasure;
3690 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3691 lpmeasure->itemHeight = FD31_GetFldrHeight();
3696 /***********************************************************************
3697 * FileOpenDlgProc [internal]
3698 * Used for open and save, in fact.
3700 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3701 WPARAM wParam, LPARAM lParam)
3703 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3705 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3706 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3709 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3711 return lRet; /* else continue message processing */
3716 return FD31_WMInitDialog(hWnd, wParam, lParam);
3718 case WM_MEASUREITEM:
3719 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3722 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3725 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3728 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3729 switch (HIWORD(lParam))
3732 SetTextColor((HDC16)wParam, 0x00000000);
3734 case CTLCOLOR_STATIC:
3735 SetTextColor((HDC16)wParam, 0x00000000);
3745 /***********************************************************************
3746 * GetFileName31A [internal]
3748 * Creates a win31 style dialog box for the user to select a file to open/save.
3750 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3751 UINT dlgType /* type dialogue : open/save */
3757 FD31_CALLBACKS callbacks;
3759 if (!lpofn || !FD31_Init()) return FALSE;
3761 TRACE("ofn flags %08x\n", lpofn->Flags);
3762 FD32_SetupCallbacks(&callbacks);
3763 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3766 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3767 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3768 FD32_FileOpenDlgProc, (LPARAM)lfs);
3769 FD31_DestroyPrivate(lfs);
3772 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3776 /***********************************************************************
3777 * GetFileName31W [internal]
3779 * Creates a win31 style dialog box for the user to select a file to open/save
3781 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3782 UINT dlgType /* type dialogue : open/save */
3788 FD31_CALLBACKS callbacks;
3790 if (!lpofn || !FD31_Init()) return FALSE;
3792 FD32_SetupCallbacks(&callbacks);
3793 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3796 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3797 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3798 FD32_FileOpenDlgProc, (LPARAM)lfs);
3799 FD31_DestroyPrivate(lfs);
3802 TRACE("file %s, file offset %d, ext offset %d\n",
3803 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3807 /* ------------------ APIs ---------------------- */
3809 /***********************************************************************
3810 * GetOpenFileNameA (COMDLG32.@)
3812 * Creates a dialog box for the user to select a file to open.
3815 * TRUE on success: user enters a valid file
3816 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3819 BOOL WINAPI GetOpenFileNameA(
3820 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3822 BOOL win16look = FALSE;
3824 TRACE("flags %08x\n", ofn->Flags);
3826 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3827 if (ofn->Flags & OFN_FILEMUSTEXIST)
3828 ofn->Flags |= OFN_PATHMUSTEXIST;
3830 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3831 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3834 return GetFileName31A(ofn, OPEN_DIALOG);
3836 return GetFileDialog95A(ofn, OPEN_DIALOG);
3839 /***********************************************************************
3840 * GetOpenFileNameW (COMDLG32.@)
3842 * Creates a dialog box for the user to select a file to open.
3845 * TRUE on success: user enters a valid file
3846 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3849 BOOL WINAPI GetOpenFileNameW(
3850 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3852 BOOL win16look = FALSE;
3854 TRACE("flags %08x\n", ofn->Flags);
3856 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3857 if (ofn->Flags & OFN_FILEMUSTEXIST)
3858 ofn->Flags |= OFN_PATHMUSTEXIST;
3860 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3861 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3864 return GetFileName31W(ofn, OPEN_DIALOG);
3866 return GetFileDialog95W(ofn, OPEN_DIALOG);
3870 /***********************************************************************
3871 * GetSaveFileNameA (COMDLG32.@)
3873 * Creates a dialog box for the user to select a file to save.
3876 * TRUE on success: user enters a valid file
3877 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3880 BOOL WINAPI GetSaveFileNameA(
3881 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3883 BOOL win16look = FALSE;
3885 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3886 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3889 return GetFileName31A(ofn, SAVE_DIALOG);
3891 return GetFileDialog95A(ofn, SAVE_DIALOG);
3894 /***********************************************************************
3895 * GetSaveFileNameW (COMDLG32.@)
3897 * Creates a dialog box for the user to select a file to save.
3900 * TRUE on success: user enters a valid file
3901 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3904 BOOL WINAPI GetSaveFileNameW(
3905 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3907 BOOL win16look = FALSE;
3909 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3910 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3913 return GetFileName31W(ofn, SAVE_DIALOG);
3915 return GetFileDialog95W(ofn, SAVE_DIALOG);