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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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: lpstrCustomFilter not handled
37 * FIXME: if the size of lpstrFile (nMaxFile) is too small the first
38 * two bytes of lpstrFile should contain the needed size
40 * FIXME: algorithm for selecting the initial directory is too simple
42 * FIXME: add to recent docs
44 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
45 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
46 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
47 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
49 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
55 #include "wine/port.h"
63 #define NONAMELESSUNION
64 #define NONAMELESSSTRUCT
70 #include "wine/unicode.h"
76 #include "wine/debug.h"
81 #include "filedlgbrowser.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
86 #define UNIMPLEMENTED_FLAGS \
87 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
88 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
89 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
90 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
92 #define IsHooked(fodInfos) \
93 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
94 /***********************************************************************
95 * Data structure and global variables
97 typedef struct SFolder
99 int m_iImageIndex; /* Index of picture in image list */
101 int m_iIndent; /* Indentation index */
102 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
104 } SFOLDER,*LPSFOLDER;
106 typedef struct tagLookInInfo
113 /***********************************************************************
114 * Defines and global variables
117 /* Draw item constant */
119 #define XTEXTOFFSET 3
124 /* SearchItem methods */
125 #define SEARCH_PIDL 1
127 #define ITEM_NOTFOUND -1
129 /* Undefined windows message sent by CreateViewObject*/
130 #define WM_GETISHELLBROWSER WM_USER+7
133 * Those macros exist in windowsx.h. However, you can't really use them since
134 * they rely on the UNICODE defines and can't be used inside Wine itself.
137 /* Combo box macros */
138 #define CBAddString(hwnd,str) \
139 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
140 #define CBAddStringW(hwnd,str) \
141 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBInsertString(hwnd,str,pos) \
144 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
146 #define CBDeleteString(hwnd,pos) \
147 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
149 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
150 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
152 #define CBGetItemDataPtr(hwnd,iItemId) \
153 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
155 #define CBGetLBText(hwnd,iItemId,str) \
156 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
158 #define CBGetCurSel(hwnd) \
159 SendMessageA(hwnd,CB_GETCURSEL,0,0);
161 #define CBSetCurSel(hwnd,pos) \
162 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
164 #define CBGetCount(hwnd) \
165 SendMessageA(hwnd,CB_GETCOUNT,0,0);
166 #define CBShowDropDown(hwnd,show) \
167 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
168 #define CBSetItemHeight(hwnd,index,height) \
169 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
171 #define CBSetExtendedUI(hwnd,flag) \
172 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
174 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
175 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
177 /***********************************************************************
181 /* Internal functions used by the dialog */
182 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
185 BOOL FILEDLG95_OnOpen(HWND hwnd);
186 static LRESULT FILEDLG95_InitControls(HWND hwnd);
187 static void FILEDLG95_Clean(HWND hwnd);
189 /* Functions used by the shell navigation */
190 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 /* Functions used by the filetype combo box */
197 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
198 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
199 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
200 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
202 /* Functions used by the Look In combo box */
203 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
204 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
205 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
207 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
208 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
209 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
210 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
211 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
213 /* Miscellaneous tool functions */
214 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
215 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
216 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
217 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
218 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
220 /* Shell memory allocation */
221 static void *MemAlloc(UINT size);
222 static void MemFree(void *mem);
224 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
225 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
226 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
227 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
228 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
229 static BOOL BrowseSelectedFolder(HWND hwnd);
231 /* old style dialogs */
232 extern BOOL GetFileName31A(LPOPENFILENAMEA lpofn, UINT dlgType);
233 extern BOOL GetFileName31W(LPOPENFILENAMEW lpofn, UINT dlgType);
235 /***********************************************************************
238 * Creates an Open common dialog box that lets the user select
239 * the drive, directory, and the name of a file or set of files to open.
241 * IN : The FileOpenDlgInfos structure associated with the dialog
242 * OUT : TRUE on success
243 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
245 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
253 /* test for missing functionality */
254 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 FIXME("Flags 0x%08lx not yet implemented\n",
257 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
260 /* Create the dialog from a template */
262 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268 !(template = LockResource( hDlgTmpl )))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
274 /* old style hook messages */
275 if (IsHooked(fodInfos))
277 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
278 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
279 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
280 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
283 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
284 (LPDLGTEMPLATEA) template,
285 fodInfos->ofnInfos->hwndOwner,
289 /* Unable to create the dialog */
296 /***********************************************************************
299 * Call GetFileName95 with this structure and clean the memory.
301 * IN : The OPENFILENAMEA initialisation structure passed to
302 * GetOpenFileNameA win api function (see filedlg.c)
304 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
307 FileOpenDlgInfos fodInfos;
308 LPSTR lpstrSavDir = NULL;
310 LPWSTR defext = NULL;
311 LPWSTR filter = NULL;
312 LPWSTR customfilter = NULL;
314 /* Initialize FileOpenDlgInfos structure */
315 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
317 /* Pass in the original ofn */
318 fodInfos.ofnInfos = ofn;
320 /* save current directory */
321 if (ofn->Flags & OFN_NOCHANGEDIR)
323 lpstrSavDir = MemAlloc(MAX_PATH);
324 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
327 fodInfos.unicode = FALSE;
329 /* convert all the input strings to unicode */
330 if(ofn->lpstrInitialDir)
332 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
333 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
334 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
337 fodInfos.initdir = NULL;
341 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
342 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
345 fodInfos.filename = NULL;
349 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
350 defext = MemAlloc((len+1)*sizeof(WCHAR));
351 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
353 fodInfos.defext = defext;
357 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
358 title = MemAlloc((len+1)*sizeof(WCHAR));
359 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
361 fodInfos.title = title;
363 if (ofn->lpstrFilter)
368 /* filter is a list... title\0ext\0......\0\0 */
369 s = ofn->lpstrFilter;
370 while (*s) s = s+strlen(s)+1;
372 n = s - ofn->lpstrFilter;
373 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
374 filter = MemAlloc(len*sizeof(WCHAR));
375 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
377 fodInfos.filter = filter;
379 /* convert lpstrCustomFilter */
380 if (ofn->lpstrCustomFilter)
385 /* filter is a list... title\0ext\0......\0\0 */
386 s = ofn->lpstrCustomFilter;
387 while (*s) s = s+strlen(s)+1;
389 n = s - ofn->lpstrCustomFilter;
390 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
391 customfilter = MemAlloc(len*sizeof(WCHAR));
392 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
394 fodInfos.customfilter = customfilter;
396 /* Initialize the dialog property */
397 fodInfos.DlgInfos.dwDlgProp = 0;
398 fodInfos.DlgInfos.hwndCustomDlg = NULL;
403 ret = GetFileName95(&fodInfos);
406 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
407 ret = GetFileName95(&fodInfos);
415 SetCurrentDirectoryA(lpstrSavDir);
416 MemFree(lpstrSavDir);
426 MemFree(customfilter);
428 MemFree(fodInfos.initdir);
430 if(fodInfos.filename)
431 MemFree(fodInfos.filename);
433 TRACE("selected file: %s\n",ofn->lpstrFile);
438 /***********************************************************************
441 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
442 * Call GetFileName95 with this structure and clean the memory.
444 * FIXME: lpstrCustomFilter has to be converted back
447 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
450 FileOpenDlgInfos fodInfos;
451 LPSTR lpstrSavDir = NULL;
453 /* Initialize FileOpenDlgInfos structure */
454 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
456 /* Pass in the original ofn */
457 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
459 fodInfos.title = ofn->lpstrTitle;
460 fodInfos.defext = ofn->lpstrDefExt;
461 fodInfos.filter = ofn->lpstrFilter;
462 fodInfos.customfilter = ofn->lpstrCustomFilter;
464 /* convert string arguments, save others */
467 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
468 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
471 fodInfos.filename = NULL;
473 if(ofn->lpstrInitialDir)
475 DWORD len = strlenW(ofn->lpstrInitialDir);
476 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
477 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
480 fodInfos.initdir = NULL;
482 /* save current directory */
483 if (ofn->Flags & OFN_NOCHANGEDIR)
485 lpstrSavDir = MemAlloc(MAX_PATH);
486 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
489 fodInfos.unicode = TRUE;
494 ret = GetFileName95(&fodInfos);
497 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
498 ret = GetFileName95(&fodInfos);
506 SetCurrentDirectoryA(lpstrSavDir);
507 MemFree(lpstrSavDir);
510 /* restore saved IN arguments and convert OUT arguments back */
511 MemFree(fodInfos.filename);
512 MemFree(fodInfos.initdir);
516 /***********************************************************************
517 * ArrangeCtrlPositions [internal]
519 * NOTE: Do not change anything here without a lot of testing.
521 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
523 HWND hwndChild, hwndStc32;
524 RECT rectParent, rectChild, rectStc32;
527 /* Take into account if open as read only checkbox and help button
532 RECT rectHelp, rectCancel;
533 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
534 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
535 /* subtract the height of the help button plus the space between
536 * the help button and the cancel button to the height of the dialog
538 help_fixup = rectHelp.bottom - rectCancel.bottom;
542 There are two possibilities to add components to the default file dialog box.
544 By default, all the new components are added below the standard dialog box (the else case).
546 However, if there is a static text component with the stc32 id, a special case happens.
547 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
548 in the window and the cx and cy indicate how to size the window.
549 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
550 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
554 GetClientRect(hwndParentDlg, &rectParent);
556 /* when arranging controls we have to use fixed parent size */
557 rectParent.bottom -= help_fixup;
559 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
562 GetWindowRect(hwndStc32, &rectStc32);
563 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
565 /* set the size of the stc32 control according to the size of
566 * client area of the parent dialog
568 SetWindowPos(hwndStc32, 0,
570 rectParent.right, rectParent.bottom,
571 SWP_NOMOVE | SWP_NOZORDER);
574 SetRectEmpty(&rectStc32);
576 /* this part moves controls of the child dialog */
577 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
580 if (hwndChild != hwndStc32)
582 GetWindowRect(hwndChild, &rectChild);
583 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
585 /* move only if stc32 exist */
586 if (hwndStc32 && rectChild.left > rectStc32.right)
588 /* move to the right of visible controls of the parent dialog */
589 rectChild.left += rectParent.right;
590 rectChild.left -= rectStc32.right;
592 /* move even if stc32 doesn't exist */
593 if (rectChild.top > rectStc32.bottom)
595 /* move below visible controls of the parent dialog */
596 rectChild.top += rectParent.bottom;
597 rectChild.top -= rectStc32.bottom - rectStc32.top;
600 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
601 0, 0, SWP_NOSIZE | SWP_NOZORDER);
603 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
606 /* this part moves controls of the parent dialog */
607 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
610 if (hwndChild != hwndChildDlg)
612 GetWindowRect(hwndChild, &rectChild);
613 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
615 /* left,top of stc32 marks the position of controls
616 * from the parent dialog
618 rectChild.left += rectStc32.left;
619 rectChild.top += rectStc32.top;
621 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
622 0, 0, SWP_NOSIZE | SWP_NOZORDER);
624 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
627 /* calculate the size of the resulting dialog */
629 /* here we have to use original parent size */
630 GetClientRect(hwndParentDlg, &rectParent);
631 GetClientRect(hwndChildDlg, &rectChild);
635 if (rectParent.right > rectChild.right)
637 rectParent.right += rectChild.right;
638 rectParent.right -= rectStc32.right - rectStc32.left;
642 rectParent.right = rectChild.right;
645 if (rectParent.bottom > rectChild.bottom)
647 rectParent.bottom += rectChild.bottom;
648 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
652 rectParent.bottom = rectChild.bottom;
657 rectParent.bottom += rectChild.bottom;
660 /* finally use fixed parent size */
661 rectParent.bottom -= help_fixup;
663 /* save the size of the parent's client area */
664 rectChild.right = rectParent.right;
665 rectChild.bottom = rectParent.bottom;
667 /* set the size of the parent dialog */
668 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
669 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
670 SetWindowPos(hwndParentDlg, 0,
672 rectParent.right - rectParent.left,
673 rectParent.bottom - rectParent.top,
674 SWP_NOMOVE | SWP_NOZORDER);
676 /* set the size of the child dialog */
677 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
678 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
681 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
690 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
700 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
701 * structure's hInstance parameter is not a HINSTANCE, but
702 * instead a pointer to a template resource to use.
704 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
707 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
710 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
712 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
718 hinst = fodInfos->ofnInfos->hInstance;
719 if(fodInfos->unicode)
721 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
722 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
726 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
727 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
731 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
734 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
735 !(template = LockResource( hDlgTmpl )))
737 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
741 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
742 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
743 (LPARAM)fodInfos->ofnInfos);
746 ShowWindow(hChildDlg,SW_SHOW);
750 else if( IsHooked(fodInfos))
755 WORD menu,class,title;
757 GetClientRect(hwnd,&rectHwnd);
758 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
759 temp.tmplate.dwExtendedStyle = 0;
760 temp.tmplate.cdit = 0;
765 temp.menu = temp.class = temp.title = 0;
767 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
768 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
775 /***********************************************************************
776 * SendCustomDlgNotificationMessage
778 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
781 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
783 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
785 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
787 if(!fodInfos) return 0;
789 if(fodInfos->unicode)
790 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
792 if(fodInfos->DlgInfos.hwndCustomDlg)
796 ofnNotify.hdr.hwndFrom=hwndParentDlg;
797 ofnNotify.hdr.idFrom=0;
798 ofnNotify.hdr.code = uCode;
799 ofnNotify.lpOFN = fodInfos->ofnInfos;
800 ofnNotify.pszFile = NULL;
801 TRACE("CALL NOTIFY for %x\n", uCode);
802 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
803 TRACE("RET NOTIFY\n");
809 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
811 UINT sizeUsed = 0, n, total;
812 LPWSTR lpstrFileList = NULL;
813 WCHAR lpstrCurrentDir[MAX_PATH];
814 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
816 TRACE("CDM_GETFILEPATH:\n");
818 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
821 /* get path and filenames */
822 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
823 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
825 TRACE("path >%s< filespec >%s< %d files\n",
826 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
828 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
829 NULL, 0, NULL, NULL);
830 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
831 NULL, 0, NULL, NULL);
833 /* Prepend the current path */
834 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
835 buffer, size, NULL, NULL);
839 /* 'n' includes trailing \0 */
841 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
842 &buffer[n], size-n, NULL, NULL);
844 MemFree(lpstrFileList);
846 TRACE("returned -> %s\n",debugstr_a(buffer));
851 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
854 LPWSTR lpstrFileList = NULL;
856 TRACE("CDM_GETSPEC:\n");
858 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
859 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
860 MemFree(lpstrFileList);
865 /***********************************************************************
866 * FILEDLG95_HandleCustomDialogMessages
868 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
870 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
872 char lpstrPath[MAX_PATH];
873 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
874 if(!fodInfos) return -1;
878 case CDM_GETFILEPATH:
879 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
881 case CDM_GETFOLDERPATH:
882 TRACE("CDM_GETFOLDERPATH:\n");
883 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
884 if ((LPSTR)lParam!=NULL)
885 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
886 return strlen(lpstrPath);
889 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
891 case CDM_SETCONTROLTEXT:
892 TRACE("CDM_SETCONTROLTEXT:\n");
894 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
897 case CDM_HIDECONTROL:
899 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
905 /***********************************************************************
908 * File open dialog procedure
910 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
913 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
920 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
922 /* Adds the FileOpenDlgInfos in the property list of the dialog
923 so it will be easily accessible through a GetPropA(...) */
924 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
926 fodInfos->DlgInfos.hwndCustomDlg =
927 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
929 FILEDLG95_InitControls(hwnd);
931 if (fodInfos->DlgInfos.hwndCustomDlg)
932 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
933 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
935 FILEDLG95_FillControls(hwnd, wParam, lParam);
937 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
938 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
939 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
943 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
946 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
949 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
955 case WM_GETISHELLBROWSER:
956 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
959 RemovePropA(hwnd, FileOpenDlgInfosStr);
964 LPNMHDR lpnmh = (LPNMHDR)lParam;
967 /* set up the button tooltips strings */
968 if(TTN_GETDISPINFOA == lpnmh->code )
970 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
971 switch(lpnmh->idFrom )
973 /* Up folder button */
974 case FCIDM_TB_UPFOLDER:
975 stringId = IDS_UPFOLDER;
977 /* New folder button */
978 case FCIDM_TB_NEWFOLDER:
979 stringId = IDS_NEWFOLDER;
981 /* List option button */
982 case FCIDM_TB_SMALLICON:
983 stringId = IDS_LISTVIEW;
985 /* Details option button */
986 case FCIDM_TB_REPORTVIEW:
987 stringId = IDS_REPORTVIEW;
990 case FCIDM_TB_DESKTOP:
991 stringId = IDS_TODESKTOP;
996 lpdi->hinst = COMDLG32_hInstance;
997 lpdi->lpszText = (LPSTR) stringId;
1002 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1003 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1008 /***********************************************************************
1009 * FILEDLG95_InitControls
1011 * WM_INITDIALOG message handler (before hook notification)
1013 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1015 int win2000plus = 0;
1017 int handledPath = FALSE;
1018 OSVERSIONINFOA osVi;
1019 const WCHAR szwSlash[] = { '\\', 0 };
1020 const WCHAR szwStar[] = { '*',0 };
1024 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1025 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1026 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1027 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1028 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1029 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1030 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1031 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1032 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1037 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1039 tba[0].hInst = HINST_COMMCTRL;
1040 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1041 tba[1].hInst = COMDLG32_hInstance;
1044 TRACE("%p\n", fodInfos);
1046 /* Get windows version emulating */
1047 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1048 GetVersionExA(&osVi);
1049 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1050 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1051 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1052 win2000plus = (osVi.dwMajorVersion > 4);
1053 if (win2000plus) win98plus = TRUE;
1055 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1057 /* Get the hwnd of the controls */
1058 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1059 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1060 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1062 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1063 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1065 /* construct the toolbar */
1066 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1067 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1069 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1070 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1071 rectTB.left = rectlook.right;
1072 rectTB.top = rectlook.top-1;
1074 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1075 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1076 rectTB.left, rectTB.top,
1077 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1078 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1080 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1082 /* FIXME: use TB_LOADIMAGES when implemented */
1083 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1084 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1085 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1087 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1088 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1090 /* Set the window text with the text specified in the OPENFILENAME structure */
1093 SetWindowTextW(hwnd,fodInfos->title);
1095 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1097 SetWindowTextA(hwnd,"Save");
1100 /* Initialise the file name edit control */
1101 handledPath = FALSE;
1102 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1104 if(fodInfos->filename)
1106 /* 1. If win2000 or higher and filename contains a path, use it
1107 in preference over the lpstrInitialDir */
1108 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1109 WCHAR tmpBuf[MAX_PATH];
1113 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1116 /* nameBit is always shorter than the original filename */
1117 strcpyW(fodInfos->filename,nameBit);
1120 if (fodInfos->initdir == NULL)
1121 MemFree(fodInfos->initdir);
1122 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1123 strcpyW(fodInfos->initdir, tmpBuf);
1125 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1126 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1128 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1131 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1135 /* 2. (All platforms) If initdir is not null, then use it */
1136 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1137 (*fodInfos->initdir!=0x00))
1139 /* Work out the proper path as supplied one might be relative */
1140 /* (Here because supplying '.' as dir browses to My Computer) */
1141 if (handledPath==FALSE) {
1142 WCHAR tmpBuf[MAX_PATH];
1143 WCHAR tmpBuf2[MAX_PATH];
1147 strcpyW(tmpBuf, fodInfos->initdir);
1148 if( PathFileExistsW(tmpBuf) ) {
1149 /* initdir does not have to be a directory. If a file is
1150 * specified, the dir part is taken */
1151 if( PathIsDirectoryW(tmpBuf)) {
1152 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1153 strcatW(tmpBuf, szwSlash);
1155 strcatW(tmpBuf, szwStar);
1157 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1160 if (fodInfos->initdir)
1161 MemFree(fodInfos->initdir);
1162 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1163 strcpyW(fodInfos->initdir, tmpBuf2);
1165 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1168 else if (fodInfos->initdir)
1170 MemFree(fodInfos->initdir);
1171 fodInfos->initdir = NULL;
1172 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1177 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1178 (*fodInfos->initdir==0x00)))
1180 /* 3. All except w2k+: if filename contains a path use it */
1181 if (!win2000plus && fodInfos->filename &&
1182 *fodInfos->filename &&
1183 strpbrkW(fodInfos->filename, szwSlash)) {
1184 WCHAR tmpBuf[MAX_PATH];
1188 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1193 /* nameBit is always shorter than the original filename */
1194 strcpyW(fodInfos->filename, nameBit);
1197 len = strlenW(tmpBuf);
1198 if(fodInfos->initdir)
1199 MemFree(fodInfos->initdir);
1200 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1201 strcpyW(fodInfos->initdir, tmpBuf);
1204 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1205 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1207 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1210 /* 4. win98+ and win2000+ if any files of specified filter types in
1211 current directory, use it */
1212 if ( win98plus && handledPath == FALSE &&
1213 fodInfos->filter && *fodInfos->filter) {
1215 BOOL searchMore = TRUE;
1216 LPCWSTR lpstrPos = fodInfos->filter;
1217 WIN32_FIND_DATAW FindFileData;
1222 /* filter is a list... title\0ext\0......\0\0 */
1224 /* Skip the title */
1225 if(! *lpstrPos) break; /* end */
1226 lpstrPos += strlenW(lpstrPos) + 1;
1228 /* See if any files exist in the current dir with this extension */
1229 if(! *lpstrPos) break; /* end */
1231 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1233 if (hFind == INVALID_HANDLE_VALUE) {
1234 /* None found - continue search */
1235 lpstrPos += strlenW(lpstrPos) + 1;
1240 if(fodInfos->initdir)
1241 MemFree(fodInfos->initdir);
1242 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1243 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1246 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1247 debugstr_w(lpstrPos));
1253 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1255 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1256 if (handledPath == FALSE && (win2000plus || win98plus)) {
1257 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1259 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1261 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1264 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1265 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1267 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1270 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1273 } else if (handledPath==FALSE) {
1274 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1275 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1277 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1280 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1281 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1283 /* Must the open as read only check box be checked ?*/
1284 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1286 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1289 /* Must the open as read only check box be hidden? */
1290 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1292 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1293 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1296 /* Must the help button be hidden? */
1297 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1299 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1300 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1303 /* Resize the height, if open as read only checkbox ad help button
1304 are hidden and we are not using a custom template nor a customDialog
1306 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1307 (!(fodInfos->ofnInfos->Flags &
1308 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1309 (!fodInfos->DlgInfos.hwndCustomDlg ))
1311 RECT rectDlg, rectHelp, rectCancel;
1312 GetWindowRect(hwnd, &rectDlg);
1313 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1314 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1315 /* subtract the height of the help button plus the space between
1316 the help button and the cancel button to the height of the dialog */
1317 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1318 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1319 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1321 /* change Open to Save FIXME: use resources */
1322 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1324 SetDlgItemTextA(hwnd,IDOK,"&Save");
1325 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1330 /***********************************************************************
1331 * FILEDLG95_FillControls
1333 * WM_INITDIALOG message handler (after hook notification)
1335 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1337 LPITEMIDLIST pidlItemId = NULL;
1339 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1341 TRACE("dir=%s file=%s\n",
1342 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1344 /* Get the initial directory pidl */
1346 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1348 WCHAR path[MAX_PATH];
1350 GetCurrentDirectoryW(MAX_PATH,path);
1351 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1354 /* Initialise shell objects */
1355 FILEDLG95_SHELL_Init(hwnd);
1357 /* Initialize the Look In combo box */
1358 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1360 /* Initialize the filter combo box */
1361 FILEDLG95_FILETYPE_Init(hwnd);
1363 /* Browse to the initial directory */
1364 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1366 /* Free pidlItem memory */
1367 COMDLG32_SHFree(pidlItemId);
1371 /***********************************************************************
1374 * Regroups all the cleaning functions of the filedlg
1376 void FILEDLG95_Clean(HWND hwnd)
1378 FILEDLG95_FILETYPE_Clean(hwnd);
1379 FILEDLG95_LOOKIN_Clean(hwnd);
1380 FILEDLG95_SHELL_Clean(hwnd);
1382 /***********************************************************************
1383 * FILEDLG95_OnWMCommand
1385 * WM_COMMAND message handler
1387 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1389 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1390 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1391 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1397 FILEDLG95_OnOpen(hwnd);
1401 FILEDLG95_Clean(hwnd);
1402 EndDialog(hwnd, FALSE);
1404 /* Filetype combo box */
1406 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1408 /* LookIn combo box */
1410 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1413 /* --- toolbar --- */
1414 /* Up folder button */
1415 case FCIDM_TB_UPFOLDER:
1416 FILEDLG95_SHELL_UpFolder(hwnd);
1418 /* New folder button */
1419 case FCIDM_TB_NEWFOLDER:
1420 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1422 /* List option button */
1423 case FCIDM_TB_SMALLICON:
1424 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1426 /* Details option button */
1427 case FCIDM_TB_REPORTVIEW:
1428 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1430 /* Details option button */
1431 case FCIDM_TB_DESKTOP:
1432 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1439 /* Do not use the listview selection anymore */
1440 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1444 /***********************************************************************
1445 * FILEDLG95_OnWMGetIShellBrowser
1447 * WM_GETISHELLBROWSER message handler
1449 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1452 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1456 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1462 /***********************************************************************
1463 * FILEDLG95_SendFileOK
1465 * Sends the CDN_FILEOK notification if required
1468 * TRUE if the dialog should close
1469 * FALSE if the dialog should not be closed
1471 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1473 /* ask the hook if we can close */
1474 if(IsHooked(fodInfos))
1477 /* First send CDN_FILEOK as MSDN doc says */
1478 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1479 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1481 TRACE("canceled\n");
1485 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1486 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1487 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1488 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1490 TRACE("canceled\n");
1497 /***********************************************************************
1498 * FILEDLG95_OnOpenMultipleFiles
1500 * Handles the opening of multiple files.
1503 * check destination buffer size
1505 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1507 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1508 UINT nCount, nSizePath;
1509 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1513 if(fodInfos->unicode)
1515 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1516 ofn->lpstrFile[0] = '\0';
1520 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1521 ofn->lpstrFile[0] = '\0';
1524 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1526 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1527 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1528 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1530 LPWSTR lpstrTemp = lpstrFileList;
1532 for ( nCount = 0; nCount < nFileCount; nCount++ )
1536 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1539 WCHAR lpstrNotFound[100];
1540 WCHAR lpstrMsg[100];
1542 WCHAR nl[] = {'\n',0};
1544 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1545 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1547 strcpyW(tmp, lpstrTemp);
1549 strcatW(tmp, lpstrNotFound);
1551 strcatW(tmp, lpstrMsg);
1553 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1557 /* move to the next file in the list of files */
1558 lpstrTemp += strlenW(lpstrTemp) + 1;
1559 COMDLG32_SHFree(pidl);
1563 nSizePath = strlenW(lpstrPathSpec) + 1;
1564 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1566 /* For "oldstyle" dialog the components have to
1567 be separated by blanks (not '\0'!) and short
1568 filenames have to be used! */
1569 FIXME("Components have to be separated by blanks\n");
1571 if(fodInfos->unicode)
1573 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1574 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1575 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1579 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1581 if (ofn->lpstrFile != NULL)
1583 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1584 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1585 if (ofn->nMaxFile > nSizePath)
1587 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1588 ofn->lpstrFile + nSizePath,
1589 ofn->nMaxFile - nSizePath, NULL, NULL);
1594 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1595 fodInfos->ofnInfos->nFileExtension = 0;
1597 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1600 /* clean and exit */
1601 FILEDLG95_Clean(hwnd);
1602 return EndDialog(hwnd,TRUE);
1605 /***********************************************************************
1608 * Ok button WM_COMMAND message handler
1610 * If the function succeeds, the return value is nonzero.
1612 #define ONOPEN_BROWSE 1
1613 #define ONOPEN_OPEN 2
1614 #define ONOPEN_SEARCH 3
1615 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1617 char strMsgTitle[MAX_PATH];
1618 char strMsgText [MAX_PATH];
1620 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1622 strMsgTitle[0] = '\0';
1623 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1624 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1627 BOOL FILEDLG95_OnOpen(HWND hwnd)
1629 LPWSTR lpstrFileList;
1630 UINT nFileCount = 0;
1633 WCHAR lpstrPathAndFile[MAX_PATH];
1634 WCHAR lpstrTemp[MAX_PATH];
1635 LPSHELLFOLDER lpsf = NULL;
1637 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1639 TRACE("hwnd=%p\n", hwnd);
1641 /* get the files from the edit control */
1642 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1644 /* try if the user selected a folder in the shellview */
1647 BrowseSelectedFolder(hwnd);
1653 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1657 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1660 Step 1: Build a complete path name from the current folder and
1661 the filename or path in the edit box.
1663 - the path in the edit box is a root path
1664 (with or without drive letter)
1665 - the edit box contains ".." (or a path with ".." in it)
1668 /* Get the current directory name */
1669 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1671 /* we are in a special folder, default to desktop */
1672 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1675 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1678 PathAddBackslashW(lpstrPathAndFile);
1680 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1682 /* if the user specifyed a fully qualified path use it */
1683 if(PathIsRelativeW(lpstrFileList))
1685 strcatW(lpstrPathAndFile, lpstrFileList);
1689 /* does the path have a drive letter? */
1690 if (PathGetDriveNumberW(lpstrFileList) == -1)
1691 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1693 strcpyW(lpstrPathAndFile, lpstrFileList);
1696 /* resolve "." and ".." */
1697 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1698 strcpyW(lpstrPathAndFile, lpstrTemp);
1699 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1701 MemFree(lpstrFileList);
1704 Step 2: here we have a cleaned up path
1706 We have to parse the path step by step to see if we have to browse
1707 to a folder if the path points to a directory or the last
1708 valid element is a directory.
1711 lpstrPathAndFile: cleaned up path
1714 nOpenAction = ONOPEN_BROWSE;
1716 /* don't apply any checks with OFN_NOVALIDATE */
1718 LPWSTR lpszTemp, lpszTemp1;
1719 LPITEMIDLIST pidl = NULL;
1720 WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1722 /* check for invalid chars */
1723 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1725 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1730 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1732 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1735 LPSHELLFOLDER lpsfChild;
1736 WCHAR lpwstrTemp[MAX_PATH];
1737 DWORD dwEaten, dwAttributes;
1740 strcpyW(lpwstrTemp, lpszTemp);
1741 p = PathFindNextComponentW(lpwstrTemp);
1743 if (!p) break; /* end of path */
1746 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1750 WCHAR wszWild[] = { '*', '?', 0 };
1751 /* if the last element is a wildcard do a search */
1752 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1754 nOpenAction = ONOPEN_SEARCH;
1758 lpszTemp1 = lpszTemp;
1760 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1762 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1764 dwAttributes = SFGAO_FOLDER;
1765 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1767 /* the path component is valid, we have a pidl of the next path component */
1768 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1769 if(dwAttributes & SFGAO_FOLDER)
1771 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1773 ERR("bind to failed\n"); /* should not fail */
1776 IShellFolder_Release(lpsf);
1784 /* end dialog, return value */
1785 nOpenAction = ONOPEN_OPEN;
1788 COMDLG32_SHFree(pidl);
1791 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1793 if(*lpszTemp) /* points to trailing null for last path element */
1795 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1797 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1803 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1804 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1806 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1810 /* change to the current folder */
1811 nOpenAction = ONOPEN_OPEN;
1816 nOpenAction = ONOPEN_OPEN;
1820 if(pidl) COMDLG32_SHFree(pidl);
1824 Step 3: here we have a cleaned up and validated path
1827 lpsf: ShellFolder bound to the rightmost valid path component
1828 lpstrPathAndFile: cleaned up path
1829 nOpenAction: action to do
1831 TRACE("end validate sf=%p\n", lpsf);
1835 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1836 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1839 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1842 /* replace the current filter */
1843 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1844 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1845 len = strlenW(lpszTemp)+1;
1846 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1847 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1849 /* set the filter cb to the extension when possible */
1850 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1851 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1854 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1855 TRACE("ONOPEN_BROWSE\n");
1857 IPersistFolder2 * ppf2;
1858 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1860 LPITEMIDLIST pidlCurrent;
1861 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1862 IPersistFolder2_Release(ppf2);
1863 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1865 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1867 else if( nOpenAction == ONOPEN_SEARCH )
1869 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1871 COMDLG32_SHFree(pidlCurrent);
1876 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1877 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1879 /* add default extension */
1880 if (fodInfos->defext)
1882 WCHAR *ext = PathFindExtensionW(lpstrPathAndFile);
1886 /* only add "." in case a default extension does exist */
1887 if (*fodInfos->defext != '\0')
1889 const WCHAR szwDot[] = {'.',0};
1890 int PathLength = strlenW(lpstrPathAndFile);
1892 strcatW(lpstrPathAndFile, szwDot);
1893 strcatW(lpstrPathAndFile, fodInfos->defext);
1895 /* In Open dialog: if file does not exist try without extension */
1896 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1897 && !PathFileExistsW(lpstrPathAndFile))
1898 lpstrPathAndFile[PathLength] = '\0';
1902 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1905 if (!lstrcmpiW(fodInfos->defext, ext))
1906 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1908 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1911 /* In Save dialog: check if the file already exists */
1912 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1913 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1914 && PathFileExistsW(lpstrPathAndFile))
1916 WCHAR lpstrOverwrite[100];
1919 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1920 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1921 MB_YESNO | MB_ICONEXCLAMATION);
1929 /* Check that the size of the file does not exceed buffer size.
1930 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1931 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1932 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1936 /* fill destination buffer */
1937 if (fodInfos->ofnInfos->lpstrFile)
1939 if(fodInfos->unicode)
1941 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1943 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1944 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1945 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1949 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1951 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1952 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1953 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1954 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1958 /* set filename offset */
1959 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1960 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1962 /* set extension offset */
1963 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1964 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1966 /* set the lpstrFileTitle */
1967 if(fodInfos->ofnInfos->lpstrFileTitle)
1969 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1970 if(fodInfos->unicode)
1972 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1973 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1977 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1978 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1979 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1983 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1987 FILEDLG95_Clean(hwnd);
1988 ret = EndDialog(hwnd, TRUE);
1992 /* FIXME set error FNERR_BUFFERTOSMALL */
1993 FILEDLG95_Clean(hwnd);
1994 ret = EndDialog(hwnd, FALSE);
2002 if(lpsf) IShellFolder_Release(lpsf);
2006 /***********************************************************************
2007 * FILEDLG95_SHELL_Init
2009 * Initialisation of the shell objects
2011 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2013 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2018 * Initialisation of the FileOpenDialogInfos structure
2024 fodInfos->ShellInfos.hwndOwner = hwnd;
2026 /* Disable multi-select if flag not set */
2027 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2029 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2031 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2032 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2034 /* Construct the IShellBrowser interface */
2035 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2040 /***********************************************************************
2041 * FILEDLG95_SHELL_ExecuteCommand
2043 * Change the folder option and refresh the view
2044 * If the function succeeds, the return value is nonzero.
2046 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2048 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2051 TRACE("(%p,%p)\n", hwnd, lpVerb);
2053 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2058 CMINVOKECOMMANDINFO ci;
2059 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2060 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2064 IContextMenu_InvokeCommand(pcm, &ci);
2065 IContextMenu_Release(pcm);
2071 /***********************************************************************
2072 * FILEDLG95_SHELL_UpFolder
2074 * Browse to the specified object
2075 * If the function succeeds, the return value is nonzero.
2077 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2079 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2083 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2092 /***********************************************************************
2093 * FILEDLG95_SHELL_BrowseToDesktop
2095 * Browse to the Desktop
2096 * If the function succeeds, the return value is nonzero.
2098 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2100 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2106 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2107 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2108 COMDLG32_SHFree(pidl);
2109 return SUCCEEDED(hres);
2111 /***********************************************************************
2112 * FILEDLG95_SHELL_Clean
2114 * Cleans the memory used by shell objects
2116 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2118 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2122 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2124 /* clean Shell interfaces */
2125 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2126 IShellView_Release(fodInfos->Shell.FOIShellView);
2127 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2128 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2129 if (fodInfos->Shell.FOIDataObject)
2130 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2133 /***********************************************************************
2134 * FILEDLG95_FILETYPE_Init
2136 * Initialisation of the file type combo box
2138 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2140 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2144 if(fodInfos->filter)
2146 int nFilters = 0; /* number of filters */
2148 LPCWSTR lpstrPos = fodInfos->filter;
2152 /* filter is a list... title\0ext\0......\0\0
2153 * Set the combo item text to the title and the item data
2156 LPCWSTR lpstrDisplay;
2160 if(! *lpstrPos) break; /* end */
2161 lpstrDisplay = lpstrPos;
2162 lpstrPos += strlenW(lpstrPos) + 1;
2164 /* Copy the extensions */
2165 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2166 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2167 strcpyW(lpstrExt,lpstrPos);
2168 lpstrPos += strlenW(lpstrPos) + 1;
2170 /* Add the item at the end of the combo */
2171 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2172 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2176 * Set the current filter to the one specified
2177 * in the initialisation structure
2178 * FIXME: lpstrCustomFilter not handled at all
2181 /* set default filter index */
2182 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2183 fodInfos->ofnInfos->nFilterIndex = 1;
2185 /* First, check to make sure our index isn't out of bounds. */
2186 if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
2187 fodInfos->ofnInfos->nFilterIndex = nFilters;
2189 /* Set the current index selection. */
2190 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
2192 /* Get the corresponding text string from the combo box. */
2193 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2194 fodInfos->ofnInfos->nFilterIndex-1);
2196 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2202 CharLowerW(lpstrFilter); /* lowercase */
2203 len = strlenW(lpstrFilter)+1;
2204 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2205 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2211 /***********************************************************************
2212 * FILEDLG95_FILETYPE_OnCommand
2214 * WM_COMMAND of the file type combo box
2215 * If the function succeeds, the return value is nonzero.
2217 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2219 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2227 /* Get the current item of the filetype combo box */
2228 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2230 /* set the current filter index - indexed from 1 */
2231 fodInfos->ofnInfos->nFilterIndex = iItem + 1;
2233 /* Set the current filter with the current selection */
2234 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2235 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2237 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2239 if((int)lpstrFilter != CB_ERR)
2242 CharLowerW(lpstrFilter); /* lowercase */
2243 len = strlenW(lpstrFilter)+1;
2244 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2245 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2246 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2249 /* Refresh the actual view to display the included items*/
2250 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2255 /***********************************************************************
2256 * FILEDLG95_FILETYPE_SearchExt
2258 * searches for a extension in the filetype box
2260 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2262 int i, iCount = CBGetCount(hwnd);
2264 TRACE("%s\n", debugstr_w(lpstrExt));
2266 if(iCount != CB_ERR)
2268 for(i=0;i<iCount;i++)
2270 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2277 /***********************************************************************
2278 * FILEDLG95_FILETYPE_Clean
2280 * Clean the memory used by the filetype combo box
2282 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2284 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2286 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2290 /* Delete each string of the combo and their associated data */
2291 if(iCount != CB_ERR)
2293 for(iPos = iCount-1;iPos>=0;iPos--)
2295 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2296 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2299 /* Current filter */
2300 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2301 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2305 /***********************************************************************
2306 * FILEDLG95_LOOKIN_Init
2308 * Initialisation of the look in combo box
2310 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2312 IShellFolder *psfRoot, *psfDrives;
2313 IEnumIDList *lpeRoot, *lpeDrives;
2314 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2316 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2320 liInfos->iMaxIndentation = 0;
2322 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2324 /* set item height for both text field and listbox */
2325 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2326 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2328 /* Turn on the extended UI for the combo box like Windows does */
2329 CBSetExtendedUI(hwndCombo, TRUE);
2331 /* Initialise data of Desktop folder */
2332 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2333 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2334 COMDLG32_SHFree(pidlTmp);
2336 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2338 SHGetDesktopFolder(&psfRoot);
2342 /* enumerate the contents of the desktop */
2343 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2345 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2347 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2349 /* special handling for CSIDL_DRIVES */
2350 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2352 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2354 /* enumerate the drives */
2355 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2357 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2359 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2360 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2361 COMDLG32_SHFree(pidlAbsTmp);
2362 COMDLG32_SHFree(pidlTmp1);
2364 IEnumIDList_Release(lpeDrives);
2366 IShellFolder_Release(psfDrives);
2369 COMDLG32_SHFree(pidlTmp);
2371 IEnumIDList_Release(lpeRoot);
2373 IShellFolder_Release(psfRoot);
2376 COMDLG32_SHFree(pidlDrives);
2380 /***********************************************************************
2381 * FILEDLG95_LOOKIN_DrawItem
2383 * WM_DRAWITEM message handler
2385 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2387 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2388 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2389 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2393 HIMAGELIST ilItemImage;
2396 LPSFOLDER tmpFolder;
2399 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2403 if(pDIStruct->itemID == -1)
2406 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2407 pDIStruct->itemID)))
2411 if(pDIStruct->itemID == liInfos->uSelectedItem)
2413 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2416 sizeof (SHFILEINFOA),
2417 SHGFI_PIDL | SHGFI_SMALLICON |
2418 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2419 SHGFI_DISPLAYNAME );
2423 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2426 sizeof (SHFILEINFOA),
2427 SHGFI_PIDL | SHGFI_SMALLICON |
2428 SHGFI_SYSICONINDEX |
2432 /* Is this item selected ? */
2433 if(pDIStruct->itemState & ODS_SELECTED)
2435 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2436 SetBkColor(pDIStruct->hDC,crHighLight);
2437 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2441 SetTextColor(pDIStruct->hDC,crText);
2442 SetBkColor(pDIStruct->hDC,crWin);
2443 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2446 /* Do not indent item if drawing in the edit of the combo */
2447 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2450 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2453 sizeof (SHFILEINFOA),
2454 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2455 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2460 iIndentation = tmpFolder->m_iIndent;
2462 /* Draw text and icon */
2464 /* Initialise the icon display area */
2465 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2466 rectIcon.top = pDIStruct->rcItem.top;
2467 rectIcon.right = rectIcon.left + ICONWIDTH;
2468 rectIcon.bottom = pDIStruct->rcItem.bottom;
2470 /* Initialise the text display area */
2471 GetTextMetricsA(pDIStruct->hDC, &tm);
2472 rectText.left = rectIcon.right;
2474 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2475 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2477 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2479 /* Draw the icon from the image list */
2480 ImageList_Draw(ilItemImage,
2487 /* Draw the associated text */
2488 if(sfi.szDisplayName)
2489 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2495 /***********************************************************************
2496 * FILEDLG95_LOOKIN_OnCommand
2498 * LookIn combo box WM_COMMAND message handler
2499 * If the function succeeds, the return value is nonzero.
2501 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2503 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2505 TRACE("%p\n", fodInfos);
2511 LPSFOLDER tmpFolder;
2514 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2516 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2521 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2522 tmpFolder->pidlItem,
2534 /***********************************************************************
2535 * FILEDLG95_LOOKIN_AddItem
2537 * Adds an absolute pidl item to the lookin combo box
2538 * returns the index of the inserted item
2540 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2542 LPITEMIDLIST pidlNext;
2545 LookInInfos *liInfos;
2547 TRACE("%08x\n", iInsertId);
2552 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2555 tmpFolder = MemAlloc(sizeof(SFOLDER));
2556 tmpFolder->m_iIndent = 0;
2558 /* Calculate the indentation of the item in the lookin*/
2560 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2562 tmpFolder->m_iIndent++;
2565 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2567 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2568 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2570 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2571 SHGetFileInfoA((LPSTR)pidl,
2575 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2576 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2578 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2580 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2584 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2586 /* Add the item at the end of the list */
2589 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2591 /* Insert the item at the iInsertId position*/
2594 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2597 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2601 COMDLG32_SHFree( tmpFolder->pidlItem );
2602 MemFree( tmpFolder );
2607 /***********************************************************************
2608 * FILEDLG95_LOOKIN_InsertItemAfterParent
2610 * Insert an item below its parent
2612 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2615 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2620 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2624 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2627 /* Free pidlParent memory */
2628 COMDLG32_SHFree((LPVOID)pidlParent);
2630 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2633 /***********************************************************************
2634 * FILEDLG95_LOOKIN_SelectItem
2636 * Adds an absolute pidl item to the lookin combo box
2637 * returns the index of the inserted item
2639 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2642 LookInInfos *liInfos;
2646 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2648 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2652 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2653 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2658 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2659 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2663 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2665 if(iRemovedItem < iItemPos)
2670 CBSetCurSel(hwnd,iItemPos);
2671 liInfos->uSelectedItem = iItemPos;
2677 /***********************************************************************
2678 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2680 * Remove the item with an expansion level over iExpansionLevel
2682 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2686 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2690 if(liInfos->iMaxIndentation <= 2)
2693 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2695 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2696 COMDLG32_SHFree(tmpFolder->pidlItem);
2698 CBDeleteString(hwnd,iItemPos);
2699 liInfos->iMaxIndentation--;
2707 /***********************************************************************
2708 * FILEDLG95_LOOKIN_SearchItem
2710 * Search for pidl in the lookin combo box
2711 * returns the index of the found item
2713 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2716 int iCount = CBGetCount(hwnd);
2718 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2720 if (iCount != CB_ERR)
2724 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2726 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2728 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2736 /***********************************************************************
2737 * FILEDLG95_LOOKIN_Clean
2739 * Clean the memory used by the lookin combo box
2741 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2743 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2745 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2749 /* Delete each string of the combo and their associated data */
2750 if (iCount != CB_ERR)
2752 for(iPos = iCount-1;iPos>=0;iPos--)
2754 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2755 COMDLG32_SHFree(tmpFolder->pidlItem);
2757 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2761 /* LookInInfos structure */
2762 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2765 /***********************************************************************
2766 * FILEDLG95_FILENAME_FillFromSelection
2768 * fills the edit box from the cached DataObject
2770 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2772 FileOpenDlgInfos *fodInfos;
2774 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2775 char lpstrTemp[MAX_PATH];
2776 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2779 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2781 /* Count how many files we have */
2782 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2784 /* calculate the string length, count files */
2785 if (nFileSelected >= 1)
2787 nLength += 3; /* first and last quotes, trailing \0 */
2788 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2790 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2794 /* get the total length of the selected file names */
2795 lpstrTemp[0] = '\0';
2796 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2798 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2800 nLength += strlen( lpstrTemp ) + 3;
2803 COMDLG32_SHFree( pidl );
2808 /* allocate the buffer */
2809 if (nFiles <= 1) nLength = MAX_PATH;
2810 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2811 lpstrAllFile[0] = '\0';
2813 /* Generate the string for the edit control */
2816 lpstrCurrFile = lpstrAllFile;
2817 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2819 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2823 /* get the file name */
2824 lpstrTemp[0] = '\0';
2825 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2827 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2831 *lpstrCurrFile++ = '\"';
2832 strcpy( lpstrCurrFile, lpstrTemp );
2833 lpstrCurrFile += strlen( lpstrTemp );
2834 strcpy( lpstrCurrFile, "\" " );
2839 strcpy( lpstrAllFile, lpstrTemp );
2842 COMDLG32_SHFree( (LPVOID) pidl );
2845 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2847 /* Select the file name like Windows does */
2848 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2850 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2854 /* copied from shell32 to avoid linking to it */
2855 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2860 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2861 COMDLG32_SHFree(src->u.pOleStr);
2865 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2869 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2873 FIXME("unknown type!\n");
2876 *(LPSTR)dest = '\0';
2883 /***********************************************************************
2884 * FILEDLG95_FILENAME_GetFileNames
2886 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2888 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2890 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2891 UINT nStrCharCount = 0; /* index in src buffer */
2892 UINT nFileIndex = 0; /* index in dest buffer */
2893 UINT nFileCount = 0; /* number of files */
2894 UINT nStrLen = 0; /* length of string in edit control */
2895 LPWSTR lpstrEdit; /* buffer for string from edit control */
2899 /* get the filenames from the edit control */
2900 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2901 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2902 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2904 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2906 /* we might get single filename without any '"',
2907 * so we need nStrLen + terminating \0 + end-of-list \0 */
2908 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2911 /* build 0-delimited file list from filenames */
2912 while ( nStrCharCount <= nStrLen )
2914 if ( lpstrEdit[nStrCharCount]=='"' )
2917 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2919 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2923 (*lpstrFileList)[nFileIndex++] = '\0';
2930 /* single, unquoted string */
2931 if ((nStrLen > 0) && (*sizeUsed == 0) )
2933 strcpyW(*lpstrFileList, lpstrEdit);
2934 nFileIndex = strlenW(lpstrEdit) + 1;
2935 (*sizeUsed) = nFileIndex;
2940 (*lpstrFileList)[nFileIndex] = '\0';
2947 #define SETDefFormatEtc(fe,cf,med) \
2949 (fe).cfFormat = cf;\
2950 (fe).dwAspect = DVASPECT_CONTENT; \
2957 * DATAOBJECT Helper functions
2960 /***********************************************************************
2961 * COMCTL32_ReleaseStgMedium
2963 * like ReleaseStgMedium from ole32
2965 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2967 if(medium.pUnkForRelease)
2969 IUnknown_Release(medium.pUnkForRelease);
2973 GlobalUnlock(medium.u.hGlobal);
2974 GlobalFree(medium.u.hGlobal);
2978 /***********************************************************************
2979 * GetPidlFromDataObject
2981 * Return pidl(s) by number from the cached DataObject
2983 * nPidlIndex=0 gets the fully qualified root path
2985 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2989 FORMATETC formatetc;
2990 LPITEMIDLIST pidl = NULL;
2992 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
2994 /* Set the FORMATETC structure*/
2995 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2997 /* Get the pidls from IDataObject */
2998 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3000 LPIDA cida = GlobalLock(medium.u.hGlobal);
3001 if(nPidlIndex <= cida->cidl)
3003 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3005 COMCTL32_ReleaseStgMedium(medium);
3010 /***********************************************************************
3013 * Return the number of selected items in the DataObject.
3016 UINT GetNumSelected( IDataObject *doSelected )
3020 FORMATETC formatetc;
3022 TRACE("sv=%p\n", doSelected);
3024 if (!doSelected) return 0;
3026 /* Set the FORMATETC structure*/
3027 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3029 /* Get the pidls from IDataObject */
3030 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3032 LPIDA cida = GlobalLock(medium.u.hGlobal);
3033 retVal = cida->cidl;
3034 COMCTL32_ReleaseStgMedium(medium);
3044 /***********************************************************************
3047 * Get the pidl's display name (relative to folder) and
3048 * put it in lpstrFileName.
3050 * Return NOERROR on success,
3054 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3059 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3064 SHGetDesktopFolder(&lpsf);
3065 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3066 IShellFolder_Release(lpsf);
3070 /* Get the display name of the pidl relative to the folder */
3071 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3073 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3078 /***********************************************************************
3079 * GetShellFolderFromPidl
3081 * pidlRel is the item pidl relative
3082 * Return the IShellFolder of the absolute pidl
3084 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3086 IShellFolder *psf = NULL,*psfParent;
3088 TRACE("%p\n", pidlAbs);
3090 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3093 if(pidlAbs && pidlAbs->mkid.cb)
3095 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3097 IShellFolder_Release(psfParent);
3101 /* return the desktop */
3107 /***********************************************************************
3110 * Return the LPITEMIDLIST to the parent of the pidl in the list
3112 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3114 LPITEMIDLIST pidlParent;
3116 TRACE("%p\n", pidl);
3118 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3119 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3124 /***********************************************************************
3127 * returns the pidl of the file name relative to folder
3128 * NULL if an error occurred
3130 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3132 LPITEMIDLIST pidl = NULL;
3135 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3137 if(!lpcstrFileName) return NULL;
3138 if(!*lpcstrFileName) return NULL;
3142 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3143 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3144 IShellFolder_Release(lpsf);
3149 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3156 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3158 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3161 TRACE("%p, %p\n", psf, pidl);
3163 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3165 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3166 /* see documentation shell 4.1*/
3167 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3170 /***********************************************************************
3171 * BrowseSelectedFolder
3173 static BOOL BrowseSelectedFolder(HWND hwnd)
3175 BOOL bBrowseSelFolder = FALSE;
3176 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3180 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3182 LPITEMIDLIST pidlSelection;
3184 /* get the file selected */
3185 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3186 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3188 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3189 pidlSelection, SBSP_RELATIVE ) ) )
3191 WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3192 ' ','n','o','t',' ','e','x','i','s','t',0};
3193 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3196 bBrowseSelFolder = TRUE;
3198 COMDLG32_SHFree( pidlSelection );
3201 return bBrowseSelFolder;
3205 * Memory allocation methods */
3206 static void *MemAlloc(UINT size)
3208 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3211 static void MemFree(void *mem)
3215 HeapFree(GetProcessHeap(),0,mem);
3219 /* ------------------ APIs ---------------------- */
3221 /***********************************************************************
3222 * GetOpenFileNameA (COMDLG32.@)
3224 * Creates a dialog box for the user to select a file to open.
3227 * TRUE on success: user enters a valid file
3228 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3231 BOOL WINAPI GetOpenFileNameA(
3232 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3234 BOOL win16look = FALSE;
3236 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3237 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3240 return GetFileName31A(ofn, OPEN_DIALOG);
3242 return GetFileDialog95A(ofn, OPEN_DIALOG);
3245 /***********************************************************************
3246 * GetOpenFileNameW (COMDLG32.@)
3248 * Creates a dialog box for the user to select a file to open.
3251 * TRUE on success: user enters a valid file
3252 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3255 BOOL WINAPI GetOpenFileNameW(
3256 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3258 BOOL win16look = FALSE;
3260 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3261 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3264 return GetFileName31W(ofn, OPEN_DIALOG);
3266 return GetFileDialog95W(ofn, OPEN_DIALOG);
3270 /***********************************************************************
3271 * GetSaveFileNameA (COMDLG32.@)
3273 * Creates a dialog box for the user to select a file to save.
3276 * TRUE on success: user enters a valid file
3277 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3280 BOOL WINAPI GetSaveFileNameA(
3281 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3283 BOOL win16look = FALSE;
3285 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3286 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3289 return GetFileName31A(ofn, SAVE_DIALOG);
3291 return GetFileDialog95A(ofn, SAVE_DIALOG);
3294 /***********************************************************************
3295 * GetSaveFileNameW (COMDLG32.@)
3297 * Creates a dialog box for the user to select a file to save.
3300 * TRUE on success: user enters a valid file
3301 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3304 BOOL WINAPI GetSaveFileNameW(
3305 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3307 BOOL win16look = FALSE;
3309 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3310 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3313 return GetFileName31W(ofn, SAVE_DIALOG);
3315 return GetFileDialog95W(ofn, SAVE_DIALOG);