Change the ARTS_Init() error message from an ERR() to a WARN() since
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blob86b98a13c65888291475f4f91580e6dbbccfc6f8
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: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winreg.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wine/unicode.h"
66 #include "wingdi.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "wine/debug.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlguid.h"
75 #include "shlobj.h"
76 #include "filedlgbrowser.h"
77 #include "shlwapi.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
83 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
84 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
87 #define IsHooked(fodInfos) \
88 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
89 /***********************************************************************
90 * Data structure and global variables
92 typedef struct SFolder
94 int m_iImageIndex; /* Index of picture in image list */
95 HIMAGELIST hImgList;
96 int m_iIndent; /* Indentation index */
97 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
99 } SFOLDER,*LPSFOLDER;
101 typedef struct tagLookInInfo
103 int iMaxIndentation;
104 UINT uSelectedItem;
105 } LookInInfos;
108 /***********************************************************************
109 * Defines and global variables
112 /* Draw item constant */
113 #define ICONWIDTH 18
114 #define XTEXTOFFSET 3
116 /* AddItem flags*/
117 #define LISTEND -1
119 /* SearchItem methods */
120 #define SEARCH_PIDL 1
121 #define SEARCH_EXP 2
122 #define ITEM_NOTFOUND -1
124 /* Undefined windows message sent by CreateViewObject*/
125 #define WM_GETISHELLBROWSER WM_USER+7
127 /* NOTE
128 * Those macros exist in windowsx.h. However, you can't really use them since
129 * they rely on the UNICODE defines and can't be used inside Wine itself.
132 /* Combo box macros */
133 #define CBAddString(hwnd,str) \
134 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
135 #define CBAddStringW(hwnd,str) \
136 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
138 #define CBInsertString(hwnd,str,pos) \
139 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
141 #define CBDeleteString(hwnd,pos) \
142 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
144 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
145 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
147 #define CBGetItemDataPtr(hwnd,iItemId) \
148 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
150 #define CBGetLBText(hwnd,iItemId,str) \
151 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
153 #define CBGetCurSel(hwnd) \
154 SendMessageA(hwnd,CB_GETCURSEL,0,0);
156 #define CBSetCurSel(hwnd,pos) \
157 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
159 #define CBGetCount(hwnd) \
160 SendMessageA(hwnd,CB_GETCOUNT,0,0);
161 #define CBShowDropDown(hwnd,show) \
162 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
163 #define CBSetItemHeight(hwnd,index,height) \
164 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
166 #define CBSetExtendedUI(hwnd,flag) \
167 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
169 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
170 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
172 /***********************************************************************
173 * Prototypes
176 /* Internal functions used by the dialog */
177 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
178 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
179 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
180 BOOL FILEDLG95_OnOpen(HWND hwnd);
181 static LRESULT FILEDLG95_InitControls(HWND hwnd);
182 static void FILEDLG95_Clean(HWND hwnd);
184 /* Functions used by the shell navigation */
185 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
186 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
187 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
188 static void FILEDLG95_SHELL_Clean(HWND hwnd);
189 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
191 /* Functions used by the filetype combo box */
192 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
193 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
194 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
195 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
197 /* Functions used by the Look In combo box */
198 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
199 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
200 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
201 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
202 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
203 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
204 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
205 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
206 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
208 /* Miscellaneous tool functions */
209 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
210 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
211 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
212 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
213 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
215 /* Shell memory allocation */
216 static void *MemAlloc(UINT size);
217 static void MemFree(void *mem);
219 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
220 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
221 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
222 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
223 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
224 static BOOL BrowseSelectedFolder(HWND hwnd);
226 /* old style dialogs */
227 extern BOOL GetFileName31A(LPOPENFILENAMEA lpofn, UINT dlgType);
228 extern BOOL GetFileName31W(LPOPENFILENAMEW lpofn, UINT dlgType);
230 /***********************************************************************
231 * GetFileName95
233 * Creates an Open common dialog box that lets the user select
234 * the drive, directory, and the name of a file or set of files to open.
236 * IN : The FileOpenDlgInfos structure associated with the dialog
237 * OUT : TRUE on success
238 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
240 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
243 LRESULT lRes;
244 LPCVOID template;
245 HRSRC hRes;
246 HANDLE hDlgTmpl = 0;
248 /* test for missing functionality */
249 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
251 FIXME("Flags 0x%08lx not yet implemented\n",
252 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
255 /* Create the dialog from a template */
257 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
259 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
260 return FALSE;
262 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
263 !(template = LockResource( hDlgTmpl )))
265 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
266 return FALSE;
269 /* old style hook messages */
270 if (IsHooked(fodInfos))
272 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
273 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
274 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
275 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
278 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
279 (LPDLGTEMPLATEA) template,
280 fodInfos->ofnInfos->hwndOwner,
281 FileOpenDlgProc95,
282 (LPARAM) fodInfos);
284 /* Unable to create the dialog */
285 if( lRes == -1)
286 return FALSE;
288 return lRes;
291 /***********************************************************************
292 * GetFileDialog95A
294 * Call GetFileName95 with this structure and clean the memory.
296 * IN : The OPENFILENAMEA initialisation structure passed to
297 * GetOpenFileNameA win api function (see filedlg.c)
299 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
301 BOOL ret;
302 FileOpenDlgInfos fodInfos;
303 LPSTR lpstrSavDir = NULL;
304 LPWSTR title = NULL;
305 LPWSTR defext = NULL;
306 LPWSTR filter = NULL;
307 LPWSTR customfilter = NULL;
309 /* Initialize FileOpenDlgInfos structure */
310 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
312 /* Pass in the original ofn */
313 fodInfos.ofnInfos = ofn;
315 /* save current directory */
316 if (ofn->Flags & OFN_NOCHANGEDIR)
318 lpstrSavDir = MemAlloc(MAX_PATH);
319 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
322 fodInfos.unicode = FALSE;
324 /* convert all the input strings to unicode */
325 if(ofn->lpstrInitialDir)
327 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
328 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
329 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
331 else
332 fodInfos.initdir = NULL;
334 if(ofn->lpstrFile)
336 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
337 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
339 else
340 fodInfos.filename = NULL;
342 if(ofn->lpstrDefExt)
344 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
345 defext = MemAlloc((len+1)*sizeof(WCHAR));
346 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
348 fodInfos.defext = defext;
350 if(ofn->lpstrTitle)
352 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
353 title = MemAlloc((len+1)*sizeof(WCHAR));
354 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
356 fodInfos.title = title;
358 if (ofn->lpstrFilter)
360 LPCSTR s;
361 int n, len;
363 /* filter is a list... title\0ext\0......\0\0 */
364 s = ofn->lpstrFilter;
365 while (*s) s = s+strlen(s)+1;
366 s++;
367 n = s - ofn->lpstrFilter;
368 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
369 filter = MemAlloc(len*sizeof(WCHAR));
370 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
372 fodInfos.filter = filter;
374 /* convert lpstrCustomFilter */
375 if (ofn->lpstrCustomFilter)
377 LPCSTR s;
378 int n, len;
380 /* customfilter contains a pair of strings... title\0ext\0 */
381 s = ofn->lpstrCustomFilter;
382 if (*s) s = s+strlen(s)+1;
383 if (*s) s = s+strlen(s)+1;
384 n = s - ofn->lpstrCustomFilter;
385 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
386 customfilter = MemAlloc(len*sizeof(WCHAR));
387 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
389 fodInfos.customfilter = customfilter;
391 /* Initialize the dialog property */
392 fodInfos.DlgInfos.dwDlgProp = 0;
393 fodInfos.DlgInfos.hwndCustomDlg = NULL;
395 switch(iDlgType)
397 case OPEN_DIALOG :
398 ret = GetFileName95(&fodInfos);
399 break;
400 case SAVE_DIALOG :
401 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
402 ret = GetFileName95(&fodInfos);
403 break;
404 default :
405 ret = 0;
408 if (lpstrSavDir)
410 SetCurrentDirectoryA(lpstrSavDir);
411 MemFree(lpstrSavDir);
414 if(title)
415 MemFree(title);
416 if(defext)
417 MemFree(defext);
418 if(filter)
419 MemFree(filter);
420 if(customfilter)
421 MemFree(customfilter);
422 if(fodInfos.initdir)
423 MemFree(fodInfos.initdir);
425 if(fodInfos.filename)
426 MemFree(fodInfos.filename);
428 TRACE("selected file: %s\n",ofn->lpstrFile);
430 return ret;
433 /***********************************************************************
434 * GetFileDialog95W
436 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
437 * Call GetFileName95 with this structure and clean the memory.
440 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
442 BOOL ret;
443 FileOpenDlgInfos fodInfos;
444 LPSTR lpstrSavDir = NULL;
446 /* Initialize FileOpenDlgInfos structure */
447 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
449 /* Pass in the original ofn */
450 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
452 fodInfos.title = ofn->lpstrTitle;
453 fodInfos.defext = ofn->lpstrDefExt;
454 fodInfos.filter = ofn->lpstrFilter;
455 fodInfos.customfilter = ofn->lpstrCustomFilter;
457 /* convert string arguments, save others */
458 if(ofn->lpstrFile)
460 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
461 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
463 else
464 fodInfos.filename = NULL;
466 if(ofn->lpstrInitialDir)
468 DWORD len = strlenW(ofn->lpstrInitialDir);
469 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
470 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
472 else
473 fodInfos.initdir = NULL;
475 /* save current directory */
476 if (ofn->Flags & OFN_NOCHANGEDIR)
478 lpstrSavDir = MemAlloc(MAX_PATH);
479 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
482 fodInfos.unicode = TRUE;
484 switch(iDlgType)
486 case OPEN_DIALOG :
487 ret = GetFileName95(&fodInfos);
488 break;
489 case SAVE_DIALOG :
490 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
491 ret = GetFileName95(&fodInfos);
492 break;
493 default :
494 ret = 0;
497 if (lpstrSavDir)
499 SetCurrentDirectoryA(lpstrSavDir);
500 MemFree(lpstrSavDir);
503 /* restore saved IN arguments and convert OUT arguments back */
504 MemFree(fodInfos.filename);
505 MemFree(fodInfos.initdir);
506 return ret;
509 /***********************************************************************
510 * ArrangeCtrlPositions [internal]
512 * NOTE: Do not change anything here without a lot of testing.
514 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
516 HWND hwndChild, hwndStc32;
517 RECT rectParent, rectChild, rectStc32;
518 INT help_fixup = 0;
520 /* Take into account if open as read only checkbox and help button
521 * are hidden
523 if (hide_help)
525 RECT rectHelp, rectCancel;
526 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
527 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
528 /* subtract the height of the help button plus the space between
529 * the help button and the cancel button to the height of the dialog
531 help_fixup = rectHelp.bottom - rectCancel.bottom;
535 There are two possibilities to add components to the default file dialog box.
537 By default, all the new components are added below the standard dialog box (the else case).
539 However, if there is a static text component with the stc32 id, a special case happens.
540 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
541 in the window and the cx and cy indicate how to size the window.
542 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
543 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
547 GetClientRect(hwndParentDlg, &rectParent);
549 /* when arranging controls we have to use fixed parent size */
550 rectParent.bottom -= help_fixup;
552 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
553 if (hwndStc32)
555 GetWindowRect(hwndStc32, &rectStc32);
556 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
558 /* set the size of the stc32 control according to the size of
559 * client area of the parent dialog
561 SetWindowPos(hwndStc32, 0,
562 0, 0,
563 rectParent.right, rectParent.bottom,
564 SWP_NOMOVE | SWP_NOZORDER);
566 else
567 SetRectEmpty(&rectStc32);
569 /* this part moves controls of the child dialog */
570 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
571 while (hwndChild)
573 if (hwndChild != hwndStc32)
575 GetWindowRect(hwndChild, &rectChild);
576 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
578 /* move only if stc32 exist */
579 if (hwndStc32 && rectChild.left > rectStc32.right)
581 /* move to the right of visible controls of the parent dialog */
582 rectChild.left += rectParent.right;
583 rectChild.left -= rectStc32.right;
585 /* move even if stc32 doesn't exist */
586 if (rectChild.top > rectStc32.bottom)
588 /* move below visible controls of the parent dialog */
589 rectChild.top += rectParent.bottom;
590 rectChild.top -= rectStc32.bottom - rectStc32.top;
593 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
594 0, 0, SWP_NOSIZE | SWP_NOZORDER);
596 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
599 /* this part moves controls of the parent dialog */
600 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
601 while (hwndChild)
603 if (hwndChild != hwndChildDlg)
605 GetWindowRect(hwndChild, &rectChild);
606 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
608 /* left,top of stc32 marks the position of controls
609 * from the parent dialog
611 rectChild.left += rectStc32.left;
612 rectChild.top += rectStc32.top;
614 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
615 0, 0, SWP_NOSIZE | SWP_NOZORDER);
617 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
620 /* calculate the size of the resulting dialog */
622 /* here we have to use original parent size */
623 GetClientRect(hwndParentDlg, &rectParent);
624 GetClientRect(hwndChildDlg, &rectChild);
626 if (hwndStc32)
628 if (rectParent.right > rectChild.right)
630 rectParent.right += rectChild.right;
631 rectParent.right -= rectStc32.right - rectStc32.left;
633 else
635 rectParent.right = rectChild.right;
638 if (rectParent.bottom > rectChild.bottom)
640 rectParent.bottom += rectChild.bottom;
641 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
643 else
645 rectParent.bottom = rectChild.bottom;
648 else
650 rectParent.bottom += rectChild.bottom;
653 /* finally use fixed parent size */
654 rectParent.bottom -= help_fixup;
656 /* save the size of the parent's client area */
657 rectChild.right = rectParent.right;
658 rectChild.bottom = rectParent.bottom;
660 /* set the size of the parent dialog */
661 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
662 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
663 SetWindowPos(hwndParentDlg, 0,
664 0, 0,
665 rectParent.right - rectParent.left,
666 rectParent.bottom - rectParent.top,
667 SWP_NOMOVE | SWP_NOZORDER);
669 /* set the size of the child dialog */
670 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
671 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
674 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
676 switch(uMsg) {
677 case WM_INITDIALOG:
678 return TRUE;
680 return FALSE;
683 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
685 LPCVOID template;
686 HRSRC hRes;
687 HANDLE hDlgTmpl = 0;
688 HWND hChildDlg = 0;
690 TRACE("\n");
693 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
694 * structure's hInstance parameter is not a HINSTANCE, but
695 * instead a pointer to a template resource to use.
697 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
699 HINSTANCE hinst;
700 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
702 hinst = 0;
703 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
705 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
706 return NULL;
709 else
711 hinst = fodInfos->ofnInfos->hInstance;
712 if(fodInfos->unicode)
714 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
715 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
717 else
719 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
720 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
722 if (!hRes)
724 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
725 return NULL;
727 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
728 !(template = LockResource( hDlgTmpl )))
730 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
731 return NULL;
734 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
735 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
736 (LPARAM)fodInfos->ofnInfos);
737 if(hChildDlg)
739 ShowWindow(hChildDlg,SW_SHOW);
740 return hChildDlg;
743 else if( IsHooked(fodInfos))
745 RECT rectHwnd;
746 struct {
747 DLGTEMPLATE tmplate;
748 WORD menu,class,title;
749 } temp;
750 GetClientRect(hwnd,&rectHwnd);
751 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
752 temp.tmplate.dwExtendedStyle = 0;
753 temp.tmplate.cdit = 0;
754 temp.tmplate.x = 0;
755 temp.tmplate.y = 0;
756 temp.tmplate.cx = 0;
757 temp.tmplate.cy = 0;
758 temp.menu = temp.class = temp.title = 0;
760 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
761 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
763 return hChildDlg;
765 return NULL;
768 /***********************************************************************
769 * SendCustomDlgNotificationMessage
771 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
774 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
776 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
778 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
780 if(!fodInfos) return 0;
782 if(fodInfos->unicode)
783 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
785 if(fodInfos->DlgInfos.hwndCustomDlg)
787 OFNOTIFYA ofnNotify;
788 HRESULT ret;
789 ofnNotify.hdr.hwndFrom=hwndParentDlg;
790 ofnNotify.hdr.idFrom=0;
791 ofnNotify.hdr.code = uCode;
792 ofnNotify.lpOFN = fodInfos->ofnInfos;
793 ofnNotify.pszFile = NULL;
794 TRACE("CALL NOTIFY for %x\n", uCode);
795 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
796 TRACE("RET NOTIFY\n");
797 return ret;
799 return TRUE;
802 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
804 UINT sizeUsed = 0, n, total;
805 LPWSTR lpstrFileList = NULL;
806 WCHAR lpstrCurrentDir[MAX_PATH];
807 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
809 TRACE("CDM_GETFILEPATH:\n");
811 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
812 return -1;
814 /* get path and filenames */
815 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
816 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
818 TRACE("path >%s< filespec >%s< %d files\n",
819 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
821 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
822 NULL, 0, NULL, NULL);
823 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
824 NULL, 0, NULL, NULL);
826 /* Prepend the current path */
827 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
828 buffer, size, NULL, NULL);
830 if(n<size)
832 /* 'n' includes trailing \0 */
833 buffer[n-1] = '\\';
834 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
835 &buffer[n], size-n, NULL, NULL);
837 MemFree(lpstrFileList);
839 TRACE("returned -> %s\n",debugstr_a(buffer));
841 return total;
844 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
846 UINT sizeUsed = 0;
847 LPWSTR lpstrFileList = NULL;
849 TRACE("CDM_GETSPEC:\n");
851 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
852 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
853 MemFree(lpstrFileList);
855 return sizeUsed;
858 /***********************************************************************
859 * FILEDLG95_HandleCustomDialogMessages
861 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
863 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
865 char lpstrPath[MAX_PATH];
866 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
867 if(!fodInfos) return -1;
869 switch(uMsg)
871 case CDM_GETFILEPATH:
872 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
874 case CDM_GETFOLDERPATH:
875 TRACE("CDM_GETFOLDERPATH:\n");
876 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
877 if ((LPSTR)lParam!=NULL)
878 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
879 return strlen(lpstrPath);
881 case CDM_GETSPEC:
882 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
884 case CDM_SETCONTROLTEXT:
885 TRACE("CDM_SETCONTROLTEXT:\n");
886 if ( 0 != lParam )
887 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
888 return TRUE;
890 case CDM_HIDECONTROL:
891 case CDM_SETDEFEXT:
892 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
893 return -1;
895 return TRUE;
898 /***********************************************************************
899 * FileOpenDlgProc95
901 * File open dialog procedure
903 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
905 #if 0
906 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
907 #endif
909 switch(uMsg)
911 case WM_INITDIALOG:
913 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
915 /* Adds the FileOpenDlgInfos in the property list of the dialog
916 so it will be easily accessible through a GetPropA(...) */
917 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
919 fodInfos->DlgInfos.hwndCustomDlg =
920 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
922 FILEDLG95_InitControls(hwnd);
924 if (fodInfos->DlgInfos.hwndCustomDlg)
925 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
926 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
928 FILEDLG95_FillControls(hwnd, wParam, lParam);
930 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
931 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
932 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
933 return 0;
935 case WM_COMMAND:
936 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
937 case WM_DRAWITEM:
939 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
941 case IDC_LOOKIN:
942 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
943 return TRUE;
946 return FALSE;
948 case WM_GETISHELLBROWSER:
949 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
951 case WM_DESTROY:
952 RemovePropA(hwnd, FileOpenDlgInfosStr);
953 return FALSE;
955 case WM_NOTIFY:
957 LPNMHDR lpnmh = (LPNMHDR)lParam;
958 UINT stringId = -1;
960 /* set up the button tooltips strings */
961 if(TTN_GETDISPINFOA == lpnmh->code )
963 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
964 switch(lpnmh->idFrom )
966 /* Up folder button */
967 case FCIDM_TB_UPFOLDER:
968 stringId = IDS_UPFOLDER;
969 break;
970 /* New folder button */
971 case FCIDM_TB_NEWFOLDER:
972 stringId = IDS_NEWFOLDER;
973 break;
974 /* List option button */
975 case FCIDM_TB_SMALLICON:
976 stringId = IDS_LISTVIEW;
977 break;
978 /* Details option button */
979 case FCIDM_TB_REPORTVIEW:
980 stringId = IDS_REPORTVIEW;
981 break;
982 /* Desktop button */
983 case FCIDM_TB_DESKTOP:
984 stringId = IDS_TODESKTOP;
985 break;
986 default:
987 stringId = 0;
989 lpdi->hinst = COMDLG32_hInstance;
990 lpdi->lpszText = (LPSTR) stringId;
992 return FALSE;
994 default :
995 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
996 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
997 return FALSE;
1001 /***********************************************************************
1002 * FILEDLG95_InitControls
1004 * WM_INITDIALOG message handler (before hook notification)
1006 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1008 int win2000plus = 0;
1009 int win98plus = 0;
1010 int handledPath = FALSE;
1011 OSVERSIONINFOA osVi;
1012 static const WCHAR szwSlash[] = { '\\', 0 };
1013 static const WCHAR szwStar[] = { '*',0 };
1015 TBBUTTON tbb[] =
1017 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1018 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1019 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1020 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1021 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1022 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1023 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1024 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1025 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1027 TBADDBITMAP tba[2];
1028 RECT rectTB;
1029 RECT rectlook;
1030 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1032 tba[0].hInst = HINST_COMMCTRL;
1033 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1034 tba[1].hInst = COMDLG32_hInstance;
1035 tba[1].nID = 800;
1037 TRACE("%p\n", fodInfos);
1039 /* Get windows version emulating */
1040 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1041 GetVersionExA(&osVi);
1042 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1043 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1044 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1045 win2000plus = (osVi.dwMajorVersion > 4);
1046 if (win2000plus) win98plus = TRUE;
1048 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1050 /* Get the hwnd of the controls */
1051 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1052 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1053 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1055 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1056 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1058 /* construct the toolbar */
1059 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1060 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1062 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1063 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1064 rectTB.left = rectlook.right;
1065 rectTB.top = rectlook.top-1;
1067 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1068 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1069 rectTB.left, rectTB.top,
1070 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1071 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1073 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1075 /* FIXME: use TB_LOADIMAGES when implemented */
1076 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1077 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1078 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1080 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1081 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1083 /* Set the window text with the text specified in the OPENFILENAME structure */
1084 if(fodInfos->title)
1086 SetWindowTextW(hwnd,fodInfos->title);
1088 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1090 SetWindowTextA(hwnd,"Save");
1093 /* Initialise the file name edit control */
1094 handledPath = FALSE;
1095 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1097 if(fodInfos->filename)
1099 /* 1. If win2000 or higher and filename contains a path, use it
1100 in preference over the lpstrInitialDir */
1101 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1102 WCHAR tmpBuf[MAX_PATH];
1103 WCHAR *nameBit;
1104 DWORD result;
1106 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1107 if (result) {
1109 /* nameBit is always shorter than the original filename */
1110 strcpyW(fodInfos->filename,nameBit);
1112 *nameBit = 0x00;
1113 if (fodInfos->initdir == NULL)
1114 MemFree(fodInfos->initdir);
1115 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1116 strcpyW(fodInfos->initdir, tmpBuf);
1117 handledPath = TRUE;
1118 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1119 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1121 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1123 } else {
1124 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1128 /* 2. (All platforms) If initdir is not null, then use it */
1129 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1130 (*fodInfos->initdir!=0x00))
1132 /* Work out the proper path as supplied one might be relative */
1133 /* (Here because supplying '.' as dir browses to My Computer) */
1134 if (handledPath==FALSE) {
1135 WCHAR tmpBuf[MAX_PATH];
1136 WCHAR tmpBuf2[MAX_PATH];
1137 WCHAR *nameBit;
1138 DWORD result;
1140 strcpyW(tmpBuf, fodInfos->initdir);
1141 if( PathFileExistsW(tmpBuf) ) {
1142 /* initdir does not have to be a directory. If a file is
1143 * specified, the dir part is taken */
1144 if( PathIsDirectoryW(tmpBuf)) {
1145 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1146 strcatW(tmpBuf, szwSlash);
1148 strcatW(tmpBuf, szwStar);
1150 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1151 if (result) {
1152 *nameBit = 0x00;
1153 if (fodInfos->initdir)
1154 MemFree(fodInfos->initdir);
1155 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1156 strcpyW(fodInfos->initdir, tmpBuf2);
1157 handledPath = TRUE;
1158 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1161 else if (fodInfos->initdir)
1163 MemFree(fodInfos->initdir);
1164 fodInfos->initdir = NULL;
1165 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1170 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1171 (*fodInfos->initdir==0x00)))
1173 /* 3. All except w2k+: if filename contains a path use it */
1174 if (!win2000plus && fodInfos->filename &&
1175 *fodInfos->filename &&
1176 strpbrkW(fodInfos->filename, szwSlash)) {
1177 WCHAR tmpBuf[MAX_PATH];
1178 WCHAR *nameBit;
1179 DWORD result;
1181 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1182 tmpBuf, &nameBit);
1183 if (result) {
1184 int len;
1186 /* nameBit is always shorter than the original filename */
1187 strcpyW(fodInfos->filename, nameBit);
1188 *nameBit = 0x00;
1190 len = strlenW(tmpBuf);
1191 if(fodInfos->initdir)
1192 MemFree(fodInfos->initdir);
1193 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1194 strcpyW(fodInfos->initdir, tmpBuf);
1196 handledPath = TRUE;
1197 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1198 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1200 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1203 /* 4. win98+ and win2000+ if any files of specified filter types in
1204 current directory, use it */
1205 if ( win98plus && handledPath == FALSE &&
1206 fodInfos->filter && *fodInfos->filter) {
1208 BOOL searchMore = TRUE;
1209 LPCWSTR lpstrPos = fodInfos->filter;
1210 WIN32_FIND_DATAW FindFileData;
1211 HANDLE hFind;
1213 while (searchMore)
1215 /* filter is a list... title\0ext\0......\0\0 */
1217 /* Skip the title */
1218 if(! *lpstrPos) break; /* end */
1219 lpstrPos += strlenW(lpstrPos) + 1;
1221 /* See if any files exist in the current dir with this extension */
1222 if(! *lpstrPos) break; /* end */
1224 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1226 if (hFind == INVALID_HANDLE_VALUE) {
1227 /* None found - continue search */
1228 lpstrPos += strlenW(lpstrPos) + 1;
1230 } else {
1231 searchMore = FALSE;
1233 if(fodInfos->initdir)
1234 MemFree(fodInfos->initdir);
1235 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1236 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1238 handledPath = TRUE;
1239 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1240 debugstr_w(lpstrPos));
1241 break;
1246 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1248 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1249 if (handledPath == FALSE && (win2000plus || win98plus)) {
1250 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1252 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1254 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1256 /* last fallback */
1257 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1258 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1259 } else {
1260 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1262 } else {
1263 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1265 handledPath = TRUE;
1266 } else if (handledPath==FALSE) {
1267 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1268 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1269 handledPath = TRUE;
1270 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1273 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1274 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1276 /* Must the open as read only check box be checked ?*/
1277 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1279 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1282 /* Must the open as read only check box be hidden? */
1283 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1285 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1286 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1289 /* Must the help button be hidden? */
1290 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1292 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1293 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1296 /* Resize the height, if open as read only checkbox ad help button
1297 are hidden and we are not using a custom template nor a customDialog
1299 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1300 (!(fodInfos->ofnInfos->Flags &
1301 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1302 (!fodInfos->DlgInfos.hwndCustomDlg ))
1304 RECT rectDlg, rectHelp, rectCancel;
1305 GetWindowRect(hwnd, &rectDlg);
1306 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1307 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1308 /* subtract the height of the help button plus the space between
1309 the help button and the cancel button to the height of the dialog */
1310 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1311 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1312 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1314 /* change Open to Save FIXME: use resources */
1315 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1317 SetDlgItemTextA(hwnd,IDOK,"&Save");
1318 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1320 return 0;
1323 /***********************************************************************
1324 * FILEDLG95_FillControls
1326 * WM_INITDIALOG message handler (after hook notification)
1328 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1330 LPITEMIDLIST pidlItemId = NULL;
1332 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1334 TRACE("dir=%s file=%s\n",
1335 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1337 /* Get the initial directory pidl */
1339 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1341 WCHAR path[MAX_PATH];
1343 GetCurrentDirectoryW(MAX_PATH,path);
1344 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1347 /* Initialise shell objects */
1348 FILEDLG95_SHELL_Init(hwnd);
1350 /* Initialize the Look In combo box */
1351 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1353 /* Initialize the filter combo box */
1354 FILEDLG95_FILETYPE_Init(hwnd);
1356 /* Browse to the initial directory */
1357 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1359 /* Free pidlItem memory */
1360 COMDLG32_SHFree(pidlItemId);
1362 return TRUE;
1364 /***********************************************************************
1365 * FILEDLG95_Clean
1367 * Regroups all the cleaning functions of the filedlg
1369 void FILEDLG95_Clean(HWND hwnd)
1371 FILEDLG95_FILETYPE_Clean(hwnd);
1372 FILEDLG95_LOOKIN_Clean(hwnd);
1373 FILEDLG95_SHELL_Clean(hwnd);
1375 /***********************************************************************
1376 * FILEDLG95_OnWMCommand
1378 * WM_COMMAND message handler
1380 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1382 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1383 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1384 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1386 switch(wID)
1388 /* OK button */
1389 case IDOK:
1390 FILEDLG95_OnOpen(hwnd);
1391 break;
1392 /* Cancel button */
1393 case IDCANCEL:
1394 FILEDLG95_Clean(hwnd);
1395 EndDialog(hwnd, FALSE);
1396 break;
1397 /* Filetype combo box */
1398 case IDC_FILETYPE:
1399 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1400 break;
1401 /* LookIn combo box */
1402 case IDC_LOOKIN:
1403 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1404 break;
1406 /* --- toolbar --- */
1407 /* Up folder button */
1408 case FCIDM_TB_UPFOLDER:
1409 FILEDLG95_SHELL_UpFolder(hwnd);
1410 break;
1411 /* New folder button */
1412 case FCIDM_TB_NEWFOLDER:
1413 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1414 break;
1415 /* List option button */
1416 case FCIDM_TB_SMALLICON:
1417 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1418 break;
1419 /* Details option button */
1420 case FCIDM_TB_REPORTVIEW:
1421 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1422 break;
1423 /* Details option button */
1424 case FCIDM_TB_DESKTOP:
1425 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1426 break;
1428 case IDC_FILENAME:
1429 break;
1432 /* Do not use the listview selection anymore */
1433 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1434 return 0;
1437 /***********************************************************************
1438 * FILEDLG95_OnWMGetIShellBrowser
1440 * WM_GETISHELLBROWSER message handler
1442 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1445 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1447 TRACE("\n");
1449 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1451 return TRUE;
1455 /***********************************************************************
1456 * FILEDLG95_SendFileOK
1458 * Sends the CDN_FILEOK notification if required
1460 * RETURNS
1461 * TRUE if the dialog should close
1462 * FALSE if the dialog should not be closed
1464 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1466 /* ask the hook if we can close */
1467 if(IsHooked(fodInfos))
1469 TRACE("---\n");
1470 /* First send CDN_FILEOK as MSDN doc says */
1471 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1472 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1474 TRACE("canceled\n");
1475 return FALSE;
1478 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1479 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1480 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1481 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1483 TRACE("canceled\n");
1484 return FALSE;
1487 return TRUE;
1490 /***********************************************************************
1491 * FILEDLG95_OnOpenMultipleFiles
1493 * Handles the opening of multiple files.
1495 * FIXME
1496 * check destination buffer size
1498 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1500 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1501 UINT nCount, nSizePath;
1502 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1504 TRACE("\n");
1506 if(fodInfos->unicode)
1508 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1509 ofn->lpstrFile[0] = '\0';
1511 else
1513 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1514 ofn->lpstrFile[0] = '\0';
1517 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1519 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1520 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1521 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1523 LPWSTR lpstrTemp = lpstrFileList;
1525 for ( nCount = 0; nCount < nFileCount; nCount++ )
1527 LPITEMIDLIST pidl;
1529 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1530 if (!pidl)
1532 WCHAR lpstrNotFound[100];
1533 WCHAR lpstrMsg[100];
1534 WCHAR tmp[400];
1535 static const WCHAR nl[] = {'\n',0};
1537 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1538 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1540 strcpyW(tmp, lpstrTemp);
1541 strcatW(tmp, nl);
1542 strcatW(tmp, lpstrNotFound);
1543 strcatW(tmp, nl);
1544 strcatW(tmp, lpstrMsg);
1546 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1547 return FALSE;
1550 /* move to the next file in the list of files */
1551 lpstrTemp += strlenW(lpstrTemp) + 1;
1552 COMDLG32_SHFree(pidl);
1556 nSizePath = strlenW(lpstrPathSpec) + 1;
1557 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1559 /* For "oldstyle" dialog the components have to
1560 be separated by blanks (not '\0'!) and short
1561 filenames have to be used! */
1562 FIXME("Components have to be separated by blanks\n");
1564 if(fodInfos->unicode)
1566 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1567 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1568 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1570 else
1572 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1574 if (ofn->lpstrFile != NULL)
1576 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1577 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1578 if (ofn->nMaxFile > nSizePath)
1580 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1581 ofn->lpstrFile + nSizePath,
1582 ofn->nMaxFile - nSizePath, NULL, NULL);
1587 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1588 fodInfos->ofnInfos->nFileExtension = 0;
1590 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1591 return FALSE;
1593 /* clean and exit */
1594 FILEDLG95_Clean(hwnd);
1595 return EndDialog(hwnd,TRUE);
1598 /***********************************************************************
1599 * FILEDLG95_OnOpen
1601 * Ok button WM_COMMAND message handler
1603 * If the function succeeds, the return value is nonzero.
1605 #define ONOPEN_BROWSE 1
1606 #define ONOPEN_OPEN 2
1607 #define ONOPEN_SEARCH 3
1608 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1610 char strMsgTitle[MAX_PATH];
1611 char strMsgText [MAX_PATH];
1612 if (idCaption)
1613 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1614 else
1615 strMsgTitle[0] = '\0';
1616 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1617 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1620 BOOL FILEDLG95_OnOpen(HWND hwnd)
1622 LPWSTR lpstrFileList;
1623 UINT nFileCount = 0;
1624 UINT sizeUsed = 0;
1625 BOOL ret = TRUE;
1626 WCHAR lpstrPathAndFile[MAX_PATH];
1627 WCHAR lpstrTemp[MAX_PATH];
1628 LPSHELLFOLDER lpsf = NULL;
1629 int nOpenAction;
1630 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1632 TRACE("hwnd=%p\n", hwnd);
1634 /* get the files from the edit control */
1635 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1637 /* try if the user selected a folder in the shellview */
1638 if(nFileCount == 0)
1640 BrowseSelectedFolder(hwnd);
1641 return FALSE;
1644 if(nFileCount > 1)
1646 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1647 goto ret;
1650 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1653 Step 1: Build a complete path name from the current folder and
1654 the filename or path in the edit box.
1655 Special cases:
1656 - the path in the edit box is a root path
1657 (with or without drive letter)
1658 - the edit box contains ".." (or a path with ".." in it)
1661 /* Get the current directory name */
1662 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1664 /* we are in a special folder, default to desktop */
1665 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1667 /* last fallback */
1668 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1671 PathAddBackslashW(lpstrPathAndFile);
1673 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1675 /* if the user specifyed a fully qualified path use it */
1676 if(PathIsRelativeW(lpstrFileList))
1678 strcatW(lpstrPathAndFile, lpstrFileList);
1680 else
1682 /* does the path have a drive letter? */
1683 if (PathGetDriveNumberW(lpstrFileList) == -1)
1684 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1685 else
1686 strcpyW(lpstrPathAndFile, lpstrFileList);
1689 /* resolve "." and ".." */
1690 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1691 strcpyW(lpstrPathAndFile, lpstrTemp);
1692 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1694 MemFree(lpstrFileList);
1697 Step 2: here we have a cleaned up path
1699 We have to parse the path step by step to see if we have to browse
1700 to a folder if the path points to a directory or the last
1701 valid element is a directory.
1703 valid variables:
1704 lpstrPathAndFile: cleaned up path
1707 nOpenAction = ONOPEN_BROWSE;
1709 /* don't apply any checks with OFN_NOVALIDATE */
1711 LPWSTR lpszTemp, lpszTemp1;
1712 LPITEMIDLIST pidl = NULL;
1713 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1715 /* check for invalid chars */
1716 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1718 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1719 ret = FALSE;
1720 goto ret;
1723 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1725 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1726 while (lpszTemp1)
1728 LPSHELLFOLDER lpsfChild;
1729 WCHAR lpwstrTemp[MAX_PATH];
1730 DWORD dwEaten, dwAttributes;
1731 LPWSTR p;
1733 strcpyW(lpwstrTemp, lpszTemp);
1734 p = PathFindNextComponentW(lpwstrTemp);
1736 if (!p) break; /* end of path */
1738 *p = 0;
1739 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1741 if(*lpszTemp==0)
1743 static const WCHAR wszWild[] = { '*', '?', 0 };
1744 /* if the last element is a wildcard do a search */
1745 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1747 nOpenAction = ONOPEN_SEARCH;
1748 break;
1751 lpszTemp1 = lpszTemp;
1753 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1755 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1757 dwAttributes = SFGAO_FOLDER;
1758 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1760 /* the path component is valid, we have a pidl of the next path component */
1761 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1762 if(dwAttributes & SFGAO_FOLDER)
1764 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1766 ERR("bind to failed\n"); /* should not fail */
1767 break;
1769 IShellFolder_Release(lpsf);
1770 lpsf = lpsfChild;
1771 lpsfChild = NULL;
1773 else
1775 TRACE("value\n");
1777 /* end dialog, return value */
1778 nOpenAction = ONOPEN_OPEN;
1779 break;
1781 COMDLG32_SHFree(pidl);
1782 pidl = NULL;
1784 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1786 if(*lpszTemp) /* points to trailing null for last path element */
1788 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1790 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1791 break;
1794 else
1796 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1797 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1799 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1800 break;
1803 /* change to the current folder */
1804 nOpenAction = ONOPEN_OPEN;
1805 break;
1807 else
1809 nOpenAction = ONOPEN_OPEN;
1810 break;
1813 if(pidl) COMDLG32_SHFree(pidl);
1817 Step 3: here we have a cleaned up and validated path
1819 valid variables:
1820 lpsf: ShellFolder bound to the rightmost valid path component
1821 lpstrPathAndFile: cleaned up path
1822 nOpenAction: action to do
1824 TRACE("end validate sf=%p\n", lpsf);
1826 switch(nOpenAction)
1828 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1829 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1831 int iPos;
1832 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1833 DWORD len;
1835 /* replace the current filter */
1836 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1837 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1838 len = strlenW(lpszTemp)+1;
1839 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1840 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1842 /* set the filter cb to the extension when possible */
1843 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1844 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1846 /* fall through */
1847 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1848 TRACE("ONOPEN_BROWSE\n");
1850 IPersistFolder2 * ppf2;
1851 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1853 LPITEMIDLIST pidlCurrent;
1854 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1855 IPersistFolder2_Release(ppf2);
1856 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1858 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1860 else if( nOpenAction == ONOPEN_SEARCH )
1862 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1864 COMDLG32_SHFree(pidlCurrent);
1867 ret = FALSE;
1868 break;
1869 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1870 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1872 /* update READONLY check box flag */
1873 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1874 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1875 else
1876 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1878 /* add default extension */
1879 if (fodInfos->defext)
1881 WCHAR *ext = PathFindExtensionW(lpstrPathAndFile);
1883 if (! *ext)
1885 /* only add "." in case a default extension does exist */
1886 if (*fodInfos->defext != '\0')
1888 static const WCHAR szwDot[] = {'.',0};
1889 int PathLength = strlenW(lpstrPathAndFile);
1891 strcatW(lpstrPathAndFile, szwDot);
1892 strcatW(lpstrPathAndFile, fodInfos->defext);
1894 /* In Open dialog: if file does not exist try without extension */
1895 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1896 && !PathFileExistsW(lpstrPathAndFile))
1897 lpstrPathAndFile[PathLength] = '\0';
1901 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1902 if (*ext)
1903 ext++;
1904 if (!lstrcmpiW(fodInfos->defext, ext))
1905 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1906 else
1907 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1910 /* In Save dialog: check if the file already exists */
1911 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1912 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1913 && PathFileExistsW(lpstrPathAndFile))
1915 WCHAR lpstrOverwrite[100];
1916 int answer;
1918 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1919 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1920 MB_YESNO | MB_ICONEXCLAMATION);
1921 if (answer == IDNO)
1923 ret = FALSE;
1924 goto ret;
1928 /* Check that the size of the file does not exceed buffer size.
1929 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1930 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1931 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1933 LPWSTR lpszTemp;
1935 /* fill destination buffer */
1936 if (fodInfos->ofnInfos->lpstrFile)
1938 if(fodInfos->unicode)
1940 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1942 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1943 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1944 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1946 else
1948 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1950 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1951 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1952 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1953 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1957 /* set filename offset */
1958 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1959 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1961 /* set extension offset */
1962 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1963 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1965 /* set the lpstrFileTitle */
1966 if(fodInfos->ofnInfos->lpstrFileTitle)
1968 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1969 if(fodInfos->unicode)
1971 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1972 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1974 else
1976 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1977 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1978 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1982 /* copy currently selected filter to lpstrCustomFilter */
1983 if (fodInfos->ofnInfos->lpstrCustomFilter)
1985 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1986 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
1987 NULL, 0, NULL, NULL);
1988 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
1990 LPSTR s = ofn->lpstrCustomFilter;
1991 s += strlen(ofn->lpstrCustomFilter)+1;
1992 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
1993 s, len, NULL, NULL);
1998 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1999 goto ret;
2001 TRACE("close\n");
2002 FILEDLG95_Clean(hwnd);
2003 ret = EndDialog(hwnd, TRUE);
2005 else
2007 WORD size;
2009 size = strlenW(lpstrPathAndFile) + 1;
2010 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2011 size += 1;
2012 /* return needed size in first two bytes of lpstrFile */
2013 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2014 FILEDLG95_Clean(hwnd);
2015 ret = EndDialog(hwnd, FALSE);
2016 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2018 goto ret;
2020 break;
2023 ret:
2024 if(lpsf) IShellFolder_Release(lpsf);
2025 return ret;
2028 /***********************************************************************
2029 * FILEDLG95_SHELL_Init
2031 * Initialisation of the shell objects
2033 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2035 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2037 TRACE("\n");
2040 * Initialisation of the FileOpenDialogInfos structure
2043 /* Shell */
2045 /*ShellInfos */
2046 fodInfos->ShellInfos.hwndOwner = hwnd;
2048 /* Disable multi-select if flag not set */
2049 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2051 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2053 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2054 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2056 /* Construct the IShellBrowser interface */
2057 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2059 return NOERROR;
2062 /***********************************************************************
2063 * FILEDLG95_SHELL_ExecuteCommand
2065 * Change the folder option and refresh the view
2066 * If the function succeeds, the return value is nonzero.
2068 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2070 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2072 IContextMenu * pcm;
2073 TRACE("(%p,%p)\n", hwnd, lpVerb);
2075 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2076 SVGIO_BACKGROUND,
2077 &IID_IContextMenu,
2078 (LPVOID*)&pcm)))
2080 CMINVOKECOMMANDINFO ci;
2081 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2082 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2083 ci.lpVerb = lpVerb;
2084 ci.hwnd = hwnd;
2086 IContextMenu_InvokeCommand(pcm, &ci);
2087 IContextMenu_Release(pcm);
2090 return FALSE;
2093 /***********************************************************************
2094 * FILEDLG95_SHELL_UpFolder
2096 * Browse to the specified object
2097 * If the function succeeds, the return value is nonzero.
2099 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2101 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2103 TRACE("\n");
2105 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2106 NULL,
2107 SBSP_PARENT)))
2109 return TRUE;
2111 return FALSE;
2114 /***********************************************************************
2115 * FILEDLG95_SHELL_BrowseToDesktop
2117 * Browse to the Desktop
2118 * If the function succeeds, the return value is nonzero.
2120 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2122 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2123 LPITEMIDLIST pidl;
2124 HRESULT hres;
2126 TRACE("\n");
2128 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2129 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2130 COMDLG32_SHFree(pidl);
2131 return SUCCEEDED(hres);
2133 /***********************************************************************
2134 * FILEDLG95_SHELL_Clean
2136 * Cleans the memory used by shell objects
2138 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2140 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2142 TRACE("\n");
2144 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2146 /* clean Shell interfaces */
2147 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2148 IShellView_Release(fodInfos->Shell.FOIShellView);
2149 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2150 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2151 if (fodInfos->Shell.FOIDataObject)
2152 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2155 /***********************************************************************
2156 * FILEDLG95_FILETYPE_Init
2158 * Initialisation of the file type combo box
2160 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2162 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2163 int nFilters = 0; /* number of filters */
2164 int nFilterIndexCB;
2166 TRACE("\n");
2168 if(fodInfos->customfilter)
2170 /* customfilter has one entry... title\0ext\0
2171 * Set first entry of combo box item with customfilter
2173 LPWSTR lpstrExt;
2174 LPCWSTR lpstrPos = fodInfos->customfilter;
2176 /* Get the title */
2177 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2179 /* Copy the extensions */
2180 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2181 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2182 strcpyW(lpstrExt,lpstrPos);
2184 /* Add the item at the end of the combo */
2185 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2186 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2187 nFilters++;
2189 if(fodInfos->filter)
2191 LPCWSTR lpstrPos = fodInfos->filter;
2193 for(;;)
2195 /* filter is a list... title\0ext\0......\0\0
2196 * Set the combo item text to the title and the item data
2197 * to the ext
2199 LPCWSTR lpstrDisplay;
2200 LPWSTR lpstrExt;
2202 /* Get the title */
2203 if(! *lpstrPos) break; /* end */
2204 lpstrDisplay = lpstrPos;
2205 lpstrPos += strlenW(lpstrPos) + 1;
2207 /* Copy the extensions */
2208 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2209 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2210 strcpyW(lpstrExt,lpstrPos);
2211 lpstrPos += strlenW(lpstrPos) + 1;
2213 /* Add the item at the end of the combo */
2214 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2215 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2216 nFilters++;
2221 * Set the current filter to the one specified
2222 * in the initialisation structure
2224 if (fodInfos->filter || fodInfos->customfilter)
2226 LPWSTR lpstrFilter;
2228 /* Check to make sure our index isn't out of bounds. */
2229 if ( fodInfos->ofnInfos->nFilterIndex >
2230 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2231 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2233 /* set default filter index */
2234 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2235 fodInfos->ofnInfos->nFilterIndex = 1;
2237 /* calculate index of Combo Box item */
2238 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2239 if (fodInfos->customfilter == NULL)
2240 nFilterIndexCB--;
2242 /* Set the current index selection. */
2243 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2245 /* Get the corresponding text string from the combo box. */
2246 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2247 nFilterIndexCB);
2249 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2250 lpstrFilter = NULL;
2252 if(lpstrFilter)
2254 DWORD len;
2255 CharLowerW(lpstrFilter); /* lowercase */
2256 len = strlenW(lpstrFilter)+1;
2257 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2258 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2260 } else
2261 fodInfos->ofnInfos->nFilterIndex = 0;
2263 return NOERROR;
2266 /***********************************************************************
2267 * FILEDLG95_FILETYPE_OnCommand
2269 * WM_COMMAND of the file type combo box
2270 * If the function succeeds, the return value is nonzero.
2272 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2274 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2276 switch(wNotifyCode)
2278 case CBN_SELENDOK:
2280 LPWSTR lpstrFilter;
2282 /* Get the current item of the filetype combo box */
2283 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2285 /* set the current filter index */
2286 fodInfos->ofnInfos->nFilterIndex = iItem +
2287 (fodInfos->customfilter == NULL ? 1 : 0);
2289 /* Set the current filter with the current selection */
2290 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2291 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2293 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2294 iItem);
2295 if((int)lpstrFilter != CB_ERR)
2297 DWORD len;
2298 CharLowerW(lpstrFilter); /* lowercase */
2299 len = strlenW(lpstrFilter)+1;
2300 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2301 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2302 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2305 /* Refresh the actual view to display the included items*/
2306 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2309 return FALSE;
2311 /***********************************************************************
2312 * FILEDLG95_FILETYPE_SearchExt
2314 * searches for a extension in the filetype box
2316 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2318 int i, iCount = CBGetCount(hwnd);
2320 TRACE("%s\n", debugstr_w(lpstrExt));
2322 if(iCount != CB_ERR)
2324 for(i=0;i<iCount;i++)
2326 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2327 return i;
2330 return -1;
2333 /***********************************************************************
2334 * FILEDLG95_FILETYPE_Clean
2336 * Clean the memory used by the filetype combo box
2338 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2340 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2341 int iPos;
2342 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2344 TRACE("\n");
2346 /* Delete each string of the combo and their associated data */
2347 if(iCount != CB_ERR)
2349 for(iPos = iCount-1;iPos>=0;iPos--)
2351 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2352 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2355 /* Current filter */
2356 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2357 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2361 /***********************************************************************
2362 * FILEDLG95_LOOKIN_Init
2364 * Initialisation of the look in combo box
2366 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2368 IShellFolder *psfRoot, *psfDrives;
2369 IEnumIDList *lpeRoot, *lpeDrives;
2370 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2372 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2374 TRACE("\n");
2376 liInfos->iMaxIndentation = 0;
2378 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2380 /* set item height for both text field and listbox */
2381 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2382 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2384 /* Turn on the extended UI for the combo box like Windows does */
2385 CBSetExtendedUI(hwndCombo, TRUE);
2387 /* Initialise data of Desktop folder */
2388 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2389 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2390 COMDLG32_SHFree(pidlTmp);
2392 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2394 SHGetDesktopFolder(&psfRoot);
2396 if (psfRoot)
2398 /* enumerate the contents of the desktop */
2399 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2401 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2403 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2405 /* special handling for CSIDL_DRIVES */
2406 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2408 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2410 /* enumerate the drives */
2411 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2413 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2415 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2416 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2417 COMDLG32_SHFree(pidlAbsTmp);
2418 COMDLG32_SHFree(pidlTmp1);
2420 IEnumIDList_Release(lpeDrives);
2422 IShellFolder_Release(psfDrives);
2425 COMDLG32_SHFree(pidlTmp);
2427 IEnumIDList_Release(lpeRoot);
2429 IShellFolder_Release(psfRoot);
2432 COMDLG32_SHFree(pidlDrives);
2433 return NOERROR;
2436 /***********************************************************************
2437 * FILEDLG95_LOOKIN_DrawItem
2439 * WM_DRAWITEM message handler
2441 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2443 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2444 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2445 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2446 RECT rectText;
2447 RECT rectIcon;
2448 SHFILEINFOA sfi;
2449 HIMAGELIST ilItemImage;
2450 int iIndentation;
2451 TEXTMETRICA tm;
2452 LPSFOLDER tmpFolder;
2455 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2457 TRACE("\n");
2459 if(pDIStruct->itemID == -1)
2460 return 0;
2462 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2463 pDIStruct->itemID)))
2464 return 0;
2467 if(pDIStruct->itemID == liInfos->uSelectedItem)
2469 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2471 &sfi,
2472 sizeof (SHFILEINFOA),
2473 SHGFI_PIDL | SHGFI_SMALLICON |
2474 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2475 SHGFI_DISPLAYNAME );
2477 else
2479 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2481 &sfi,
2482 sizeof (SHFILEINFOA),
2483 SHGFI_PIDL | SHGFI_SMALLICON |
2484 SHGFI_SYSICONINDEX |
2485 SHGFI_DISPLAYNAME);
2488 /* Is this item selected ? */
2489 if(pDIStruct->itemState & ODS_SELECTED)
2491 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2492 SetBkColor(pDIStruct->hDC,crHighLight);
2493 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2495 else
2497 SetTextColor(pDIStruct->hDC,crText);
2498 SetBkColor(pDIStruct->hDC,crWin);
2499 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2502 /* Do not indent item if drawing in the edit of the combo */
2503 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2505 iIndentation = 0;
2506 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2508 &sfi,
2509 sizeof (SHFILEINFOA),
2510 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2511 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2514 else
2516 iIndentation = tmpFolder->m_iIndent;
2518 /* Draw text and icon */
2520 /* Initialise the icon display area */
2521 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2522 rectIcon.top = pDIStruct->rcItem.top;
2523 rectIcon.right = rectIcon.left + ICONWIDTH;
2524 rectIcon.bottom = pDIStruct->rcItem.bottom;
2526 /* Initialise the text display area */
2527 GetTextMetricsA(pDIStruct->hDC, &tm);
2528 rectText.left = rectIcon.right;
2529 rectText.top =
2530 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2531 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2532 rectText.bottom =
2533 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2535 /* Draw the icon from the image list */
2536 ImageList_Draw(ilItemImage,
2537 sfi.iIcon,
2538 pDIStruct->hDC,
2539 rectIcon.left,
2540 rectIcon.top,
2541 ILD_TRANSPARENT );
2543 /* Draw the associated text */
2544 if(sfi.szDisplayName)
2545 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2548 return NOERROR;
2551 /***********************************************************************
2552 * FILEDLG95_LOOKIN_OnCommand
2554 * LookIn combo box WM_COMMAND message handler
2555 * If the function succeeds, the return value is nonzero.
2557 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2559 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2561 TRACE("%p\n", fodInfos);
2563 switch(wNotifyCode)
2565 case CBN_SELENDOK:
2567 LPSFOLDER tmpFolder;
2568 int iItem;
2570 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2572 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2573 iItem)))
2574 return FALSE;
2577 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2578 tmpFolder->pidlItem,
2579 SBSP_ABSOLUTE)))
2581 return TRUE;
2583 break;
2587 return FALSE;
2590 /***********************************************************************
2591 * FILEDLG95_LOOKIN_AddItem
2593 * Adds an absolute pidl item to the lookin combo box
2594 * returns the index of the inserted item
2596 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2598 LPITEMIDLIST pidlNext;
2599 SHFILEINFOA sfi;
2600 SFOLDER *tmpFolder;
2601 LookInInfos *liInfos;
2603 TRACE("%08x\n", iInsertId);
2605 if(!pidl)
2606 return -1;
2608 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2609 return -1;
2611 tmpFolder = MemAlloc(sizeof(SFOLDER));
2612 tmpFolder->m_iIndent = 0;
2614 /* Calculate the indentation of the item in the lookin*/
2615 pidlNext = pidl;
2616 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2618 tmpFolder->m_iIndent++;
2621 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2623 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2624 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2626 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2627 SHGetFileInfoA((LPSTR)pidl,
2629 &sfi,
2630 sizeof(sfi),
2631 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2632 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2634 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2636 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2638 int iItemID;
2640 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2642 /* Add the item at the end of the list */
2643 if(iInsertId < 0)
2645 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2647 /* Insert the item at the iInsertId position*/
2648 else
2650 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2653 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2654 return iItemID;
2657 COMDLG32_SHFree( tmpFolder->pidlItem );
2658 MemFree( tmpFolder );
2659 return -1;
2663 /***********************************************************************
2664 * FILEDLG95_LOOKIN_InsertItemAfterParent
2666 * Insert an item below its parent
2668 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2671 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2672 int iParentPos;
2674 TRACE("\n");
2676 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2678 if(iParentPos < 0)
2680 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2683 /* Free pidlParent memory */
2684 COMDLG32_SHFree((LPVOID)pidlParent);
2686 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2689 /***********************************************************************
2690 * FILEDLG95_LOOKIN_SelectItem
2692 * Adds an absolute pidl item to the lookin combo box
2693 * returns the index of the inserted item
2695 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2697 int iItemPos;
2698 LookInInfos *liInfos;
2700 TRACE("\n");
2702 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2704 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2706 if(iItemPos < 0)
2708 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2709 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2712 else
2714 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2715 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2717 int iRemovedItem;
2719 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2720 break;
2721 if(iRemovedItem < iItemPos)
2722 iItemPos--;
2726 CBSetCurSel(hwnd,iItemPos);
2727 liInfos->uSelectedItem = iItemPos;
2729 return 0;
2733 /***********************************************************************
2734 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2736 * Remove the item with an expansion level over iExpansionLevel
2738 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2740 int iItemPos;
2742 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2744 TRACE("\n");
2746 if(liInfos->iMaxIndentation <= 2)
2747 return -1;
2749 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2751 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2752 COMDLG32_SHFree(tmpFolder->pidlItem);
2753 MemFree(tmpFolder);
2754 CBDeleteString(hwnd,iItemPos);
2755 liInfos->iMaxIndentation--;
2757 return iItemPos;
2760 return -1;
2763 /***********************************************************************
2764 * FILEDLG95_LOOKIN_SearchItem
2766 * Search for pidl in the lookin combo box
2767 * returns the index of the found item
2769 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2771 int i = 0;
2772 int iCount = CBGetCount(hwnd);
2774 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2776 if (iCount != CB_ERR)
2778 for(;i<iCount;i++)
2780 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2782 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2783 return i;
2784 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2785 return i;
2789 return -1;
2792 /***********************************************************************
2793 * FILEDLG95_LOOKIN_Clean
2795 * Clean the memory used by the lookin combo box
2797 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2799 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2800 int iPos;
2801 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2803 TRACE("\n");
2805 /* Delete each string of the combo and their associated data */
2806 if (iCount != CB_ERR)
2808 for(iPos = iCount-1;iPos>=0;iPos--)
2810 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2811 COMDLG32_SHFree(tmpFolder->pidlItem);
2812 MemFree(tmpFolder);
2813 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2817 /* LookInInfos structure */
2818 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2821 /***********************************************************************
2822 * FILEDLG95_FILENAME_FillFromSelection
2824 * fills the edit box from the cached DataObject
2826 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2828 FileOpenDlgInfos *fodInfos;
2829 LPITEMIDLIST pidl;
2830 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2831 char lpstrTemp[MAX_PATH];
2832 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2834 TRACE("\n");
2835 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2837 /* Count how many files we have */
2838 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2840 /* calculate the string length, count files */
2841 if (nFileSelected >= 1)
2843 nLength += 3; /* first and last quotes, trailing \0 */
2844 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2846 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2848 if (pidl)
2850 /* get the total length of the selected file names */
2851 lpstrTemp[0] = '\0';
2852 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2854 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2856 nLength += strlen( lpstrTemp ) + 3;
2857 nFiles++;
2859 COMDLG32_SHFree( pidl );
2864 /* allocate the buffer */
2865 if (nFiles <= 1) nLength = MAX_PATH;
2866 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2867 lpstrAllFile[0] = '\0';
2869 /* Generate the string for the edit control */
2870 if(nFiles >= 1)
2872 lpstrCurrFile = lpstrAllFile;
2873 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2875 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2877 if (pidl)
2879 /* get the file name */
2880 lpstrTemp[0] = '\0';
2881 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2883 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2885 if ( nFiles > 1)
2887 *lpstrCurrFile++ = '\"';
2888 strcpy( lpstrCurrFile, lpstrTemp );
2889 lpstrCurrFile += strlen( lpstrTemp );
2890 strcpy( lpstrCurrFile, "\" " );
2891 lpstrCurrFile += 2;
2893 else
2895 strcpy( lpstrAllFile, lpstrTemp );
2898 COMDLG32_SHFree( (LPVOID) pidl );
2901 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2903 /* Select the file name like Windows does */
2904 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2906 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2910 /* copied from shell32 to avoid linking to it */
2911 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2913 switch (src->uType)
2915 case STRRET_WSTR:
2916 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2917 COMDLG32_SHFree(src->u.pOleStr);
2918 break;
2920 case STRRET_CSTR:
2921 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2922 break;
2924 case STRRET_OFFSET:
2925 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2926 break;
2928 default:
2929 FIXME("unknown type!\n");
2930 if (len)
2932 *(LPSTR)dest = '\0';
2934 return(FALSE);
2936 return S_OK;
2939 /***********************************************************************
2940 * FILEDLG95_FILENAME_GetFileNames
2942 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2944 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2946 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2947 UINT nStrCharCount = 0; /* index in src buffer */
2948 UINT nFileIndex = 0; /* index in dest buffer */
2949 UINT nFileCount = 0; /* number of files */
2950 UINT nStrLen = 0; /* length of string in edit control */
2951 LPWSTR lpstrEdit; /* buffer for string from edit control */
2953 TRACE("\n");
2955 /* get the filenames from the edit control */
2956 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2957 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2958 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2960 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2962 /* we might get single filename without any '"',
2963 * so we need nStrLen + terminating \0 + end-of-list \0 */
2964 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2965 *sizeUsed = 0;
2967 /* build 0-delimited file list from filenames */
2968 while ( nStrCharCount <= nStrLen )
2970 if ( lpstrEdit[nStrCharCount]=='"' )
2972 nStrCharCount++;
2973 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2975 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2976 (*sizeUsed)++;
2977 nStrCharCount++;
2979 (*lpstrFileList)[nFileIndex++] = '\0';
2980 (*sizeUsed)++;
2981 nFileCount++;
2983 nStrCharCount++;
2986 /* single, unquoted string */
2987 if ((nStrLen > 0) && (*sizeUsed == 0) )
2989 strcpyW(*lpstrFileList, lpstrEdit);
2990 nFileIndex = strlenW(lpstrEdit) + 1;
2991 (*sizeUsed) = nFileIndex;
2992 nFileCount = 1;
2995 /* trailing \0 */
2996 (*lpstrFileList)[nFileIndex] = '\0';
2997 (*sizeUsed)++;
2999 MemFree(lpstrEdit);
3000 return nFileCount;
3003 #define SETDefFormatEtc(fe,cf,med) \
3005 (fe).cfFormat = cf;\
3006 (fe).dwAspect = DVASPECT_CONTENT; \
3007 (fe).ptd =NULL;\
3008 (fe).tymed = med;\
3009 (fe).lindex = -1;\
3013 * DATAOBJECT Helper functions
3016 /***********************************************************************
3017 * COMCTL32_ReleaseStgMedium
3019 * like ReleaseStgMedium from ole32
3021 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3023 if(medium.pUnkForRelease)
3025 IUnknown_Release(medium.pUnkForRelease);
3027 else
3029 GlobalUnlock(medium.u.hGlobal);
3030 GlobalFree(medium.u.hGlobal);
3034 /***********************************************************************
3035 * GetPidlFromDataObject
3037 * Return pidl(s) by number from the cached DataObject
3039 * nPidlIndex=0 gets the fully qualified root path
3041 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3044 STGMEDIUM medium;
3045 FORMATETC formatetc;
3046 LPITEMIDLIST pidl = NULL;
3048 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3050 /* Set the FORMATETC structure*/
3051 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3053 /* Get the pidls from IDataObject */
3054 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3056 LPIDA cida = GlobalLock(medium.u.hGlobal);
3057 if(nPidlIndex <= cida->cidl)
3059 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3061 COMCTL32_ReleaseStgMedium(medium);
3063 return pidl;
3066 /***********************************************************************
3067 * GetNumSelected
3069 * Return the number of selected items in the DataObject.
3072 UINT GetNumSelected( IDataObject *doSelected )
3074 UINT retVal = 0;
3075 STGMEDIUM medium;
3076 FORMATETC formatetc;
3078 TRACE("sv=%p\n", doSelected);
3080 if (!doSelected) return 0;
3082 /* Set the FORMATETC structure*/
3083 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3085 /* Get the pidls from IDataObject */
3086 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3088 LPIDA cida = GlobalLock(medium.u.hGlobal);
3089 retVal = cida->cidl;
3090 COMCTL32_ReleaseStgMedium(medium);
3091 return retVal;
3093 return 0;
3097 * TOOLS
3100 /***********************************************************************
3101 * GetName
3103 * Get the pidl's display name (relative to folder) and
3104 * put it in lpstrFileName.
3106 * Return NOERROR on success,
3107 * E_FAIL otherwise
3110 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3112 STRRET str;
3113 HRESULT hRes;
3115 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3117 if(!lpsf)
3119 HRESULT hRes;
3120 SHGetDesktopFolder(&lpsf);
3121 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3122 IShellFolder_Release(lpsf);
3123 return hRes;
3126 /* Get the display name of the pidl relative to the folder */
3127 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3129 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3131 return E_FAIL;
3134 /***********************************************************************
3135 * GetShellFolderFromPidl
3137 * pidlRel is the item pidl relative
3138 * Return the IShellFolder of the absolute pidl
3140 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3142 IShellFolder *psf = NULL,*psfParent;
3144 TRACE("%p\n", pidlAbs);
3146 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3148 psf = psfParent;
3149 if(pidlAbs && pidlAbs->mkid.cb)
3151 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3153 IShellFolder_Release(psfParent);
3154 return psf;
3157 /* return the desktop */
3158 return psfParent;
3160 return NULL;
3163 /***********************************************************************
3164 * GetParentPidl
3166 * Return the LPITEMIDLIST to the parent of the pidl in the list
3168 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3170 LPITEMIDLIST pidlParent;
3172 TRACE("%p\n", pidl);
3174 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3175 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3177 return pidlParent;
3180 /***********************************************************************
3181 * GetPidlFromName
3183 * returns the pidl of the file name relative to folder
3184 * NULL if an error occurred
3186 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3188 LPITEMIDLIST pidl = NULL;
3189 ULONG ulEaten;
3191 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3193 if(!lpcstrFileName) return NULL;
3194 if(!*lpcstrFileName) return NULL;
3196 if(!lpsf)
3198 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3199 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3200 IShellFolder_Release(lpsf);
3203 else
3205 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3207 return pidl;
3212 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3214 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3215 HRESULT ret;
3217 TRACE("%p, %p\n", psf, pidl);
3219 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3221 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3222 /* see documentation shell 4.1*/
3223 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3226 /***********************************************************************
3227 * BrowseSelectedFolder
3229 static BOOL BrowseSelectedFolder(HWND hwnd)
3231 BOOL bBrowseSelFolder = FALSE;
3232 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3234 TRACE("\n");
3236 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3238 LPITEMIDLIST pidlSelection;
3240 /* get the file selected */
3241 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3242 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3244 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3245 pidlSelection, SBSP_RELATIVE ) ) )
3247 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3248 ' ','n','o','t',' ','e','x','i','s','t',0};
3249 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3252 bBrowseSelFolder = TRUE;
3254 COMDLG32_SHFree( pidlSelection );
3257 return bBrowseSelFolder;
3261 * Memory allocation methods */
3262 static void *MemAlloc(UINT size)
3264 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3267 static void MemFree(void *mem)
3269 if(mem)
3271 HeapFree(GetProcessHeap(),0,mem);
3275 /* ------------------ APIs ---------------------- */
3277 /***********************************************************************
3278 * GetOpenFileNameA (COMDLG32.@)
3280 * Creates a dialog box for the user to select a file to open.
3282 * RETURNS
3283 * TRUE on success: user enters a valid file
3284 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3287 BOOL WINAPI GetOpenFileNameA(
3288 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3290 BOOL win16look = FALSE;
3292 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3293 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3295 if (win16look)
3296 return GetFileName31A(ofn, OPEN_DIALOG);
3297 else
3298 return GetFileDialog95A(ofn, OPEN_DIALOG);
3301 /***********************************************************************
3302 * GetOpenFileNameW (COMDLG32.@)
3304 * Creates a dialog box for the user to select a file to open.
3306 * RETURNS
3307 * TRUE on success: user enters a valid file
3308 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3311 BOOL WINAPI GetOpenFileNameW(
3312 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3314 BOOL win16look = FALSE;
3316 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3317 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3319 if (win16look)
3320 return GetFileName31W(ofn, OPEN_DIALOG);
3321 else
3322 return GetFileDialog95W(ofn, OPEN_DIALOG);
3326 /***********************************************************************
3327 * GetSaveFileNameA (COMDLG32.@)
3329 * Creates a dialog box for the user to select a file to save.
3331 * RETURNS
3332 * TRUE on success: user enters a valid file
3333 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3336 BOOL WINAPI GetSaveFileNameA(
3337 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3339 BOOL win16look = FALSE;
3341 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3342 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3344 if (win16look)
3345 return GetFileName31A(ofn, SAVE_DIALOG);
3346 else
3347 return GetFileDialog95A(ofn, SAVE_DIALOG);
3350 /***********************************************************************
3351 * GetSaveFileNameW (COMDLG32.@)
3353 * Creates a dialog box for the user to select a file to save.
3355 * RETURNS
3356 * TRUE on success: user enters a valid file
3357 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3360 BOOL WINAPI GetSaveFileNameW(
3361 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3363 BOOL win16look = FALSE;
3365 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3366 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3368 if (win16look)
3369 return GetFileName31W(ofn, SAVE_DIALOG);
3370 else
3371 return GetFileDialog95W(ofn, SAVE_DIALOG);