Do not forget to allocate internal OPENFILENAMEW structure for 16-bit
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blob0064152884f175a254b78301da7873663c022458
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 COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "commdlg.h"
71 #include "dlgs.h"
72 #include "cdlg.h"
73 #include "filedlg31.h"
74 #include "wine/debug.h"
75 #include "cderr.h"
76 #include "shellapi.h"
77 #include "shlguid.h"
78 #include "shlobj.h"
79 #include "filedlgbrowser.h"
80 #include "shlwapi.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
124 /* AddItem flags*/
125 #define LISTEND -1
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
135 /* NOTE
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBAddStringW(hwnd,str) \
144 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
146 #define CBInsertString(hwnd,str,pos) \
147 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
149 #define CBDeleteString(hwnd,pos) \
150 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
152 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
153 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
155 #define CBGetItemDataPtr(hwnd,iItemId) \
156 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
158 #define CBGetLBText(hwnd,iItemId,str) \
159 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
161 #define CBGetCurSel(hwnd) \
162 SendMessageA(hwnd,CB_GETCURSEL,0,0);
164 #define CBSetCurSel(hwnd,pos) \
165 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
167 #define CBGetCount(hwnd) \
168 SendMessageA(hwnd,CB_GETCOUNT,0,0);
169 #define CBShowDropDown(hwnd,show) \
170 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
171 #define CBSetItemHeight(hwnd,index,height) \
172 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
174 #define CBSetExtendedUI(hwnd,flag) \
175 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
177 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
178 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
180 /***********************************************************************
181 * Prototypes
184 /* Internal functions used by the dialog */
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Miscellaneous tool functions */
217 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
218 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
221 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
223 /* Shell memory allocation */
224 static void *MemAlloc(UINT size);
225 static void MemFree(void *mem);
227 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
228 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
230 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
235 * GetFileName95
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
247 LRESULT lRes;
248 LPCVOID template;
249 HRSRC hRes;
250 HANDLE hDlgTmpl = 0;
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08lx not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
282 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
283 (LPDLGTEMPLATEA) template,
284 fodInfos->ofnInfos->hwndOwner,
285 FileOpenDlgProc95,
286 (LPARAM) fodInfos);
288 /* Unable to create the dialog */
289 if( lRes == -1)
290 return FALSE;
292 return lRes;
295 /***********************************************************************
296 * GetFileDialog95A
298 * Call GetFileName95 with this structure and clean the memory.
300 * IN : The OPENFILENAMEA initialisation structure passed to
301 * GetOpenFileNameA win api function (see filedlg.c)
303 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
305 BOOL ret;
306 FileOpenDlgInfos fodInfos;
307 LPSTR lpstrSavDir = NULL;
308 LPWSTR title = NULL;
309 LPWSTR defext = NULL;
310 LPWSTR filter = NULL;
311 LPWSTR customfilter = NULL;
313 /* Initialize FileOpenDlgInfos structure */
314 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
316 /* Pass in the original ofn */
317 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
319 /* save current directory */
320 if (ofn->Flags & OFN_NOCHANGEDIR)
322 lpstrSavDir = MemAlloc(MAX_PATH);
323 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
326 fodInfos.unicode = FALSE;
328 /* convert all the input strings to unicode */
329 if(ofn->lpstrInitialDir)
331 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
332 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
333 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
335 else
336 fodInfos.initdir = NULL;
338 if(ofn->lpstrFile)
340 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
343 else
344 fodInfos.filename = NULL;
346 if(ofn->lpstrDefExt)
348 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
349 defext = MemAlloc((len+1)*sizeof(WCHAR));
350 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
352 fodInfos.defext = defext;
354 if(ofn->lpstrTitle)
356 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
357 title = MemAlloc((len+1)*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
360 fodInfos.title = title;
362 if (ofn->lpstrFilter)
364 LPCSTR s;
365 int n, len;
367 /* filter is a list... title\0ext\0......\0\0 */
368 s = ofn->lpstrFilter;
369 while (*s) s = s+strlen(s)+1;
370 s++;
371 n = s - ofn->lpstrFilter;
372 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
373 filter = MemAlloc(len*sizeof(WCHAR));
374 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
376 fodInfos.filter = filter;
378 /* convert lpstrCustomFilter */
379 if (ofn->lpstrCustomFilter)
381 LPCSTR s;
382 int n, len;
384 /* customfilter contains a pair of strings... title\0ext\0 */
385 s = ofn->lpstrCustomFilter;
386 if (*s) s = s+strlen(s)+1;
387 if (*s) s = s+strlen(s)+1;
388 n = s - ofn->lpstrCustomFilter;
389 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
390 customfilter = MemAlloc(len*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
393 fodInfos.customfilter = customfilter;
395 /* Initialize the dialog property */
396 fodInfos.DlgInfos.dwDlgProp = 0;
397 fodInfos.DlgInfos.hwndCustomDlg = NULL;
399 switch(iDlgType)
401 case OPEN_DIALOG :
402 ret = GetFileName95(&fodInfos);
403 break;
404 case SAVE_DIALOG :
405 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
406 ret = GetFileName95(&fodInfos);
407 break;
408 default :
409 ret = 0;
412 if (lpstrSavDir)
414 SetCurrentDirectoryA(lpstrSavDir);
415 MemFree(lpstrSavDir);
418 if(title)
419 MemFree(title);
420 if(defext)
421 MemFree(defext);
422 if(filter)
423 MemFree(filter);
424 if(customfilter)
425 MemFree(customfilter);
426 if(fodInfos.initdir)
427 MemFree(fodInfos.initdir);
429 if(fodInfos.filename)
430 MemFree(fodInfos.filename);
432 TRACE("selected file: %s\n",ofn->lpstrFile);
434 return ret;
437 /***********************************************************************
438 * GetFileDialog95W
440 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
441 * Call GetFileName95 with this structure and clean the memory.
444 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
446 BOOL ret;
447 FileOpenDlgInfos fodInfos;
448 LPWSTR lpstrSavDir = NULL;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
453 /* Pass in the original ofn */
454 fodInfos.ofnInfos = ofn;
456 fodInfos.title = ofn->lpstrTitle;
457 fodInfos.defext = ofn->lpstrDefExt;
458 fodInfos.filter = ofn->lpstrFilter;
459 fodInfos.customfilter = ofn->lpstrCustomFilter;
461 /* convert string arguments, save others */
462 if(ofn->lpstrFile)
464 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
467 else
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 DWORD len = strlenW(ofn->lpstrInitialDir);
473 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
474 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
476 else
477 fodInfos.initdir = NULL;
479 /* save current directory */
480 if (ofn->Flags & OFN_NOCHANGEDIR)
482 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
483 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
486 fodInfos.unicode = TRUE;
488 switch(iDlgType)
490 case OPEN_DIALOG :
491 ret = GetFileName95(&fodInfos);
492 break;
493 case SAVE_DIALOG :
494 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
495 ret = GetFileName95(&fodInfos);
496 break;
497 default :
498 ret = 0;
501 if (lpstrSavDir)
503 SetCurrentDirectoryW(lpstrSavDir);
504 MemFree(lpstrSavDir);
507 /* restore saved IN arguments and convert OUT arguments back */
508 MemFree(fodInfos.filename);
509 MemFree(fodInfos.initdir);
510 return ret;
513 /***********************************************************************
514 * ArrangeCtrlPositions [internal]
516 * NOTE: Do not change anything here without a lot of testing.
518 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
520 HWND hwndChild, hwndStc32;
521 RECT rectParent, rectChild, rectStc32;
522 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
524 /* Take into account if open as read only checkbox and help button
525 * are hidden
527 if (hide_help)
529 RECT rectHelp, rectCancel;
530 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
531 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
532 /* subtract the height of the help button plus the space between
533 * the help button and the cancel button to the height of the dialog
535 help_fixup = rectHelp.bottom - rectCancel.bottom;
539 There are two possibilities to add components to the default file dialog box.
541 By default, all the new components are added below the standard dialog box (the else case).
543 However, if there is a static text component with the stc32 id, a special case happens.
544 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
545 in the window and the cx and cy indicate how to size the window.
546 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
547 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
551 GetClientRect(hwndParentDlg, &rectParent);
553 /* when arranging controls we have to use fixed parent size */
554 rectParent.bottom -= help_fixup;
556 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
557 if (hwndStc32)
559 GetWindowRect(hwndStc32, &rectStc32);
560 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
562 /* set the size of the stc32 control according to the size of
563 * client area of the parent dialog
565 SetWindowPos(hwndStc32, 0,
566 0, 0,
567 rectParent.right, rectParent.bottom,
568 SWP_NOMOVE | SWP_NOZORDER);
570 else
571 SetRectEmpty(&rectStc32);
573 /* this part moves controls of the child dialog */
574 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
575 while (hwndChild)
577 if (hwndChild != hwndStc32)
579 GetWindowRect(hwndChild, &rectChild);
580 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
582 /* move only if stc32 exist */
583 if (hwndStc32 && rectChild.left > rectStc32.right)
585 LONG old_left = rectChild.left;
587 /* move to the right of visible controls of the parent dialog */
588 rectChild.left += rectParent.right;
589 rectChild.left -= rectStc32.right;
591 child_width_fixup = rectChild.left - old_left;
593 /* move even if stc32 doesn't exist */
594 if (rectChild.top >= rectStc32.bottom)
596 LONG old_top = rectChild.top;
598 /* move below visible controls of the parent dialog */
599 rectChild.top += rectParent.bottom;
600 rectChild.top -= rectStc32.bottom - rectStc32.top;
602 child_height_fixup = rectChild.top - old_top;
605 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
606 0, 0, SWP_NOSIZE | SWP_NOZORDER);
608 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
611 /* this part moves controls of the parent dialog */
612 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
613 while (hwndChild)
615 if (hwndChild != hwndChildDlg)
617 GetWindowRect(hwndChild, &rectChild);
618 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
620 /* left,top of stc32 marks the position of controls
621 * from the parent dialog
623 rectChild.left += rectStc32.left;
624 rectChild.top += rectStc32.top;
626 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
627 0, 0, SWP_NOSIZE | SWP_NOZORDER);
629 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
632 /* calculate the size of the resulting dialog */
634 /* here we have to use original parent size */
635 GetClientRect(hwndParentDlg, &rectParent);
636 GetClientRect(hwndChildDlg, &rectChild);
638 if (hwndStc32)
640 rectChild.right += child_width_fixup;
641 rectChild.bottom += child_height_fixup;
643 if (rectParent.right > rectChild.right)
645 rectParent.right += rectChild.right;
646 rectParent.right -= rectStc32.right - rectStc32.left;
648 else
650 rectParent.right = rectChild.right;
653 if (rectParent.bottom > rectChild.bottom)
655 rectParent.bottom += rectChild.bottom;
656 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
658 else
660 /* child dialog is higher, unconditionally set new dialog
661 * height to its size (help_fixup will be subtracted below)
663 rectParent.bottom = rectChild.bottom + help_fixup;
666 else
668 rectParent.bottom += rectChild.bottom;
671 /* finally use fixed parent size */
672 rectParent.bottom -= help_fixup;
674 /* save the size of the parent's client area */
675 rectChild.right = rectParent.right;
676 rectChild.bottom = rectParent.bottom;
678 /* set the size of the parent dialog */
679 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
680 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
681 SetWindowPos(hwndParentDlg, 0,
682 0, 0,
683 rectParent.right - rectParent.left,
684 rectParent.bottom - rectParent.top,
685 SWP_NOMOVE | SWP_NOZORDER);
687 /* set the size of the child dialog */
688 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
689 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
692 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
694 switch(uMsg) {
695 case WM_INITDIALOG:
696 return TRUE;
698 return FALSE;
701 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
703 LPCVOID template;
704 HRSRC hRes;
705 HANDLE hDlgTmpl = 0;
706 HWND hChildDlg = 0;
708 TRACE("\n");
711 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
712 * structure's hInstance parameter is not a HINSTANCE, but
713 * instead a pointer to a template resource to use.
715 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
717 HINSTANCE hinst;
718 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
720 hinst = 0;
721 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
723 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
724 return NULL;
727 else
729 hinst = fodInfos->ofnInfos->hInstance;
730 if(fodInfos->unicode)
732 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
733 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
735 else
737 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
738 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
740 if (!hRes)
742 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
743 return NULL;
745 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
746 !(template = LockResource( hDlgTmpl )))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
749 return NULL;
752 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
753 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
754 (LPARAM)fodInfos->ofnInfos);
755 if(hChildDlg)
757 ShowWindow(hChildDlg,SW_SHOW);
758 return hChildDlg;
761 else if( IsHooked(fodInfos))
763 RECT rectHwnd;
764 struct {
765 DLGTEMPLATE tmplate;
766 WORD menu,class,title;
767 } temp;
768 GetClientRect(hwnd,&rectHwnd);
769 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
770 temp.tmplate.dwExtendedStyle = 0;
771 temp.tmplate.cdit = 0;
772 temp.tmplate.x = 0;
773 temp.tmplate.y = 0;
774 temp.tmplate.cx = 0;
775 temp.tmplate.cy = 0;
776 temp.menu = temp.class = temp.title = 0;
778 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
779 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
781 return hChildDlg;
783 return NULL;
786 /***********************************************************************
787 * SendCustomDlgNotificationMessage
789 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
792 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
794 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
796 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
798 if(!fodInfos) return 0;
800 if(fodInfos->DlgInfos.hwndCustomDlg)
802 HRESULT ret;
803 TRACE("CALL NOTIFY for %x\n", uCode);
804 if(fodInfos->unicode)
806 OFNOTIFYW ofnNotify;
807 ofnNotify.hdr.hwndFrom=hwndParentDlg;
808 ofnNotify.hdr.idFrom=0;
809 ofnNotify.hdr.code = uCode;
810 ofnNotify.lpOFN = fodInfos->ofnInfos;
811 ofnNotify.pszFile = NULL;
812 ret = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
814 else
816 OFNOTIFYA ofnNotify;
817 ofnNotify.hdr.hwndFrom=hwndParentDlg;
818 ofnNotify.hdr.idFrom=0;
819 ofnNotify.hdr.code = uCode;
820 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
821 ofnNotify.pszFile = NULL;
822 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
824 TRACE("RET NOTIFY\n");
825 return ret;
827 return TRUE;
830 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
832 UINT sizeUsed = 0, n, total;
833 LPWSTR lpstrFileList = NULL;
834 WCHAR lpstrCurrentDir[MAX_PATH];
835 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
837 TRACE("CDM_GETFILEPATH:\n");
839 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
840 return -1;
842 /* get path and filenames */
843 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
844 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
846 TRACE("path >%s< filespec >%s< %d files\n",
847 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
849 if( fodInfos->unicode )
851 LPWSTR bufW = buffer;
852 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
854 /* Prepend the current path */
855 n = strlenW(lpstrCurrentDir) + 1;
856 strncpyW( bufW, lpstrCurrentDir, size );
857 if(n<size)
859 /* 'n' includes trailing \0 */
860 bufW[n-1] = '\\';
861 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
863 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
865 else
867 LPSTR bufA = buffer;
868 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
869 NULL, 0, NULL, NULL);
870 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
871 NULL, 0, NULL, NULL);
873 /* Prepend the current path */
874 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
875 bufA, size, NULL, NULL);
877 if(n<size)
879 /* 'n' includes trailing \0 */
880 bufA[n-1] = '\\';
881 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
882 &bufA[n], size-n, NULL, NULL);
885 TRACE("returned -> %s\n",debugstr_an(bufA, total));
887 MemFree(lpstrFileList);
889 return total;
892 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
894 UINT sizeUsed = 0;
895 LPWSTR lpstrFileList = NULL;
896 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
898 TRACE("CDM_GETSPEC:\n");
900 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
901 if( fodInfos->unicode )
903 LPWSTR bufW = buffer;
904 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
906 else
908 LPSTR bufA = buffer;
909 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
910 NULL, 0, NULL, NULL);
911 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
912 bufA, size, NULL, NULL);
914 MemFree(lpstrFileList);
916 return sizeUsed;
919 /***********************************************************************
920 * FILEDLG95_HandleCustomDialogMessages
922 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
924 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
926 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
927 if(!fodInfos) return -1;
929 switch(uMsg)
931 case CDM_GETFILEPATH:
932 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
934 case CDM_GETFOLDERPATH:
935 TRACE("CDM_GETFOLDERPATH:\n");
936 if( fodInfos->unicode )
938 WCHAR lpstrPath[MAX_PATH], *bufW = (LPWSTR)lParam;
939 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
940 if (bufW)
941 lstrcpynW(bufW,lpstrPath,(int)wParam);
942 return strlenW(lpstrPath);
944 else
946 char lpstrPath[MAX_PATH], *bufA = (LPSTR)lParam;
947 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
948 if (bufA)
949 lstrcpynA(bufA,lpstrPath,(int)wParam);
950 return strlen(lpstrPath);
953 case CDM_GETSPEC:
954 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
956 case CDM_SETCONTROLTEXT:
957 TRACE("CDM_SETCONTROLTEXT:\n");
958 if ( lParam )
960 if( fodInfos->unicode )
961 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
962 else
963 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
965 return TRUE;
967 case CDM_HIDECONTROL:
968 case CDM_SETDEFEXT:
969 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
970 return -1;
972 return TRUE;
975 /***********************************************************************
976 * FileOpenDlgProc95
978 * File open dialog procedure
980 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
982 #if 0
983 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
984 #endif
986 switch(uMsg)
988 case WM_INITDIALOG:
990 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
992 /* Adds the FileOpenDlgInfos in the property list of the dialog
993 so it will be easily accessible through a GetPropA(...) */
994 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
996 fodInfos->DlgInfos.hwndCustomDlg =
997 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
999 FILEDLG95_InitControls(hwnd);
1001 if (fodInfos->DlgInfos.hwndCustomDlg)
1002 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1003 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1005 FILEDLG95_FillControls(hwnd, wParam, lParam);
1007 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1008 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1009 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1010 return 0;
1012 case WM_COMMAND:
1013 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1014 case WM_DRAWITEM:
1016 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1018 case IDC_LOOKIN:
1019 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1020 return TRUE;
1023 return FALSE;
1025 case WM_GETISHELLBROWSER:
1026 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1028 case WM_DESTROY:
1029 RemovePropA(hwnd, FileOpenDlgInfosStr);
1030 return FALSE;
1032 case WM_NOTIFY:
1034 LPNMHDR lpnmh = (LPNMHDR)lParam;
1035 UINT stringId = -1;
1037 /* set up the button tooltips strings */
1038 if(TTN_GETDISPINFOA == lpnmh->code )
1040 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1041 switch(lpnmh->idFrom )
1043 /* Up folder button */
1044 case FCIDM_TB_UPFOLDER:
1045 stringId = IDS_UPFOLDER;
1046 break;
1047 /* New folder button */
1048 case FCIDM_TB_NEWFOLDER:
1049 stringId = IDS_NEWFOLDER;
1050 break;
1051 /* List option button */
1052 case FCIDM_TB_SMALLICON:
1053 stringId = IDS_LISTVIEW;
1054 break;
1055 /* Details option button */
1056 case FCIDM_TB_REPORTVIEW:
1057 stringId = IDS_REPORTVIEW;
1058 break;
1059 /* Desktop button */
1060 case FCIDM_TB_DESKTOP:
1061 stringId = IDS_TODESKTOP;
1062 break;
1063 default:
1064 stringId = 0;
1066 lpdi->hinst = COMDLG32_hInstance;
1067 lpdi->lpszText = (LPSTR) stringId;
1069 return FALSE;
1071 default :
1072 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1073 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1074 return FALSE;
1078 /***********************************************************************
1079 * FILEDLG95_InitControls
1081 * WM_INITDIALOG message handler (before hook notification)
1083 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1085 int win2000plus = 0;
1086 int win98plus = 0;
1087 int handledPath = FALSE;
1088 OSVERSIONINFOA osVi;
1089 static const WCHAR szwSlash[] = { '\\', 0 };
1090 static const WCHAR szwStar[] = { '*',0 };
1092 TBBUTTON tbb[] =
1094 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1095 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1096 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1097 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1098 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1099 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1100 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1101 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1102 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1104 TBADDBITMAP tba[2];
1105 RECT rectTB;
1106 RECT rectlook;
1107 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1109 tba[0].hInst = HINST_COMMCTRL;
1110 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1111 tba[1].hInst = COMDLG32_hInstance;
1112 tba[1].nID = 800;
1114 TRACE("%p\n", fodInfos);
1116 /* Get windows version emulating */
1117 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1118 GetVersionExA(&osVi);
1119 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1120 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1121 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1122 win2000plus = (osVi.dwMajorVersion > 4);
1123 if (win2000plus) win98plus = TRUE;
1125 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1127 /* Get the hwnd of the controls */
1128 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1129 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1130 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1132 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1133 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1135 /* construct the toolbar */
1136 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1137 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1139 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1140 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1141 rectTB.left = rectlook.right;
1142 rectTB.top = rectlook.top-1;
1144 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1145 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1146 rectTB.left, rectTB.top,
1147 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1148 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1150 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1152 /* FIXME: use TB_LOADIMAGES when implemented */
1153 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1154 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1155 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1157 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1158 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1160 /* Set the window text with the text specified in the OPENFILENAME structure */
1161 if(fodInfos->title)
1163 SetWindowTextW(hwnd,fodInfos->title);
1165 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1167 WCHAR buf[16];
1168 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1169 SetWindowTextW(hwnd, buf);
1172 /* Initialise the file name edit control */
1173 handledPath = FALSE;
1174 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1176 if(fodInfos->filename)
1178 /* 1. If win2000 or higher and filename contains a path, use it
1179 in preference over the lpstrInitialDir */
1180 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1181 WCHAR tmpBuf[MAX_PATH];
1182 WCHAR *nameBit;
1183 DWORD result;
1185 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1186 if (result) {
1188 /* nameBit is always shorter than the original filename */
1189 strcpyW(fodInfos->filename,nameBit);
1191 *nameBit = 0x00;
1192 if (fodInfos->initdir == NULL)
1193 MemFree(fodInfos->initdir);
1194 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1195 strcpyW(fodInfos->initdir, tmpBuf);
1196 handledPath = TRUE;
1197 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1198 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1200 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1202 } else {
1203 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1207 /* 2. (All platforms) If initdir is not null, then use it */
1208 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1209 (*fodInfos->initdir!=0x00))
1211 /* Work out the proper path as supplied one might be relative */
1212 /* (Here because supplying '.' as dir browses to My Computer) */
1213 if (handledPath==FALSE) {
1214 WCHAR tmpBuf[MAX_PATH];
1215 WCHAR tmpBuf2[MAX_PATH];
1216 WCHAR *nameBit;
1217 DWORD result;
1219 strcpyW(tmpBuf, fodInfos->initdir);
1220 if( PathFileExistsW(tmpBuf) ) {
1221 /* initdir does not have to be a directory. If a file is
1222 * specified, the dir part is taken */
1223 if( PathIsDirectoryW(tmpBuf)) {
1224 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1225 strcatW(tmpBuf, szwSlash);
1227 strcatW(tmpBuf, szwStar);
1229 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1230 if (result) {
1231 *nameBit = 0x00;
1232 if (fodInfos->initdir)
1233 MemFree(fodInfos->initdir);
1234 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1235 strcpyW(fodInfos->initdir, tmpBuf2);
1236 handledPath = TRUE;
1237 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1240 else if (fodInfos->initdir)
1242 MemFree(fodInfos->initdir);
1243 fodInfos->initdir = NULL;
1244 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1249 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1250 (*fodInfos->initdir==0x00)))
1252 /* 3. All except w2k+: if filename contains a path use it */
1253 if (!win2000plus && fodInfos->filename &&
1254 *fodInfos->filename &&
1255 strpbrkW(fodInfos->filename, szwSlash)) {
1256 WCHAR tmpBuf[MAX_PATH];
1257 WCHAR *nameBit;
1258 DWORD result;
1260 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1261 tmpBuf, &nameBit);
1262 if (result) {
1263 int len;
1265 /* nameBit is always shorter than the original filename */
1266 strcpyW(fodInfos->filename, nameBit);
1267 *nameBit = 0x00;
1269 len = strlenW(tmpBuf);
1270 if(fodInfos->initdir)
1271 MemFree(fodInfos->initdir);
1272 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1273 strcpyW(fodInfos->initdir, tmpBuf);
1275 handledPath = TRUE;
1276 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1277 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1279 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1282 /* 4. win98+ and win2000+ if any files of specified filter types in
1283 current directory, use it */
1284 if ( win98plus && handledPath == FALSE &&
1285 fodInfos->filter && *fodInfos->filter) {
1287 BOOL searchMore = TRUE;
1288 LPCWSTR lpstrPos = fodInfos->filter;
1289 WIN32_FIND_DATAW FindFileData;
1290 HANDLE hFind;
1292 while (searchMore)
1294 /* filter is a list... title\0ext\0......\0\0 */
1296 /* Skip the title */
1297 if(! *lpstrPos) break; /* end */
1298 lpstrPos += strlenW(lpstrPos) + 1;
1300 /* See if any files exist in the current dir with this extension */
1301 if(! *lpstrPos) break; /* end */
1303 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1305 if (hFind == INVALID_HANDLE_VALUE) {
1306 /* None found - continue search */
1307 lpstrPos += strlenW(lpstrPos) + 1;
1309 } else {
1310 searchMore = FALSE;
1312 if(fodInfos->initdir)
1313 MemFree(fodInfos->initdir);
1314 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1315 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1317 handledPath = TRUE;
1318 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1319 debugstr_w(lpstrPos));
1320 break;
1325 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1327 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1328 if (handledPath == FALSE && (win2000plus || win98plus)) {
1329 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1331 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1333 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1335 /* last fallback */
1336 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1337 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1338 } else {
1339 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1341 } else {
1342 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1344 handledPath = TRUE;
1345 } else if (handledPath==FALSE) {
1346 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1347 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1348 handledPath = TRUE;
1349 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1352 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1353 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1355 /* Must the open as read only check box be checked ?*/
1356 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1358 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1361 /* Must the open as read only check box be hidden? */
1362 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1364 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1365 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1368 /* Must the help button be hidden? */
1369 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1371 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1372 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1375 /* Resize the height, if open as read only checkbox ad help button
1376 are hidden and we are not using a custom template nor a customDialog
1378 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1379 (!(fodInfos->ofnInfos->Flags &
1380 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1381 (!fodInfos->DlgInfos.hwndCustomDlg ))
1383 RECT rectDlg, rectHelp, rectCancel;
1384 GetWindowRect(hwnd, &rectDlg);
1385 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1386 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1387 /* subtract the height of the help button plus the space between
1388 the help button and the cancel button to the height of the dialog */
1389 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1390 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1391 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1393 /* change Open to Save */
1394 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1396 WCHAR buf[16];
1397 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1398 SetDlgItemTextW(hwnd, IDOK, buf);
1399 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1400 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1402 return 0;
1405 /***********************************************************************
1406 * FILEDLG95_FillControls
1408 * WM_INITDIALOG message handler (after hook notification)
1410 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1412 LPITEMIDLIST pidlItemId = NULL;
1414 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1416 TRACE("dir=%s file=%s\n",
1417 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1419 /* Get the initial directory pidl */
1421 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1423 WCHAR path[MAX_PATH];
1425 GetCurrentDirectoryW(MAX_PATH,path);
1426 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1429 /* Initialise shell objects */
1430 FILEDLG95_SHELL_Init(hwnd);
1432 /* Initialize the Look In combo box */
1433 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1435 /* Initialize the filter combo box */
1436 FILEDLG95_FILETYPE_Init(hwnd);
1438 /* Browse to the initial directory */
1439 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1441 /* Free pidlItem memory */
1442 COMDLG32_SHFree(pidlItemId);
1444 return TRUE;
1446 /***********************************************************************
1447 * FILEDLG95_Clean
1449 * Regroups all the cleaning functions of the filedlg
1451 void FILEDLG95_Clean(HWND hwnd)
1453 FILEDLG95_FILETYPE_Clean(hwnd);
1454 FILEDLG95_LOOKIN_Clean(hwnd);
1455 FILEDLG95_SHELL_Clean(hwnd);
1457 /***********************************************************************
1458 * FILEDLG95_OnWMCommand
1460 * WM_COMMAND message handler
1462 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1464 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1465 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1466 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1468 switch(wID)
1470 /* OK button */
1471 case IDOK:
1472 FILEDLG95_OnOpen(hwnd);
1473 break;
1474 /* Cancel button */
1475 case IDCANCEL:
1476 FILEDLG95_Clean(hwnd);
1477 EndDialog(hwnd, FALSE);
1478 break;
1479 /* Filetype combo box */
1480 case IDC_FILETYPE:
1481 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1482 break;
1483 /* LookIn combo box */
1484 case IDC_LOOKIN:
1485 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1486 break;
1488 /* --- toolbar --- */
1489 /* Up folder button */
1490 case FCIDM_TB_UPFOLDER:
1491 FILEDLG95_SHELL_UpFolder(hwnd);
1492 break;
1493 /* New folder button */
1494 case FCIDM_TB_NEWFOLDER:
1495 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1496 break;
1497 /* List option button */
1498 case FCIDM_TB_SMALLICON:
1499 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1500 break;
1501 /* Details option button */
1502 case FCIDM_TB_REPORTVIEW:
1503 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1504 break;
1505 /* Details option button */
1506 case FCIDM_TB_DESKTOP:
1507 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1508 break;
1510 case IDC_FILENAME:
1511 break;
1514 /* Do not use the listview selection anymore */
1515 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1516 return 0;
1519 /***********************************************************************
1520 * FILEDLG95_OnWMGetIShellBrowser
1522 * WM_GETISHELLBROWSER message handler
1524 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1527 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1529 TRACE("\n");
1531 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1533 return TRUE;
1537 /***********************************************************************
1538 * FILEDLG95_SendFileOK
1540 * Sends the CDN_FILEOK notification if required
1542 * RETURNS
1543 * TRUE if the dialog should close
1544 * FALSE if the dialog should not be closed
1546 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1548 /* ask the hook if we can close */
1549 if(IsHooked(fodInfos))
1551 TRACE("---\n");
1552 /* First send CDN_FILEOK as MSDN doc says */
1553 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1554 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1556 TRACE("canceled\n");
1557 return FALSE;
1560 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1561 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1562 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1563 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1565 TRACE("canceled\n");
1566 return FALSE;
1569 return TRUE;
1572 /***********************************************************************
1573 * FILEDLG95_OnOpenMultipleFiles
1575 * Handles the opening of multiple files.
1577 * FIXME
1578 * check destination buffer size
1580 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1582 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1583 UINT nCount, nSizePath;
1584 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1586 TRACE("\n");
1588 if(fodInfos->unicode)
1590 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1591 ofn->lpstrFile[0] = '\0';
1593 else
1595 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1596 ofn->lpstrFile[0] = '\0';
1599 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1601 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1602 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1603 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1605 LPWSTR lpstrTemp = lpstrFileList;
1607 for ( nCount = 0; nCount < nFileCount; nCount++ )
1609 LPITEMIDLIST pidl;
1611 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1612 if (!pidl)
1614 WCHAR lpstrNotFound[100];
1615 WCHAR lpstrMsg[100];
1616 WCHAR tmp[400];
1617 static const WCHAR nl[] = {'\n',0};
1619 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1620 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1622 strcpyW(tmp, lpstrTemp);
1623 strcatW(tmp, nl);
1624 strcatW(tmp, lpstrNotFound);
1625 strcatW(tmp, nl);
1626 strcatW(tmp, lpstrMsg);
1628 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1629 return FALSE;
1632 /* move to the next file in the list of files */
1633 lpstrTemp += strlenW(lpstrTemp) + 1;
1634 COMDLG32_SHFree(pidl);
1638 nSizePath = strlenW(lpstrPathSpec) + 1;
1639 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1641 /* For "oldstyle" dialog the components have to
1642 be separated by blanks (not '\0'!) and short
1643 filenames have to be used! */
1644 FIXME("Components have to be separated by blanks\n");
1646 if(fodInfos->unicode)
1648 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1649 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1650 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1652 else
1654 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1656 if (ofn->lpstrFile != NULL)
1658 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1659 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1660 if (ofn->nMaxFile > nSizePath)
1662 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1663 ofn->lpstrFile + nSizePath,
1664 ofn->nMaxFile - nSizePath, NULL, NULL);
1669 fodInfos->ofnInfos->nFileOffset = nSizePath;
1670 fodInfos->ofnInfos->nFileExtension = 0;
1672 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1673 return FALSE;
1675 /* clean and exit */
1676 FILEDLG95_Clean(hwnd);
1677 return EndDialog(hwnd,TRUE);
1680 /***********************************************************************
1681 * FILEDLG95_OnOpen
1683 * Ok button WM_COMMAND message handler
1685 * If the function succeeds, the return value is nonzero.
1687 #define ONOPEN_BROWSE 1
1688 #define ONOPEN_OPEN 2
1689 #define ONOPEN_SEARCH 3
1690 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1692 WCHAR strMsgTitle[MAX_PATH];
1693 WCHAR strMsgText [MAX_PATH];
1694 if (idCaption)
1695 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1696 else
1697 strMsgTitle[0] = '\0';
1698 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1699 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1702 BOOL FILEDLG95_OnOpen(HWND hwnd)
1704 LPWSTR lpstrFileList;
1705 UINT nFileCount = 0;
1706 UINT sizeUsed = 0;
1707 BOOL ret = TRUE;
1708 WCHAR lpstrPathAndFile[MAX_PATH];
1709 WCHAR lpstrTemp[MAX_PATH];
1710 LPSHELLFOLDER lpsf = NULL;
1711 int nOpenAction;
1712 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1714 TRACE("hwnd=%p\n", hwnd);
1716 /* get the files from the edit control */
1717 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1719 /* try if the user selected a folder in the shellview */
1720 if(nFileCount == 0)
1722 BrowseSelectedFolder(hwnd);
1723 return FALSE;
1726 if(nFileCount > 1)
1728 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1729 goto ret;
1732 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1735 Step 1: Build a complete path name from the current folder and
1736 the filename or path in the edit box.
1737 Special cases:
1738 - the path in the edit box is a root path
1739 (with or without drive letter)
1740 - the edit box contains ".." (or a path with ".." in it)
1743 /* Get the current directory name */
1744 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1746 /* we are in a special folder, default to desktop */
1747 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1749 /* last fallback */
1750 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1753 PathAddBackslashW(lpstrPathAndFile);
1755 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1757 /* if the user specifyed a fully qualified path use it */
1758 if(PathIsRelativeW(lpstrFileList))
1760 strcatW(lpstrPathAndFile, lpstrFileList);
1762 else
1764 /* does the path have a drive letter? */
1765 if (PathGetDriveNumberW(lpstrFileList) == -1)
1766 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1767 else
1768 strcpyW(lpstrPathAndFile, lpstrFileList);
1771 /* resolve "." and ".." */
1772 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1773 strcpyW(lpstrPathAndFile, lpstrTemp);
1774 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1776 MemFree(lpstrFileList);
1779 Step 2: here we have a cleaned up path
1781 We have to parse the path step by step to see if we have to browse
1782 to a folder if the path points to a directory or the last
1783 valid element is a directory.
1785 valid variables:
1786 lpstrPathAndFile: cleaned up path
1789 nOpenAction = ONOPEN_BROWSE;
1791 /* don't apply any checks with OFN_NOVALIDATE */
1793 LPWSTR lpszTemp, lpszTemp1;
1794 LPITEMIDLIST pidl = NULL;
1795 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1797 /* check for invalid chars */
1798 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1800 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1801 ret = FALSE;
1802 goto ret;
1805 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1807 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1808 while (lpszTemp1)
1810 LPSHELLFOLDER lpsfChild;
1811 WCHAR lpwstrTemp[MAX_PATH];
1812 DWORD dwEaten, dwAttributes;
1813 LPWSTR p;
1815 strcpyW(lpwstrTemp, lpszTemp);
1816 p = PathFindNextComponentW(lpwstrTemp);
1818 if (!p) break; /* end of path */
1820 *p = 0;
1821 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1823 if(*lpszTemp==0)
1825 static const WCHAR wszWild[] = { '*', '?', 0 };
1826 /* if the last element is a wildcard do a search */
1827 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1829 nOpenAction = ONOPEN_SEARCH;
1830 break;
1833 lpszTemp1 = lpszTemp;
1835 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1837 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1839 dwAttributes = SFGAO_FOLDER;
1840 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1842 /* the path component is valid, we have a pidl of the next path component */
1843 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1844 if(dwAttributes & SFGAO_FOLDER)
1846 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1848 ERR("bind to failed\n"); /* should not fail */
1849 break;
1851 IShellFolder_Release(lpsf);
1852 lpsf = lpsfChild;
1853 lpsfChild = NULL;
1855 else
1857 TRACE("value\n");
1859 /* end dialog, return value */
1860 nOpenAction = ONOPEN_OPEN;
1861 break;
1863 COMDLG32_SHFree(pidl);
1864 pidl = NULL;
1866 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1868 if(*lpszTemp) /* points to trailing null for last path element */
1870 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1872 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1873 break;
1876 else
1878 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1879 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1881 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1882 break;
1885 /* change to the current folder */
1886 nOpenAction = ONOPEN_OPEN;
1887 break;
1889 else
1891 nOpenAction = ONOPEN_OPEN;
1892 break;
1895 if(pidl) COMDLG32_SHFree(pidl);
1899 Step 3: here we have a cleaned up and validated path
1901 valid variables:
1902 lpsf: ShellFolder bound to the rightmost valid path component
1903 lpstrPathAndFile: cleaned up path
1904 nOpenAction: action to do
1906 TRACE("end validate sf=%p\n", lpsf);
1908 switch(nOpenAction)
1910 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1911 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1913 int iPos;
1914 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1915 DWORD len;
1917 /* replace the current filter */
1918 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1919 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1920 len = strlenW(lpszTemp)+1;
1921 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1922 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1924 /* set the filter cb to the extension when possible */
1925 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1926 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1928 /* fall through */
1929 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1930 TRACE("ONOPEN_BROWSE\n");
1932 IPersistFolder2 * ppf2;
1933 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1935 LPITEMIDLIST pidlCurrent;
1936 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1937 IPersistFolder2_Release(ppf2);
1938 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1940 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1942 else if( nOpenAction == ONOPEN_SEARCH )
1944 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1946 COMDLG32_SHFree(pidlCurrent);
1949 ret = FALSE;
1950 break;
1951 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1952 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1954 WCHAR *ext = NULL;
1956 /* update READONLY check box flag */
1957 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1958 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1959 else
1960 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1962 /* Attach the file extension with file name*/
1963 ext = PathFindExtensionW(lpstrPathAndFile);
1964 if (! *ext)
1966 /* if no extension is specified with file name, then */
1967 /* attach the extension from file filter or default one */
1969 WCHAR *filterExt = NULL;
1970 LPWSTR lpstrFilter = NULL;
1971 static const WCHAR szwDot[] = {'.',0};
1972 int PathLength = strlenW(lpstrPathAndFile);
1974 /* Attach the dot*/
1975 strcatW(lpstrPathAndFile, szwDot);
1977 /*Get the file extension from file type filter*/
1978 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1979 fodInfos->ofnInfos->nFilterIndex-1);
1981 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
1982 filterExt = PathFindExtensionW(lpstrFilter);
1984 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
1985 strcatW(lpstrPathAndFile, filterExt + 1);
1986 else if ( fodInfos->defext ) /* attach the default file extension*/
1987 strcatW(lpstrPathAndFile, fodInfos->defext);
1989 /* In Open dialog: if file does not exist try without extension */
1990 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
1991 lpstrPathAndFile[PathLength] = '\0';
1994 if (fodInfos->defext) /* add default extension */
1996 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1997 if (*ext)
1998 ext++;
1999 if (!lstrcmpiW(fodInfos->defext, ext))
2000 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2001 else
2002 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2005 /* In Save dialog: check if the file already exists */
2006 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2007 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2008 && PathFileExistsW(lpstrPathAndFile))
2010 WCHAR lpstrOverwrite[100];
2011 int answer;
2013 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2014 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2015 MB_YESNO | MB_ICONEXCLAMATION);
2016 if (answer == IDNO)
2018 ret = FALSE;
2019 goto ret;
2023 /* Check that the size of the file does not exceed buffer size.
2024 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2025 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2026 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2028 LPWSTR lpszTemp;
2030 /* fill destination buffer */
2031 if (fodInfos->ofnInfos->lpstrFile)
2033 if(fodInfos->unicode)
2035 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2037 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2038 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2039 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2041 else
2043 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2045 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2046 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2047 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2048 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2052 /* set filename offset */
2053 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2054 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2056 /* set extension offset */
2057 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2058 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2060 /* set the lpstrFileTitle */
2061 if(fodInfos->ofnInfos->lpstrFileTitle)
2063 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2064 if(fodInfos->unicode)
2066 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2067 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2069 else
2071 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2072 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2073 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2077 /* copy currently selected filter to lpstrCustomFilter */
2078 if (fodInfos->ofnInfos->lpstrCustomFilter)
2080 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2081 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2082 NULL, 0, NULL, NULL);
2083 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2085 LPSTR s = ofn->lpstrCustomFilter;
2086 s += strlen(ofn->lpstrCustomFilter)+1;
2087 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2088 s, len, NULL, NULL);
2093 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2094 goto ret;
2096 TRACE("close\n");
2097 FILEDLG95_Clean(hwnd);
2098 ret = EndDialog(hwnd, TRUE);
2100 else
2102 WORD size;
2104 size = strlenW(lpstrPathAndFile) + 1;
2105 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2106 size += 1;
2107 /* return needed size in first two bytes of lpstrFile */
2108 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2109 FILEDLG95_Clean(hwnd);
2110 ret = EndDialog(hwnd, FALSE);
2111 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2113 goto ret;
2115 break;
2118 ret:
2119 if(lpsf) IShellFolder_Release(lpsf);
2120 return ret;
2123 /***********************************************************************
2124 * FILEDLG95_SHELL_Init
2126 * Initialisation of the shell objects
2128 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2130 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2132 TRACE("\n");
2135 * Initialisation of the FileOpenDialogInfos structure
2138 /* Shell */
2140 /*ShellInfos */
2141 fodInfos->ShellInfos.hwndOwner = hwnd;
2143 /* Disable multi-select if flag not set */
2144 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2146 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2148 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2149 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2151 /* Construct the IShellBrowser interface */
2152 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2154 return NOERROR;
2157 /***********************************************************************
2158 * FILEDLG95_SHELL_ExecuteCommand
2160 * Change the folder option and refresh the view
2161 * If the function succeeds, the return value is nonzero.
2163 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2165 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2167 IContextMenu * pcm;
2168 TRACE("(%p,%p)\n", hwnd, lpVerb);
2170 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2171 SVGIO_BACKGROUND,
2172 &IID_IContextMenu,
2173 (LPVOID*)&pcm)))
2175 CMINVOKECOMMANDINFO ci;
2176 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2177 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2178 ci.lpVerb = lpVerb;
2179 ci.hwnd = hwnd;
2181 IContextMenu_InvokeCommand(pcm, &ci);
2182 IContextMenu_Release(pcm);
2185 return FALSE;
2188 /***********************************************************************
2189 * FILEDLG95_SHELL_UpFolder
2191 * Browse to the specified object
2192 * If the function succeeds, the return value is nonzero.
2194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2196 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2198 TRACE("\n");
2200 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2201 NULL,
2202 SBSP_PARENT)))
2204 return TRUE;
2206 return FALSE;
2209 /***********************************************************************
2210 * FILEDLG95_SHELL_BrowseToDesktop
2212 * Browse to the Desktop
2213 * If the function succeeds, the return value is nonzero.
2215 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2217 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2218 LPITEMIDLIST pidl;
2219 HRESULT hres;
2221 TRACE("\n");
2223 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2224 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2225 COMDLG32_SHFree(pidl);
2226 return SUCCEEDED(hres);
2228 /***********************************************************************
2229 * FILEDLG95_SHELL_Clean
2231 * Cleans the memory used by shell objects
2233 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2235 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2237 TRACE("\n");
2239 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2241 /* clean Shell interfaces */
2242 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2243 IShellView_Release(fodInfos->Shell.FOIShellView);
2244 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2245 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2246 if (fodInfos->Shell.FOIDataObject)
2247 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2250 /***********************************************************************
2251 * FILEDLG95_FILETYPE_Init
2253 * Initialisation of the file type combo box
2255 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2257 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2258 int nFilters = 0; /* number of filters */
2259 int nFilterIndexCB;
2261 TRACE("\n");
2263 if(fodInfos->customfilter)
2265 /* customfilter has one entry... title\0ext\0
2266 * Set first entry of combo box item with customfilter
2268 LPWSTR lpstrExt;
2269 LPCWSTR lpstrPos = fodInfos->customfilter;
2271 /* Get the title */
2272 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2274 /* Copy the extensions */
2275 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2276 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2277 strcpyW(lpstrExt,lpstrPos);
2279 /* Add the item at the end of the combo */
2280 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2281 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2282 nFilters++;
2284 if(fodInfos->filter)
2286 LPCWSTR lpstrPos = fodInfos->filter;
2288 for(;;)
2290 /* filter is a list... title\0ext\0......\0\0
2291 * Set the combo item text to the title and the item data
2292 * to the ext
2294 LPCWSTR lpstrDisplay;
2295 LPWSTR lpstrExt;
2297 /* Get the title */
2298 if(! *lpstrPos) break; /* end */
2299 lpstrDisplay = lpstrPos;
2300 lpstrPos += strlenW(lpstrPos) + 1;
2302 /* Copy the extensions */
2303 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2304 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2305 strcpyW(lpstrExt,lpstrPos);
2306 lpstrPos += strlenW(lpstrPos) + 1;
2308 /* Add the item at the end of the combo */
2309 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2310 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2311 nFilters++;
2316 * Set the current filter to the one specified
2317 * in the initialisation structure
2319 if (fodInfos->filter || fodInfos->customfilter)
2321 LPWSTR lpstrFilter;
2323 /* Check to make sure our index isn't out of bounds. */
2324 if ( fodInfos->ofnInfos->nFilterIndex >
2325 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2326 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2328 /* set default filter index */
2329 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2330 fodInfos->ofnInfos->nFilterIndex = 1;
2332 /* calculate index of Combo Box item */
2333 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2334 if (fodInfos->customfilter == NULL)
2335 nFilterIndexCB--;
2337 /* Set the current index selection. */
2338 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2340 /* Get the corresponding text string from the combo box. */
2341 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2342 nFilterIndexCB);
2344 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2345 lpstrFilter = NULL;
2347 if(lpstrFilter)
2349 DWORD len;
2350 CharLowerW(lpstrFilter); /* lowercase */
2351 len = strlenW(lpstrFilter)+1;
2352 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2353 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2355 } else
2356 fodInfos->ofnInfos->nFilterIndex = 0;
2358 return NOERROR;
2361 /***********************************************************************
2362 * FILEDLG95_FILETYPE_OnCommand
2364 * WM_COMMAND of the file type combo box
2365 * If the function succeeds, the return value is nonzero.
2367 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2369 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2371 switch(wNotifyCode)
2373 case CBN_SELENDOK:
2375 LPWSTR lpstrFilter;
2377 /* Get the current item of the filetype combo box */
2378 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2380 /* set the current filter index */
2381 fodInfos->ofnInfos->nFilterIndex = iItem +
2382 (fodInfos->customfilter == NULL ? 1 : 0);
2384 /* Set the current filter with the current selection */
2385 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2386 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2388 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2389 iItem);
2390 if((int)lpstrFilter != CB_ERR)
2392 DWORD len;
2393 CharLowerW(lpstrFilter); /* lowercase */
2394 len = strlenW(lpstrFilter)+1;
2395 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2396 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2397 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2400 /* Refresh the actual view to display the included items*/
2401 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2404 return FALSE;
2406 /***********************************************************************
2407 * FILEDLG95_FILETYPE_SearchExt
2409 * searches for a extension in the filetype box
2411 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2413 int i, iCount = CBGetCount(hwnd);
2415 TRACE("%s\n", debugstr_w(lpstrExt));
2417 if(iCount != CB_ERR)
2419 for(i=0;i<iCount;i++)
2421 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2422 return i;
2425 return -1;
2428 /***********************************************************************
2429 * FILEDLG95_FILETYPE_Clean
2431 * Clean the memory used by the filetype combo box
2433 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2435 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2436 int iPos;
2437 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2439 TRACE("\n");
2441 /* Delete each string of the combo and their associated data */
2442 if(iCount != CB_ERR)
2444 for(iPos = iCount-1;iPos>=0;iPos--)
2446 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2447 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2450 /* Current filter */
2451 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2452 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2456 /***********************************************************************
2457 * FILEDLG95_LOOKIN_Init
2459 * Initialisation of the look in combo box
2461 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2463 IShellFolder *psfRoot, *psfDrives;
2464 IEnumIDList *lpeRoot, *lpeDrives;
2465 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2467 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2469 TRACE("\n");
2471 liInfos->iMaxIndentation = 0;
2473 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2475 /* set item height for both text field and listbox */
2476 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2477 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2479 /* Turn on the extended UI for the combo box like Windows does */
2480 CBSetExtendedUI(hwndCombo, TRUE);
2482 /* Initialise data of Desktop folder */
2483 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2484 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2485 COMDLG32_SHFree(pidlTmp);
2487 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2489 SHGetDesktopFolder(&psfRoot);
2491 if (psfRoot)
2493 /* enumerate the contents of the desktop */
2494 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2496 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2498 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2500 /* special handling for CSIDL_DRIVES */
2501 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2503 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2505 /* enumerate the drives */
2506 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2508 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2510 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2511 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2512 COMDLG32_SHFree(pidlAbsTmp);
2513 COMDLG32_SHFree(pidlTmp1);
2515 IEnumIDList_Release(lpeDrives);
2517 IShellFolder_Release(psfDrives);
2520 COMDLG32_SHFree(pidlTmp);
2522 IEnumIDList_Release(lpeRoot);
2524 IShellFolder_Release(psfRoot);
2527 COMDLG32_SHFree(pidlDrives);
2528 return NOERROR;
2531 /***********************************************************************
2532 * FILEDLG95_LOOKIN_DrawItem
2534 * WM_DRAWITEM message handler
2536 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2538 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2539 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2540 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2541 RECT rectText;
2542 RECT rectIcon;
2543 SHFILEINFOA sfi;
2544 HIMAGELIST ilItemImage;
2545 int iIndentation;
2546 TEXTMETRICA tm;
2547 LPSFOLDER tmpFolder;
2550 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2552 TRACE("\n");
2554 if(pDIStruct->itemID == -1)
2555 return 0;
2557 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2558 pDIStruct->itemID)))
2559 return 0;
2562 if(pDIStruct->itemID == liInfos->uSelectedItem)
2564 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2566 &sfi,
2567 sizeof (SHFILEINFOA),
2568 SHGFI_PIDL | SHGFI_SMALLICON |
2569 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2570 SHGFI_DISPLAYNAME );
2572 else
2574 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2576 &sfi,
2577 sizeof (SHFILEINFOA),
2578 SHGFI_PIDL | SHGFI_SMALLICON |
2579 SHGFI_SYSICONINDEX |
2580 SHGFI_DISPLAYNAME);
2583 /* Is this item selected ? */
2584 if(pDIStruct->itemState & ODS_SELECTED)
2586 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2587 SetBkColor(pDIStruct->hDC,crHighLight);
2588 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2590 else
2592 SetTextColor(pDIStruct->hDC,crText);
2593 SetBkColor(pDIStruct->hDC,crWin);
2594 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2597 /* Do not indent item if drawing in the edit of the combo */
2598 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2600 iIndentation = 0;
2601 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2603 &sfi,
2604 sizeof (SHFILEINFOA),
2605 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2606 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2609 else
2611 iIndentation = tmpFolder->m_iIndent;
2613 /* Draw text and icon */
2615 /* Initialise the icon display area */
2616 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2617 rectIcon.top = pDIStruct->rcItem.top;
2618 rectIcon.right = rectIcon.left + ICONWIDTH;
2619 rectIcon.bottom = pDIStruct->rcItem.bottom;
2621 /* Initialise the text display area */
2622 GetTextMetricsA(pDIStruct->hDC, &tm);
2623 rectText.left = rectIcon.right;
2624 rectText.top =
2625 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2626 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2627 rectText.bottom =
2628 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2630 /* Draw the icon from the image list */
2631 ImageList_Draw(ilItemImage,
2632 sfi.iIcon,
2633 pDIStruct->hDC,
2634 rectIcon.left,
2635 rectIcon.top,
2636 ILD_TRANSPARENT );
2638 /* Draw the associated text */
2639 if(sfi.szDisplayName)
2640 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2643 return NOERROR;
2646 /***********************************************************************
2647 * FILEDLG95_LOOKIN_OnCommand
2649 * LookIn combo box WM_COMMAND message handler
2650 * If the function succeeds, the return value is nonzero.
2652 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2654 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2656 TRACE("%p\n", fodInfos);
2658 switch(wNotifyCode)
2660 case CBN_SELENDOK:
2662 LPSFOLDER tmpFolder;
2663 int iItem;
2665 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2667 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2668 iItem)))
2669 return FALSE;
2672 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2673 tmpFolder->pidlItem,
2674 SBSP_ABSOLUTE)))
2676 return TRUE;
2678 break;
2682 return FALSE;
2685 /***********************************************************************
2686 * FILEDLG95_LOOKIN_AddItem
2688 * Adds an absolute pidl item to the lookin combo box
2689 * returns the index of the inserted item
2691 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2693 LPITEMIDLIST pidlNext;
2694 SHFILEINFOA sfi;
2695 SFOLDER *tmpFolder;
2696 LookInInfos *liInfos;
2698 TRACE("%08x\n", iInsertId);
2700 if(!pidl)
2701 return -1;
2703 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2704 return -1;
2706 tmpFolder = MemAlloc(sizeof(SFOLDER));
2707 tmpFolder->m_iIndent = 0;
2709 /* Calculate the indentation of the item in the lookin*/
2710 pidlNext = pidl;
2711 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2713 tmpFolder->m_iIndent++;
2716 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2718 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2719 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2721 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2722 SHGetFileInfoA((LPSTR)pidl,
2724 &sfi,
2725 sizeof(sfi),
2726 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2727 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2729 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2731 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2733 int iItemID;
2735 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2737 /* Add the item at the end of the list */
2738 if(iInsertId < 0)
2740 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2742 /* Insert the item at the iInsertId position*/
2743 else
2745 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2748 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2749 return iItemID;
2752 COMDLG32_SHFree( tmpFolder->pidlItem );
2753 MemFree( tmpFolder );
2754 return -1;
2758 /***********************************************************************
2759 * FILEDLG95_LOOKIN_InsertItemAfterParent
2761 * Insert an item below its parent
2763 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2766 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2767 int iParentPos;
2769 TRACE("\n");
2771 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2773 if(iParentPos < 0)
2775 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2778 /* Free pidlParent memory */
2779 COMDLG32_SHFree((LPVOID)pidlParent);
2781 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2784 /***********************************************************************
2785 * FILEDLG95_LOOKIN_SelectItem
2787 * Adds an absolute pidl item to the lookin combo box
2788 * returns the index of the inserted item
2790 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2792 int iItemPos;
2793 LookInInfos *liInfos;
2795 TRACE("\n");
2797 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2799 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2801 if(iItemPos < 0)
2803 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2804 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2807 else
2809 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2810 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2812 int iRemovedItem;
2814 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2815 break;
2816 if(iRemovedItem < iItemPos)
2817 iItemPos--;
2821 CBSetCurSel(hwnd,iItemPos);
2822 liInfos->uSelectedItem = iItemPos;
2824 return 0;
2828 /***********************************************************************
2829 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2831 * Remove the item with an expansion level over iExpansionLevel
2833 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2835 int iItemPos;
2837 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2839 TRACE("\n");
2841 if(liInfos->iMaxIndentation <= 2)
2842 return -1;
2844 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2846 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2847 COMDLG32_SHFree(tmpFolder->pidlItem);
2848 MemFree(tmpFolder);
2849 CBDeleteString(hwnd,iItemPos);
2850 liInfos->iMaxIndentation--;
2852 return iItemPos;
2855 return -1;
2858 /***********************************************************************
2859 * FILEDLG95_LOOKIN_SearchItem
2861 * Search for pidl in the lookin combo box
2862 * returns the index of the found item
2864 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2866 int i = 0;
2867 int iCount = CBGetCount(hwnd);
2869 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2871 if (iCount != CB_ERR)
2873 for(;i<iCount;i++)
2875 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2877 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2878 return i;
2879 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2880 return i;
2884 return -1;
2887 /***********************************************************************
2888 * FILEDLG95_LOOKIN_Clean
2890 * Clean the memory used by the lookin combo box
2892 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2894 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2895 int iPos;
2896 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2898 TRACE("\n");
2900 /* Delete each string of the combo and their associated data */
2901 if (iCount != CB_ERR)
2903 for(iPos = iCount-1;iPos>=0;iPos--)
2905 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2906 COMDLG32_SHFree(tmpFolder->pidlItem);
2907 MemFree(tmpFolder);
2908 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2912 /* LookInInfos structure */
2913 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2916 /***********************************************************************
2917 * FILEDLG95_FILENAME_FillFromSelection
2919 * fills the edit box from the cached DataObject
2921 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2923 FileOpenDlgInfos *fodInfos;
2924 LPITEMIDLIST pidl;
2925 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2926 char lpstrTemp[MAX_PATH];
2927 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2929 TRACE("\n");
2930 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2932 /* Count how many files we have */
2933 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2935 /* calculate the string length, count files */
2936 if (nFileSelected >= 1)
2938 nLength += 3; /* first and last quotes, trailing \0 */
2939 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2941 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2943 if (pidl)
2945 /* get the total length of the selected file names */
2946 lpstrTemp[0] = '\0';
2947 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2949 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2951 nLength += strlen( lpstrTemp ) + 3;
2952 nFiles++;
2954 COMDLG32_SHFree( pidl );
2959 /* allocate the buffer */
2960 if (nFiles <= 1) nLength = MAX_PATH;
2961 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2962 lpstrAllFile[0] = '\0';
2964 /* Generate the string for the edit control */
2965 if(nFiles >= 1)
2967 lpstrCurrFile = lpstrAllFile;
2968 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2970 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2972 if (pidl)
2974 /* get the file name */
2975 lpstrTemp[0] = '\0';
2976 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2978 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2980 if ( nFiles > 1)
2982 *lpstrCurrFile++ = '\"';
2983 strcpy( lpstrCurrFile, lpstrTemp );
2984 lpstrCurrFile += strlen( lpstrTemp );
2985 strcpy( lpstrCurrFile, "\" " );
2986 lpstrCurrFile += 2;
2988 else
2990 strcpy( lpstrAllFile, lpstrTemp );
2993 COMDLG32_SHFree( (LPVOID) pidl );
2996 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2998 /* Select the file name like Windows does */
2999 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3001 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3005 /* copied from shell32 to avoid linking to it */
3006 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3008 switch (src->uType)
3010 case STRRET_WSTR:
3011 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3012 COMDLG32_SHFree(src->u.pOleStr);
3013 break;
3015 case STRRET_CSTR:
3016 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3017 break;
3019 case STRRET_OFFSET:
3020 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3021 break;
3023 default:
3024 FIXME("unknown type!\n");
3025 if (len)
3027 *(LPSTR)dest = '\0';
3029 return(FALSE);
3031 return S_OK;
3034 /***********************************************************************
3035 * FILEDLG95_FILENAME_GetFileNames
3037 * Copies the filenames to a delimited string list.
3038 * The delimiter is specified by the parameter 'separator',
3039 * usually either a space or a nul
3041 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3043 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3044 UINT nStrCharCount = 0; /* index in src buffer */
3045 UINT nFileIndex = 0; /* index in dest buffer */
3046 UINT nFileCount = 0; /* number of files */
3047 UINT nStrLen = 0; /* length of string in edit control */
3048 LPWSTR lpstrEdit; /* buffer for string from edit control */
3050 TRACE("\n");
3052 /* get the filenames from the edit control */
3053 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3054 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3055 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3057 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3059 /* we might get single filename without any '"',
3060 * so we need nStrLen + terminating \0 + end-of-list \0 */
3061 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3062 *sizeUsed = 0;
3064 /* build delimited file list from filenames */
3065 while ( nStrCharCount <= nStrLen )
3067 if ( lpstrEdit[nStrCharCount]=='"' )
3069 nStrCharCount++;
3070 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3072 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3073 (*sizeUsed)++;
3074 nStrCharCount++;
3076 (*lpstrFileList)[nFileIndex++] = separator;
3077 (*sizeUsed)++;
3078 nFileCount++;
3080 nStrCharCount++;
3083 /* single, unquoted string */
3084 if ((nStrLen > 0) && (*sizeUsed == 0) )
3086 strcpyW(*lpstrFileList, lpstrEdit);
3087 nFileIndex = strlenW(lpstrEdit) + 1;
3088 (*sizeUsed) = nFileIndex;
3089 nFileCount = 1;
3092 /* trailing \0 */
3093 (*lpstrFileList)[nFileIndex] = '\0';
3094 (*sizeUsed)++;
3096 MemFree(lpstrEdit);
3097 return nFileCount;
3100 #define SETDefFormatEtc(fe,cf,med) \
3102 (fe).cfFormat = cf;\
3103 (fe).dwAspect = DVASPECT_CONTENT; \
3104 (fe).ptd =NULL;\
3105 (fe).tymed = med;\
3106 (fe).lindex = -1;\
3110 * DATAOBJECT Helper functions
3113 /***********************************************************************
3114 * COMCTL32_ReleaseStgMedium
3116 * like ReleaseStgMedium from ole32
3118 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3120 if(medium.pUnkForRelease)
3122 IUnknown_Release(medium.pUnkForRelease);
3124 else
3126 GlobalUnlock(medium.u.hGlobal);
3127 GlobalFree(medium.u.hGlobal);
3131 /***********************************************************************
3132 * GetPidlFromDataObject
3134 * Return pidl(s) by number from the cached DataObject
3136 * nPidlIndex=0 gets the fully qualified root path
3138 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3141 STGMEDIUM medium;
3142 FORMATETC formatetc;
3143 LPITEMIDLIST pidl = NULL;
3145 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3147 /* Set the FORMATETC structure*/
3148 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3150 /* Get the pidls from IDataObject */
3151 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3153 LPIDA cida = GlobalLock(medium.u.hGlobal);
3154 if(nPidlIndex <= cida->cidl)
3156 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3158 COMCTL32_ReleaseStgMedium(medium);
3160 return pidl;
3163 /***********************************************************************
3164 * GetNumSelected
3166 * Return the number of selected items in the DataObject.
3169 UINT GetNumSelected( IDataObject *doSelected )
3171 UINT retVal = 0;
3172 STGMEDIUM medium;
3173 FORMATETC formatetc;
3175 TRACE("sv=%p\n", doSelected);
3177 if (!doSelected) return 0;
3179 /* Set the FORMATETC structure*/
3180 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3182 /* Get the pidls from IDataObject */
3183 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3185 LPIDA cida = GlobalLock(medium.u.hGlobal);
3186 retVal = cida->cidl;
3187 COMCTL32_ReleaseStgMedium(medium);
3188 return retVal;
3190 return 0;
3194 * TOOLS
3197 /***********************************************************************
3198 * GetName
3200 * Get the pidl's display name (relative to folder) and
3201 * put it in lpstrFileName.
3203 * Return NOERROR on success,
3204 * E_FAIL otherwise
3207 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3209 STRRET str;
3210 HRESULT hRes;
3212 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3214 if(!lpsf)
3216 SHGetDesktopFolder(&lpsf);
3217 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3218 IShellFolder_Release(lpsf);
3219 return hRes;
3222 /* Get the display name of the pidl relative to the folder */
3223 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3225 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3227 return E_FAIL;
3230 /***********************************************************************
3231 * GetShellFolderFromPidl
3233 * pidlRel is the item pidl relative
3234 * Return the IShellFolder of the absolute pidl
3236 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3238 IShellFolder *psf = NULL,*psfParent;
3240 TRACE("%p\n", pidlAbs);
3242 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3244 psf = psfParent;
3245 if(pidlAbs && pidlAbs->mkid.cb)
3247 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3249 IShellFolder_Release(psfParent);
3250 return psf;
3253 /* return the desktop */
3254 return psfParent;
3256 return NULL;
3259 /***********************************************************************
3260 * GetParentPidl
3262 * Return the LPITEMIDLIST to the parent of the pidl in the list
3264 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3266 LPITEMIDLIST pidlParent;
3268 TRACE("%p\n", pidl);
3270 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3271 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3273 return pidlParent;
3276 /***********************************************************************
3277 * GetPidlFromName
3279 * returns the pidl of the file name relative to folder
3280 * NULL if an error occurred
3282 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3284 LPITEMIDLIST pidl = NULL;
3285 ULONG ulEaten;
3287 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3289 if(!lpcstrFileName) return NULL;
3290 if(!*lpcstrFileName) return NULL;
3292 if(!lpsf)
3294 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3295 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3296 IShellFolder_Release(lpsf);
3299 else
3301 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3303 return pidl;
3308 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3310 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3311 HRESULT ret;
3313 TRACE("%p, %p\n", psf, pidl);
3315 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3317 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3318 /* see documentation shell 4.1*/
3319 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3322 /***********************************************************************
3323 * BrowseSelectedFolder
3325 static BOOL BrowseSelectedFolder(HWND hwnd)
3327 BOOL bBrowseSelFolder = FALSE;
3328 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3330 TRACE("\n");
3332 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3334 LPITEMIDLIST pidlSelection;
3336 /* get the file selected */
3337 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3338 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3340 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3341 pidlSelection, SBSP_RELATIVE ) ) )
3343 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3344 ' ','n','o','t',' ','e','x','i','s','t',0};
3345 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3348 bBrowseSelFolder = TRUE;
3350 COMDLG32_SHFree( pidlSelection );
3353 return bBrowseSelFolder;
3357 * Memory allocation methods */
3358 static void *MemAlloc(UINT size)
3360 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3363 static void MemFree(void *mem)
3365 HeapFree(GetProcessHeap(),0,mem);
3369 * Old-style (win3.1) dialogs */
3371 /***********************************************************************
3372 * FD32_GetTemplate [internal]
3374 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3375 * by a 32 bits application
3378 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3380 LPOPENFILENAMEW ofnW = lfs->ofnW;
3381 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3382 HANDLE hDlgTmpl;
3384 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3386 if (!(lfs->template = LockResource( ofnW->hInstance )))
3388 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3389 return FALSE;
3392 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3394 HRSRC hResInfo;
3395 if (priv->ofnA)
3396 hResInfo = FindResourceA(priv->ofnA->hInstance,
3397 priv->ofnA->lpTemplateName,
3398 (LPSTR)RT_DIALOG);
3399 else
3400 hResInfo = FindResourceW(ofnW->hInstance,
3401 ofnW->lpTemplateName,
3402 (LPWSTR)RT_DIALOG);
3403 if (!hResInfo)
3405 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3406 return FALSE;
3408 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3409 hResInfo)) ||
3410 !(lfs->template = LockResource(hDlgTmpl)))
3412 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3413 return FALSE;
3415 } else { /* get it from internal Wine resource */
3416 HRSRC hResInfo;
3417 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3418 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3420 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3421 return FALSE;
3423 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3424 !(lfs->template = LockResource( hDlgTmpl )))
3426 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3427 return FALSE;
3430 return TRUE;
3434 /************************************************************************
3435 * FD32_Init [internal]
3436 * called from the common 16/32 code to initialize 32 bit data
3438 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3440 BOOL IsUnicode = (BOOL) data;
3441 PFD32_PRIVATE priv;
3443 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3444 lfs->private1632 = priv;
3445 if (NULL == lfs->private1632) return FALSE;
3446 if (IsUnicode)
3448 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3449 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3450 if (lfs->ofnW->lpfnHook)
3451 lfs->hook = TRUE;
3453 else
3455 priv->ofnA = (LPOPENFILENAMEA) lParam;
3456 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3457 if (priv->ofnA->lpfnHook)
3458 lfs->hook = TRUE;
3459 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3460 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3463 if (! FD32_GetTemplate(lfs)) return FALSE;
3465 return TRUE;
3468 /***********************************************************************
3469 * FD32_CallWindowProc [internal]
3471 * called from the common 16/32 code to call the appropriate hook
3473 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3474 LPARAM lParam)
3476 BOOL ret;
3477 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3479 if (priv->ofnA)
3481 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3482 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3483 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3484 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3485 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3486 return ret;
3489 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3490 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3491 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3492 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3493 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3494 return ret;
3497 /***********************************************************************
3498 * FD32_UpdateResult [internal]
3499 * update the real client structures if any
3501 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3503 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3504 LPOPENFILENAMEW ofnW = lfs->ofnW;
3506 if (priv->ofnA)
3508 if (ofnW->nMaxFile &&
3509 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3510 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3511 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3512 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3513 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3517 /***********************************************************************
3518 * FD32_UpdateFileTitle [internal]
3519 * update the real client structures if any
3521 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3523 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3524 LPOPENFILENAMEW ofnW = lfs->ofnW;
3526 if (priv->ofnA)
3528 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3529 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3530 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3535 /***********************************************************************
3536 * FD32_SendLbGetCurSel [internal]
3537 * retrieve selected listbox item
3539 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3541 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3545 /************************************************************************
3546 * FD32_Destroy [internal]
3547 * called from the common 16/32 code to cleanup 32 bit data
3549 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3551 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3553 /* if ofnW has been allocated, have to free everything in it */
3554 if (NULL != priv && NULL != priv->ofnA)
3556 FD31_FreeOfnW(lfs->ofnW);
3557 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3561 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3563 callbacks->Init = FD32_Init;
3564 callbacks->CWP = FD32_CallWindowProc;
3565 callbacks->UpdateResult = FD32_UpdateResult;
3566 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3567 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3568 callbacks->Destroy = FD32_Destroy;
3571 /***********************************************************************
3572 * FD32_WMMeasureItem [internal]
3574 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3576 LPMEASUREITEMSTRUCT lpmeasure;
3578 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3579 lpmeasure->itemHeight = FD31_GetFldrHeight();
3580 return TRUE;
3584 /***********************************************************************
3585 * FileOpenDlgProc [internal]
3586 * Used for open and save, in fact.
3588 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3589 WPARAM wParam, LPARAM lParam)
3591 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3593 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3594 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3596 INT_PTR lRet;
3597 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3598 if (lRet)
3599 return lRet; /* else continue message processing */
3601 switch (wMsg)
3603 case WM_INITDIALOG:
3604 return FD31_WMInitDialog(hWnd, wParam, lParam);
3606 case WM_MEASUREITEM:
3607 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3609 case WM_DRAWITEM:
3610 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3612 case WM_COMMAND:
3613 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3614 #if 0
3615 case WM_CTLCOLOR:
3616 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3617 switch (HIWORD(lParam))
3619 case CTLCOLOR_BTN:
3620 SetTextColor((HDC16)wParam, 0x00000000);
3621 return hGRAYBrush;
3622 case CTLCOLOR_STATIC:
3623 SetTextColor((HDC16)wParam, 0x00000000);
3624 return hGRAYBrush;
3626 break;
3627 #endif
3629 return FALSE;
3633 /***********************************************************************
3634 * GetFileName31A [internal]
3636 * Creates a win31 style dialog box for the user to select a file to open/save.
3638 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3639 UINT dlgType /* type dialogue : open/save */
3642 HINSTANCE hInst;
3643 BOOL bRet = FALSE;
3644 PFD31_DATA lfs;
3645 FD31_CALLBACKS callbacks;
3647 if (!lpofn || !FD31_Init()) return FALSE;
3649 TRACE("ofn flags %08lx\n", lpofn->Flags);
3650 FD32_SetupCallbacks(&callbacks);
3651 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3652 if (lfs)
3654 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3655 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3656 FD32_FileOpenDlgProc, (LPARAM)lfs);
3657 FD31_DestroyPrivate(lfs);
3660 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3661 return bRet;
3664 /***********************************************************************
3665 * GetFileName31W [internal]
3667 * Creates a win31 style dialog box for the user to select a file to open/save
3669 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3670 UINT dlgType /* type dialogue : open/save */
3673 HINSTANCE hInst;
3674 BOOL bRet = FALSE;
3675 PFD31_DATA lfs;
3676 FD31_CALLBACKS callbacks;
3678 if (!lpofn || !FD31_Init()) return FALSE;
3680 FD32_SetupCallbacks(&callbacks);
3681 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3682 if (lfs)
3684 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3685 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3686 FD32_FileOpenDlgProc, (LPARAM)lfs);
3687 FD31_DestroyPrivate(lfs);
3690 TRACE("file %s, file offset %d, ext offset %d\n",
3691 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3692 return bRet;
3695 /* ------------------ APIs ---------------------- */
3697 /***********************************************************************
3698 * GetOpenFileNameA (COMDLG32.@)
3700 * Creates a dialog box for the user to select a file to open.
3702 * RETURNS
3703 * TRUE on success: user enters a valid file
3704 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3707 BOOL WINAPI GetOpenFileNameA(
3708 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3710 BOOL win16look = FALSE;
3712 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3713 if (ofn->Flags & OFN_FILEMUSTEXIST)
3714 ofn->Flags |= OFN_PATHMUSTEXIST;
3716 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3717 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3719 if (win16look)
3720 return GetFileName31A(ofn, OPEN_DIALOG);
3721 else
3722 return GetFileDialog95A(ofn, OPEN_DIALOG);
3725 /***********************************************************************
3726 * GetOpenFileNameW (COMDLG32.@)
3728 * Creates a dialog box for the user to select a file to open.
3730 * RETURNS
3731 * TRUE on success: user enters a valid file
3732 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3735 BOOL WINAPI GetOpenFileNameW(
3736 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3738 BOOL win16look = FALSE;
3740 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3741 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3743 if (win16look)
3744 return GetFileName31W(ofn, OPEN_DIALOG);
3745 else
3746 return GetFileDialog95W(ofn, OPEN_DIALOG);
3750 /***********************************************************************
3751 * GetSaveFileNameA (COMDLG32.@)
3753 * Creates a dialog box for the user to select a file to save.
3755 * RETURNS
3756 * TRUE on success: user enters a valid file
3757 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3760 BOOL WINAPI GetSaveFileNameA(
3761 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3763 BOOL win16look = FALSE;
3765 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3766 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3768 if (win16look)
3769 return GetFileName31A(ofn, SAVE_DIALOG);
3770 else
3771 return GetFileDialog95A(ofn, SAVE_DIALOG);
3774 /***********************************************************************
3775 * GetSaveFileNameW (COMDLG32.@)
3777 * Creates a dialog box for the user to select a file to save.
3779 * RETURNS
3780 * TRUE on success: user enters a valid file
3781 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3784 BOOL WINAPI GetSaveFileNameW(
3785 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3787 BOOL win16look = FALSE;
3789 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3790 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3792 if (win16look)
3793 return GetFileName31W(ofn, SAVE_DIALOG);
3794 else
3795 return GetFileDialog95W(ofn, SAVE_DIALOG);