Handle the cases when initdir is either invalid, or specifies a file.
[wine.git] / dlls / commdlg / filedlg.c
blob7cfd524ac4738cdd5aff8510d101076ab932c410
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: if the size of lpstrFile (nMaxFile) is too small the first
38 * two bytes of lpstrFile should contain the needed size
40 * FIXME: algorithm for selecting the initial directory is too simple
42 * FIXME: add to recent docs
44 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
45 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
46 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
47 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
49 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
54 #include "config.h"
55 #include "wine/port.h"
57 #include <ctype.h>
58 #include <stdlib.h>
59 #include <stdarg.h>
60 #include <stdio.h>
61 #include <string.h>
63 #define NONAMELESSUNION
64 #define NONAMELESSSTRUCT
65 #include "windef.h"
66 #include "winbase.h"
67 #include "winreg.h"
68 #include "winternl.h"
69 #include "winnls.h"
70 #include "wine/unicode.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "commdlg.h"
74 #include "dlgs.h"
75 #include "cdlg.h"
76 #include "wine/debug.h"
77 #include "cderr.h"
78 #include "shellapi.h"
79 #include "shlguid.h"
80 #include "shlobj.h"
81 #include "filedlgbrowser.h"
82 #include "shlwapi.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
86 #define UNIMPLEMENTED_FLAGS \
87 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
88 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
89 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
90 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
92 #define IsHooked(fodInfos) \
93 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
94 /***********************************************************************
95 * Data structure and global variables
97 typedef struct SFolder
99 int m_iImageIndex; /* Index of picture in image list */
100 HIMAGELIST hImgList;
101 int m_iIndent; /* Indentation index */
102 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
104 } SFOLDER,*LPSFOLDER;
106 typedef struct tagLookInInfo
108 int iMaxIndentation;
109 UINT uSelectedItem;
110 } LookInInfos;
113 /***********************************************************************
114 * Defines and global variables
117 /* Draw item constant */
118 #define ICONWIDTH 18
119 #define XTEXTOFFSET 3
121 /* AddItem flags*/
122 #define LISTEND -1
124 /* SearchItem methods */
125 #define SEARCH_PIDL 1
126 #define SEARCH_EXP 2
127 #define ITEM_NOTFOUND -1
129 /* Undefined windows message sent by CreateViewObject*/
130 #define WM_GETISHELLBROWSER WM_USER+7
132 /* NOTE
133 * Those macros exist in windowsx.h. However, you can't really use them since
134 * they rely on the UNICODE defines and can't be used inside Wine itself.
137 /* Combo box macros */
138 #define CBAddString(hwnd,str) \
139 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
140 #define CBAddStringW(hwnd,str) \
141 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBInsertString(hwnd,str,pos) \
144 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
146 #define CBDeleteString(hwnd,pos) \
147 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
149 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
150 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
152 #define CBGetItemDataPtr(hwnd,iItemId) \
153 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
155 #define CBGetLBText(hwnd,iItemId,str) \
156 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
158 #define CBGetCurSel(hwnd) \
159 SendMessageA(hwnd,CB_GETCURSEL,0,0);
161 #define CBSetCurSel(hwnd,pos) \
162 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
164 #define CBGetCount(hwnd) \
165 SendMessageA(hwnd,CB_GETCOUNT,0,0);
166 #define CBShowDropDown(hwnd,show) \
167 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
168 #define CBSetItemHeight(hwnd,index,height) \
169 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
171 #define CBSetExtendedUI(hwnd,flag) \
172 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
174 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
175 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
177 /***********************************************************************
178 * Prototypes
181 /* Internal functions used by the dialog */
182 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
185 BOOL FILEDLG95_OnOpen(HWND hwnd);
186 static LRESULT FILEDLG95_InitControls(HWND hwnd);
187 static void FILEDLG95_Clean(HWND hwnd);
189 /* Functions used by the shell navigation */
190 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 /* Functions used by the filetype combo box */
197 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
198 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
199 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
200 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
202 /* Functions used by the Look In combo box */
203 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
204 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
205 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
207 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
208 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
209 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
210 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
211 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
213 /* Miscellaneous tool functions */
214 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
215 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
216 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
217 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
218 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
220 /* Shell memory allocation */
221 static void *MemAlloc(UINT size);
222 static void MemFree(void *mem);
224 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
225 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
226 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
227 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
228 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
229 static BOOL BrowseSelectedFolder(HWND hwnd);
231 /***********************************************************************
232 * GetFileName95
234 * Creates an Open common dialog box that lets the user select
235 * the drive, directory, and the name of a file or set of files to open.
237 * IN : The FileOpenDlgInfos structure associated with the dialog
238 * OUT : TRUE on success
239 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
241 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
244 LRESULT lRes;
245 LPCVOID template;
246 HRSRC hRes;
247 HANDLE hDlgTmpl = 0;
249 /* test for missing functionality */
250 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
252 FIXME("Flags 0x%08lx not yet implemented\n",
253 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
256 /* Create the dialog from a template */
258 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
260 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
261 return FALSE;
263 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
264 !(template = LockResource( hDlgTmpl )))
266 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
267 return FALSE;
270 /* old style hook messages */
271 if (IsHooked(fodInfos))
273 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
274 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
275 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
276 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
279 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
280 (LPDLGTEMPLATEA) template,
281 fodInfos->ofnInfos->hwndOwner,
282 FileOpenDlgProc95,
283 (LPARAM) fodInfos);
285 /* Unable to create the dialog */
286 if( lRes == -1)
287 return FALSE;
289 return lRes;
292 /***********************************************************************
293 * GetFileDialog95A
295 * Call GetFileName95 with this structure and clean the memory.
297 * IN : The OPENFILENAMEA initialisation structure passed to
298 * GetOpenFileNameA win api function (see filedlg.c)
300 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
302 BOOL ret;
303 FileOpenDlgInfos fodInfos;
304 LPSTR lpstrSavDir = NULL;
305 LPWSTR title = NULL;
306 LPWSTR defext = NULL;
307 LPWSTR filter = NULL;
308 LPWSTR customfilter = NULL;
310 /* Initialize FileOpenDlgInfos structure */
311 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
313 /* Pass in the original ofn */
314 fodInfos.ofnInfos = ofn;
316 /* save current directory */
317 if (ofn->Flags & OFN_NOCHANGEDIR)
319 lpstrSavDir = MemAlloc(MAX_PATH);
320 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
323 fodInfos.unicode = FALSE;
325 /* convert all the input strings to unicode */
326 if(ofn->lpstrInitialDir)
328 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
329 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
330 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
332 else
333 fodInfos.initdir = NULL;
335 if(ofn->lpstrFile)
337 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
338 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
340 else
341 fodInfos.filename = NULL;
343 if(ofn->lpstrDefExt)
345 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
346 defext = MemAlloc((len+1)*sizeof(WCHAR));
347 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
349 fodInfos.defext = defext;
351 if(ofn->lpstrTitle)
353 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
354 title = MemAlloc((len+1)*sizeof(WCHAR));
355 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
357 fodInfos.title = title;
359 if (ofn->lpstrFilter)
361 LPCSTR s;
362 int n, len;
364 /* filter is a list... title\0ext\0......\0\0 */
365 s = ofn->lpstrFilter;
366 while (*s) s = s+strlen(s)+1;
367 s++;
368 n = s - ofn->lpstrFilter;
369 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
370 filter = MemAlloc(len*sizeof(WCHAR));
371 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
373 fodInfos.filter = filter;
375 /* convert lpstrCustomFilter */
376 if (ofn->lpstrCustomFilter)
378 LPCSTR s;
379 int n, len;
381 /* filter is a list... title\0ext\0......\0\0 */
382 s = ofn->lpstrCustomFilter;
383 while (*s) s = s+strlen(s)+1;
384 s++;
385 n = s - ofn->lpstrCustomFilter;
386 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
387 customfilter = MemAlloc(len*sizeof(WCHAR));
388 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
390 fodInfos.customfilter = customfilter;
392 /* Initialize the dialog property */
393 fodInfos.DlgInfos.dwDlgProp = 0;
394 fodInfos.DlgInfos.hwndCustomDlg = NULL;
396 switch(iDlgType)
398 case OPEN_DIALOG :
399 ret = GetFileName95(&fodInfos);
400 break;
401 case SAVE_DIALOG :
402 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
403 ret = GetFileName95(&fodInfos);
404 break;
405 default :
406 ret = 0;
409 if (lpstrSavDir)
411 SetCurrentDirectoryA(lpstrSavDir);
412 MemFree(lpstrSavDir);
415 if(title)
416 MemFree(title);
417 if(defext)
418 MemFree(defext);
419 if(filter)
420 MemFree(filter);
421 if(customfilter)
422 MemFree(customfilter);
423 if(fodInfos.initdir)
424 MemFree(fodInfos.initdir);
426 if(fodInfos.filename)
427 MemFree(fodInfos.filename);
429 TRACE("selected file: %s\n",ofn->lpstrFile);
431 return ret;
434 /***********************************************************************
435 * GetFileDialog95W
437 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
438 * Call GetFileName95 with this structure and clean the memory.
440 * FIXME: lpstrCustomFilter has to be converted back
443 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
445 BOOL ret;
446 FileOpenDlgInfos fodInfos;
447 LPSTR lpstrSavDir = NULL;
449 /* Initialize FileOpenDlgInfos structure */
450 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
452 /* Pass in the original ofn */
453 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
455 fodInfos.title = ofn->lpstrTitle;
456 fodInfos.defext = ofn->lpstrDefExt;
457 fodInfos.filter = ofn->lpstrFilter;
458 fodInfos.customfilter = ofn->lpstrCustomFilter;
460 /* convert string arguments, save others */
461 if(ofn->lpstrFile)
463 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
464 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
466 else
467 fodInfos.filename = NULL;
469 if(ofn->lpstrInitialDir)
471 DWORD len = strlenW(ofn->lpstrInitialDir);
472 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
473 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
475 else
476 fodInfos.initdir = NULL;
478 /* save current directory */
479 if (ofn->Flags & OFN_NOCHANGEDIR)
481 lpstrSavDir = MemAlloc(MAX_PATH);
482 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
485 fodInfos.unicode = TRUE;
487 switch(iDlgType)
489 case OPEN_DIALOG :
490 ret = GetFileName95(&fodInfos);
491 break;
492 case SAVE_DIALOG :
493 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
494 ret = GetFileName95(&fodInfos);
495 break;
496 default :
497 ret = 0;
500 if (lpstrSavDir)
502 SetCurrentDirectoryA(lpstrSavDir);
503 MemFree(lpstrSavDir);
506 /* restore saved IN arguments and convert OUT arguments back */
507 MemFree(fodInfos.filename);
508 MemFree(fodInfos.initdir);
509 return ret;
512 /***********************************************************************
513 * ArrangeCtrlPositions [internal]
515 * NOTE: Do not change anything here without a lot of testing.
517 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
519 HWND hwndChild, hwndStc32;
520 RECT rectParent, rectChild, rectStc32;
521 INT help_fixup = 0;
523 /* Take into account if open as read only checkbox and help button
524 * are hidden
526 if (hide_help)
528 RECT rectHelp, rectCancel;
529 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
530 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
531 /* subtract the height of the help button plus the space between
532 * the help button and the cancel button to the height of the dialog
534 help_fixup = rectHelp.bottom - rectCancel.bottom;
538 There are two possibilities to add components to the default file dialog box.
540 By default, all the new components are added below the standard dialog box (the else case).
542 However, if there is a static text component with the stc32 id, a special case happens.
543 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
544 in the window and the cx and cy indicate how to size the window.
545 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
546 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
550 GetClientRect(hwndParentDlg, &rectParent);
552 /* when arranging controls we have to use fixed parent size */
553 rectParent.bottom -= help_fixup;
555 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
556 if (hwndStc32)
558 GetWindowRect(hwndStc32, &rectStc32);
559 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
561 /* set the size of the stc32 control according to the size of
562 * client area of the parent dialog
564 SetWindowPos(hwndStc32, 0,
565 0, 0,
566 rectParent.right, rectParent.bottom,
567 SWP_NOMOVE | SWP_NOZORDER);
569 else
570 SetRectEmpty(&rectStc32);
572 /* this part moves controls of the child dialog */
573 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
574 while (hwndChild)
576 if (hwndChild != hwndStc32)
578 GetWindowRect(hwndChild, &rectChild);
579 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
581 /* move only if stc32 exist */
582 if (hwndStc32 && rectChild.left > rectStc32.right)
584 /* move to the right of visible controls of the parent dialog */
585 rectChild.left += rectParent.right;
586 rectChild.left -= rectStc32.right;
588 /* move even if stc32 doesn't exist */
589 if (rectChild.top > rectStc32.bottom)
591 /* move below visible controls of the parent dialog */
592 rectChild.top += rectParent.bottom;
593 rectChild.top -= rectStc32.bottom - rectStc32.top;
596 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
597 0, 0, SWP_NOSIZE | SWP_NOZORDER);
599 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
602 /* this part moves controls of the parent dialog */
603 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
604 while (hwndChild)
606 if (hwndChild != hwndChildDlg)
608 GetWindowRect(hwndChild, &rectChild);
609 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
611 /* left,top of stc32 marks the position of controls
612 * from the parent dialog
614 rectChild.left += rectStc32.left;
615 rectChild.top += rectStc32.top;
617 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
618 0, 0, SWP_NOSIZE | SWP_NOZORDER);
620 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
623 /* calculate the size of the resulting dialog */
625 /* here we have to use original parent size */
626 GetClientRect(hwndParentDlg, &rectParent);
627 GetClientRect(hwndChildDlg, &rectChild);
629 if (hwndStc32)
631 if (rectParent.right > rectChild.right)
633 rectParent.right += rectChild.right;
634 rectParent.right -= rectStc32.right - rectStc32.left;
636 else
638 rectParent.right = rectChild.right;
641 if (rectParent.bottom > rectChild.bottom)
643 rectParent.bottom += rectChild.bottom;
644 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
646 else
648 rectParent.bottom = rectChild.bottom;
651 else
653 rectParent.bottom += rectChild.bottom;
656 /* finally use fixed parent size */
657 rectParent.bottom -= help_fixup;
659 /* save the size of the parent's client area */
660 rectChild.right = rectParent.right;
661 rectChild.bottom = rectParent.bottom;
663 /* set the size of the parent dialog */
664 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
665 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
666 SetWindowPos(hwndParentDlg, 0,
667 0, 0,
668 rectParent.right - rectParent.left,
669 rectParent.bottom - rectParent.top,
670 SWP_NOMOVE | SWP_NOZORDER);
672 /* set the size of the child dialog */
673 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
674 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
677 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
679 FileOpenDlgInfos *fodInfos;
681 #if 0
682 TRACE("0x%04x\n", uMsg);
683 #endif
685 switch(uMsg)
687 case WM_INITDIALOG:
689 fodInfos = (FileOpenDlgInfos *)lParam;
690 lParam = (LPARAM) fodInfos->ofnInfos;
692 if(fodInfos && IsHooked(fodInfos))
693 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
694 return 0;
698 fodInfos = (FileOpenDlgInfos *) GetPropA(GetParent(hwnd),FileOpenDlgInfosStr);
699 if(fodInfos && IsHooked(fodInfos))
700 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
702 return 0;
705 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
707 LPCVOID template;
708 HRSRC hRes;
709 HANDLE hDlgTmpl = 0;
710 HWND hChildDlg = 0;
712 TRACE("\n");
715 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
716 * structure's hInstance parameter is not a HINSTANCE, but
717 * instead a pointer to a template resource to use.
719 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
721 HINSTANCE hinst;
722 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
724 hinst = 0;
725 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
727 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
728 return NULL;
731 else
733 hinst = fodInfos->ofnInfos->hInstance;
734 if(fodInfos->unicode)
736 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
737 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
739 else
741 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
742 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
744 if (!hRes)
746 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
747 return NULL;
749 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
750 !(template = LockResource( hDlgTmpl )))
752 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
753 return NULL;
756 hChildDlg= CreateDialogIndirectParamA(COMDLG32_hInstance, template,
757 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
758 if(hChildDlg)
760 ShowWindow(hChildDlg,SW_SHOW);
761 return hChildDlg;
764 else if( IsHooked(fodInfos))
766 RECT rectHwnd;
767 struct {
768 DLGTEMPLATE tmplate;
769 WORD menu,class,title;
770 } temp;
771 GetClientRect(hwnd,&rectHwnd);
772 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
773 temp.tmplate.dwExtendedStyle = 0;
774 temp.tmplate.cdit = 0;
775 temp.tmplate.x = 0;
776 temp.tmplate.y = 0;
777 temp.tmplate.cx = 0;
778 temp.tmplate.cy = 0;
779 temp.menu = temp.class = temp.title = 0;
781 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
782 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
784 return hChildDlg;
786 return NULL;
789 /***********************************************************************
790 * SendCustomDlgNotificationMessage
792 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
795 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
797 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
799 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
801 if(!fodInfos) return 0;
803 if(fodInfos->unicode)
804 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
806 if(fodInfos->DlgInfos.hwndCustomDlg)
808 OFNOTIFYA ofnNotify;
809 HRESULT ret;
810 ofnNotify.hdr.hwndFrom=hwndParentDlg;
811 ofnNotify.hdr.idFrom=0;
812 ofnNotify.hdr.code = uCode;
813 ofnNotify.lpOFN = fodInfos->ofnInfos;
814 ofnNotify.pszFile = NULL;
815 TRACE("CALL NOTIFY for %x\n", uCode);
816 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
817 TRACE("RET NOTIFY\n");
818 return ret;
820 return TRUE;
823 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
825 UINT sizeUsed = 0, n, total;
826 LPWSTR lpstrFileList = NULL;
827 WCHAR lpstrCurrentDir[MAX_PATH];
828 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
830 TRACE("CDM_GETFILEPATH:\n");
832 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
833 return -1;
835 /* get path and filenames */
836 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
837 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
839 TRACE("path >%s< filespec >%s< %d files\n",
840 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
842 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
843 NULL, 0, NULL, NULL);
844 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
845 NULL, 0, NULL, NULL);
847 /* Prepend the current path */
848 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
849 buffer, size, NULL, NULL);
851 if(n<size)
853 /* 'n' includes trailing \0 */
854 buffer[n-1] = '\\';
855 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
856 &buffer[n], size-n, NULL, NULL);
858 MemFree(lpstrFileList);
860 TRACE("returned -> %s\n",debugstr_a(buffer));
862 return total;
865 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
867 UINT sizeUsed = 0;
868 LPWSTR lpstrFileList = NULL;
870 TRACE("CDM_GETSPEC:\n");
872 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
873 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
874 MemFree(lpstrFileList);
876 return sizeUsed;
879 /***********************************************************************
880 * FILEDLG95_HandleCustomDialogMessages
882 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
884 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
886 char lpstrPath[MAX_PATH];
887 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
888 if(!fodInfos) return -1;
890 switch(uMsg)
892 case CDM_GETFILEPATH:
893 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
895 case CDM_GETFOLDERPATH:
896 TRACE("CDM_GETFOLDERPATH:\n");
897 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
898 if ((LPSTR)lParam!=NULL)
899 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
900 return strlen(lpstrPath);
902 case CDM_GETSPEC:
903 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
905 case CDM_SETCONTROLTEXT:
906 TRACE("CDM_SETCONTROLTEXT:\n");
907 if ( 0 != lParam )
908 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
909 return TRUE;
911 case CDM_HIDECONTROL:
912 case CDM_SETDEFEXT:
913 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
914 return -1;
916 return TRUE;
919 /***********************************************************************
920 * FileOpenDlgProc95
922 * File open dialog procedure
924 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
926 #if 0
927 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
928 #endif
930 switch(uMsg)
932 case WM_INITDIALOG:
934 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
936 /* Adds the FileOpenDlgInfos in the property list of the dialog
937 so it will be easily accessible through a GetPropA(...) */
938 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
940 fodInfos->DlgInfos.hwndCustomDlg =
941 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
943 FILEDLG95_InitControls(hwnd);
945 if (fodInfos->DlgInfos.hwndCustomDlg)
946 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
947 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
949 FILEDLG95_FillControls(hwnd, wParam, lParam);
951 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
952 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
953 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
954 return 0;
956 case WM_COMMAND:
957 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
958 case WM_DRAWITEM:
960 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
962 case IDC_LOOKIN:
963 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
964 return TRUE;
967 return FALSE;
969 case WM_GETISHELLBROWSER:
970 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
972 case WM_DESTROY:
973 RemovePropA(hwnd, FileOpenDlgInfosStr);
974 return FALSE;
976 case WM_NOTIFY:
978 LPNMHDR lpnmh = (LPNMHDR)lParam;
979 UINT stringId = -1;
981 /* set up the button tooltips strings */
982 if(TTN_GETDISPINFOA == lpnmh->code )
984 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
985 switch(lpnmh->idFrom )
987 /* Up folder button */
988 case FCIDM_TB_UPFOLDER:
989 stringId = IDS_UPFOLDER;
990 break;
991 /* New folder button */
992 case FCIDM_TB_NEWFOLDER:
993 stringId = IDS_NEWFOLDER;
994 break;
995 /* List option button */
996 case FCIDM_TB_SMALLICON:
997 stringId = IDS_LISTVIEW;
998 break;
999 /* Details option button */
1000 case FCIDM_TB_REPORTVIEW:
1001 stringId = IDS_REPORTVIEW;
1002 break;
1003 /* Desktop button */
1004 case FCIDM_TB_DESKTOP:
1005 stringId = IDS_TODESKTOP;
1006 break;
1007 default:
1008 stringId = 0;
1010 lpdi->hinst = COMDLG32_hInstance;
1011 lpdi->lpszText = (LPSTR) stringId;
1013 return FALSE;
1015 default :
1016 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1017 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1018 return FALSE;
1022 /***********************************************************************
1023 * FILEDLG95_InitControls
1025 * WM_INITDIALOG message handler (before hook notification)
1027 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1029 int win2000plus = 0;
1030 int win98plus = 0;
1031 int handledPath = FALSE;
1032 OSVERSIONINFOA osVi;
1033 const WCHAR szwSlash[] = { '\\', 0 };
1034 const WCHAR szwStar[] = { '*',0 };
1036 TBBUTTON tbb[] =
1038 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1039 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1040 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1041 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1042 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1043 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1044 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1045 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1046 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1048 TBADDBITMAP tba[2];
1049 RECT rectTB;
1050 RECT rectlook;
1051 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1053 tba[0].hInst = HINST_COMMCTRL;
1054 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1055 tba[1].hInst = COMDLG32_hInstance;
1056 tba[1].nID = 800;
1058 TRACE("%p\n", fodInfos);
1060 /* Get windows version emulating */
1061 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1062 GetVersionExA(&osVi);
1063 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1064 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1065 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1066 win2000plus = (osVi.dwMajorVersion > 4);
1067 if (win2000plus) win98plus = TRUE;
1069 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1071 /* Get the hwnd of the controls */
1072 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1073 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1074 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1076 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1077 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1079 /* construct the toolbar */
1080 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1081 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1083 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1084 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1085 rectTB.left = rectlook.right;
1086 rectTB.top = rectlook.top-1;
1088 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1089 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1090 rectTB.left, rectTB.top,
1091 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1092 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1094 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1096 /* FIXME: use TB_LOADIMAGES when implemented */
1097 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1098 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1099 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1101 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1102 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1104 /* Set the window text with the text specified in the OPENFILENAME structure */
1105 if(fodInfos->title)
1107 SetWindowTextW(hwnd,fodInfos->title);
1109 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1111 SetWindowTextA(hwnd,"Save");
1114 /* Initialise the file name edit control */
1115 handledPath = FALSE;
1116 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1118 if(fodInfos->filename)
1120 /* 1. If win2000 or higher and filename contains a path, use it
1121 in preference over the lpstrInitialDir */
1122 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1123 WCHAR tmpBuf[MAX_PATH];
1124 WCHAR *nameBit;
1125 DWORD result;
1127 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1128 if (result) {
1130 /* nameBit is always shorter than the original filename */
1131 strcpyW(fodInfos->filename,nameBit);
1133 *nameBit = 0x00;
1134 if (fodInfos->initdir == NULL)
1135 MemFree(fodInfos->initdir);
1136 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1137 strcpyW(fodInfos->initdir, tmpBuf);
1138 handledPath = TRUE;
1139 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1140 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1142 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1144 } else {
1145 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1149 /* 2. (All platforms) If initdir is not null, then use it */
1150 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1151 (*fodInfos->initdir!=0x00))
1153 /* Work out the proper path as supplied one might be relative */
1154 /* (Here because supplying '.' as dir browses to My Computer) */
1155 if (handledPath==FALSE) {
1156 WCHAR tmpBuf[MAX_PATH];
1157 WCHAR tmpBuf2[MAX_PATH];
1158 WCHAR *nameBit;
1159 DWORD result;
1161 strcpyW(tmpBuf, fodInfos->initdir);
1162 if( PathFileExistsW(tmpBuf) ) {
1163 /* initdir does not have to be a directory. If a file is
1164 * specified, the dir part is taken */
1165 if( PathIsDirectoryW(tmpBuf)) {
1166 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1167 strcatW(tmpBuf, szwSlash);
1169 strcatW(tmpBuf, szwStar);
1171 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1172 if (result) {
1173 *nameBit = 0x00;
1174 if (fodInfos->initdir)
1175 MemFree(fodInfos->initdir);
1176 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1177 strcpyW(fodInfos->initdir, tmpBuf2);
1178 handledPath = TRUE;
1179 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1182 else if (fodInfos->initdir)
1184 MemFree(fodInfos->initdir);
1185 fodInfos->initdir = NULL;
1186 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1191 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1192 (*fodInfos->initdir==0x00)))
1194 /* 3. All except w2k+: if filename contains a path use it */
1195 if (!win2000plus && fodInfos->filename &&
1196 *fodInfos->filename &&
1197 strpbrkW(fodInfos->filename, szwSlash)) {
1198 WCHAR tmpBuf[MAX_PATH];
1199 WCHAR *nameBit;
1200 DWORD result;
1202 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1203 tmpBuf, &nameBit);
1204 if (result) {
1205 int len;
1207 /* nameBit is always shorter than the original filename */
1208 strcpyW(fodInfos->filename, nameBit);
1209 *nameBit = 0x00;
1211 len = strlenW(tmpBuf);
1212 if(fodInfos->initdir)
1213 MemFree(fodInfos->initdir);
1214 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1215 strcpyW(fodInfos->initdir, tmpBuf);
1217 handledPath = TRUE;
1218 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1219 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1221 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1224 /* 4. win98+ and win2000+ if any files of specified filter types in
1225 current directory, use it */
1226 if ( win98plus && handledPath == FALSE &&
1227 fodInfos->filter && *fodInfos->filter) {
1229 BOOL searchMore = TRUE;
1230 LPCWSTR lpstrPos = fodInfos->filter;
1231 WIN32_FIND_DATAW FindFileData;
1232 HANDLE hFind;
1234 while (searchMore)
1236 /* filter is a list... title\0ext\0......\0\0 */
1238 /* Skip the title */
1239 if(! *lpstrPos) break; /* end */
1240 lpstrPos += strlenW(lpstrPos) + 1;
1242 /* See if any files exist in the current dir with this extension */
1243 if(! *lpstrPos) break; /* end */
1245 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1247 if (hFind == INVALID_HANDLE_VALUE) {
1248 /* None found - continue search */
1249 lpstrPos += strlenW(lpstrPos) + 1;
1251 } else {
1252 searchMore = FALSE;
1254 if(fodInfos->initdir)
1255 MemFree(fodInfos->initdir);
1256 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1257 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1259 handledPath = TRUE;
1260 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1261 debugstr_w(lpstrPos));
1262 break;
1267 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1269 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1270 if (handledPath == FALSE && (win2000plus || win98plus)) {
1271 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1273 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1275 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1277 /* last fallback */
1278 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1279 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1280 } else {
1281 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1283 } else {
1284 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1286 handledPath = TRUE;
1287 } else if (handledPath==FALSE) {
1288 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1289 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1290 handledPath = TRUE;
1291 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1294 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1295 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1297 /* Must the open as read only check box be checked ?*/
1298 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1300 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1303 /* Must the open as read only check box be hidden? */
1304 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1306 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1307 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1310 /* Must the help button be hidden? */
1311 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1313 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1314 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1317 /* Resize the height, if open as read only checkbox ad help button
1318 are hidden and we are not using a custom template nor a customDialog
1320 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1321 (!(fodInfos->ofnInfos->Flags &
1322 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1323 (!fodInfos->DlgInfos.hwndCustomDlg ))
1325 RECT rectDlg, rectHelp, rectCancel;
1326 GetWindowRect(hwnd, &rectDlg);
1327 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1328 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1329 /* subtract the height of the help button plus the space between
1330 the help button and the cancel button to the height of the dialog */
1331 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1332 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1333 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1335 /* change Open to Save FIXME: use resources */
1336 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1338 SetDlgItemTextA(hwnd,IDOK,"&Save");
1339 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1341 return 0;
1344 /***********************************************************************
1345 * FILEDLG95_FillControls
1347 * WM_INITDIALOG message handler (after hook notification)
1349 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1351 LPITEMIDLIST pidlItemId = NULL;
1353 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1355 TRACE("dir=%s file=%s\n",
1356 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1358 /* Get the initial directory pidl */
1360 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1362 WCHAR path[MAX_PATH];
1364 GetCurrentDirectoryW(MAX_PATH,path);
1365 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1368 /* Initialise shell objects */
1369 FILEDLG95_SHELL_Init(hwnd);
1371 /* Initialize the Look In combo box */
1372 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1374 /* Initialize the filter combo box */
1375 FILEDLG95_FILETYPE_Init(hwnd);
1377 /* Browse to the initial directory */
1378 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1380 /* Free pidlItem memory */
1381 COMDLG32_SHFree(pidlItemId);
1383 return TRUE;
1385 /***********************************************************************
1386 * FILEDLG95_Clean
1388 * Regroups all the cleaning functions of the filedlg
1390 void FILEDLG95_Clean(HWND hwnd)
1392 FILEDLG95_FILETYPE_Clean(hwnd);
1393 FILEDLG95_LOOKIN_Clean(hwnd);
1394 FILEDLG95_SHELL_Clean(hwnd);
1396 /***********************************************************************
1397 * FILEDLG95_OnWMCommand
1399 * WM_COMMAND message handler
1401 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1403 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1404 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1405 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1407 switch(wID)
1409 /* OK button */
1410 case IDOK:
1411 FILEDLG95_OnOpen(hwnd);
1412 break;
1413 /* Cancel button */
1414 case IDCANCEL:
1415 FILEDLG95_Clean(hwnd);
1416 EndDialog(hwnd, FALSE);
1417 break;
1418 /* Filetype combo box */
1419 case IDC_FILETYPE:
1420 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1421 break;
1422 /* LookIn combo box */
1423 case IDC_LOOKIN:
1424 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1425 break;
1427 /* --- toolbar --- */
1428 /* Up folder button */
1429 case FCIDM_TB_UPFOLDER:
1430 FILEDLG95_SHELL_UpFolder(hwnd);
1431 break;
1432 /* New folder button */
1433 case FCIDM_TB_NEWFOLDER:
1434 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1435 break;
1436 /* List option button */
1437 case FCIDM_TB_SMALLICON:
1438 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1439 break;
1440 /* Details option button */
1441 case FCIDM_TB_REPORTVIEW:
1442 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1443 break;
1444 /* Details option button */
1445 case FCIDM_TB_DESKTOP:
1446 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1447 break;
1449 case IDC_FILENAME:
1450 break;
1453 /* Do not use the listview selection anymore */
1454 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1455 return 0;
1458 /***********************************************************************
1459 * FILEDLG95_OnWMGetIShellBrowser
1461 * WM_GETISHELLBROWSER message handler
1463 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1466 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1468 TRACE("\n");
1470 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1472 return TRUE;
1476 /***********************************************************************
1477 * FILEDLG95_SendFileOK
1479 * Sends the CDN_FILEOK notification if required
1481 * RETURNS
1482 * TRUE if the dialog should close
1483 * FALSE if the dialog should not be closed
1485 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1487 /* ask the hook if we can close */
1488 if(IsHooked(fodInfos))
1490 TRACE("---\n");
1491 /* First send CDN_FILEOK as MSDN doc says */
1492 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1494 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1495 CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,
1496 fodInfos->DlgInfos.hwndCustomDlg,
1497 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1498 if (GetWindowLongA(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1500 TRACE("canceled\n");
1501 return FALSE;
1504 return TRUE;
1507 /***********************************************************************
1508 * FILEDLG95_OnOpenMultipleFiles
1510 * Handles the opening of multiple files.
1512 * FIXME
1513 * check destination buffer size
1515 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1517 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1518 UINT nCount, nSizePath;
1519 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1521 TRACE("\n");
1523 if(fodInfos->unicode)
1525 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1526 ofn->lpstrFile[0] = '\0';
1528 else
1530 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1531 ofn->lpstrFile[0] = '\0';
1534 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1536 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1537 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1538 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1540 LPWSTR lpstrTemp = lpstrFileList;
1542 for ( nCount = 0; nCount < nFileCount; nCount++ )
1544 LPITEMIDLIST pidl;
1546 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1547 if (!pidl)
1549 WCHAR lpstrNotFound[100];
1550 WCHAR lpstrMsg[100];
1551 WCHAR tmp[400];
1552 WCHAR nl[] = {'\n',0};
1554 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1555 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1557 strcpyW(tmp, lpstrTemp);
1558 strcatW(tmp, nl);
1559 strcatW(tmp, lpstrNotFound);
1560 strcatW(tmp, nl);
1561 strcatW(tmp, lpstrMsg);
1563 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1564 return FALSE;
1567 /* move to the next file in the list of files */
1568 lpstrTemp += strlenW(lpstrTemp) + 1;
1569 COMDLG32_SHFree(pidl);
1573 nSizePath = strlenW(lpstrPathSpec) + 1;
1574 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1576 /* For "oldstyle" dialog the components have to
1577 be spearated by blanks (not '\0'!) and short
1578 filenames have to be used! */
1579 FIXME("Components have to be separated by blanks");
1581 if(fodInfos->unicode)
1583 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1584 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1585 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1587 else
1589 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1591 if (ofn->lpstrFile != NULL)
1593 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1594 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1595 if (ofn->nMaxFile > nSizePath)
1597 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1598 ofn->lpstrFile + nSizePath,
1599 ofn->nMaxFile - nSizePath, NULL, NULL);
1604 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1605 fodInfos->ofnInfos->nFileExtension = 0;
1607 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1608 return FALSE;
1610 /* clean and exit */
1611 FILEDLG95_Clean(hwnd);
1612 return EndDialog(hwnd,TRUE);
1615 /***********************************************************************
1616 * FILEDLG95_OnOpen
1618 * Ok button WM_COMMAND message handler
1620 * If the function succeeds, the return value is nonzero.
1622 #define ONOPEN_BROWSE 1
1623 #define ONOPEN_OPEN 2
1624 #define ONOPEN_SEARCH 3
1625 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1627 char strMsgTitle[MAX_PATH];
1628 char strMsgText [MAX_PATH];
1629 if (idCaption)
1630 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1631 else
1632 strMsgTitle[0] = '\0';
1633 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1634 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1637 BOOL FILEDLG95_OnOpen(HWND hwnd)
1639 LPWSTR lpstrFileList;
1640 UINT nFileCount = 0;
1641 UINT sizeUsed = 0;
1642 BOOL ret = TRUE;
1643 WCHAR lpstrPathAndFile[MAX_PATH];
1644 WCHAR lpstrTemp[MAX_PATH];
1645 LPSHELLFOLDER lpsf = NULL;
1646 int nOpenAction;
1647 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1649 TRACE("hwnd=%p\n", hwnd);
1651 /* get the files from the edit control */
1652 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1654 /* try if the user selected a folder in the shellview */
1655 if(nFileCount == 0)
1657 BrowseSelectedFolder(hwnd);
1658 return FALSE;
1661 if(nFileCount > 1)
1663 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1664 goto ret;
1667 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1670 Step 1: Build a complete path name from the current folder and
1671 the filename or path in the edit box.
1672 Special cases:
1673 - the path in the edit box is a root path
1674 (with or without drive letter)
1675 - the edit box contains ".." (or a path with ".." in it)
1678 /* Get the current directory name */
1679 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1681 /* we are in a special folder, default to desktop */
1682 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1684 /* last fallback */
1685 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1688 PathAddBackslashW(lpstrPathAndFile);
1690 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1692 /* if the user specifyed a fully qualified path use it */
1693 if(PathIsRelativeW(lpstrFileList))
1695 strcatW(lpstrPathAndFile, lpstrFileList);
1697 else
1699 /* does the path have a drive letter? */
1700 if (PathGetDriveNumberW(lpstrFileList) == -1)
1701 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1702 else
1703 strcpyW(lpstrPathAndFile, lpstrFileList);
1706 /* resolve "." and ".." */
1707 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1708 strcpyW(lpstrPathAndFile, lpstrTemp);
1709 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1711 MemFree(lpstrFileList);
1714 Step 2: here we have a cleaned up path
1716 We have to parse the path step by step to see if we have to browse
1717 to a folder if the path points to a directory or the last
1718 valid element is a directory.
1720 valid variables:
1721 lpstrPathAndFile: cleaned up path
1724 nOpenAction = ONOPEN_BROWSE;
1726 /* don't apply any checks with OFN_NOVALIDATE */
1728 LPWSTR lpszTemp, lpszTemp1;
1729 LPITEMIDLIST pidl = NULL;
1730 WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1732 /* check for invalid chars */
1733 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1735 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1736 ret = FALSE;
1737 goto ret;
1740 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1742 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1743 while (lpszTemp1)
1745 LPSHELLFOLDER lpsfChild;
1746 WCHAR lpwstrTemp[MAX_PATH];
1747 DWORD dwEaten, dwAttributes;
1748 LPWSTR p;
1750 strcpyW(lpwstrTemp, lpszTemp);
1751 p = PathFindNextComponentW(lpwstrTemp);
1753 if (!p) break; /* end of path */
1755 *p = 0;
1756 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1758 if(*lpszTemp==0)
1760 WCHAR wszWild[] = { '*', '?', 0 };
1761 /* if the last element is a wildcard do a search */
1762 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1764 nOpenAction = ONOPEN_SEARCH;
1765 break;
1768 lpszTemp1 = lpszTemp;
1770 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1772 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1774 dwAttributes = SFGAO_FOLDER;
1775 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1777 /* the path component is valid, we have a pidl of the next path component */
1778 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1779 if(dwAttributes & SFGAO_FOLDER)
1781 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1783 ERR("bind to failed\n"); /* should not fail */
1784 break;
1786 IShellFolder_Release(lpsf);
1787 lpsf = lpsfChild;
1788 lpsfChild = NULL;
1790 else
1792 TRACE("value\n");
1794 /* end dialog, return value */
1795 nOpenAction = ONOPEN_OPEN;
1796 break;
1798 COMDLG32_SHFree(pidl);
1799 pidl = NULL;
1801 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1803 if(*lpszTemp) /* points to trailing null for last path element */
1805 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1807 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1808 break;
1811 else
1813 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1814 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1816 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1817 break;
1820 /* change to the current folder */
1821 nOpenAction = ONOPEN_OPEN;
1822 break;
1824 else
1826 nOpenAction = ONOPEN_OPEN;
1827 break;
1830 if(pidl) COMDLG32_SHFree(pidl);
1834 Step 3: here we have a cleaned up and validated path
1836 valid variables:
1837 lpsf: ShellFolder bound to the rightmost valid path component
1838 lpstrPathAndFile: cleaned up path
1839 nOpenAction: action to do
1841 TRACE("end validate sf=%p\n", lpsf);
1843 switch(nOpenAction)
1845 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1846 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1848 int iPos;
1849 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1850 DWORD len;
1852 /* replace the current filter */
1853 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1854 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1855 len = strlenW(lpszTemp)+1;
1856 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1857 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1859 /* set the filter cb to the extension when possible */
1860 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1861 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1863 /* fall through */
1864 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1865 TRACE("ONOPEN_BROWSE\n");
1867 IPersistFolder2 * ppf2;
1868 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1870 LPITEMIDLIST pidlCurrent;
1871 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1872 IPersistFolder2_Release(ppf2);
1873 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1875 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1877 else if( nOpenAction == ONOPEN_SEARCH )
1879 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1881 COMDLG32_SHFree(pidlCurrent);
1884 ret = FALSE;
1885 break;
1886 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1887 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1889 /* add default extension */
1890 if (fodInfos->defext)
1892 WCHAR *ext = PathFindExtensionW(lpstrPathAndFile);
1894 if (! *ext)
1896 /* only add "." in case a default extension does exist */
1897 if (*fodInfos->defext != '\0')
1899 const WCHAR szwDot[] = {'.',0};
1900 int PathLength = strlenW(lpstrPathAndFile);
1902 strcatW(lpstrPathAndFile, szwDot);
1903 strcatW(lpstrPathAndFile, fodInfos->defext);
1905 /* In Open dialog: if file does not exist try without extension */
1906 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1907 && !PathFileExistsW(lpstrPathAndFile))
1908 lpstrPathAndFile[PathLength] = '\0';
1912 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1913 if (*ext)
1914 ext++;
1915 if (!lstrcmpiW(fodInfos->defext, ext))
1916 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1917 else
1918 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1921 /* In Save dialog: check if the file already exists */
1922 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1923 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1924 && PathFileExistsW(lpstrPathAndFile))
1926 WCHAR lpstrOverwrite[100];
1927 int answer;
1929 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1930 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1931 MB_YESNO | MB_ICONEXCLAMATION);
1932 if (answer == IDNO)
1934 ret = FALSE;
1935 goto ret;
1939 /* Check that the size of the file does not exceed buffer size.
1940 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1941 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1942 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1944 LPWSTR lpszTemp;
1946 /* fill destination buffer */
1947 if (fodInfos->ofnInfos->lpstrFile)
1949 if(fodInfos->unicode)
1951 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1953 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1954 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1955 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1957 else
1959 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1961 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1962 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1963 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1964 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1968 /* set filename offset */
1969 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1970 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1972 /* set extension offset */
1973 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1974 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1976 /* set the lpstrFileTitle */
1977 if(fodInfos->ofnInfos->lpstrFileTitle)
1979 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1980 if(fodInfos->unicode)
1982 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1983 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1985 else
1987 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1988 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1989 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1993 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1994 goto ret;
1996 TRACE("close\n");
1997 FILEDLG95_Clean(hwnd);
1998 ret = EndDialog(hwnd, TRUE);
2000 else
2002 /* FIXME set error FNERR_BUFFERTOSMALL */
2003 FILEDLG95_Clean(hwnd);
2004 ret = EndDialog(hwnd, FALSE);
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);
2385 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 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 return GetFileDialog95A(ofn, OPEN_DIALOG);
3247 /***********************************************************************
3248 * GetOpenFileNameW (COMDLG32.@)
3250 * Creates a dialog box for the user to select a file to open.
3252 * RETURNS
3253 * TRUE on success: user enters a valid file
3254 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3257 BOOL WINAPI GetOpenFileNameW(
3258 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3260 return GetFileDialog95W(ofn, OPEN_DIALOG);
3263 /***********************************************************************
3264 * GetSaveFileNameA (COMDLG32.@)
3266 * Creates a dialog box for the user to select a file to save.
3268 * RETURNS
3269 * TRUE on success: user enters a valid file
3270 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3273 BOOL WINAPI GetSaveFileNameA(
3274 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3276 return GetFileDialog95A(ofn, SAVE_DIALOG);
3279 /***********************************************************************
3280 * GetSaveFileNameW (COMDLG32.@)
3282 * Creates a dialog box for the user to select a file to save.
3284 * RETURNS
3285 * TRUE on success: user enters a valid file
3286 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3289 BOOL WINAPI GetSaveFileNameW(
3290 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3292 return GetFileDialog95W(ofn, SAVE_DIALOG);