Release 20040408.
[wine.git] / dlls / commdlg / filedlg.c
blobb4d33ad4afe2aa61135340203e73150ec2d58b8d
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 switch(uMsg) {
680 case WM_INITDIALOG:
681 return TRUE;
683 return FALSE;
686 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
688 LPCVOID template;
689 HRSRC hRes;
690 HANDLE hDlgTmpl = 0;
691 HWND hChildDlg = 0;
693 TRACE("\n");
696 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
697 * structure's hInstance parameter is not a HINSTANCE, but
698 * instead a pointer to a template resource to use.
700 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
702 HINSTANCE hinst;
703 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
705 hinst = 0;
706 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
708 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
709 return NULL;
712 else
714 hinst = fodInfos->ofnInfos->hInstance;
715 if(fodInfos->unicode)
717 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
718 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
720 else
722 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
723 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
725 if (!hRes)
727 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
728 return NULL;
730 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
731 !(template = LockResource( hDlgTmpl )))
733 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
734 return NULL;
737 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
738 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
739 (LPARAM)fodInfos->ofnInfos);
740 if(hChildDlg)
742 ShowWindow(hChildDlg,SW_SHOW);
743 return hChildDlg;
746 else if( IsHooked(fodInfos))
748 RECT rectHwnd;
749 struct {
750 DLGTEMPLATE tmplate;
751 WORD menu,class,title;
752 } temp;
753 GetClientRect(hwnd,&rectHwnd);
754 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
755 temp.tmplate.dwExtendedStyle = 0;
756 temp.tmplate.cdit = 0;
757 temp.tmplate.x = 0;
758 temp.tmplate.y = 0;
759 temp.tmplate.cx = 0;
760 temp.tmplate.cy = 0;
761 temp.menu = temp.class = temp.title = 0;
763 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
764 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
766 return hChildDlg;
768 return NULL;
771 /***********************************************************************
772 * SendCustomDlgNotificationMessage
774 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
777 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
779 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
781 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
783 if(!fodInfos) return 0;
785 if(fodInfos->unicode)
786 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
788 if(fodInfos->DlgInfos.hwndCustomDlg)
790 OFNOTIFYA ofnNotify;
791 HRESULT ret;
792 ofnNotify.hdr.hwndFrom=hwndParentDlg;
793 ofnNotify.hdr.idFrom=0;
794 ofnNotify.hdr.code = uCode;
795 ofnNotify.lpOFN = fodInfos->ofnInfos;
796 ofnNotify.pszFile = NULL;
797 TRACE("CALL NOTIFY for %x\n", uCode);
798 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
799 TRACE("RET NOTIFY\n");
800 return ret;
802 return TRUE;
805 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
807 UINT sizeUsed = 0, n, total;
808 LPWSTR lpstrFileList = NULL;
809 WCHAR lpstrCurrentDir[MAX_PATH];
810 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
812 TRACE("CDM_GETFILEPATH:\n");
814 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
815 return -1;
817 /* get path and filenames */
818 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
819 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
821 TRACE("path >%s< filespec >%s< %d files\n",
822 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
824 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
825 NULL, 0, NULL, NULL);
826 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
827 NULL, 0, NULL, NULL);
829 /* Prepend the current path */
830 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
831 buffer, size, NULL, NULL);
833 if(n<size)
835 /* 'n' includes trailing \0 */
836 buffer[n-1] = '\\';
837 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
838 &buffer[n], size-n, NULL, NULL);
840 MemFree(lpstrFileList);
842 TRACE("returned -> %s\n",debugstr_a(buffer));
844 return total;
847 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
849 UINT sizeUsed = 0;
850 LPWSTR lpstrFileList = NULL;
852 TRACE("CDM_GETSPEC:\n");
854 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
855 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
856 MemFree(lpstrFileList);
858 return sizeUsed;
861 /***********************************************************************
862 * FILEDLG95_HandleCustomDialogMessages
864 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
866 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
868 char lpstrPath[MAX_PATH];
869 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
870 if(!fodInfos) return -1;
872 switch(uMsg)
874 case CDM_GETFILEPATH:
875 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
877 case CDM_GETFOLDERPATH:
878 TRACE("CDM_GETFOLDERPATH:\n");
879 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
880 if ((LPSTR)lParam!=NULL)
881 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
882 return strlen(lpstrPath);
884 case CDM_GETSPEC:
885 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
887 case CDM_SETCONTROLTEXT:
888 TRACE("CDM_SETCONTROLTEXT:\n");
889 if ( 0 != lParam )
890 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
891 return TRUE;
893 case CDM_HIDECONTROL:
894 case CDM_SETDEFEXT:
895 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
896 return -1;
898 return TRUE;
901 /***********************************************************************
902 * FileOpenDlgProc95
904 * File open dialog procedure
906 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
908 #if 0
909 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
910 #endif
912 switch(uMsg)
914 case WM_INITDIALOG:
916 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
918 /* Adds the FileOpenDlgInfos in the property list of the dialog
919 so it will be easily accessible through a GetPropA(...) */
920 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
922 fodInfos->DlgInfos.hwndCustomDlg =
923 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
925 FILEDLG95_InitControls(hwnd);
927 if (fodInfos->DlgInfos.hwndCustomDlg)
928 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
929 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
931 FILEDLG95_FillControls(hwnd, wParam, lParam);
933 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
934 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
935 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
936 return 0;
938 case WM_COMMAND:
939 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
940 case WM_DRAWITEM:
942 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
944 case IDC_LOOKIN:
945 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
946 return TRUE;
949 return FALSE;
951 case WM_GETISHELLBROWSER:
952 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
954 case WM_DESTROY:
955 RemovePropA(hwnd, FileOpenDlgInfosStr);
956 return FALSE;
958 case WM_NOTIFY:
960 LPNMHDR lpnmh = (LPNMHDR)lParam;
961 UINT stringId = -1;
963 /* set up the button tooltips strings */
964 if(TTN_GETDISPINFOA == lpnmh->code )
966 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
967 switch(lpnmh->idFrom )
969 /* Up folder button */
970 case FCIDM_TB_UPFOLDER:
971 stringId = IDS_UPFOLDER;
972 break;
973 /* New folder button */
974 case FCIDM_TB_NEWFOLDER:
975 stringId = IDS_NEWFOLDER;
976 break;
977 /* List option button */
978 case FCIDM_TB_SMALLICON:
979 stringId = IDS_LISTVIEW;
980 break;
981 /* Details option button */
982 case FCIDM_TB_REPORTVIEW:
983 stringId = IDS_REPORTVIEW;
984 break;
985 /* Desktop button */
986 case FCIDM_TB_DESKTOP:
987 stringId = IDS_TODESKTOP;
988 break;
989 default:
990 stringId = 0;
992 lpdi->hinst = COMDLG32_hInstance;
993 lpdi->lpszText = (LPSTR) stringId;
995 return FALSE;
997 default :
998 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
999 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1000 return FALSE;
1004 /***********************************************************************
1005 * FILEDLG95_InitControls
1007 * WM_INITDIALOG message handler (before hook notification)
1009 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1011 int win2000plus = 0;
1012 int win98plus = 0;
1013 int handledPath = FALSE;
1014 OSVERSIONINFOA osVi;
1015 const WCHAR szwSlash[] = { '\\', 0 };
1016 const WCHAR szwStar[] = { '*',0 };
1018 TBBUTTON tbb[] =
1020 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1021 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1022 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1023 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1024 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1025 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1026 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1027 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1028 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1030 TBADDBITMAP tba[2];
1031 RECT rectTB;
1032 RECT rectlook;
1033 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1035 tba[0].hInst = HINST_COMMCTRL;
1036 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1037 tba[1].hInst = COMDLG32_hInstance;
1038 tba[1].nID = 800;
1040 TRACE("%p\n", fodInfos);
1042 /* Get windows version emulating */
1043 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1044 GetVersionExA(&osVi);
1045 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1046 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1047 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1048 win2000plus = (osVi.dwMajorVersion > 4);
1049 if (win2000plus) win98plus = TRUE;
1051 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1053 /* Get the hwnd of the controls */
1054 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1055 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1056 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1058 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1059 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1061 /* construct the toolbar */
1062 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1063 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1065 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1066 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1067 rectTB.left = rectlook.right;
1068 rectTB.top = rectlook.top-1;
1070 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1071 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1072 rectTB.left, rectTB.top,
1073 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1074 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1076 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1078 /* FIXME: use TB_LOADIMAGES when implemented */
1079 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1080 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1081 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1083 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1084 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1086 /* Set the window text with the text specified in the OPENFILENAME structure */
1087 if(fodInfos->title)
1089 SetWindowTextW(hwnd,fodInfos->title);
1091 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1093 SetWindowTextA(hwnd,"Save");
1096 /* Initialise the file name edit control */
1097 handledPath = FALSE;
1098 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1100 if(fodInfos->filename)
1102 /* 1. If win2000 or higher and filename contains a path, use it
1103 in preference over the lpstrInitialDir */
1104 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1105 WCHAR tmpBuf[MAX_PATH];
1106 WCHAR *nameBit;
1107 DWORD result;
1109 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1110 if (result) {
1112 /* nameBit is always shorter than the original filename */
1113 strcpyW(fodInfos->filename,nameBit);
1115 *nameBit = 0x00;
1116 if (fodInfos->initdir == NULL)
1117 MemFree(fodInfos->initdir);
1118 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1119 strcpyW(fodInfos->initdir, tmpBuf);
1120 handledPath = TRUE;
1121 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1122 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1124 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1126 } else {
1127 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1131 /* 2. (All platforms) If initdir is not null, then use it */
1132 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1133 (*fodInfos->initdir!=0x00))
1135 /* Work out the proper path as supplied one might be relative */
1136 /* (Here because supplying '.' as dir browses to My Computer) */
1137 if (handledPath==FALSE) {
1138 WCHAR tmpBuf[MAX_PATH];
1139 WCHAR tmpBuf2[MAX_PATH];
1140 WCHAR *nameBit;
1141 DWORD result;
1143 strcpyW(tmpBuf, fodInfos->initdir);
1144 if( PathFileExistsW(tmpBuf) ) {
1145 /* initdir does not have to be a directory. If a file is
1146 * specified, the dir part is taken */
1147 if( PathIsDirectoryW(tmpBuf)) {
1148 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1149 strcatW(tmpBuf, szwSlash);
1151 strcatW(tmpBuf, szwStar);
1153 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1154 if (result) {
1155 *nameBit = 0x00;
1156 if (fodInfos->initdir)
1157 MemFree(fodInfos->initdir);
1158 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1159 strcpyW(fodInfos->initdir, tmpBuf2);
1160 handledPath = TRUE;
1161 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1164 else if (fodInfos->initdir)
1166 MemFree(fodInfos->initdir);
1167 fodInfos->initdir = NULL;
1168 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1173 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1174 (*fodInfos->initdir==0x00)))
1176 /* 3. All except w2k+: if filename contains a path use it */
1177 if (!win2000plus && fodInfos->filename &&
1178 *fodInfos->filename &&
1179 strpbrkW(fodInfos->filename, szwSlash)) {
1180 WCHAR tmpBuf[MAX_PATH];
1181 WCHAR *nameBit;
1182 DWORD result;
1184 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1185 tmpBuf, &nameBit);
1186 if (result) {
1187 int len;
1189 /* nameBit is always shorter than the original filename */
1190 strcpyW(fodInfos->filename, nameBit);
1191 *nameBit = 0x00;
1193 len = strlenW(tmpBuf);
1194 if(fodInfos->initdir)
1195 MemFree(fodInfos->initdir);
1196 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1197 strcpyW(fodInfos->initdir, tmpBuf);
1199 handledPath = TRUE;
1200 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1201 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1203 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1206 /* 4. win98+ and win2000+ if any files of specified filter types in
1207 current directory, use it */
1208 if ( win98plus && handledPath == FALSE &&
1209 fodInfos->filter && *fodInfos->filter) {
1211 BOOL searchMore = TRUE;
1212 LPCWSTR lpstrPos = fodInfos->filter;
1213 WIN32_FIND_DATAW FindFileData;
1214 HANDLE hFind;
1216 while (searchMore)
1218 /* filter is a list... title\0ext\0......\0\0 */
1220 /* Skip the title */
1221 if(! *lpstrPos) break; /* end */
1222 lpstrPos += strlenW(lpstrPos) + 1;
1224 /* See if any files exist in the current dir with this extension */
1225 if(! *lpstrPos) break; /* end */
1227 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1229 if (hFind == INVALID_HANDLE_VALUE) {
1230 /* None found - continue search */
1231 lpstrPos += strlenW(lpstrPos) + 1;
1233 } else {
1234 searchMore = FALSE;
1236 if(fodInfos->initdir)
1237 MemFree(fodInfos->initdir);
1238 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1239 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1241 handledPath = TRUE;
1242 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1243 debugstr_w(lpstrPos));
1244 break;
1249 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1251 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1252 if (handledPath == FALSE && (win2000plus || win98plus)) {
1253 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1255 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1257 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1259 /* last fallback */
1260 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1261 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1262 } else {
1263 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1265 } else {
1266 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1268 handledPath = TRUE;
1269 } else if (handledPath==FALSE) {
1270 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1271 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1272 handledPath = TRUE;
1273 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1276 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1277 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1279 /* Must the open as read only check box be checked ?*/
1280 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1282 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1285 /* Must the open as read only check box be hidden? */
1286 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1288 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1289 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1292 /* Must the help button be hidden? */
1293 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1295 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1296 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1299 /* Resize the height, if open as read only checkbox ad help button
1300 are hidden and we are not using a custom template nor a customDialog
1302 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1303 (!(fodInfos->ofnInfos->Flags &
1304 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1305 (!fodInfos->DlgInfos.hwndCustomDlg ))
1307 RECT rectDlg, rectHelp, rectCancel;
1308 GetWindowRect(hwnd, &rectDlg);
1309 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1310 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1311 /* subtract the height of the help button plus the space between
1312 the help button and the cancel button to the height of the dialog */
1313 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1314 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1315 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1317 /* change Open to Save FIXME: use resources */
1318 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1320 SetDlgItemTextA(hwnd,IDOK,"&Save");
1321 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1323 return 0;
1326 /***********************************************************************
1327 * FILEDLG95_FillControls
1329 * WM_INITDIALOG message handler (after hook notification)
1331 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1333 LPITEMIDLIST pidlItemId = NULL;
1335 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1337 TRACE("dir=%s file=%s\n",
1338 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1340 /* Get the initial directory pidl */
1342 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1344 WCHAR path[MAX_PATH];
1346 GetCurrentDirectoryW(MAX_PATH,path);
1347 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1350 /* Initialise shell objects */
1351 FILEDLG95_SHELL_Init(hwnd);
1353 /* Initialize the Look In combo box */
1354 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1356 /* Initialize the filter combo box */
1357 FILEDLG95_FILETYPE_Init(hwnd);
1359 /* Browse to the initial directory */
1360 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1362 /* Free pidlItem memory */
1363 COMDLG32_SHFree(pidlItemId);
1365 return TRUE;
1367 /***********************************************************************
1368 * FILEDLG95_Clean
1370 * Regroups all the cleaning functions of the filedlg
1372 void FILEDLG95_Clean(HWND hwnd)
1374 FILEDLG95_FILETYPE_Clean(hwnd);
1375 FILEDLG95_LOOKIN_Clean(hwnd);
1376 FILEDLG95_SHELL_Clean(hwnd);
1378 /***********************************************************************
1379 * FILEDLG95_OnWMCommand
1381 * WM_COMMAND message handler
1383 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1385 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1386 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1387 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1389 switch(wID)
1391 /* OK button */
1392 case IDOK:
1393 FILEDLG95_OnOpen(hwnd);
1394 break;
1395 /* Cancel button */
1396 case IDCANCEL:
1397 FILEDLG95_Clean(hwnd);
1398 EndDialog(hwnd, FALSE);
1399 break;
1400 /* Filetype combo box */
1401 case IDC_FILETYPE:
1402 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1403 break;
1404 /* LookIn combo box */
1405 case IDC_LOOKIN:
1406 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1407 break;
1409 /* --- toolbar --- */
1410 /* Up folder button */
1411 case FCIDM_TB_UPFOLDER:
1412 FILEDLG95_SHELL_UpFolder(hwnd);
1413 break;
1414 /* New folder button */
1415 case FCIDM_TB_NEWFOLDER:
1416 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1417 break;
1418 /* List option button */
1419 case FCIDM_TB_SMALLICON:
1420 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1421 break;
1422 /* Details option button */
1423 case FCIDM_TB_REPORTVIEW:
1424 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1425 break;
1426 /* Details option button */
1427 case FCIDM_TB_DESKTOP:
1428 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1429 break;
1431 case IDC_FILENAME:
1432 break;
1435 /* Do not use the listview selection anymore */
1436 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1437 return 0;
1440 /***********************************************************************
1441 * FILEDLG95_OnWMGetIShellBrowser
1443 * WM_GETISHELLBROWSER message handler
1445 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1448 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1450 TRACE("\n");
1452 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1454 return TRUE;
1458 /***********************************************************************
1459 * FILEDLG95_SendFileOK
1461 * Sends the CDN_FILEOK notification if required
1463 * RETURNS
1464 * TRUE if the dialog should close
1465 * FALSE if the dialog should not be closed
1467 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1469 /* ask the hook if we can close */
1470 if(IsHooked(fodInfos))
1472 TRACE("---\n");
1473 /* First send CDN_FILEOK as MSDN doc says */
1474 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1475 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1477 TRACE("canceled\n");
1478 return FALSE;
1481 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1482 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1483 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1484 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1486 TRACE("canceled\n");
1487 return FALSE;
1490 return TRUE;
1493 /***********************************************************************
1494 * FILEDLG95_OnOpenMultipleFiles
1496 * Handles the opening of multiple files.
1498 * FIXME
1499 * check destination buffer size
1501 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1503 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1504 UINT nCount, nSizePath;
1505 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1507 TRACE("\n");
1509 if(fodInfos->unicode)
1511 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1512 ofn->lpstrFile[0] = '\0';
1514 else
1516 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1517 ofn->lpstrFile[0] = '\0';
1520 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1522 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1523 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1524 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1526 LPWSTR lpstrTemp = lpstrFileList;
1528 for ( nCount = 0; nCount < nFileCount; nCount++ )
1530 LPITEMIDLIST pidl;
1532 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1533 if (!pidl)
1535 WCHAR lpstrNotFound[100];
1536 WCHAR lpstrMsg[100];
1537 WCHAR tmp[400];
1538 WCHAR nl[] = {'\n',0};
1540 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1541 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1543 strcpyW(tmp, lpstrTemp);
1544 strcatW(tmp, nl);
1545 strcatW(tmp, lpstrNotFound);
1546 strcatW(tmp, nl);
1547 strcatW(tmp, lpstrMsg);
1549 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1550 return FALSE;
1553 /* move to the next file in the list of files */
1554 lpstrTemp += strlenW(lpstrTemp) + 1;
1555 COMDLG32_SHFree(pidl);
1559 nSizePath = strlenW(lpstrPathSpec) + 1;
1560 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1562 /* For "oldstyle" dialog the components have to
1563 be separated by blanks (not '\0'!) and short
1564 filenames have to be used! */
1565 FIXME("Components have to be separated by blanks\n");
1567 if(fodInfos->unicode)
1569 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1570 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1571 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1573 else
1575 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1577 if (ofn->lpstrFile != NULL)
1579 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1580 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1581 if (ofn->nMaxFile > nSizePath)
1583 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1584 ofn->lpstrFile + nSizePath,
1585 ofn->nMaxFile - nSizePath, NULL, NULL);
1590 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1591 fodInfos->ofnInfos->nFileExtension = 0;
1593 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1594 return FALSE;
1596 /* clean and exit */
1597 FILEDLG95_Clean(hwnd);
1598 return EndDialog(hwnd,TRUE);
1601 /***********************************************************************
1602 * FILEDLG95_OnOpen
1604 * Ok button WM_COMMAND message handler
1606 * If the function succeeds, the return value is nonzero.
1608 #define ONOPEN_BROWSE 1
1609 #define ONOPEN_OPEN 2
1610 #define ONOPEN_SEARCH 3
1611 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1613 char strMsgTitle[MAX_PATH];
1614 char strMsgText [MAX_PATH];
1615 if (idCaption)
1616 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1617 else
1618 strMsgTitle[0] = '\0';
1619 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1620 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1623 BOOL FILEDLG95_OnOpen(HWND hwnd)
1625 LPWSTR lpstrFileList;
1626 UINT nFileCount = 0;
1627 UINT sizeUsed = 0;
1628 BOOL ret = TRUE;
1629 WCHAR lpstrPathAndFile[MAX_PATH];
1630 WCHAR lpstrTemp[MAX_PATH];
1631 LPSHELLFOLDER lpsf = NULL;
1632 int nOpenAction;
1633 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1635 TRACE("hwnd=%p\n", hwnd);
1637 /* get the files from the edit control */
1638 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1640 /* try if the user selected a folder in the shellview */
1641 if(nFileCount == 0)
1643 BrowseSelectedFolder(hwnd);
1644 return FALSE;
1647 if(nFileCount > 1)
1649 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1650 goto ret;
1653 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1656 Step 1: Build a complete path name from the current folder and
1657 the filename or path in the edit box.
1658 Special cases:
1659 - the path in the edit box is a root path
1660 (with or without drive letter)
1661 - the edit box contains ".." (or a path with ".." in it)
1664 /* Get the current directory name */
1665 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1667 /* we are in a special folder, default to desktop */
1668 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1670 /* last fallback */
1671 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1674 PathAddBackslashW(lpstrPathAndFile);
1676 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1678 /* if the user specifyed a fully qualified path use it */
1679 if(PathIsRelativeW(lpstrFileList))
1681 strcatW(lpstrPathAndFile, lpstrFileList);
1683 else
1685 /* does the path have a drive letter? */
1686 if (PathGetDriveNumberW(lpstrFileList) == -1)
1687 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1688 else
1689 strcpyW(lpstrPathAndFile, lpstrFileList);
1692 /* resolve "." and ".." */
1693 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1694 strcpyW(lpstrPathAndFile, lpstrTemp);
1695 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1697 MemFree(lpstrFileList);
1700 Step 2: here we have a cleaned up path
1702 We have to parse the path step by step to see if we have to browse
1703 to a folder if the path points to a directory or the last
1704 valid element is a directory.
1706 valid variables:
1707 lpstrPathAndFile: cleaned up path
1710 nOpenAction = ONOPEN_BROWSE;
1712 /* don't apply any checks with OFN_NOVALIDATE */
1714 LPWSTR lpszTemp, lpszTemp1;
1715 LPITEMIDLIST pidl = NULL;
1716 WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1718 /* check for invalid chars */
1719 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1721 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1722 ret = FALSE;
1723 goto ret;
1726 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1728 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1729 while (lpszTemp1)
1731 LPSHELLFOLDER lpsfChild;
1732 WCHAR lpwstrTemp[MAX_PATH];
1733 DWORD dwEaten, dwAttributes;
1734 LPWSTR p;
1736 strcpyW(lpwstrTemp, lpszTemp);
1737 p = PathFindNextComponentW(lpwstrTemp);
1739 if (!p) break; /* end of path */
1741 *p = 0;
1742 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1744 if(*lpszTemp==0)
1746 WCHAR wszWild[] = { '*', '?', 0 };
1747 /* if the last element is a wildcard do a search */
1748 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1750 nOpenAction = ONOPEN_SEARCH;
1751 break;
1754 lpszTemp1 = lpszTemp;
1756 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1758 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1760 dwAttributes = SFGAO_FOLDER;
1761 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1763 /* the path component is valid, we have a pidl of the next path component */
1764 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1765 if(dwAttributes & SFGAO_FOLDER)
1767 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1769 ERR("bind to failed\n"); /* should not fail */
1770 break;
1772 IShellFolder_Release(lpsf);
1773 lpsf = lpsfChild;
1774 lpsfChild = NULL;
1776 else
1778 TRACE("value\n");
1780 /* end dialog, return value */
1781 nOpenAction = ONOPEN_OPEN;
1782 break;
1784 COMDLG32_SHFree(pidl);
1785 pidl = NULL;
1787 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1789 if(*lpszTemp) /* points to trailing null for last path element */
1791 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1793 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1794 break;
1797 else
1799 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1800 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1802 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1803 break;
1806 /* change to the current folder */
1807 nOpenAction = ONOPEN_OPEN;
1808 break;
1810 else
1812 nOpenAction = ONOPEN_OPEN;
1813 break;
1816 if(pidl) COMDLG32_SHFree(pidl);
1820 Step 3: here we have a cleaned up and validated path
1822 valid variables:
1823 lpsf: ShellFolder bound to the rightmost valid path component
1824 lpstrPathAndFile: cleaned up path
1825 nOpenAction: action to do
1827 TRACE("end validate sf=%p\n", lpsf);
1829 switch(nOpenAction)
1831 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1832 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1834 int iPos;
1835 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1836 DWORD len;
1838 /* replace the current filter */
1839 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1840 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1841 len = strlenW(lpszTemp)+1;
1842 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1843 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1845 /* set the filter cb to the extension when possible */
1846 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1847 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1849 /* fall through */
1850 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1851 TRACE("ONOPEN_BROWSE\n");
1853 IPersistFolder2 * ppf2;
1854 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1856 LPITEMIDLIST pidlCurrent;
1857 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1858 IPersistFolder2_Release(ppf2);
1859 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1861 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1863 else if( nOpenAction == ONOPEN_SEARCH )
1865 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1867 COMDLG32_SHFree(pidlCurrent);
1870 ret = FALSE;
1871 break;
1872 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1873 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1875 /* add default extension */
1876 if (fodInfos->defext)
1878 WCHAR *ext = PathFindExtensionW(lpstrPathAndFile);
1880 if (! *ext)
1882 /* only add "." in case a default extension does exist */
1883 if (*fodInfos->defext != '\0')
1885 const WCHAR szwDot[] = {'.',0};
1886 int PathLength = strlenW(lpstrPathAndFile);
1888 strcatW(lpstrPathAndFile, szwDot);
1889 strcatW(lpstrPathAndFile, fodInfos->defext);
1891 /* In Open dialog: if file does not exist try without extension */
1892 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1893 && !PathFileExistsW(lpstrPathAndFile))
1894 lpstrPathAndFile[PathLength] = '\0';
1898 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1899 if (*ext)
1900 ext++;
1901 if (!lstrcmpiW(fodInfos->defext, ext))
1902 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1903 else
1904 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1907 /* In Save dialog: check if the file already exists */
1908 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1909 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1910 && PathFileExistsW(lpstrPathAndFile))
1912 WCHAR lpstrOverwrite[100];
1913 int answer;
1915 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1916 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1917 MB_YESNO | MB_ICONEXCLAMATION);
1918 if (answer == IDNO)
1920 ret = FALSE;
1921 goto ret;
1925 /* Check that the size of the file does not exceed buffer size.
1926 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1927 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1928 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1930 LPWSTR lpszTemp;
1932 /* fill destination buffer */
1933 if (fodInfos->ofnInfos->lpstrFile)
1935 if(fodInfos->unicode)
1937 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1939 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1940 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1941 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1943 else
1945 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1947 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1948 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1949 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1950 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1954 /* set filename offset */
1955 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1956 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1958 /* set extension offset */
1959 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1960 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1962 /* set the lpstrFileTitle */
1963 if(fodInfos->ofnInfos->lpstrFileTitle)
1965 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1966 if(fodInfos->unicode)
1968 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1969 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1971 else
1973 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1974 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1975 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1979 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1980 goto ret;
1982 TRACE("close\n");
1983 FILEDLG95_Clean(hwnd);
1984 ret = EndDialog(hwnd, TRUE);
1986 else
1988 /* FIXME set error FNERR_BUFFERTOSMALL */
1989 FILEDLG95_Clean(hwnd);
1990 ret = EndDialog(hwnd, FALSE);
1992 goto ret;
1994 break;
1997 ret:
1998 if(lpsf) IShellFolder_Release(lpsf);
1999 return ret;
2002 /***********************************************************************
2003 * FILEDLG95_SHELL_Init
2005 * Initialisation of the shell objects
2007 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2009 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2011 TRACE("\n");
2014 * Initialisation of the FileOpenDialogInfos structure
2017 /* Shell */
2019 /*ShellInfos */
2020 fodInfos->ShellInfos.hwndOwner = hwnd;
2022 /* Disable multi-select if flag not set */
2023 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2025 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2027 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2028 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2030 /* Construct the IShellBrowser interface */
2031 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2033 return NOERROR;
2036 /***********************************************************************
2037 * FILEDLG95_SHELL_ExecuteCommand
2039 * Change the folder option and refresh the view
2040 * If the function succeeds, the return value is nonzero.
2042 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2044 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2046 IContextMenu * pcm;
2047 TRACE("(%p,%p)\n", hwnd, lpVerb);
2049 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2050 SVGIO_BACKGROUND,
2051 &IID_IContextMenu,
2052 (LPVOID*)&pcm)))
2054 CMINVOKECOMMANDINFO ci;
2055 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2056 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2057 ci.lpVerb = lpVerb;
2058 ci.hwnd = hwnd;
2060 IContextMenu_InvokeCommand(pcm, &ci);
2061 IContextMenu_Release(pcm);
2064 return FALSE;
2067 /***********************************************************************
2068 * FILEDLG95_SHELL_UpFolder
2070 * Browse to the specified object
2071 * If the function succeeds, the return value is nonzero.
2073 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2075 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2077 TRACE("\n");
2079 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2080 NULL,
2081 SBSP_PARENT)))
2083 return TRUE;
2085 return FALSE;
2088 /***********************************************************************
2089 * FILEDLG95_SHELL_BrowseToDesktop
2091 * Browse to the Desktop
2092 * If the function succeeds, the return value is nonzero.
2094 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2096 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2097 LPITEMIDLIST pidl;
2098 HRESULT hres;
2100 TRACE("\n");
2102 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2103 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2104 COMDLG32_SHFree(pidl);
2105 return SUCCEEDED(hres);
2107 /***********************************************************************
2108 * FILEDLG95_SHELL_Clean
2110 * Cleans the memory used by shell objects
2112 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2114 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2116 TRACE("\n");
2118 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2120 /* clean Shell interfaces */
2121 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2122 IShellView_Release(fodInfos->Shell.FOIShellView);
2123 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2124 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2125 if (fodInfos->Shell.FOIDataObject)
2126 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2129 /***********************************************************************
2130 * FILEDLG95_FILETYPE_Init
2132 * Initialisation of the file type combo box
2134 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2136 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2138 TRACE("\n");
2140 if(fodInfos->filter)
2142 int nFilters = 0; /* number of filters */
2143 LPWSTR lpstrFilter;
2144 LPCWSTR lpstrPos = fodInfos->filter;
2146 for(;;)
2148 /* filter is a list... title\0ext\0......\0\0
2149 * Set the combo item text to the title and the item data
2150 * to the ext
2152 LPCWSTR lpstrDisplay;
2153 LPWSTR lpstrExt;
2155 /* Get the title */
2156 if(! *lpstrPos) break; /* end */
2157 lpstrDisplay = lpstrPos;
2158 lpstrPos += strlenW(lpstrPos) + 1;
2160 /* Copy the extensions */
2161 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2162 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2163 strcpyW(lpstrExt,lpstrPos);
2164 lpstrPos += strlenW(lpstrPos) + 1;
2166 /* Add the item at the end of the combo */
2167 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2168 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2169 nFilters++;
2172 * Set the current filter to the one specified
2173 * in the initialisation structure
2174 * FIXME: lpstrCustomFilter not handled at all
2177 /* set default filter index */
2178 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2179 fodInfos->ofnInfos->nFilterIndex = 1;
2181 /* First, check to make sure our index isn't out of bounds. */
2182 if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
2183 fodInfos->ofnInfos->nFilterIndex = nFilters;
2185 /* Set the current index selection. */
2186 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
2188 /* Get the corresponding text string from the combo box. */
2189 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2190 fodInfos->ofnInfos->nFilterIndex-1);
2192 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2193 lpstrFilter = NULL;
2195 if(lpstrFilter)
2197 DWORD len;
2198 CharLowerW(lpstrFilter); /* lowercase */
2199 len = strlenW(lpstrFilter)+1;
2200 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2201 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2204 return NOERROR;
2207 /***********************************************************************
2208 * FILEDLG95_FILETYPE_OnCommand
2210 * WM_COMMAND of the file type combo box
2211 * If the function succeeds, the return value is nonzero.
2213 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2215 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2217 switch(wNotifyCode)
2219 case CBN_SELENDOK:
2221 LPWSTR lpstrFilter;
2223 /* Get the current item of the filetype combo box */
2224 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2226 /* set the current filter index - indexed from 1 */
2227 fodInfos->ofnInfos->nFilterIndex = iItem + 1;
2229 /* Set the current filter with the current selection */
2230 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2231 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2233 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2234 iItem);
2235 if((int)lpstrFilter != CB_ERR)
2237 DWORD len;
2238 CharLowerW(lpstrFilter); /* lowercase */
2239 len = strlenW(lpstrFilter)+1;
2240 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2241 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2242 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2245 /* Refresh the actual view to display the included items*/
2246 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2249 return FALSE;
2251 /***********************************************************************
2252 * FILEDLG95_FILETYPE_SearchExt
2254 * searches for a extension in the filetype box
2256 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2258 int i, iCount = CBGetCount(hwnd);
2260 TRACE("%s\n", debugstr_w(lpstrExt));
2262 if(iCount != CB_ERR)
2264 for(i=0;i<iCount;i++)
2266 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2267 return i;
2270 return -1;
2273 /***********************************************************************
2274 * FILEDLG95_FILETYPE_Clean
2276 * Clean the memory used by the filetype combo box
2278 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2280 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2281 int iPos;
2282 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2284 TRACE("\n");
2286 /* Delete each string of the combo and their associated data */
2287 if(iCount != CB_ERR)
2289 for(iPos = iCount-1;iPos>=0;iPos--)
2291 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2292 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2295 /* Current filter */
2296 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2297 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2301 /***********************************************************************
2302 * FILEDLG95_LOOKIN_Init
2304 * Initialisation of the look in combo box
2306 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2308 IShellFolder *psfRoot, *psfDrives;
2309 IEnumIDList *lpeRoot, *lpeDrives;
2310 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2312 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2314 TRACE("\n");
2316 liInfos->iMaxIndentation = 0;
2318 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2320 /* set item height for both text field and listbox */
2321 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2322 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2324 /* Turn on the extended UI for the combo box like Windows does */
2325 CBSetExtendedUI(hwndCombo, TRUE);
2327 /* Initialise data of Desktop folder */
2328 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2329 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2330 COMDLG32_SHFree(pidlTmp);
2332 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2334 SHGetDesktopFolder(&psfRoot);
2336 if (psfRoot)
2338 /* enumerate the contents of the desktop */
2339 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2341 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2343 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2345 /* special handling for CSIDL_DRIVES */
2346 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2348 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2350 /* enumerate the drives */
2351 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2353 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2355 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2356 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2357 COMDLG32_SHFree(pidlAbsTmp);
2358 COMDLG32_SHFree(pidlTmp1);
2360 IEnumIDList_Release(lpeDrives);
2362 IShellFolder_Release(psfDrives);
2365 COMDLG32_SHFree(pidlTmp);
2367 IEnumIDList_Release(lpeRoot);
2369 IShellFolder_Release(psfRoot);
2372 COMDLG32_SHFree(pidlDrives);
2373 return NOERROR;
2376 /***********************************************************************
2377 * FILEDLG95_LOOKIN_DrawItem
2379 * WM_DRAWITEM message handler
2381 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2383 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2384 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2385 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2386 RECT rectText;
2387 RECT rectIcon;
2388 SHFILEINFOA sfi;
2389 HIMAGELIST ilItemImage;
2390 int iIndentation;
2391 TEXTMETRICA tm;
2392 LPSFOLDER tmpFolder;
2395 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2397 TRACE("\n");
2399 if(pDIStruct->itemID == -1)
2400 return 0;
2402 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2403 pDIStruct->itemID)))
2404 return 0;
2407 if(pDIStruct->itemID == liInfos->uSelectedItem)
2409 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2411 &sfi,
2412 sizeof (SHFILEINFOA),
2413 SHGFI_PIDL | SHGFI_SMALLICON |
2414 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2415 SHGFI_DISPLAYNAME );
2417 else
2419 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2421 &sfi,
2422 sizeof (SHFILEINFOA),
2423 SHGFI_PIDL | SHGFI_SMALLICON |
2424 SHGFI_SYSICONINDEX |
2425 SHGFI_DISPLAYNAME);
2428 /* Is this item selected ? */
2429 if(pDIStruct->itemState & ODS_SELECTED)
2431 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2432 SetBkColor(pDIStruct->hDC,crHighLight);
2433 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2435 else
2437 SetTextColor(pDIStruct->hDC,crText);
2438 SetBkColor(pDIStruct->hDC,crWin);
2439 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2442 /* Do not indent item if drawing in the edit of the combo */
2443 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2445 iIndentation = 0;
2446 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2448 &sfi,
2449 sizeof (SHFILEINFOA),
2450 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2451 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2454 else
2456 iIndentation = tmpFolder->m_iIndent;
2458 /* Draw text and icon */
2460 /* Initialise the icon display area */
2461 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2462 rectIcon.top = pDIStruct->rcItem.top;
2463 rectIcon.right = rectIcon.left + ICONWIDTH;
2464 rectIcon.bottom = pDIStruct->rcItem.bottom;
2466 /* Initialise the text display area */
2467 GetTextMetricsA(pDIStruct->hDC, &tm);
2468 rectText.left = rectIcon.right;
2469 rectText.top =
2470 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2471 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2472 rectText.bottom =
2473 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2475 /* Draw the icon from the image list */
2476 ImageList_Draw(ilItemImage,
2477 sfi.iIcon,
2478 pDIStruct->hDC,
2479 rectIcon.left,
2480 rectIcon.top,
2481 ILD_TRANSPARENT );
2483 /* Draw the associated text */
2484 if(sfi.szDisplayName)
2485 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2488 return NOERROR;
2491 /***********************************************************************
2492 * FILEDLG95_LOOKIN_OnCommand
2494 * LookIn combo box WM_COMMAND message handler
2495 * If the function succeeds, the return value is nonzero.
2497 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2499 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2501 TRACE("%p\n", fodInfos);
2503 switch(wNotifyCode)
2505 case CBN_SELENDOK:
2507 LPSFOLDER tmpFolder;
2508 int iItem;
2510 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2512 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2513 iItem)))
2514 return FALSE;
2517 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2518 tmpFolder->pidlItem,
2519 SBSP_ABSOLUTE)))
2521 return TRUE;
2523 break;
2527 return FALSE;
2530 /***********************************************************************
2531 * FILEDLG95_LOOKIN_AddItem
2533 * Adds an absolute pidl item to the lookin combo box
2534 * returns the index of the inserted item
2536 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2538 LPITEMIDLIST pidlNext;
2539 SHFILEINFOA sfi;
2540 SFOLDER *tmpFolder;
2541 LookInInfos *liInfos;
2543 TRACE("%08x\n", iInsertId);
2545 if(!pidl)
2546 return -1;
2548 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2549 return -1;
2551 tmpFolder = MemAlloc(sizeof(SFOLDER));
2552 tmpFolder->m_iIndent = 0;
2554 /* Calculate the indentation of the item in the lookin*/
2555 pidlNext = pidl;
2556 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2558 tmpFolder->m_iIndent++;
2561 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2563 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2564 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2566 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2567 SHGetFileInfoA((LPSTR)pidl,
2569 &sfi,
2570 sizeof(sfi),
2571 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2572 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2574 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2576 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2578 int iItemID;
2580 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2582 /* Add the item at the end of the list */
2583 if(iInsertId < 0)
2585 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2587 /* Insert the item at the iInsertId position*/
2588 else
2590 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2593 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2594 return iItemID;
2597 COMDLG32_SHFree( tmpFolder->pidlItem );
2598 MemFree( tmpFolder );
2599 return -1;
2603 /***********************************************************************
2604 * FILEDLG95_LOOKIN_InsertItemAfterParent
2606 * Insert an item below its parent
2608 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2611 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2612 int iParentPos;
2614 TRACE("\n");
2616 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2618 if(iParentPos < 0)
2620 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2623 /* Free pidlParent memory */
2624 COMDLG32_SHFree((LPVOID)pidlParent);
2626 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2629 /***********************************************************************
2630 * FILEDLG95_LOOKIN_SelectItem
2632 * Adds an absolute pidl item to the lookin combo box
2633 * returns the index of the inserted item
2635 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2637 int iItemPos;
2638 LookInInfos *liInfos;
2640 TRACE("\n");
2642 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2644 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2646 if(iItemPos < 0)
2648 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2649 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2652 else
2654 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2655 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2657 int iRemovedItem;
2659 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2660 break;
2661 if(iRemovedItem < iItemPos)
2662 iItemPos--;
2666 CBSetCurSel(hwnd,iItemPos);
2667 liInfos->uSelectedItem = iItemPos;
2669 return 0;
2673 /***********************************************************************
2674 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2676 * Remove the item with an expansion level over iExpansionLevel
2678 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2680 int iItemPos;
2682 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2684 TRACE("\n");
2686 if(liInfos->iMaxIndentation <= 2)
2687 return -1;
2689 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2691 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2692 COMDLG32_SHFree(tmpFolder->pidlItem);
2693 MemFree(tmpFolder);
2694 CBDeleteString(hwnd,iItemPos);
2695 liInfos->iMaxIndentation--;
2697 return iItemPos;
2700 return -1;
2703 /***********************************************************************
2704 * FILEDLG95_LOOKIN_SearchItem
2706 * Search for pidl in the lookin combo box
2707 * returns the index of the found item
2709 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2711 int i = 0;
2712 int iCount = CBGetCount(hwnd);
2714 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2716 if (iCount != CB_ERR)
2718 for(;i<iCount;i++)
2720 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2722 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2723 return i;
2724 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2725 return i;
2729 return -1;
2732 /***********************************************************************
2733 * FILEDLG95_LOOKIN_Clean
2735 * Clean the memory used by the lookin combo box
2737 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2739 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2740 int iPos;
2741 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2743 TRACE("\n");
2745 /* Delete each string of the combo and their associated data */
2746 if (iCount != CB_ERR)
2748 for(iPos = iCount-1;iPos>=0;iPos--)
2750 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2751 COMDLG32_SHFree(tmpFolder->pidlItem);
2752 MemFree(tmpFolder);
2753 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2757 /* LookInInfos structure */
2758 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2761 /***********************************************************************
2762 * FILEDLG95_FILENAME_FillFromSelection
2764 * fills the edit box from the cached DataObject
2766 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2768 FileOpenDlgInfos *fodInfos;
2769 LPITEMIDLIST pidl;
2770 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2771 char lpstrTemp[MAX_PATH];
2772 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2774 TRACE("\n");
2775 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2777 /* Count how many files we have */
2778 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2780 /* calculate the string length, count files */
2781 if (nFileSelected >= 1)
2783 nLength += 3; /* first and last quotes, trailing \0 */
2784 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2786 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2788 if (pidl)
2790 /* get the total length of the selected file names */
2791 lpstrTemp[0] = '\0';
2792 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2794 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2796 nLength += strlen( lpstrTemp ) + 3;
2797 nFiles++;
2799 COMDLG32_SHFree( pidl );
2804 /* allocate the buffer */
2805 if (nFiles <= 1) nLength = MAX_PATH;
2806 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2807 lpstrAllFile[0] = '\0';
2809 /* Generate the string for the edit control */
2810 if(nFiles >= 1)
2812 lpstrCurrFile = lpstrAllFile;
2813 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2815 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2817 if (pidl)
2819 /* get the file name */
2820 lpstrTemp[0] = '\0';
2821 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2823 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2825 if ( nFiles > 1)
2827 *lpstrCurrFile++ = '\"';
2828 strcpy( lpstrCurrFile, lpstrTemp );
2829 lpstrCurrFile += strlen( lpstrTemp );
2830 strcpy( lpstrCurrFile, "\" " );
2831 lpstrCurrFile += 2;
2833 else
2835 strcpy( lpstrAllFile, lpstrTemp );
2838 COMDLG32_SHFree( (LPVOID) pidl );
2841 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2843 /* Select the file name like Windows does */
2844 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2846 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2850 /* copied from shell32 to avoid linking to it */
2851 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2853 switch (src->uType)
2855 case STRRET_WSTR:
2856 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2857 COMDLG32_SHFree(src->u.pOleStr);
2858 break;
2860 case STRRET_CSTR:
2861 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2862 break;
2864 case STRRET_OFFSET:
2865 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2866 break;
2868 default:
2869 FIXME("unknown type!\n");
2870 if (len)
2872 *(LPSTR)dest = '\0';
2874 return(FALSE);
2876 return S_OK;
2879 /***********************************************************************
2880 * FILEDLG95_FILENAME_GetFileNames
2882 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2884 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2886 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2887 UINT nStrCharCount = 0; /* index in src buffer */
2888 UINT nFileIndex = 0; /* index in dest buffer */
2889 UINT nFileCount = 0; /* number of files */
2890 UINT nStrLen = 0; /* length of string in edit control */
2891 LPWSTR lpstrEdit; /* buffer for string from edit control */
2893 TRACE("\n");
2895 /* get the filenames from the edit control */
2896 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2897 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2898 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2900 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2902 /* we might get single filename without any '"',
2903 * so we need nStrLen + terminating \0 + end-of-list \0 */
2904 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2905 *sizeUsed = 0;
2907 /* build 0-delimited file list from filenames */
2908 while ( nStrCharCount <= nStrLen )
2910 if ( lpstrEdit[nStrCharCount]=='"' )
2912 nStrCharCount++;
2913 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2915 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2916 (*sizeUsed)++;
2917 nStrCharCount++;
2919 (*lpstrFileList)[nFileIndex++] = '\0';
2920 (*sizeUsed)++;
2921 nFileCount++;
2923 nStrCharCount++;
2926 /* single, unquoted string */
2927 if ((nStrLen > 0) && (*sizeUsed == 0) )
2929 strcpyW(*lpstrFileList, lpstrEdit);
2930 nFileIndex = strlenW(lpstrEdit) + 1;
2931 (*sizeUsed) = nFileIndex;
2932 nFileCount = 1;
2935 /* trailing \0 */
2936 (*lpstrFileList)[nFileIndex] = '\0';
2937 (*sizeUsed)++;
2939 MemFree(lpstrEdit);
2940 return nFileCount;
2943 #define SETDefFormatEtc(fe,cf,med) \
2945 (fe).cfFormat = cf;\
2946 (fe).dwAspect = DVASPECT_CONTENT; \
2947 (fe).ptd =NULL;\
2948 (fe).tymed = med;\
2949 (fe).lindex = -1;\
2953 * DATAOBJECT Helper functions
2956 /***********************************************************************
2957 * COMCTL32_ReleaseStgMedium
2959 * like ReleaseStgMedium from ole32
2961 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2963 if(medium.pUnkForRelease)
2965 IUnknown_Release(medium.pUnkForRelease);
2967 else
2969 GlobalUnlock(medium.u.hGlobal);
2970 GlobalFree(medium.u.hGlobal);
2974 /***********************************************************************
2975 * GetPidlFromDataObject
2977 * Return pidl(s) by number from the cached DataObject
2979 * nPidlIndex=0 gets the fully qualified root path
2981 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2984 STGMEDIUM medium;
2985 FORMATETC formatetc;
2986 LPITEMIDLIST pidl = NULL;
2988 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
2990 /* Set the FORMATETC structure*/
2991 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2993 /* Get the pidls from IDataObject */
2994 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2996 LPIDA cida = GlobalLock(medium.u.hGlobal);
2997 if(nPidlIndex <= cida->cidl)
2999 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3001 COMCTL32_ReleaseStgMedium(medium);
3003 return pidl;
3006 /***********************************************************************
3007 * GetNumSelected
3009 * Return the number of selected items in the DataObject.
3012 UINT GetNumSelected( IDataObject *doSelected )
3014 UINT retVal = 0;
3015 STGMEDIUM medium;
3016 FORMATETC formatetc;
3018 TRACE("sv=%p\n", doSelected);
3020 if (!doSelected) return 0;
3022 /* Set the FORMATETC structure*/
3023 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3025 /* Get the pidls from IDataObject */
3026 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3028 LPIDA cida = GlobalLock(medium.u.hGlobal);
3029 retVal = cida->cidl;
3030 COMCTL32_ReleaseStgMedium(medium);
3031 return retVal;
3033 return 0;
3037 * TOOLS
3040 /***********************************************************************
3041 * GetName
3043 * Get the pidl's display name (relative to folder) and
3044 * put it in lpstrFileName.
3046 * Return NOERROR on success,
3047 * E_FAIL otherwise
3050 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3052 STRRET str;
3053 HRESULT hRes;
3055 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3057 if(!lpsf)
3059 HRESULT hRes;
3060 SHGetDesktopFolder(&lpsf);
3061 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3062 IShellFolder_Release(lpsf);
3063 return hRes;
3066 /* Get the display name of the pidl relative to the folder */
3067 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3069 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3071 return E_FAIL;
3074 /***********************************************************************
3075 * GetShellFolderFromPidl
3077 * pidlRel is the item pidl relative
3078 * Return the IShellFolder of the absolute pidl
3080 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3082 IShellFolder *psf = NULL,*psfParent;
3084 TRACE("%p\n", pidlAbs);
3086 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3088 psf = psfParent;
3089 if(pidlAbs && pidlAbs->mkid.cb)
3091 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3093 IShellFolder_Release(psfParent);
3094 return psf;
3097 /* return the desktop */
3098 return psfParent;
3100 return NULL;
3103 /***********************************************************************
3104 * GetParentPidl
3106 * Return the LPITEMIDLIST to the parent of the pidl in the list
3108 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3110 LPITEMIDLIST pidlParent;
3112 TRACE("%p\n", pidl);
3114 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3115 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3117 return pidlParent;
3120 /***********************************************************************
3121 * GetPidlFromName
3123 * returns the pidl of the file name relative to folder
3124 * NULL if an error occurred
3126 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3128 LPITEMIDLIST pidl = NULL;
3129 ULONG ulEaten;
3131 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3133 if(!lpcstrFileName) return NULL;
3134 if(!*lpcstrFileName) return NULL;
3136 if(!lpsf)
3138 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3139 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3140 IShellFolder_Release(lpsf);
3143 else
3145 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3147 return pidl;
3152 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3154 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3155 HRESULT ret;
3157 TRACE("%p, %p\n", psf, pidl);
3159 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3161 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3162 /* see documentation shell 4.1*/
3163 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3166 /***********************************************************************
3167 * BrowseSelectedFolder
3169 static BOOL BrowseSelectedFolder(HWND hwnd)
3171 BOOL bBrowseSelFolder = FALSE;
3172 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3174 TRACE("\n");
3176 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3178 LPITEMIDLIST pidlSelection;
3180 /* get the file selected */
3181 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3182 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3184 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3185 pidlSelection, SBSP_RELATIVE ) ) )
3187 WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3188 ' ','n','o','t',' ','e','x','i','s','t',0};
3189 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3192 bBrowseSelFolder = TRUE;
3194 COMDLG32_SHFree( pidlSelection );
3197 return bBrowseSelFolder;
3201 * Memory allocation methods */
3202 static void *MemAlloc(UINT size)
3204 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3207 static void MemFree(void *mem)
3209 if(mem)
3211 HeapFree(GetProcessHeap(),0,mem);
3215 /* ------------------ APIs ---------------------- */
3217 /***********************************************************************
3218 * GetOpenFileNameA (COMDLG32.@)
3220 * Creates a dialog box for the user to select a file to open.
3222 * RETURNS
3223 * TRUE on success: user enters a valid file
3224 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3227 BOOL WINAPI GetOpenFileNameA(
3228 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3230 return GetFileDialog95A(ofn, OPEN_DIALOG);
3233 /***********************************************************************
3234 * GetOpenFileNameW (COMDLG32.@)
3236 * Creates a dialog box for the user to select a file to open.
3238 * RETURNS
3239 * TRUE on success: user enters a valid file
3240 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3243 BOOL WINAPI GetOpenFileNameW(
3244 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3246 return GetFileDialog95W(ofn, OPEN_DIALOG);
3249 /***********************************************************************
3250 * GetSaveFileNameA (COMDLG32.@)
3252 * Creates a dialog box for the user to select a file to save.
3254 * RETURNS
3255 * TRUE on success: user enters a valid file
3256 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3259 BOOL WINAPI GetSaveFileNameA(
3260 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3262 return GetFileDialog95A(ofn, SAVE_DIALOG);
3265 /***********************************************************************
3266 * GetSaveFileNameW (COMDLG32.@)
3268 * Creates a dialog box for the user to select a file to save.
3270 * RETURNS
3271 * TRUE on success: user enters a valid file
3272 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3275 BOOL WINAPI GetSaveFileNameW(
3276 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3278 return GetFileDialog95W(ofn, SAVE_DIALOG);