Update OFN_READONLY flag when closing file dialog.
[wine/dcerpc.git] / dlls / commdlg / filedlg.c
blob9dc236fb988da9938dc06d7f0a3bf535f5287bed
1 /*
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: algorithm for selecting the initial directory is too simple
39 * FIXME: add to recent docs
41 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
42 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
43 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
44 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
46 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
51 #include "config.h"
52 #include "wine/port.h"
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <string.h>
60 #define NONAMELESSUNION
61 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "commdlg.h"
71 #include "dlgs.h"
72 #include "cdlg.h"
73 #include "wine/debug.h"
74 #include "cderr.h"
75 #include "shellapi.h"
76 #include "shlguid.h"
77 #include "shlobj.h"
78 #include "filedlgbrowser.h"
79 #include "shlwapi.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
85 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
86 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
87 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
89 #define IsHooked(fodInfos) \
90 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
91 /***********************************************************************
92 * Data structure and global variables
94 typedef struct SFolder
96 int m_iImageIndex; /* Index of picture in image list */
97 HIMAGELIST hImgList;
98 int m_iIndent; /* Indentation index */
99 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
101 } SFOLDER,*LPSFOLDER;
103 typedef struct tagLookInInfo
105 int iMaxIndentation;
106 UINT uSelectedItem;
107 } LookInInfos;
110 /***********************************************************************
111 * Defines and global variables
114 /* Draw item constant */
115 #define ICONWIDTH 18
116 #define XTEXTOFFSET 3
118 /* AddItem flags*/
119 #define LISTEND -1
121 /* SearchItem methods */
122 #define SEARCH_PIDL 1
123 #define SEARCH_EXP 2
124 #define ITEM_NOTFOUND -1
126 /* Undefined windows message sent by CreateViewObject*/
127 #define WM_GETISHELLBROWSER WM_USER+7
129 /* NOTE
130 * Those macros exist in windowsx.h. However, you can't really use them since
131 * they rely on the UNICODE defines and can't be used inside Wine itself.
134 /* Combo box macros */
135 #define CBAddString(hwnd,str) \
136 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
137 #define CBAddStringW(hwnd,str) \
138 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
140 #define CBInsertString(hwnd,str,pos) \
141 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
143 #define CBDeleteString(hwnd,pos) \
144 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
146 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
147 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
149 #define CBGetItemDataPtr(hwnd,iItemId) \
150 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
152 #define CBGetLBText(hwnd,iItemId,str) \
153 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
155 #define CBGetCurSel(hwnd) \
156 SendMessageA(hwnd,CB_GETCURSEL,0,0);
158 #define CBSetCurSel(hwnd,pos) \
159 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
161 #define CBGetCount(hwnd) \
162 SendMessageA(hwnd,CB_GETCOUNT,0,0);
163 #define CBShowDropDown(hwnd,show) \
164 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
165 #define CBSetItemHeight(hwnd,index,height) \
166 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
168 #define CBSetExtendedUI(hwnd,flag) \
169 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
171 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
172 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
174 /***********************************************************************
175 * Prototypes
178 /* Internal functions used by the dialog */
179 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
180 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
181 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
182 BOOL FILEDLG95_OnOpen(HWND hwnd);
183 static LRESULT FILEDLG95_InitControls(HWND hwnd);
184 static void FILEDLG95_Clean(HWND hwnd);
186 /* Functions used by the shell navigation */
187 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
188 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
189 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
190 static void FILEDLG95_SHELL_Clean(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
193 /* Functions used by the filetype combo box */
194 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
195 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
196 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
197 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
199 /* Functions used by the Look In combo box */
200 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
201 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
202 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
204 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
205 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
206 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
207 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
208 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
210 /* Miscellaneous tool functions */
211 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
212 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
213 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
214 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
215 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
217 /* Shell memory allocation */
218 static void *MemAlloc(UINT size);
219 static void MemFree(void *mem);
221 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
222 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
223 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
224 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
225 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
226 static BOOL BrowseSelectedFolder(HWND hwnd);
228 /* old style dialogs */
229 extern BOOL GetFileName31A(LPOPENFILENAMEA lpofn, UINT dlgType);
230 extern BOOL GetFileName31W(LPOPENFILENAMEW lpofn, UINT dlgType);
232 /***********************************************************************
233 * GetFileName95
235 * Creates an Open common dialog box that lets the user select
236 * the drive, directory, and the name of a file or set of files to open.
238 * IN : The FileOpenDlgInfos structure associated with the dialog
239 * OUT : TRUE on success
240 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
242 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
245 LRESULT lRes;
246 LPCVOID template;
247 HRSRC hRes;
248 HANDLE hDlgTmpl = 0;
250 /* test for missing functionality */
251 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
253 FIXME("Flags 0x%08lx not yet implemented\n",
254 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
257 /* Create the dialog from a template */
259 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
261 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
262 return FALSE;
264 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
265 !(template = LockResource( hDlgTmpl )))
267 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
268 return FALSE;
271 /* old style hook messages */
272 if (IsHooked(fodInfos))
274 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
275 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
276 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
277 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
280 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
281 (LPDLGTEMPLATEA) template,
282 fodInfos->ofnInfos->hwndOwner,
283 FileOpenDlgProc95,
284 (LPARAM) fodInfos);
286 /* Unable to create the dialog */
287 if( lRes == -1)
288 return FALSE;
290 return lRes;
293 /***********************************************************************
294 * GetFileDialog95A
296 * Call GetFileName95 with this structure and clean the memory.
298 * IN : The OPENFILENAMEA initialisation structure passed to
299 * GetOpenFileNameA win api function (see filedlg.c)
301 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
303 BOOL ret;
304 FileOpenDlgInfos fodInfos;
305 LPSTR lpstrSavDir = NULL;
306 LPWSTR title = NULL;
307 LPWSTR defext = NULL;
308 LPWSTR filter = NULL;
309 LPWSTR customfilter = NULL;
311 /* Initialize FileOpenDlgInfos structure */
312 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
314 /* Pass in the original ofn */
315 fodInfos.ofnInfos = ofn;
317 /* save current directory */
318 if (ofn->Flags & OFN_NOCHANGEDIR)
320 lpstrSavDir = MemAlloc(MAX_PATH);
321 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
324 fodInfos.unicode = FALSE;
326 /* convert all the input strings to unicode */
327 if(ofn->lpstrInitialDir)
329 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
330 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
331 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
333 else
334 fodInfos.initdir = NULL;
336 if(ofn->lpstrFile)
338 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
339 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
341 else
342 fodInfos.filename = NULL;
344 if(ofn->lpstrDefExt)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
347 defext = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
350 fodInfos.defext = defext;
352 if(ofn->lpstrTitle)
354 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
355 title = MemAlloc((len+1)*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
358 fodInfos.title = title;
360 if (ofn->lpstrFilter)
362 LPCSTR s;
363 int n, len;
365 /* filter is a list... title\0ext\0......\0\0 */
366 s = ofn->lpstrFilter;
367 while (*s) s = s+strlen(s)+1;
368 s++;
369 n = s - ofn->lpstrFilter;
370 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
371 filter = MemAlloc(len*sizeof(WCHAR));
372 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
374 fodInfos.filter = filter;
376 /* convert lpstrCustomFilter */
377 if (ofn->lpstrCustomFilter)
379 LPCSTR s;
380 int n, len;
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrCustomFilter;
384 while (*s) s = s+strlen(s)+1;
385 s++;
386 n = s - ofn->lpstrCustomFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
388 customfilter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
391 fodInfos.customfilter = customfilter;
393 /* Initialize the dialog property */
394 fodInfos.DlgInfos.dwDlgProp = 0;
395 fodInfos.DlgInfos.hwndCustomDlg = NULL;
397 switch(iDlgType)
399 case OPEN_DIALOG :
400 ret = GetFileName95(&fodInfos);
401 break;
402 case SAVE_DIALOG :
403 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
404 ret = GetFileName95(&fodInfos);
405 break;
406 default :
407 ret = 0;
410 if (lpstrSavDir)
412 SetCurrentDirectoryA(lpstrSavDir);
413 MemFree(lpstrSavDir);
416 if(title)
417 MemFree(title);
418 if(defext)
419 MemFree(defext);
420 if(filter)
421 MemFree(filter);
422 if(customfilter)
423 MemFree(customfilter);
424 if(fodInfos.initdir)
425 MemFree(fodInfos.initdir);
427 if(fodInfos.filename)
428 MemFree(fodInfos.filename);
430 TRACE("selected file: %s\n",ofn->lpstrFile);
432 return ret;
435 /***********************************************************************
436 * GetFileDialog95W
438 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
439 * Call GetFileName95 with this structure and clean the memory.
441 * FIXME: lpstrCustomFilter has to be converted back
444 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
446 BOOL ret;
447 FileOpenDlgInfos fodInfos;
448 LPSTR lpstrSavDir = NULL;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
453 /* Pass in the original ofn */
454 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
456 fodInfos.title = ofn->lpstrTitle;
457 fodInfos.defext = ofn->lpstrDefExt;
458 fodInfos.filter = ofn->lpstrFilter;
459 fodInfos.customfilter = ofn->lpstrCustomFilter;
461 /* convert string arguments, save others */
462 if(ofn->lpstrFile)
464 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
467 else
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 DWORD len = strlenW(ofn->lpstrInitialDir);
473 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
474 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
476 else
477 fodInfos.initdir = NULL;
479 /* save current directory */
480 if (ofn->Flags & OFN_NOCHANGEDIR)
482 lpstrSavDir = MemAlloc(MAX_PATH);
483 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
486 fodInfos.unicode = TRUE;
488 switch(iDlgType)
490 case OPEN_DIALOG :
491 ret = GetFileName95(&fodInfos);
492 break;
493 case SAVE_DIALOG :
494 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
495 ret = GetFileName95(&fodInfos);
496 break;
497 default :
498 ret = 0;
501 if (lpstrSavDir)
503 SetCurrentDirectoryA(lpstrSavDir);
504 MemFree(lpstrSavDir);
507 /* restore saved IN arguments and convert OUT arguments back */
508 MemFree(fodInfos.filename);
509 MemFree(fodInfos.initdir);
510 return ret;
513 /***********************************************************************
514 * ArrangeCtrlPositions [internal]
516 * NOTE: Do not change anything here without a lot of testing.
518 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
520 HWND hwndChild, hwndStc32;
521 RECT rectParent, rectChild, rectStc32;
522 INT help_fixup = 0;
524 /* Take into account if open as read only checkbox and help button
525 * are hidden
527 if (hide_help)
529 RECT rectHelp, rectCancel;
530 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
531 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
532 /* subtract the height of the help button plus the space between
533 * the help button and the cancel button to the height of the dialog
535 help_fixup = rectHelp.bottom - rectCancel.bottom;
539 There are two possibilities to add components to the default file dialog box.
541 By default, all the new components are added below the standard dialog box (the else case).
543 However, if there is a static text component with the stc32 id, a special case happens.
544 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
545 in the window and the cx and cy indicate how to size the window.
546 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
547 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
551 GetClientRect(hwndParentDlg, &rectParent);
553 /* when arranging controls we have to use fixed parent size */
554 rectParent.bottom -= help_fixup;
556 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
557 if (hwndStc32)
559 GetWindowRect(hwndStc32, &rectStc32);
560 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
562 /* set the size of the stc32 control according to the size of
563 * client area of the parent dialog
565 SetWindowPos(hwndStc32, 0,
566 0, 0,
567 rectParent.right, rectParent.bottom,
568 SWP_NOMOVE | SWP_NOZORDER);
570 else
571 SetRectEmpty(&rectStc32);
573 /* this part moves controls of the child dialog */
574 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
575 while (hwndChild)
577 if (hwndChild != hwndStc32)
579 GetWindowRect(hwndChild, &rectChild);
580 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
582 /* move only if stc32 exist */
583 if (hwndStc32 && rectChild.left > rectStc32.right)
585 /* move to the right of visible controls of the parent dialog */
586 rectChild.left += rectParent.right;
587 rectChild.left -= rectStc32.right;
589 /* move even if stc32 doesn't exist */
590 if (rectChild.top > rectStc32.bottom)
592 /* move below visible controls of the parent dialog */
593 rectChild.top += rectParent.bottom;
594 rectChild.top -= rectStc32.bottom - rectStc32.top;
597 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
598 0, 0, SWP_NOSIZE | SWP_NOZORDER);
600 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
603 /* this part moves controls of the parent dialog */
604 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
605 while (hwndChild)
607 if (hwndChild != hwndChildDlg)
609 GetWindowRect(hwndChild, &rectChild);
610 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
612 /* left,top of stc32 marks the position of controls
613 * from the parent dialog
615 rectChild.left += rectStc32.left;
616 rectChild.top += rectStc32.top;
618 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
619 0, 0, SWP_NOSIZE | SWP_NOZORDER);
621 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
624 /* calculate the size of the resulting dialog */
626 /* here we have to use original parent size */
627 GetClientRect(hwndParentDlg, &rectParent);
628 GetClientRect(hwndChildDlg, &rectChild);
630 if (hwndStc32)
632 if (rectParent.right > rectChild.right)
634 rectParent.right += rectChild.right;
635 rectParent.right -= rectStc32.right - rectStc32.left;
637 else
639 rectParent.right = rectChild.right;
642 if (rectParent.bottom > rectChild.bottom)
644 rectParent.bottom += rectChild.bottom;
645 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
647 else
649 rectParent.bottom = rectChild.bottom;
652 else
654 rectParent.bottom += rectChild.bottom;
657 /* finally use fixed parent size */
658 rectParent.bottom -= help_fixup;
660 /* save the size of the parent's client area */
661 rectChild.right = rectParent.right;
662 rectChild.bottom = rectParent.bottom;
664 /* set the size of the parent dialog */
665 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
666 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
667 SetWindowPos(hwndParentDlg, 0,
668 0, 0,
669 rectParent.right - rectParent.left,
670 rectParent.bottom - rectParent.top,
671 SWP_NOMOVE | SWP_NOZORDER);
673 /* set the size of the child dialog */
674 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
675 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
678 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
680 switch(uMsg) {
681 case WM_INITDIALOG:
682 return TRUE;
684 return FALSE;
687 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
689 LPCVOID template;
690 HRSRC hRes;
691 HANDLE hDlgTmpl = 0;
692 HWND hChildDlg = 0;
694 TRACE("\n");
697 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
698 * structure's hInstance parameter is not a HINSTANCE, but
699 * instead a pointer to a template resource to use.
701 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
703 HINSTANCE hinst;
704 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
706 hinst = 0;
707 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
709 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
710 return NULL;
713 else
715 hinst = fodInfos->ofnInfos->hInstance;
716 if(fodInfos->unicode)
718 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
719 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
721 else
723 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
724 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
726 if (!hRes)
728 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
729 return NULL;
731 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
732 !(template = LockResource( hDlgTmpl )))
734 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
735 return NULL;
738 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
739 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
740 (LPARAM)fodInfos->ofnInfos);
741 if(hChildDlg)
743 ShowWindow(hChildDlg,SW_SHOW);
744 return hChildDlg;
747 else if( IsHooked(fodInfos))
749 RECT rectHwnd;
750 struct {
751 DLGTEMPLATE tmplate;
752 WORD menu,class,title;
753 } temp;
754 GetClientRect(hwnd,&rectHwnd);
755 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
756 temp.tmplate.dwExtendedStyle = 0;
757 temp.tmplate.cdit = 0;
758 temp.tmplate.x = 0;
759 temp.tmplate.y = 0;
760 temp.tmplate.cx = 0;
761 temp.tmplate.cy = 0;
762 temp.menu = temp.class = temp.title = 0;
764 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
765 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
767 return hChildDlg;
769 return NULL;
772 /***********************************************************************
773 * SendCustomDlgNotificationMessage
775 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
778 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
780 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
782 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
784 if(!fodInfos) return 0;
786 if(fodInfos->unicode)
787 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
789 if(fodInfos->DlgInfos.hwndCustomDlg)
791 OFNOTIFYA ofnNotify;
792 HRESULT ret;
793 ofnNotify.hdr.hwndFrom=hwndParentDlg;
794 ofnNotify.hdr.idFrom=0;
795 ofnNotify.hdr.code = uCode;
796 ofnNotify.lpOFN = fodInfos->ofnInfos;
797 ofnNotify.pszFile = NULL;
798 TRACE("CALL NOTIFY for %x\n", uCode);
799 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
800 TRACE("RET NOTIFY\n");
801 return ret;
803 return TRUE;
806 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
808 UINT sizeUsed = 0, n, total;
809 LPWSTR lpstrFileList = NULL;
810 WCHAR lpstrCurrentDir[MAX_PATH];
811 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
813 TRACE("CDM_GETFILEPATH:\n");
815 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
816 return -1;
818 /* get path and filenames */
819 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
820 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
822 TRACE("path >%s< filespec >%s< %d files\n",
823 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
825 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
826 NULL, 0, NULL, NULL);
827 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
828 NULL, 0, NULL, NULL);
830 /* Prepend the current path */
831 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
832 buffer, size, NULL, NULL);
834 if(n<size)
836 /* 'n' includes trailing \0 */
837 buffer[n-1] = '\\';
838 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
839 &buffer[n], size-n, NULL, NULL);
841 MemFree(lpstrFileList);
843 TRACE("returned -> %s\n",debugstr_a(buffer));
845 return total;
848 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
850 UINT sizeUsed = 0;
851 LPWSTR lpstrFileList = NULL;
853 TRACE("CDM_GETSPEC:\n");
855 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
856 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
857 MemFree(lpstrFileList);
859 return sizeUsed;
862 /***********************************************************************
863 * FILEDLG95_HandleCustomDialogMessages
865 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
867 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
869 char lpstrPath[MAX_PATH];
870 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
871 if(!fodInfos) return -1;
873 switch(uMsg)
875 case CDM_GETFILEPATH:
876 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
878 case CDM_GETFOLDERPATH:
879 TRACE("CDM_GETFOLDERPATH:\n");
880 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
881 if ((LPSTR)lParam!=NULL)
882 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
883 return strlen(lpstrPath);
885 case CDM_GETSPEC:
886 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
888 case CDM_SETCONTROLTEXT:
889 TRACE("CDM_SETCONTROLTEXT:\n");
890 if ( 0 != lParam )
891 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
892 return TRUE;
894 case CDM_HIDECONTROL:
895 case CDM_SETDEFEXT:
896 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
897 return -1;
899 return TRUE;
902 /***********************************************************************
903 * FileOpenDlgProc95
905 * File open dialog procedure
907 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
909 #if 0
910 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
911 #endif
913 switch(uMsg)
915 case WM_INITDIALOG:
917 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
919 /* Adds the FileOpenDlgInfos in the property list of the dialog
920 so it will be easily accessible through a GetPropA(...) */
921 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
923 fodInfos->DlgInfos.hwndCustomDlg =
924 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
926 FILEDLG95_InitControls(hwnd);
928 if (fodInfos->DlgInfos.hwndCustomDlg)
929 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
930 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
932 FILEDLG95_FillControls(hwnd, wParam, lParam);
934 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
935 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
936 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
937 return 0;
939 case WM_COMMAND:
940 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
941 case WM_DRAWITEM:
943 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
945 case IDC_LOOKIN:
946 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
947 return TRUE;
950 return FALSE;
952 case WM_GETISHELLBROWSER:
953 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
955 case WM_DESTROY:
956 RemovePropA(hwnd, FileOpenDlgInfosStr);
957 return FALSE;
959 case WM_NOTIFY:
961 LPNMHDR lpnmh = (LPNMHDR)lParam;
962 UINT stringId = -1;
964 /* set up the button tooltips strings */
965 if(TTN_GETDISPINFOA == lpnmh->code )
967 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
968 switch(lpnmh->idFrom )
970 /* Up folder button */
971 case FCIDM_TB_UPFOLDER:
972 stringId = IDS_UPFOLDER;
973 break;
974 /* New folder button */
975 case FCIDM_TB_NEWFOLDER:
976 stringId = IDS_NEWFOLDER;
977 break;
978 /* List option button */
979 case FCIDM_TB_SMALLICON:
980 stringId = IDS_LISTVIEW;
981 break;
982 /* Details option button */
983 case FCIDM_TB_REPORTVIEW:
984 stringId = IDS_REPORTVIEW;
985 break;
986 /* Desktop button */
987 case FCIDM_TB_DESKTOP:
988 stringId = IDS_TODESKTOP;
989 break;
990 default:
991 stringId = 0;
993 lpdi->hinst = COMDLG32_hInstance;
994 lpdi->lpszText = (LPSTR) stringId;
996 return FALSE;
998 default :
999 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1000 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1001 return FALSE;
1005 /***********************************************************************
1006 * FILEDLG95_InitControls
1008 * WM_INITDIALOG message handler (before hook notification)
1010 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1012 int win2000plus = 0;
1013 int win98plus = 0;
1014 int handledPath = FALSE;
1015 OSVERSIONINFOA osVi;
1016 static const WCHAR szwSlash[] = { '\\', 0 };
1017 static const WCHAR szwStar[] = { '*',0 };
1019 TBBUTTON tbb[] =
1021 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1022 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1023 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1024 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1025 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1026 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1027 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1028 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1029 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1031 TBADDBITMAP tba[2];
1032 RECT rectTB;
1033 RECT rectlook;
1034 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1036 tba[0].hInst = HINST_COMMCTRL;
1037 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1038 tba[1].hInst = COMDLG32_hInstance;
1039 tba[1].nID = 800;
1041 TRACE("%p\n", fodInfos);
1043 /* Get windows version emulating */
1044 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1045 GetVersionExA(&osVi);
1046 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1047 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1048 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1049 win2000plus = (osVi.dwMajorVersion > 4);
1050 if (win2000plus) win98plus = TRUE;
1052 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1054 /* Get the hwnd of the controls */
1055 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1056 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1057 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1059 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1060 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1062 /* construct the toolbar */
1063 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1064 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1066 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1067 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1068 rectTB.left = rectlook.right;
1069 rectTB.top = rectlook.top-1;
1071 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1072 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1073 rectTB.left, rectTB.top,
1074 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1075 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1077 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1079 /* FIXME: use TB_LOADIMAGES when implemented */
1080 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1081 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1082 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1084 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1085 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1087 /* Set the window text with the text specified in the OPENFILENAME structure */
1088 if(fodInfos->title)
1090 SetWindowTextW(hwnd,fodInfos->title);
1092 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1094 SetWindowTextA(hwnd,"Save");
1097 /* Initialise the file name edit control */
1098 handledPath = FALSE;
1099 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1101 if(fodInfos->filename)
1103 /* 1. If win2000 or higher and filename contains a path, use it
1104 in preference over the lpstrInitialDir */
1105 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1106 WCHAR tmpBuf[MAX_PATH];
1107 WCHAR *nameBit;
1108 DWORD result;
1110 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1111 if (result) {
1113 /* nameBit is always shorter than the original filename */
1114 strcpyW(fodInfos->filename,nameBit);
1116 *nameBit = 0x00;
1117 if (fodInfos->initdir == NULL)
1118 MemFree(fodInfos->initdir);
1119 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1120 strcpyW(fodInfos->initdir, tmpBuf);
1121 handledPath = TRUE;
1122 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1123 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1125 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1127 } else {
1128 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1132 /* 2. (All platforms) If initdir is not null, then use it */
1133 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1134 (*fodInfos->initdir!=0x00))
1136 /* Work out the proper path as supplied one might be relative */
1137 /* (Here because supplying '.' as dir browses to My Computer) */
1138 if (handledPath==FALSE) {
1139 WCHAR tmpBuf[MAX_PATH];
1140 WCHAR tmpBuf2[MAX_PATH];
1141 WCHAR *nameBit;
1142 DWORD result;
1144 strcpyW(tmpBuf, fodInfos->initdir);
1145 if( PathFileExistsW(tmpBuf) ) {
1146 /* initdir does not have to be a directory. If a file is
1147 * specified, the dir part is taken */
1148 if( PathIsDirectoryW(tmpBuf)) {
1149 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1150 strcatW(tmpBuf, szwSlash);
1152 strcatW(tmpBuf, szwStar);
1154 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1155 if (result) {
1156 *nameBit = 0x00;
1157 if (fodInfos->initdir)
1158 MemFree(fodInfos->initdir);
1159 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1160 strcpyW(fodInfos->initdir, tmpBuf2);
1161 handledPath = TRUE;
1162 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1165 else if (fodInfos->initdir)
1167 MemFree(fodInfos->initdir);
1168 fodInfos->initdir = NULL;
1169 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1174 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1175 (*fodInfos->initdir==0x00)))
1177 /* 3. All except w2k+: if filename contains a path use it */
1178 if (!win2000plus && fodInfos->filename &&
1179 *fodInfos->filename &&
1180 strpbrkW(fodInfos->filename, szwSlash)) {
1181 WCHAR tmpBuf[MAX_PATH];
1182 WCHAR *nameBit;
1183 DWORD result;
1185 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1186 tmpBuf, &nameBit);
1187 if (result) {
1188 int len;
1190 /* nameBit is always shorter than the original filename */
1191 strcpyW(fodInfos->filename, nameBit);
1192 *nameBit = 0x00;
1194 len = strlenW(tmpBuf);
1195 if(fodInfos->initdir)
1196 MemFree(fodInfos->initdir);
1197 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1198 strcpyW(fodInfos->initdir, tmpBuf);
1200 handledPath = TRUE;
1201 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1202 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1204 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1207 /* 4. win98+ and win2000+ if any files of specified filter types in
1208 current directory, use it */
1209 if ( win98plus && handledPath == FALSE &&
1210 fodInfos->filter && *fodInfos->filter) {
1212 BOOL searchMore = TRUE;
1213 LPCWSTR lpstrPos = fodInfos->filter;
1214 WIN32_FIND_DATAW FindFileData;
1215 HANDLE hFind;
1217 while (searchMore)
1219 /* filter is a list... title\0ext\0......\0\0 */
1221 /* Skip the title */
1222 if(! *lpstrPos) break; /* end */
1223 lpstrPos += strlenW(lpstrPos) + 1;
1225 /* See if any files exist in the current dir with this extension */
1226 if(! *lpstrPos) break; /* end */
1228 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1230 if (hFind == INVALID_HANDLE_VALUE) {
1231 /* None found - continue search */
1232 lpstrPos += strlenW(lpstrPos) + 1;
1234 } else {
1235 searchMore = FALSE;
1237 if(fodInfos->initdir)
1238 MemFree(fodInfos->initdir);
1239 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1240 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1242 handledPath = TRUE;
1243 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1244 debugstr_w(lpstrPos));
1245 break;
1250 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1252 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1253 if (handledPath == FALSE && (win2000plus || win98plus)) {
1254 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1256 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1258 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1260 /* last fallback */
1261 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1262 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1263 } else {
1264 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1266 } else {
1267 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1269 handledPath = TRUE;
1270 } else if (handledPath==FALSE) {
1271 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1272 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1273 handledPath = TRUE;
1274 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1277 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1278 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1280 /* Must the open as read only check box be checked ?*/
1281 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1283 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1286 /* Must the open as read only check box be hidden? */
1287 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1289 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1290 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1293 /* Must the help button be hidden? */
1294 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1296 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1297 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1300 /* Resize the height, if open as read only checkbox ad help button
1301 are hidden and we are not using a custom template nor a customDialog
1303 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1304 (!(fodInfos->ofnInfos->Flags &
1305 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1306 (!fodInfos->DlgInfos.hwndCustomDlg ))
1308 RECT rectDlg, rectHelp, rectCancel;
1309 GetWindowRect(hwnd, &rectDlg);
1310 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1311 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1312 /* subtract the height of the help button plus the space between
1313 the help button and the cancel button to the height of the dialog */
1314 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1315 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1316 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1318 /* change Open to Save FIXME: use resources */
1319 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1321 SetDlgItemTextA(hwnd,IDOK,"&Save");
1322 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1324 return 0;
1327 /***********************************************************************
1328 * FILEDLG95_FillControls
1330 * WM_INITDIALOG message handler (after hook notification)
1332 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1334 LPITEMIDLIST pidlItemId = NULL;
1336 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1338 TRACE("dir=%s file=%s\n",
1339 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1341 /* Get the initial directory pidl */
1343 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1345 WCHAR path[MAX_PATH];
1347 GetCurrentDirectoryW(MAX_PATH,path);
1348 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1351 /* Initialise shell objects */
1352 FILEDLG95_SHELL_Init(hwnd);
1354 /* Initialize the Look In combo box */
1355 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1357 /* Initialize the filter combo box */
1358 FILEDLG95_FILETYPE_Init(hwnd);
1360 /* Browse to the initial directory */
1361 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1363 /* Free pidlItem memory */
1364 COMDLG32_SHFree(pidlItemId);
1366 return TRUE;
1368 /***********************************************************************
1369 * FILEDLG95_Clean
1371 * Regroups all the cleaning functions of the filedlg
1373 void FILEDLG95_Clean(HWND hwnd)
1375 FILEDLG95_FILETYPE_Clean(hwnd);
1376 FILEDLG95_LOOKIN_Clean(hwnd);
1377 FILEDLG95_SHELL_Clean(hwnd);
1379 /***********************************************************************
1380 * FILEDLG95_OnWMCommand
1382 * WM_COMMAND message handler
1384 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1386 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1387 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1388 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1390 switch(wID)
1392 /* OK button */
1393 case IDOK:
1394 FILEDLG95_OnOpen(hwnd);
1395 break;
1396 /* Cancel button */
1397 case IDCANCEL:
1398 FILEDLG95_Clean(hwnd);
1399 EndDialog(hwnd, FALSE);
1400 break;
1401 /* Filetype combo box */
1402 case IDC_FILETYPE:
1403 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1404 break;
1405 /* LookIn combo box */
1406 case IDC_LOOKIN:
1407 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1408 break;
1410 /* --- toolbar --- */
1411 /* Up folder button */
1412 case FCIDM_TB_UPFOLDER:
1413 FILEDLG95_SHELL_UpFolder(hwnd);
1414 break;
1415 /* New folder button */
1416 case FCIDM_TB_NEWFOLDER:
1417 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1418 break;
1419 /* List option button */
1420 case FCIDM_TB_SMALLICON:
1421 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1422 break;
1423 /* Details option button */
1424 case FCIDM_TB_REPORTVIEW:
1425 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1426 break;
1427 /* Details option button */
1428 case FCIDM_TB_DESKTOP:
1429 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1430 break;
1432 case IDC_FILENAME:
1433 break;
1436 /* Do not use the listview selection anymore */
1437 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1438 return 0;
1441 /***********************************************************************
1442 * FILEDLG95_OnWMGetIShellBrowser
1444 * WM_GETISHELLBROWSER message handler
1446 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1449 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1451 TRACE("\n");
1453 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1455 return TRUE;
1459 /***********************************************************************
1460 * FILEDLG95_SendFileOK
1462 * Sends the CDN_FILEOK notification if required
1464 * RETURNS
1465 * TRUE if the dialog should close
1466 * FALSE if the dialog should not be closed
1468 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1470 /* ask the hook if we can close */
1471 if(IsHooked(fodInfos))
1473 TRACE("---\n");
1474 /* First send CDN_FILEOK as MSDN doc says */
1475 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1476 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1478 TRACE("canceled\n");
1479 return FALSE;
1482 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1483 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1484 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1485 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1487 TRACE("canceled\n");
1488 return FALSE;
1491 return TRUE;
1494 /***********************************************************************
1495 * FILEDLG95_OnOpenMultipleFiles
1497 * Handles the opening of multiple files.
1499 * FIXME
1500 * check destination buffer size
1502 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1504 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1505 UINT nCount, nSizePath;
1506 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1508 TRACE("\n");
1510 if(fodInfos->unicode)
1512 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1513 ofn->lpstrFile[0] = '\0';
1515 else
1517 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1518 ofn->lpstrFile[0] = '\0';
1521 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1523 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1524 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1525 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1527 LPWSTR lpstrTemp = lpstrFileList;
1529 for ( nCount = 0; nCount < nFileCount; nCount++ )
1531 LPITEMIDLIST pidl;
1533 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1534 if (!pidl)
1536 WCHAR lpstrNotFound[100];
1537 WCHAR lpstrMsg[100];
1538 WCHAR tmp[400];
1539 static const WCHAR nl[] = {'\n',0};
1541 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1542 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1544 strcpyW(tmp, lpstrTemp);
1545 strcatW(tmp, nl);
1546 strcatW(tmp, lpstrNotFound);
1547 strcatW(tmp, nl);
1548 strcatW(tmp, lpstrMsg);
1550 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1551 return FALSE;
1554 /* move to the next file in the list of files */
1555 lpstrTemp += strlenW(lpstrTemp) + 1;
1556 COMDLG32_SHFree(pidl);
1560 nSizePath = strlenW(lpstrPathSpec) + 1;
1561 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1563 /* For "oldstyle" dialog the components have to
1564 be separated by blanks (not '\0'!) and short
1565 filenames have to be used! */
1566 FIXME("Components have to be separated by blanks\n");
1568 if(fodInfos->unicode)
1570 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1571 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1572 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1574 else
1576 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1578 if (ofn->lpstrFile != NULL)
1580 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1581 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1582 if (ofn->nMaxFile > nSizePath)
1584 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1585 ofn->lpstrFile + nSizePath,
1586 ofn->nMaxFile - nSizePath, NULL, NULL);
1591 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1592 fodInfos->ofnInfos->nFileExtension = 0;
1594 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1595 return FALSE;
1597 /* clean and exit */
1598 FILEDLG95_Clean(hwnd);
1599 return EndDialog(hwnd,TRUE);
1602 /***********************************************************************
1603 * FILEDLG95_OnOpen
1605 * Ok button WM_COMMAND message handler
1607 * If the function succeeds, the return value is nonzero.
1609 #define ONOPEN_BROWSE 1
1610 #define ONOPEN_OPEN 2
1611 #define ONOPEN_SEARCH 3
1612 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1614 char strMsgTitle[MAX_PATH];
1615 char strMsgText [MAX_PATH];
1616 if (idCaption)
1617 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1618 else
1619 strMsgTitle[0] = '\0';
1620 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1621 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1624 BOOL FILEDLG95_OnOpen(HWND hwnd)
1626 LPWSTR lpstrFileList;
1627 UINT nFileCount = 0;
1628 UINT sizeUsed = 0;
1629 BOOL ret = TRUE;
1630 WCHAR lpstrPathAndFile[MAX_PATH];
1631 WCHAR lpstrTemp[MAX_PATH];
1632 LPSHELLFOLDER lpsf = NULL;
1633 int nOpenAction;
1634 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1636 TRACE("hwnd=%p\n", hwnd);
1638 /* get the files from the edit control */
1639 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1641 /* try if the user selected a folder in the shellview */
1642 if(nFileCount == 0)
1644 BrowseSelectedFolder(hwnd);
1645 return FALSE;
1648 if(nFileCount > 1)
1650 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1651 goto ret;
1654 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1657 Step 1: Build a complete path name from the current folder and
1658 the filename or path in the edit box.
1659 Special cases:
1660 - the path in the edit box is a root path
1661 (with or without drive letter)
1662 - the edit box contains ".." (or a path with ".." in it)
1665 /* Get the current directory name */
1666 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1668 /* we are in a special folder, default to desktop */
1669 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1671 /* last fallback */
1672 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1675 PathAddBackslashW(lpstrPathAndFile);
1677 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1679 /* if the user specifyed a fully qualified path use it */
1680 if(PathIsRelativeW(lpstrFileList))
1682 strcatW(lpstrPathAndFile, lpstrFileList);
1684 else
1686 /* does the path have a drive letter? */
1687 if (PathGetDriveNumberW(lpstrFileList) == -1)
1688 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1689 else
1690 strcpyW(lpstrPathAndFile, lpstrFileList);
1693 /* resolve "." and ".." */
1694 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1695 strcpyW(lpstrPathAndFile, lpstrTemp);
1696 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1698 MemFree(lpstrFileList);
1701 Step 2: here we have a cleaned up path
1703 We have to parse the path step by step to see if we have to browse
1704 to a folder if the path points to a directory or the last
1705 valid element is a directory.
1707 valid variables:
1708 lpstrPathAndFile: cleaned up path
1711 nOpenAction = ONOPEN_BROWSE;
1713 /* don't apply any checks with OFN_NOVALIDATE */
1715 LPWSTR lpszTemp, lpszTemp1;
1716 LPITEMIDLIST pidl = NULL;
1717 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1719 /* check for invalid chars */
1720 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1722 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1723 ret = FALSE;
1724 goto ret;
1727 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1729 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1730 while (lpszTemp1)
1732 LPSHELLFOLDER lpsfChild;
1733 WCHAR lpwstrTemp[MAX_PATH];
1734 DWORD dwEaten, dwAttributes;
1735 LPWSTR p;
1737 strcpyW(lpwstrTemp, lpszTemp);
1738 p = PathFindNextComponentW(lpwstrTemp);
1740 if (!p) break; /* end of path */
1742 *p = 0;
1743 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1745 if(*lpszTemp==0)
1747 static const WCHAR wszWild[] = { '*', '?', 0 };
1748 /* if the last element is a wildcard do a search */
1749 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1751 nOpenAction = ONOPEN_SEARCH;
1752 break;
1755 lpszTemp1 = lpszTemp;
1757 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1759 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1761 dwAttributes = SFGAO_FOLDER;
1762 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1764 /* the path component is valid, we have a pidl of the next path component */
1765 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1766 if(dwAttributes & SFGAO_FOLDER)
1768 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1770 ERR("bind to failed\n"); /* should not fail */
1771 break;
1773 IShellFolder_Release(lpsf);
1774 lpsf = lpsfChild;
1775 lpsfChild = NULL;
1777 else
1779 TRACE("value\n");
1781 /* end dialog, return value */
1782 nOpenAction = ONOPEN_OPEN;
1783 break;
1785 COMDLG32_SHFree(pidl);
1786 pidl = NULL;
1788 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1790 if(*lpszTemp) /* points to trailing null for last path element */
1792 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1794 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1795 break;
1798 else
1800 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1801 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1803 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1804 break;
1807 /* change to the current folder */
1808 nOpenAction = ONOPEN_OPEN;
1809 break;
1811 else
1813 nOpenAction = ONOPEN_OPEN;
1814 break;
1817 if(pidl) COMDLG32_SHFree(pidl);
1821 Step 3: here we have a cleaned up and validated path
1823 valid variables:
1824 lpsf: ShellFolder bound to the rightmost valid path component
1825 lpstrPathAndFile: cleaned up path
1826 nOpenAction: action to do
1828 TRACE("end validate sf=%p\n", lpsf);
1830 switch(nOpenAction)
1832 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1833 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1835 int iPos;
1836 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1837 DWORD len;
1839 /* replace the current filter */
1840 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1841 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1842 len = strlenW(lpszTemp)+1;
1843 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1844 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1846 /* set the filter cb to the extension when possible */
1847 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1848 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1850 /* fall through */
1851 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1852 TRACE("ONOPEN_BROWSE\n");
1854 IPersistFolder2 * ppf2;
1855 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1857 LPITEMIDLIST pidlCurrent;
1858 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1859 IPersistFolder2_Release(ppf2);
1860 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1862 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1864 else if( nOpenAction == ONOPEN_SEARCH )
1866 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1868 COMDLG32_SHFree(pidlCurrent);
1871 ret = FALSE;
1872 break;
1873 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1874 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1876 /* update READONLY check box flag */
1877 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1878 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1879 else
1880 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1882 /* add default extension */
1883 if (fodInfos->defext)
1885 WCHAR *ext = PathFindExtensionW(lpstrPathAndFile);
1887 if (! *ext)
1889 /* only add "." in case a default extension does exist */
1890 if (*fodInfos->defext != '\0')
1892 static const WCHAR szwDot[] = {'.',0};
1893 int PathLength = strlenW(lpstrPathAndFile);
1895 strcatW(lpstrPathAndFile, szwDot);
1896 strcatW(lpstrPathAndFile, fodInfos->defext);
1898 /* In Open dialog: if file does not exist try without extension */
1899 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1900 && !PathFileExistsW(lpstrPathAndFile))
1901 lpstrPathAndFile[PathLength] = '\0';
1905 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1906 if (*ext)
1907 ext++;
1908 if (!lstrcmpiW(fodInfos->defext, ext))
1909 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1910 else
1911 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1914 /* In Save dialog: check if the file already exists */
1915 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1916 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1917 && PathFileExistsW(lpstrPathAndFile))
1919 WCHAR lpstrOverwrite[100];
1920 int answer;
1922 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1923 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1924 MB_YESNO | MB_ICONEXCLAMATION);
1925 if (answer == IDNO)
1927 ret = FALSE;
1928 goto ret;
1932 /* Check that the size of the file does not exceed buffer size.
1933 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1934 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1935 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1937 LPWSTR lpszTemp;
1939 /* fill destination buffer */
1940 if (fodInfos->ofnInfos->lpstrFile)
1942 if(fodInfos->unicode)
1944 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1946 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1947 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1948 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1950 else
1952 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1954 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1955 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1956 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1957 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1961 /* set filename offset */
1962 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1963 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1965 /* set extension offset */
1966 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1967 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1969 /* set the lpstrFileTitle */
1970 if(fodInfos->ofnInfos->lpstrFileTitle)
1972 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1973 if(fodInfos->unicode)
1975 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1976 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1978 else
1980 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1981 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1982 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1986 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1987 goto ret;
1989 TRACE("close\n");
1990 FILEDLG95_Clean(hwnd);
1991 ret = EndDialog(hwnd, TRUE);
1993 else
1995 WORD size;
1997 size = strlenW(lpstrPathAndFile) + 1;
1998 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
1999 size += 1;
2000 /* return needed size in first two bytes of lpstrFile */
2001 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2002 FILEDLG95_Clean(hwnd);
2003 ret = EndDialog(hwnd, FALSE);
2004 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2006 goto ret;
2008 break;
2011 ret:
2012 if(lpsf) IShellFolder_Release(lpsf);
2013 return ret;
2016 /***********************************************************************
2017 * FILEDLG95_SHELL_Init
2019 * Initialisation of the shell objects
2021 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2023 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2025 TRACE("\n");
2028 * Initialisation of the FileOpenDialogInfos structure
2031 /* Shell */
2033 /*ShellInfos */
2034 fodInfos->ShellInfos.hwndOwner = hwnd;
2036 /* Disable multi-select if flag not set */
2037 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2039 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2041 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2042 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2044 /* Construct the IShellBrowser interface */
2045 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2047 return NOERROR;
2050 /***********************************************************************
2051 * FILEDLG95_SHELL_ExecuteCommand
2053 * Change the folder option and refresh the view
2054 * If the function succeeds, the return value is nonzero.
2056 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2058 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2060 IContextMenu * pcm;
2061 TRACE("(%p,%p)\n", hwnd, lpVerb);
2063 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2064 SVGIO_BACKGROUND,
2065 &IID_IContextMenu,
2066 (LPVOID*)&pcm)))
2068 CMINVOKECOMMANDINFO ci;
2069 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2070 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2071 ci.lpVerb = lpVerb;
2072 ci.hwnd = hwnd;
2074 IContextMenu_InvokeCommand(pcm, &ci);
2075 IContextMenu_Release(pcm);
2078 return FALSE;
2081 /***********************************************************************
2082 * FILEDLG95_SHELL_UpFolder
2084 * Browse to the specified object
2085 * If the function succeeds, the return value is nonzero.
2087 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2089 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2091 TRACE("\n");
2093 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2094 NULL,
2095 SBSP_PARENT)))
2097 return TRUE;
2099 return FALSE;
2102 /***********************************************************************
2103 * FILEDLG95_SHELL_BrowseToDesktop
2105 * Browse to the Desktop
2106 * If the function succeeds, the return value is nonzero.
2108 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2110 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2111 LPITEMIDLIST pidl;
2112 HRESULT hres;
2114 TRACE("\n");
2116 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2117 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2118 COMDLG32_SHFree(pidl);
2119 return SUCCEEDED(hres);
2121 /***********************************************************************
2122 * FILEDLG95_SHELL_Clean
2124 * Cleans the memory used by shell objects
2126 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2128 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2130 TRACE("\n");
2132 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2134 /* clean Shell interfaces */
2135 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2136 IShellView_Release(fodInfos->Shell.FOIShellView);
2137 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2138 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2139 if (fodInfos->Shell.FOIDataObject)
2140 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2143 /***********************************************************************
2144 * FILEDLG95_FILETYPE_Init
2146 * Initialisation of the file type combo box
2148 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2150 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2152 TRACE("\n");
2154 if(fodInfos->filter)
2156 int nFilters = 0; /* number of filters */
2157 LPWSTR lpstrFilter;
2158 LPCWSTR lpstrPos = fodInfos->filter;
2160 for(;;)
2162 /* filter is a list... title\0ext\0......\0\0
2163 * Set the combo item text to the title and the item data
2164 * to the ext
2166 LPCWSTR lpstrDisplay;
2167 LPWSTR lpstrExt;
2169 /* Get the title */
2170 if(! *lpstrPos) break; /* end */
2171 lpstrDisplay = lpstrPos;
2172 lpstrPos += strlenW(lpstrPos) + 1;
2174 /* Copy the extensions */
2175 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2176 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2177 strcpyW(lpstrExt,lpstrPos);
2178 lpstrPos += strlenW(lpstrPos) + 1;
2180 /* Add the item at the end of the combo */
2181 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2182 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2183 nFilters++;
2186 * Set the current filter to the one specified
2187 * in the initialisation structure
2188 * FIXME: lpstrCustomFilter not handled at all
2191 /* set default filter index */
2192 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2193 fodInfos->ofnInfos->nFilterIndex = 1;
2195 /* First, check to make sure our index isn't out of bounds. */
2196 if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
2197 fodInfos->ofnInfos->nFilterIndex = nFilters;
2199 /* Set the current index selection. */
2200 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
2202 /* Get the corresponding text string from the combo box. */
2203 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2204 fodInfos->ofnInfos->nFilterIndex-1);
2206 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2207 lpstrFilter = NULL;
2209 if(lpstrFilter)
2211 DWORD len;
2212 CharLowerW(lpstrFilter); /* lowercase */
2213 len = strlenW(lpstrFilter)+1;
2214 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2215 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2218 return NOERROR;
2221 /***********************************************************************
2222 * FILEDLG95_FILETYPE_OnCommand
2224 * WM_COMMAND of the file type combo box
2225 * If the function succeeds, the return value is nonzero.
2227 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2229 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2231 switch(wNotifyCode)
2233 case CBN_SELENDOK:
2235 LPWSTR lpstrFilter;
2237 /* Get the current item of the filetype combo box */
2238 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2240 /* set the current filter index - indexed from 1 */
2241 fodInfos->ofnInfos->nFilterIndex = iItem + 1;
2243 /* Set the current filter with the current selection */
2244 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2245 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2247 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2248 iItem);
2249 if((int)lpstrFilter != CB_ERR)
2251 DWORD len;
2252 CharLowerW(lpstrFilter); /* lowercase */
2253 len = strlenW(lpstrFilter)+1;
2254 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2255 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2256 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2259 /* Refresh the actual view to display the included items*/
2260 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2263 return FALSE;
2265 /***********************************************************************
2266 * FILEDLG95_FILETYPE_SearchExt
2268 * searches for a extension in the filetype box
2270 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2272 int i, iCount = CBGetCount(hwnd);
2274 TRACE("%s\n", debugstr_w(lpstrExt));
2276 if(iCount != CB_ERR)
2278 for(i=0;i<iCount;i++)
2280 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2281 return i;
2284 return -1;
2287 /***********************************************************************
2288 * FILEDLG95_FILETYPE_Clean
2290 * Clean the memory used by the filetype combo box
2292 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2294 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2295 int iPos;
2296 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2298 TRACE("\n");
2300 /* Delete each string of the combo and their associated data */
2301 if(iCount != CB_ERR)
2303 for(iPos = iCount-1;iPos>=0;iPos--)
2305 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2306 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2309 /* Current filter */
2310 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2311 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2315 /***********************************************************************
2316 * FILEDLG95_LOOKIN_Init
2318 * Initialisation of the look in combo box
2320 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2322 IShellFolder *psfRoot, *psfDrives;
2323 IEnumIDList *lpeRoot, *lpeDrives;
2324 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2326 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2328 TRACE("\n");
2330 liInfos->iMaxIndentation = 0;
2332 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2334 /* set item height for both text field and listbox */
2335 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2336 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2338 /* Turn on the extended UI for the combo box like Windows does */
2339 CBSetExtendedUI(hwndCombo, TRUE);
2341 /* Initialise data of Desktop folder */
2342 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2343 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2344 COMDLG32_SHFree(pidlTmp);
2346 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2348 SHGetDesktopFolder(&psfRoot);
2350 if (psfRoot)
2352 /* enumerate the contents of the desktop */
2353 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2355 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2357 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2359 /* special handling for CSIDL_DRIVES */
2360 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2362 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2364 /* enumerate the drives */
2365 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2367 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2369 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2370 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2371 COMDLG32_SHFree(pidlAbsTmp);
2372 COMDLG32_SHFree(pidlTmp1);
2374 IEnumIDList_Release(lpeDrives);
2376 IShellFolder_Release(psfDrives);
2379 COMDLG32_SHFree(pidlTmp);
2381 IEnumIDList_Release(lpeRoot);
2383 IShellFolder_Release(psfRoot);
2386 COMDLG32_SHFree(pidlDrives);
2387 return NOERROR;
2390 /***********************************************************************
2391 * FILEDLG95_LOOKIN_DrawItem
2393 * WM_DRAWITEM message handler
2395 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2397 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2398 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2399 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2400 RECT rectText;
2401 RECT rectIcon;
2402 SHFILEINFOA sfi;
2403 HIMAGELIST ilItemImage;
2404 int iIndentation;
2405 TEXTMETRICA tm;
2406 LPSFOLDER tmpFolder;
2409 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2411 TRACE("\n");
2413 if(pDIStruct->itemID == -1)
2414 return 0;
2416 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2417 pDIStruct->itemID)))
2418 return 0;
2421 if(pDIStruct->itemID == liInfos->uSelectedItem)
2423 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2425 &sfi,
2426 sizeof (SHFILEINFOA),
2427 SHGFI_PIDL | SHGFI_SMALLICON |
2428 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2429 SHGFI_DISPLAYNAME );
2431 else
2433 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2435 &sfi,
2436 sizeof (SHFILEINFOA),
2437 SHGFI_PIDL | SHGFI_SMALLICON |
2438 SHGFI_SYSICONINDEX |
2439 SHGFI_DISPLAYNAME);
2442 /* Is this item selected ? */
2443 if(pDIStruct->itemState & ODS_SELECTED)
2445 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2446 SetBkColor(pDIStruct->hDC,crHighLight);
2447 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2449 else
2451 SetTextColor(pDIStruct->hDC,crText);
2452 SetBkColor(pDIStruct->hDC,crWin);
2453 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2456 /* Do not indent item if drawing in the edit of the combo */
2457 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2459 iIndentation = 0;
2460 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2462 &sfi,
2463 sizeof (SHFILEINFOA),
2464 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2465 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2468 else
2470 iIndentation = tmpFolder->m_iIndent;
2472 /* Draw text and icon */
2474 /* Initialise the icon display area */
2475 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2476 rectIcon.top = pDIStruct->rcItem.top;
2477 rectIcon.right = rectIcon.left + ICONWIDTH;
2478 rectIcon.bottom = pDIStruct->rcItem.bottom;
2480 /* Initialise the text display area */
2481 GetTextMetricsA(pDIStruct->hDC, &tm);
2482 rectText.left = rectIcon.right;
2483 rectText.top =
2484 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2485 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2486 rectText.bottom =
2487 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2489 /* Draw the icon from the image list */
2490 ImageList_Draw(ilItemImage,
2491 sfi.iIcon,
2492 pDIStruct->hDC,
2493 rectIcon.left,
2494 rectIcon.top,
2495 ILD_TRANSPARENT );
2497 /* Draw the associated text */
2498 if(sfi.szDisplayName)
2499 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2502 return NOERROR;
2505 /***********************************************************************
2506 * FILEDLG95_LOOKIN_OnCommand
2508 * LookIn combo box WM_COMMAND message handler
2509 * If the function succeeds, the return value is nonzero.
2511 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2513 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2515 TRACE("%p\n", fodInfos);
2517 switch(wNotifyCode)
2519 case CBN_SELENDOK:
2521 LPSFOLDER tmpFolder;
2522 int iItem;
2524 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2526 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2527 iItem)))
2528 return FALSE;
2531 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2532 tmpFolder->pidlItem,
2533 SBSP_ABSOLUTE)))
2535 return TRUE;
2537 break;
2541 return FALSE;
2544 /***********************************************************************
2545 * FILEDLG95_LOOKIN_AddItem
2547 * Adds an absolute pidl item to the lookin combo box
2548 * returns the index of the inserted item
2550 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2552 LPITEMIDLIST pidlNext;
2553 SHFILEINFOA sfi;
2554 SFOLDER *tmpFolder;
2555 LookInInfos *liInfos;
2557 TRACE("%08x\n", iInsertId);
2559 if(!pidl)
2560 return -1;
2562 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2563 return -1;
2565 tmpFolder = MemAlloc(sizeof(SFOLDER));
2566 tmpFolder->m_iIndent = 0;
2568 /* Calculate the indentation of the item in the lookin*/
2569 pidlNext = pidl;
2570 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2572 tmpFolder->m_iIndent++;
2575 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2577 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2578 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2580 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2581 SHGetFileInfoA((LPSTR)pidl,
2583 &sfi,
2584 sizeof(sfi),
2585 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2586 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2588 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2590 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2592 int iItemID;
2594 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2596 /* Add the item at the end of the list */
2597 if(iInsertId < 0)
2599 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2601 /* Insert the item at the iInsertId position*/
2602 else
2604 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2607 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2608 return iItemID;
2611 COMDLG32_SHFree( tmpFolder->pidlItem );
2612 MemFree( tmpFolder );
2613 return -1;
2617 /***********************************************************************
2618 * FILEDLG95_LOOKIN_InsertItemAfterParent
2620 * Insert an item below its parent
2622 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2625 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2626 int iParentPos;
2628 TRACE("\n");
2630 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2632 if(iParentPos < 0)
2634 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2637 /* Free pidlParent memory */
2638 COMDLG32_SHFree((LPVOID)pidlParent);
2640 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2643 /***********************************************************************
2644 * FILEDLG95_LOOKIN_SelectItem
2646 * Adds an absolute pidl item to the lookin combo box
2647 * returns the index of the inserted item
2649 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2651 int iItemPos;
2652 LookInInfos *liInfos;
2654 TRACE("\n");
2656 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2658 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2660 if(iItemPos < 0)
2662 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2663 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2666 else
2668 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2669 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2671 int iRemovedItem;
2673 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2674 break;
2675 if(iRemovedItem < iItemPos)
2676 iItemPos--;
2680 CBSetCurSel(hwnd,iItemPos);
2681 liInfos->uSelectedItem = iItemPos;
2683 return 0;
2687 /***********************************************************************
2688 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2690 * Remove the item with an expansion level over iExpansionLevel
2692 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2694 int iItemPos;
2696 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2698 TRACE("\n");
2700 if(liInfos->iMaxIndentation <= 2)
2701 return -1;
2703 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2705 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2706 COMDLG32_SHFree(tmpFolder->pidlItem);
2707 MemFree(tmpFolder);
2708 CBDeleteString(hwnd,iItemPos);
2709 liInfos->iMaxIndentation--;
2711 return iItemPos;
2714 return -1;
2717 /***********************************************************************
2718 * FILEDLG95_LOOKIN_SearchItem
2720 * Search for pidl in the lookin combo box
2721 * returns the index of the found item
2723 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2725 int i = 0;
2726 int iCount = CBGetCount(hwnd);
2728 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2730 if (iCount != CB_ERR)
2732 for(;i<iCount;i++)
2734 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2736 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2737 return i;
2738 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2739 return i;
2743 return -1;
2746 /***********************************************************************
2747 * FILEDLG95_LOOKIN_Clean
2749 * Clean the memory used by the lookin combo box
2751 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2753 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2754 int iPos;
2755 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2757 TRACE("\n");
2759 /* Delete each string of the combo and their associated data */
2760 if (iCount != CB_ERR)
2762 for(iPos = iCount-1;iPos>=0;iPos--)
2764 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2765 COMDLG32_SHFree(tmpFolder->pidlItem);
2766 MemFree(tmpFolder);
2767 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2771 /* LookInInfos structure */
2772 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2775 /***********************************************************************
2776 * FILEDLG95_FILENAME_FillFromSelection
2778 * fills the edit box from the cached DataObject
2780 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2782 FileOpenDlgInfos *fodInfos;
2783 LPITEMIDLIST pidl;
2784 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2785 char lpstrTemp[MAX_PATH];
2786 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2788 TRACE("\n");
2789 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2791 /* Count how many files we have */
2792 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2794 /* calculate the string length, count files */
2795 if (nFileSelected >= 1)
2797 nLength += 3; /* first and last quotes, trailing \0 */
2798 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2800 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2802 if (pidl)
2804 /* get the total length of the selected file names */
2805 lpstrTemp[0] = '\0';
2806 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2808 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2810 nLength += strlen( lpstrTemp ) + 3;
2811 nFiles++;
2813 COMDLG32_SHFree( pidl );
2818 /* allocate the buffer */
2819 if (nFiles <= 1) nLength = MAX_PATH;
2820 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2821 lpstrAllFile[0] = '\0';
2823 /* Generate the string for the edit control */
2824 if(nFiles >= 1)
2826 lpstrCurrFile = lpstrAllFile;
2827 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2829 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2831 if (pidl)
2833 /* get the file name */
2834 lpstrTemp[0] = '\0';
2835 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2837 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2839 if ( nFiles > 1)
2841 *lpstrCurrFile++ = '\"';
2842 strcpy( lpstrCurrFile, lpstrTemp );
2843 lpstrCurrFile += strlen( lpstrTemp );
2844 strcpy( lpstrCurrFile, "\" " );
2845 lpstrCurrFile += 2;
2847 else
2849 strcpy( lpstrAllFile, lpstrTemp );
2852 COMDLG32_SHFree( (LPVOID) pidl );
2855 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2857 /* Select the file name like Windows does */
2858 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2860 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2864 /* copied from shell32 to avoid linking to it */
2865 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2867 switch (src->uType)
2869 case STRRET_WSTR:
2870 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2871 COMDLG32_SHFree(src->u.pOleStr);
2872 break;
2874 case STRRET_CSTR:
2875 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2876 break;
2878 case STRRET_OFFSET:
2879 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2880 break;
2882 default:
2883 FIXME("unknown type!\n");
2884 if (len)
2886 *(LPSTR)dest = '\0';
2888 return(FALSE);
2890 return S_OK;
2893 /***********************************************************************
2894 * FILEDLG95_FILENAME_GetFileNames
2896 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2898 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2900 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2901 UINT nStrCharCount = 0; /* index in src buffer */
2902 UINT nFileIndex = 0; /* index in dest buffer */
2903 UINT nFileCount = 0; /* number of files */
2904 UINT nStrLen = 0; /* length of string in edit control */
2905 LPWSTR lpstrEdit; /* buffer for string from edit control */
2907 TRACE("\n");
2909 /* get the filenames from the edit control */
2910 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2911 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2912 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2914 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2916 /* we might get single filename without any '"',
2917 * so we need nStrLen + terminating \0 + end-of-list \0 */
2918 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2919 *sizeUsed = 0;
2921 /* build 0-delimited file list from filenames */
2922 while ( nStrCharCount <= nStrLen )
2924 if ( lpstrEdit[nStrCharCount]=='"' )
2926 nStrCharCount++;
2927 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2929 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2930 (*sizeUsed)++;
2931 nStrCharCount++;
2933 (*lpstrFileList)[nFileIndex++] = '\0';
2934 (*sizeUsed)++;
2935 nFileCount++;
2937 nStrCharCount++;
2940 /* single, unquoted string */
2941 if ((nStrLen > 0) && (*sizeUsed == 0) )
2943 strcpyW(*lpstrFileList, lpstrEdit);
2944 nFileIndex = strlenW(lpstrEdit) + 1;
2945 (*sizeUsed) = nFileIndex;
2946 nFileCount = 1;
2949 /* trailing \0 */
2950 (*lpstrFileList)[nFileIndex] = '\0';
2951 (*sizeUsed)++;
2953 MemFree(lpstrEdit);
2954 return nFileCount;
2957 #define SETDefFormatEtc(fe,cf,med) \
2959 (fe).cfFormat = cf;\
2960 (fe).dwAspect = DVASPECT_CONTENT; \
2961 (fe).ptd =NULL;\
2962 (fe).tymed = med;\
2963 (fe).lindex = -1;\
2967 * DATAOBJECT Helper functions
2970 /***********************************************************************
2971 * COMCTL32_ReleaseStgMedium
2973 * like ReleaseStgMedium from ole32
2975 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2977 if(medium.pUnkForRelease)
2979 IUnknown_Release(medium.pUnkForRelease);
2981 else
2983 GlobalUnlock(medium.u.hGlobal);
2984 GlobalFree(medium.u.hGlobal);
2988 /***********************************************************************
2989 * GetPidlFromDataObject
2991 * Return pidl(s) by number from the cached DataObject
2993 * nPidlIndex=0 gets the fully qualified root path
2995 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2998 STGMEDIUM medium;
2999 FORMATETC formatetc;
3000 LPITEMIDLIST pidl = NULL;
3002 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3004 /* Set the FORMATETC structure*/
3005 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3007 /* Get the pidls from IDataObject */
3008 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3010 LPIDA cida = GlobalLock(medium.u.hGlobal);
3011 if(nPidlIndex <= cida->cidl)
3013 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3015 COMCTL32_ReleaseStgMedium(medium);
3017 return pidl;
3020 /***********************************************************************
3021 * GetNumSelected
3023 * Return the number of selected items in the DataObject.
3026 UINT GetNumSelected( IDataObject *doSelected )
3028 UINT retVal = 0;
3029 STGMEDIUM medium;
3030 FORMATETC formatetc;
3032 TRACE("sv=%p\n", doSelected);
3034 if (!doSelected) return 0;
3036 /* Set the FORMATETC structure*/
3037 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3039 /* Get the pidls from IDataObject */
3040 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3042 LPIDA cida = GlobalLock(medium.u.hGlobal);
3043 retVal = cida->cidl;
3044 COMCTL32_ReleaseStgMedium(medium);
3045 return retVal;
3047 return 0;
3051 * TOOLS
3054 /***********************************************************************
3055 * GetName
3057 * Get the pidl's display name (relative to folder) and
3058 * put it in lpstrFileName.
3060 * Return NOERROR on success,
3061 * E_FAIL otherwise
3064 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3066 STRRET str;
3067 HRESULT hRes;
3069 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3071 if(!lpsf)
3073 HRESULT hRes;
3074 SHGetDesktopFolder(&lpsf);
3075 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3076 IShellFolder_Release(lpsf);
3077 return hRes;
3080 /* Get the display name of the pidl relative to the folder */
3081 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3083 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3085 return E_FAIL;
3088 /***********************************************************************
3089 * GetShellFolderFromPidl
3091 * pidlRel is the item pidl relative
3092 * Return the IShellFolder of the absolute pidl
3094 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3096 IShellFolder *psf = NULL,*psfParent;
3098 TRACE("%p\n", pidlAbs);
3100 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3102 psf = psfParent;
3103 if(pidlAbs && pidlAbs->mkid.cb)
3105 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3107 IShellFolder_Release(psfParent);
3108 return psf;
3111 /* return the desktop */
3112 return psfParent;
3114 return NULL;
3117 /***********************************************************************
3118 * GetParentPidl
3120 * Return the LPITEMIDLIST to the parent of the pidl in the list
3122 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3124 LPITEMIDLIST pidlParent;
3126 TRACE("%p\n", pidl);
3128 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3129 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3131 return pidlParent;
3134 /***********************************************************************
3135 * GetPidlFromName
3137 * returns the pidl of the file name relative to folder
3138 * NULL if an error occurred
3140 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3142 LPITEMIDLIST pidl = NULL;
3143 ULONG ulEaten;
3145 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3147 if(!lpcstrFileName) return NULL;
3148 if(!*lpcstrFileName) return NULL;
3150 if(!lpsf)
3152 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3153 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3154 IShellFolder_Release(lpsf);
3157 else
3159 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3161 return pidl;
3166 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3168 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3169 HRESULT ret;
3171 TRACE("%p, %p\n", psf, pidl);
3173 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3175 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3176 /* see documentation shell 4.1*/
3177 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3180 /***********************************************************************
3181 * BrowseSelectedFolder
3183 static BOOL BrowseSelectedFolder(HWND hwnd)
3185 BOOL bBrowseSelFolder = FALSE;
3186 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3188 TRACE("\n");
3190 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3192 LPITEMIDLIST pidlSelection;
3194 /* get the file selected */
3195 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3196 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3198 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3199 pidlSelection, SBSP_RELATIVE ) ) )
3201 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3202 ' ','n','o','t',' ','e','x','i','s','t',0};
3203 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3206 bBrowseSelFolder = TRUE;
3208 COMDLG32_SHFree( pidlSelection );
3211 return bBrowseSelFolder;
3215 * Memory allocation methods */
3216 static void *MemAlloc(UINT size)
3218 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3221 static void MemFree(void *mem)
3223 if(mem)
3225 HeapFree(GetProcessHeap(),0,mem);
3229 /* ------------------ APIs ---------------------- */
3231 /***********************************************************************
3232 * GetOpenFileNameA (COMDLG32.@)
3234 * Creates a dialog box for the user to select a file to open.
3236 * RETURNS
3237 * TRUE on success: user enters a valid file
3238 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3241 BOOL WINAPI GetOpenFileNameA(
3242 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3244 BOOL win16look = FALSE;
3246 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3247 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3249 if (win16look)
3250 return GetFileName31A(ofn, OPEN_DIALOG);
3251 else
3252 return GetFileDialog95A(ofn, OPEN_DIALOG);
3255 /***********************************************************************
3256 * GetOpenFileNameW (COMDLG32.@)
3258 * Creates a dialog box for the user to select a file to open.
3260 * RETURNS
3261 * TRUE on success: user enters a valid file
3262 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3265 BOOL WINAPI GetOpenFileNameW(
3266 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3268 BOOL win16look = FALSE;
3270 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3271 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3273 if (win16look)
3274 return GetFileName31W(ofn, OPEN_DIALOG);
3275 else
3276 return GetFileDialog95W(ofn, OPEN_DIALOG);
3280 /***********************************************************************
3281 * GetSaveFileNameA (COMDLG32.@)
3283 * Creates a dialog box for the user to select a file to save.
3285 * RETURNS
3286 * TRUE on success: user enters a valid file
3287 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3290 BOOL WINAPI GetSaveFileNameA(
3291 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3293 BOOL win16look = FALSE;
3295 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3296 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3298 if (win16look)
3299 return GetFileName31A(ofn, SAVE_DIALOG);
3300 else
3301 return GetFileDialog95A(ofn, SAVE_DIALOG);
3304 /***********************************************************************
3305 * GetSaveFileNameW (COMDLG32.@)
3307 * Creates a dialog box for the user to select a file to save.
3309 * RETURNS
3310 * TRUE on success: user enters a valid file
3311 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3314 BOOL WINAPI GetSaveFileNameW(
3315 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3317 BOOL win16look = FALSE;
3319 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3320 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3322 if (win16look)
3323 return GetFileName31W(ofn, SAVE_DIALOG);
3324 else
3325 return GetFileDialog95W(ofn, SAVE_DIALOG);