Define DirectPlayLobbyCreate to be either the W or A version.
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blob64530ee1ba5bb19d1722608e573ee7ef06ea6646
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 = 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 LPSTR lpstrSavDir = NULL;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
453 /* Pass in the original ofn */
454 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
456 fodInfos.title = ofn->lpstrTitle;
457 fodInfos.defext = ofn->lpstrDefExt;
458 fodInfos.filter = ofn->lpstrFilter;
459 fodInfos.customfilter = ofn->lpstrCustomFilter;
461 /* convert string arguments, save others */
462 if(ofn->lpstrFile)
464 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
467 else
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 DWORD len = strlenW(ofn->lpstrInitialDir);
473 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
474 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
476 else
477 fodInfos.initdir = NULL;
479 /* save current directory */
480 if (ofn->Flags & OFN_NOCHANGEDIR)
482 lpstrSavDir = MemAlloc(MAX_PATH);
483 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
486 fodInfos.unicode = TRUE;
488 switch(iDlgType)
490 case OPEN_DIALOG :
491 ret = GetFileName95(&fodInfos);
492 break;
493 case SAVE_DIALOG :
494 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
495 ret = GetFileName95(&fodInfos);
496 break;
497 default :
498 ret = 0;
501 if (lpstrSavDir)
503 SetCurrentDirectoryA(lpstrSavDir);
504 MemFree(lpstrSavDir);
507 /* restore saved IN arguments and convert OUT arguments back */
508 MemFree(fodInfos.filename);
509 MemFree(fodInfos.initdir);
510 return ret;
513 /***********************************************************************
514 * ArrangeCtrlPositions [internal]
516 * NOTE: Do not change anything here without a lot of testing.
518 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
520 HWND hwndChild, hwndStc32;
521 RECT rectParent, rectChild, rectStc32;
522 INT help_fixup = 0, 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 = (LPOPENFILENAMEW) fodInfos->ofnInfos;
733 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
735 else
737 LPOPENFILENAMEA ofn = 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 = (LPOPENFILENAMEW) 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 = 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 SetWindowTextA(hwnd,"Save");
1170 /* Initialise the file name edit control */
1171 handledPath = FALSE;
1172 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1174 if(fodInfos->filename)
1176 /* 1. If win2000 or higher and filename contains a path, use it
1177 in preference over the lpstrInitialDir */
1178 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1179 WCHAR tmpBuf[MAX_PATH];
1180 WCHAR *nameBit;
1181 DWORD result;
1183 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1184 if (result) {
1186 /* nameBit is always shorter than the original filename */
1187 strcpyW(fodInfos->filename,nameBit);
1189 *nameBit = 0x00;
1190 if (fodInfos->initdir == NULL)
1191 MemFree(fodInfos->initdir);
1192 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1193 strcpyW(fodInfos->initdir, tmpBuf);
1194 handledPath = TRUE;
1195 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1196 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1198 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1200 } else {
1201 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1205 /* 2. (All platforms) If initdir is not null, then use it */
1206 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1207 (*fodInfos->initdir!=0x00))
1209 /* Work out the proper path as supplied one might be relative */
1210 /* (Here because supplying '.' as dir browses to My Computer) */
1211 if (handledPath==FALSE) {
1212 WCHAR tmpBuf[MAX_PATH];
1213 WCHAR tmpBuf2[MAX_PATH];
1214 WCHAR *nameBit;
1215 DWORD result;
1217 strcpyW(tmpBuf, fodInfos->initdir);
1218 if( PathFileExistsW(tmpBuf) ) {
1219 /* initdir does not have to be a directory. If a file is
1220 * specified, the dir part is taken */
1221 if( PathIsDirectoryW(tmpBuf)) {
1222 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1223 strcatW(tmpBuf, szwSlash);
1225 strcatW(tmpBuf, szwStar);
1227 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1228 if (result) {
1229 *nameBit = 0x00;
1230 if (fodInfos->initdir)
1231 MemFree(fodInfos->initdir);
1232 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1233 strcpyW(fodInfos->initdir, tmpBuf2);
1234 handledPath = TRUE;
1235 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1238 else if (fodInfos->initdir)
1240 MemFree(fodInfos->initdir);
1241 fodInfos->initdir = NULL;
1242 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1247 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1248 (*fodInfos->initdir==0x00)))
1250 /* 3. All except w2k+: if filename contains a path use it */
1251 if (!win2000plus && fodInfos->filename &&
1252 *fodInfos->filename &&
1253 strpbrkW(fodInfos->filename, szwSlash)) {
1254 WCHAR tmpBuf[MAX_PATH];
1255 WCHAR *nameBit;
1256 DWORD result;
1258 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1259 tmpBuf, &nameBit);
1260 if (result) {
1261 int len;
1263 /* nameBit is always shorter than the original filename */
1264 strcpyW(fodInfos->filename, nameBit);
1265 *nameBit = 0x00;
1267 len = strlenW(tmpBuf);
1268 if(fodInfos->initdir)
1269 MemFree(fodInfos->initdir);
1270 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1271 strcpyW(fodInfos->initdir, tmpBuf);
1273 handledPath = TRUE;
1274 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1275 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1277 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1280 /* 4. win98+ and win2000+ if any files of specified filter types in
1281 current directory, use it */
1282 if ( win98plus && handledPath == FALSE &&
1283 fodInfos->filter && *fodInfos->filter) {
1285 BOOL searchMore = TRUE;
1286 LPCWSTR lpstrPos = fodInfos->filter;
1287 WIN32_FIND_DATAW FindFileData;
1288 HANDLE hFind;
1290 while (searchMore)
1292 /* filter is a list... title\0ext\0......\0\0 */
1294 /* Skip the title */
1295 if(! *lpstrPos) break; /* end */
1296 lpstrPos += strlenW(lpstrPos) + 1;
1298 /* See if any files exist in the current dir with this extension */
1299 if(! *lpstrPos) break; /* end */
1301 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1303 if (hFind == INVALID_HANDLE_VALUE) {
1304 /* None found - continue search */
1305 lpstrPos += strlenW(lpstrPos) + 1;
1307 } else {
1308 searchMore = FALSE;
1310 if(fodInfos->initdir)
1311 MemFree(fodInfos->initdir);
1312 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1313 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1315 handledPath = TRUE;
1316 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1317 debugstr_w(lpstrPos));
1318 break;
1323 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1325 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1326 if (handledPath == FALSE && (win2000plus || win98plus)) {
1327 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1329 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1331 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1333 /* last fallback */
1334 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1335 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1336 } else {
1337 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1339 } else {
1340 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1342 handledPath = TRUE;
1343 } else if (handledPath==FALSE) {
1344 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1345 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1346 handledPath = TRUE;
1347 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1350 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1351 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1353 /* Must the open as read only check box be checked ?*/
1354 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1356 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1359 /* Must the open as read only check box be hidden? */
1360 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1362 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1363 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1366 /* Must the help button be hidden? */
1367 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1369 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1370 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1373 /* Resize the height, if open as read only checkbox ad help button
1374 are hidden and we are not using a custom template nor a customDialog
1376 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1377 (!(fodInfos->ofnInfos->Flags &
1378 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1379 (!fodInfos->DlgInfos.hwndCustomDlg ))
1381 RECT rectDlg, rectHelp, rectCancel;
1382 GetWindowRect(hwnd, &rectDlg);
1383 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1384 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1385 /* subtract the height of the help button plus the space between
1386 the help button and the cancel button to the height of the dialog */
1387 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1388 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1389 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1391 /* change Open to Save FIXME: use resources */
1392 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1394 SetDlgItemTextA(hwnd,IDOK,"&Save");
1395 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1397 return 0;
1400 /***********************************************************************
1401 * FILEDLG95_FillControls
1403 * WM_INITDIALOG message handler (after hook notification)
1405 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1407 LPITEMIDLIST pidlItemId = NULL;
1409 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1411 TRACE("dir=%s file=%s\n",
1412 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1414 /* Get the initial directory pidl */
1416 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1418 WCHAR path[MAX_PATH];
1420 GetCurrentDirectoryW(MAX_PATH,path);
1421 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1424 /* Initialise shell objects */
1425 FILEDLG95_SHELL_Init(hwnd);
1427 /* Initialize the Look In combo box */
1428 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1430 /* Initialize the filter combo box */
1431 FILEDLG95_FILETYPE_Init(hwnd);
1433 /* Browse to the initial directory */
1434 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1436 /* Free pidlItem memory */
1437 COMDLG32_SHFree(pidlItemId);
1439 return TRUE;
1441 /***********************************************************************
1442 * FILEDLG95_Clean
1444 * Regroups all the cleaning functions of the filedlg
1446 void FILEDLG95_Clean(HWND hwnd)
1448 FILEDLG95_FILETYPE_Clean(hwnd);
1449 FILEDLG95_LOOKIN_Clean(hwnd);
1450 FILEDLG95_SHELL_Clean(hwnd);
1452 /***********************************************************************
1453 * FILEDLG95_OnWMCommand
1455 * WM_COMMAND message handler
1457 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1459 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1460 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1461 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1463 switch(wID)
1465 /* OK button */
1466 case IDOK:
1467 FILEDLG95_OnOpen(hwnd);
1468 break;
1469 /* Cancel button */
1470 case IDCANCEL:
1471 FILEDLG95_Clean(hwnd);
1472 EndDialog(hwnd, FALSE);
1473 break;
1474 /* Filetype combo box */
1475 case IDC_FILETYPE:
1476 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1477 break;
1478 /* LookIn combo box */
1479 case IDC_LOOKIN:
1480 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1481 break;
1483 /* --- toolbar --- */
1484 /* Up folder button */
1485 case FCIDM_TB_UPFOLDER:
1486 FILEDLG95_SHELL_UpFolder(hwnd);
1487 break;
1488 /* New folder button */
1489 case FCIDM_TB_NEWFOLDER:
1490 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1491 break;
1492 /* List option button */
1493 case FCIDM_TB_SMALLICON:
1494 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1495 break;
1496 /* Details option button */
1497 case FCIDM_TB_REPORTVIEW:
1498 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1499 break;
1500 /* Details option button */
1501 case FCIDM_TB_DESKTOP:
1502 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1503 break;
1505 case IDC_FILENAME:
1506 break;
1509 /* Do not use the listview selection anymore */
1510 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1511 return 0;
1514 /***********************************************************************
1515 * FILEDLG95_OnWMGetIShellBrowser
1517 * WM_GETISHELLBROWSER message handler
1519 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1522 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1524 TRACE("\n");
1526 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1528 return TRUE;
1532 /***********************************************************************
1533 * FILEDLG95_SendFileOK
1535 * Sends the CDN_FILEOK notification if required
1537 * RETURNS
1538 * TRUE if the dialog should close
1539 * FALSE if the dialog should not be closed
1541 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1543 /* ask the hook if we can close */
1544 if(IsHooked(fodInfos))
1546 TRACE("---\n");
1547 /* First send CDN_FILEOK as MSDN doc says */
1548 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1549 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1551 TRACE("canceled\n");
1552 return FALSE;
1555 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1556 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1557 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1558 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1560 TRACE("canceled\n");
1561 return FALSE;
1564 return TRUE;
1567 /***********************************************************************
1568 * FILEDLG95_OnOpenMultipleFiles
1570 * Handles the opening of multiple files.
1572 * FIXME
1573 * check destination buffer size
1575 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1577 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1578 UINT nCount, nSizePath;
1579 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1581 TRACE("\n");
1583 if(fodInfos->unicode)
1585 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1586 ofn->lpstrFile[0] = '\0';
1588 else
1590 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1591 ofn->lpstrFile[0] = '\0';
1594 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1596 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1597 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1598 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1600 LPWSTR lpstrTemp = lpstrFileList;
1602 for ( nCount = 0; nCount < nFileCount; nCount++ )
1604 LPITEMIDLIST pidl;
1606 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1607 if (!pidl)
1609 WCHAR lpstrNotFound[100];
1610 WCHAR lpstrMsg[100];
1611 WCHAR tmp[400];
1612 static const WCHAR nl[] = {'\n',0};
1614 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1615 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1617 strcpyW(tmp, lpstrTemp);
1618 strcatW(tmp, nl);
1619 strcatW(tmp, lpstrNotFound);
1620 strcatW(tmp, nl);
1621 strcatW(tmp, lpstrMsg);
1623 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1624 return FALSE;
1627 /* move to the next file in the list of files */
1628 lpstrTemp += strlenW(lpstrTemp) + 1;
1629 COMDLG32_SHFree(pidl);
1633 nSizePath = strlenW(lpstrPathSpec) + 1;
1634 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1636 /* For "oldstyle" dialog the components have to
1637 be separated by blanks (not '\0'!) and short
1638 filenames have to be used! */
1639 FIXME("Components have to be separated by blanks\n");
1641 if(fodInfos->unicode)
1643 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1644 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1645 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1647 else
1649 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1651 if (ofn->lpstrFile != NULL)
1653 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1654 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1655 if (ofn->nMaxFile > nSizePath)
1657 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1658 ofn->lpstrFile + nSizePath,
1659 ofn->nMaxFile - nSizePath, NULL, NULL);
1664 fodInfos->ofnInfos->nFileOffset = nSizePath;
1665 fodInfos->ofnInfos->nFileExtension = 0;
1667 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1668 return FALSE;
1670 /* clean and exit */
1671 FILEDLG95_Clean(hwnd);
1672 return EndDialog(hwnd,TRUE);
1675 /***********************************************************************
1676 * FILEDLG95_OnOpen
1678 * Ok button WM_COMMAND message handler
1680 * If the function succeeds, the return value is nonzero.
1682 #define ONOPEN_BROWSE 1
1683 #define ONOPEN_OPEN 2
1684 #define ONOPEN_SEARCH 3
1685 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1687 char strMsgTitle[MAX_PATH];
1688 char strMsgText [MAX_PATH];
1689 if (idCaption)
1690 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1691 else
1692 strMsgTitle[0] = '\0';
1693 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1694 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1697 BOOL FILEDLG95_OnOpen(HWND hwnd)
1699 LPWSTR lpstrFileList;
1700 UINT nFileCount = 0;
1701 UINT sizeUsed = 0;
1702 BOOL ret = TRUE;
1703 WCHAR lpstrPathAndFile[MAX_PATH];
1704 WCHAR lpstrTemp[MAX_PATH];
1705 LPSHELLFOLDER lpsf = NULL;
1706 int nOpenAction;
1707 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1709 TRACE("hwnd=%p\n", hwnd);
1711 /* get the files from the edit control */
1712 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1714 /* try if the user selected a folder in the shellview */
1715 if(nFileCount == 0)
1717 BrowseSelectedFolder(hwnd);
1718 return FALSE;
1721 if(nFileCount > 1)
1723 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1724 goto ret;
1727 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1730 Step 1: Build a complete path name from the current folder and
1731 the filename or path in the edit box.
1732 Special cases:
1733 - the path in the edit box is a root path
1734 (with or without drive letter)
1735 - the edit box contains ".." (or a path with ".." in it)
1738 /* Get the current directory name */
1739 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1741 /* we are in a special folder, default to desktop */
1742 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1744 /* last fallback */
1745 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1748 PathAddBackslashW(lpstrPathAndFile);
1750 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1752 /* if the user specifyed a fully qualified path use it */
1753 if(PathIsRelativeW(lpstrFileList))
1755 strcatW(lpstrPathAndFile, lpstrFileList);
1757 else
1759 /* does the path have a drive letter? */
1760 if (PathGetDriveNumberW(lpstrFileList) == -1)
1761 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1762 else
1763 strcpyW(lpstrPathAndFile, lpstrFileList);
1766 /* resolve "." and ".." */
1767 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1768 strcpyW(lpstrPathAndFile, lpstrTemp);
1769 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1771 MemFree(lpstrFileList);
1774 Step 2: here we have a cleaned up path
1776 We have to parse the path step by step to see if we have to browse
1777 to a folder if the path points to a directory or the last
1778 valid element is a directory.
1780 valid variables:
1781 lpstrPathAndFile: cleaned up path
1784 nOpenAction = ONOPEN_BROWSE;
1786 /* don't apply any checks with OFN_NOVALIDATE */
1788 LPWSTR lpszTemp, lpszTemp1;
1789 LPITEMIDLIST pidl = NULL;
1790 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1792 /* check for invalid chars */
1793 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1795 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1796 ret = FALSE;
1797 goto ret;
1800 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1802 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1803 while (lpszTemp1)
1805 LPSHELLFOLDER lpsfChild;
1806 WCHAR lpwstrTemp[MAX_PATH];
1807 DWORD dwEaten, dwAttributes;
1808 LPWSTR p;
1810 strcpyW(lpwstrTemp, lpszTemp);
1811 p = PathFindNextComponentW(lpwstrTemp);
1813 if (!p) break; /* end of path */
1815 *p = 0;
1816 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1818 if(*lpszTemp==0)
1820 static const WCHAR wszWild[] = { '*', '?', 0 };
1821 /* if the last element is a wildcard do a search */
1822 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1824 nOpenAction = ONOPEN_SEARCH;
1825 break;
1828 lpszTemp1 = lpszTemp;
1830 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1832 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1834 dwAttributes = SFGAO_FOLDER;
1835 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1837 /* the path component is valid, we have a pidl of the next path component */
1838 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1839 if(dwAttributes & SFGAO_FOLDER)
1841 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1843 ERR("bind to failed\n"); /* should not fail */
1844 break;
1846 IShellFolder_Release(lpsf);
1847 lpsf = lpsfChild;
1848 lpsfChild = NULL;
1850 else
1852 TRACE("value\n");
1854 /* end dialog, return value */
1855 nOpenAction = ONOPEN_OPEN;
1856 break;
1858 COMDLG32_SHFree(pidl);
1859 pidl = NULL;
1861 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1863 if(*lpszTemp) /* points to trailing null for last path element */
1865 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1867 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1868 break;
1871 else
1873 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1874 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1876 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1877 break;
1880 /* change to the current folder */
1881 nOpenAction = ONOPEN_OPEN;
1882 break;
1884 else
1886 nOpenAction = ONOPEN_OPEN;
1887 break;
1890 if(pidl) COMDLG32_SHFree(pidl);
1894 Step 3: here we have a cleaned up and validated path
1896 valid variables:
1897 lpsf: ShellFolder bound to the rightmost valid path component
1898 lpstrPathAndFile: cleaned up path
1899 nOpenAction: action to do
1901 TRACE("end validate sf=%p\n", lpsf);
1903 switch(nOpenAction)
1905 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1906 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1908 int iPos;
1909 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1910 DWORD len;
1912 /* replace the current filter */
1913 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1914 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1915 len = strlenW(lpszTemp)+1;
1916 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1917 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1919 /* set the filter cb to the extension when possible */
1920 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1921 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1923 /* fall through */
1924 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1925 TRACE("ONOPEN_BROWSE\n");
1927 IPersistFolder2 * ppf2;
1928 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1930 LPITEMIDLIST pidlCurrent;
1931 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1932 IPersistFolder2_Release(ppf2);
1933 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1935 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1937 else if( nOpenAction == ONOPEN_SEARCH )
1939 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1941 COMDLG32_SHFree(pidlCurrent);
1944 ret = FALSE;
1945 break;
1946 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1947 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1949 WCHAR *ext = NULL;
1951 /* update READONLY check box flag */
1952 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1953 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1954 else
1955 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1957 /* Attach the file extension with file name*/
1958 ext = PathFindExtensionW(lpstrPathAndFile);
1959 if (! *ext)
1961 /* if no extension is specified with file name, then */
1962 /* attach the extension from file filter or default one */
1964 WCHAR *filterExt = NULL;
1965 LPWSTR lpstrFilter = NULL;
1966 static const WCHAR szwDot[] = {'.',0};
1967 int PathLength = strlenW(lpstrPathAndFile);
1969 /* Attach the dot*/
1970 strcatW(lpstrPathAndFile, szwDot);
1972 /*Get the file extension from file type filter*/
1973 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1974 fodInfos->ofnInfos->nFilterIndex-1);
1976 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
1977 filterExt = PathFindExtensionW(lpstrFilter);
1979 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
1980 strcatW(lpstrPathAndFile, filterExt + 1);
1981 else if ( fodInfos->defext ) /* attach the default file extension*/
1982 strcatW(lpstrPathAndFile, fodInfos->defext);
1984 /* In Open dialog: if file does not exist try without extension */
1985 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
1986 lpstrPathAndFile[PathLength] = '\0';
1989 if (fodInfos->defext) /* add default extension */
1991 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1992 if (*ext)
1993 ext++;
1994 if (!lstrcmpiW(fodInfos->defext, ext))
1995 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1996 else
1997 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2000 /* In Save dialog: check if the file already exists */
2001 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2002 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2003 && PathFileExistsW(lpstrPathAndFile))
2005 WCHAR lpstrOverwrite[100];
2006 int answer;
2008 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2009 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2010 MB_YESNO | MB_ICONEXCLAMATION);
2011 if (answer == IDNO)
2013 ret = FALSE;
2014 goto ret;
2018 /* Check that the size of the file does not exceed buffer size.
2019 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2020 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2021 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2023 LPWSTR lpszTemp;
2025 /* fill destination buffer */
2026 if (fodInfos->ofnInfos->lpstrFile)
2028 if(fodInfos->unicode)
2030 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
2032 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2033 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2034 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2036 else
2038 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
2040 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2041 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2042 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2043 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2047 /* set filename offset */
2048 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2049 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2051 /* set extension offset */
2052 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2053 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2055 /* set the lpstrFileTitle */
2056 if(fodInfos->ofnInfos->lpstrFileTitle)
2058 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2059 if(fodInfos->unicode)
2061 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
2062 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2064 else
2066 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
2067 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2068 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2072 /* copy currently selected filter to lpstrCustomFilter */
2073 if (fodInfos->ofnInfos->lpstrCustomFilter)
2075 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
2076 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2077 NULL, 0, NULL, NULL);
2078 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2080 LPSTR s = ofn->lpstrCustomFilter;
2081 s += strlen(ofn->lpstrCustomFilter)+1;
2082 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2083 s, len, NULL, NULL);
2088 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2089 goto ret;
2091 TRACE("close\n");
2092 FILEDLG95_Clean(hwnd);
2093 ret = EndDialog(hwnd, TRUE);
2095 else
2097 WORD size;
2099 size = strlenW(lpstrPathAndFile) + 1;
2100 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2101 size += 1;
2102 /* return needed size in first two bytes of lpstrFile */
2103 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2104 FILEDLG95_Clean(hwnd);
2105 ret = EndDialog(hwnd, FALSE);
2106 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2108 goto ret;
2110 break;
2113 ret:
2114 if(lpsf) IShellFolder_Release(lpsf);
2115 return ret;
2118 /***********************************************************************
2119 * FILEDLG95_SHELL_Init
2121 * Initialisation of the shell objects
2123 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2125 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2127 TRACE("\n");
2130 * Initialisation of the FileOpenDialogInfos structure
2133 /* Shell */
2135 /*ShellInfos */
2136 fodInfos->ShellInfos.hwndOwner = hwnd;
2138 /* Disable multi-select if flag not set */
2139 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2141 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2143 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2144 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2146 /* Construct the IShellBrowser interface */
2147 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2149 return NOERROR;
2152 /***********************************************************************
2153 * FILEDLG95_SHELL_ExecuteCommand
2155 * Change the folder option and refresh the view
2156 * If the function succeeds, the return value is nonzero.
2158 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2160 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2162 IContextMenu * pcm;
2163 TRACE("(%p,%p)\n", hwnd, lpVerb);
2165 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2166 SVGIO_BACKGROUND,
2167 &IID_IContextMenu,
2168 (LPVOID*)&pcm)))
2170 CMINVOKECOMMANDINFO ci;
2171 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2172 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2173 ci.lpVerb = lpVerb;
2174 ci.hwnd = hwnd;
2176 IContextMenu_InvokeCommand(pcm, &ci);
2177 IContextMenu_Release(pcm);
2180 return FALSE;
2183 /***********************************************************************
2184 * FILEDLG95_SHELL_UpFolder
2186 * Browse to the specified object
2187 * If the function succeeds, the return value is nonzero.
2189 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2191 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2193 TRACE("\n");
2195 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2196 NULL,
2197 SBSP_PARENT)))
2199 return TRUE;
2201 return FALSE;
2204 /***********************************************************************
2205 * FILEDLG95_SHELL_BrowseToDesktop
2207 * Browse to the Desktop
2208 * If the function succeeds, the return value is nonzero.
2210 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2212 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2213 LPITEMIDLIST pidl;
2214 HRESULT hres;
2216 TRACE("\n");
2218 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2219 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2220 COMDLG32_SHFree(pidl);
2221 return SUCCEEDED(hres);
2223 /***********************************************************************
2224 * FILEDLG95_SHELL_Clean
2226 * Cleans the memory used by shell objects
2228 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2230 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2232 TRACE("\n");
2234 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2236 /* clean Shell interfaces */
2237 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2238 IShellView_Release(fodInfos->Shell.FOIShellView);
2239 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2240 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2241 if (fodInfos->Shell.FOIDataObject)
2242 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2245 /***********************************************************************
2246 * FILEDLG95_FILETYPE_Init
2248 * Initialisation of the file type combo box
2250 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2252 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2253 int nFilters = 0; /* number of filters */
2254 int nFilterIndexCB;
2256 TRACE("\n");
2258 if(fodInfos->customfilter)
2260 /* customfilter has one entry... title\0ext\0
2261 * Set first entry of combo box item with customfilter
2263 LPWSTR lpstrExt;
2264 LPCWSTR lpstrPos = fodInfos->customfilter;
2266 /* Get the title */
2267 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2269 /* Copy the extensions */
2270 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2271 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2272 strcpyW(lpstrExt,lpstrPos);
2274 /* Add the item at the end of the combo */
2275 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2276 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2277 nFilters++;
2279 if(fodInfos->filter)
2281 LPCWSTR lpstrPos = fodInfos->filter;
2283 for(;;)
2285 /* filter is a list... title\0ext\0......\0\0
2286 * Set the combo item text to the title and the item data
2287 * to the ext
2289 LPCWSTR lpstrDisplay;
2290 LPWSTR lpstrExt;
2292 /* Get the title */
2293 if(! *lpstrPos) break; /* end */
2294 lpstrDisplay = lpstrPos;
2295 lpstrPos += strlenW(lpstrPos) + 1;
2297 /* Copy the extensions */
2298 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2299 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2300 strcpyW(lpstrExt,lpstrPos);
2301 lpstrPos += strlenW(lpstrPos) + 1;
2303 /* Add the item at the end of the combo */
2304 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2305 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2306 nFilters++;
2311 * Set the current filter to the one specified
2312 * in the initialisation structure
2314 if (fodInfos->filter || fodInfos->customfilter)
2316 LPWSTR lpstrFilter;
2318 /* Check to make sure our index isn't out of bounds. */
2319 if ( fodInfos->ofnInfos->nFilterIndex >
2320 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2321 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2323 /* set default filter index */
2324 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2325 fodInfos->ofnInfos->nFilterIndex = 1;
2327 /* calculate index of Combo Box item */
2328 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2329 if (fodInfos->customfilter == NULL)
2330 nFilterIndexCB--;
2332 /* Set the current index selection. */
2333 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2335 /* Get the corresponding text string from the combo box. */
2336 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2337 nFilterIndexCB);
2339 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2340 lpstrFilter = NULL;
2342 if(lpstrFilter)
2344 DWORD len;
2345 CharLowerW(lpstrFilter); /* lowercase */
2346 len = strlenW(lpstrFilter)+1;
2347 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2348 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2350 } else
2351 fodInfos->ofnInfos->nFilterIndex = 0;
2353 return NOERROR;
2356 /***********************************************************************
2357 * FILEDLG95_FILETYPE_OnCommand
2359 * WM_COMMAND of the file type combo box
2360 * If the function succeeds, the return value is nonzero.
2362 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2364 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2366 switch(wNotifyCode)
2368 case CBN_SELENDOK:
2370 LPWSTR lpstrFilter;
2372 /* Get the current item of the filetype combo box */
2373 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2375 /* set the current filter index */
2376 fodInfos->ofnInfos->nFilterIndex = iItem +
2377 (fodInfos->customfilter == NULL ? 1 : 0);
2379 /* Set the current filter with the current selection */
2380 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2381 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2383 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2384 iItem);
2385 if((int)lpstrFilter != CB_ERR)
2387 DWORD len;
2388 CharLowerW(lpstrFilter); /* lowercase */
2389 len = strlenW(lpstrFilter)+1;
2390 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2391 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2392 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2395 /* Refresh the actual view to display the included items*/
2396 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2399 return FALSE;
2401 /***********************************************************************
2402 * FILEDLG95_FILETYPE_SearchExt
2404 * searches for a extension in the filetype box
2406 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2408 int i, iCount = CBGetCount(hwnd);
2410 TRACE("%s\n", debugstr_w(lpstrExt));
2412 if(iCount != CB_ERR)
2414 for(i=0;i<iCount;i++)
2416 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2417 return i;
2420 return -1;
2423 /***********************************************************************
2424 * FILEDLG95_FILETYPE_Clean
2426 * Clean the memory used by the filetype combo box
2428 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2430 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2431 int iPos;
2432 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2434 TRACE("\n");
2436 /* Delete each string of the combo and their associated data */
2437 if(iCount != CB_ERR)
2439 for(iPos = iCount-1;iPos>=0;iPos--)
2441 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2442 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2445 /* Current filter */
2446 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2447 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2451 /***********************************************************************
2452 * FILEDLG95_LOOKIN_Init
2454 * Initialisation of the look in combo box
2456 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2458 IShellFolder *psfRoot, *psfDrives;
2459 IEnumIDList *lpeRoot, *lpeDrives;
2460 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2462 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2464 TRACE("\n");
2466 liInfos->iMaxIndentation = 0;
2468 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2470 /* set item height for both text field and listbox */
2471 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2472 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2474 /* Turn on the extended UI for the combo box like Windows does */
2475 CBSetExtendedUI(hwndCombo, TRUE);
2477 /* Initialise data of Desktop folder */
2478 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2479 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2480 COMDLG32_SHFree(pidlTmp);
2482 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2484 SHGetDesktopFolder(&psfRoot);
2486 if (psfRoot)
2488 /* enumerate the contents of the desktop */
2489 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2491 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2493 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2495 /* special handling for CSIDL_DRIVES */
2496 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2498 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2500 /* enumerate the drives */
2501 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2503 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2505 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2506 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2507 COMDLG32_SHFree(pidlAbsTmp);
2508 COMDLG32_SHFree(pidlTmp1);
2510 IEnumIDList_Release(lpeDrives);
2512 IShellFolder_Release(psfDrives);
2515 COMDLG32_SHFree(pidlTmp);
2517 IEnumIDList_Release(lpeRoot);
2519 IShellFolder_Release(psfRoot);
2522 COMDLG32_SHFree(pidlDrives);
2523 return NOERROR;
2526 /***********************************************************************
2527 * FILEDLG95_LOOKIN_DrawItem
2529 * WM_DRAWITEM message handler
2531 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2533 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2534 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2535 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2536 RECT rectText;
2537 RECT rectIcon;
2538 SHFILEINFOA sfi;
2539 HIMAGELIST ilItemImage;
2540 int iIndentation;
2541 TEXTMETRICA tm;
2542 LPSFOLDER tmpFolder;
2545 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2547 TRACE("\n");
2549 if(pDIStruct->itemID == -1)
2550 return 0;
2552 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2553 pDIStruct->itemID)))
2554 return 0;
2557 if(pDIStruct->itemID == liInfos->uSelectedItem)
2559 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2561 &sfi,
2562 sizeof (SHFILEINFOA),
2563 SHGFI_PIDL | SHGFI_SMALLICON |
2564 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2565 SHGFI_DISPLAYNAME );
2567 else
2569 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2571 &sfi,
2572 sizeof (SHFILEINFOA),
2573 SHGFI_PIDL | SHGFI_SMALLICON |
2574 SHGFI_SYSICONINDEX |
2575 SHGFI_DISPLAYNAME);
2578 /* Is this item selected ? */
2579 if(pDIStruct->itemState & ODS_SELECTED)
2581 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2582 SetBkColor(pDIStruct->hDC,crHighLight);
2583 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2585 else
2587 SetTextColor(pDIStruct->hDC,crText);
2588 SetBkColor(pDIStruct->hDC,crWin);
2589 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2592 /* Do not indent item if drawing in the edit of the combo */
2593 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2595 iIndentation = 0;
2596 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2598 &sfi,
2599 sizeof (SHFILEINFOA),
2600 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2601 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2604 else
2606 iIndentation = tmpFolder->m_iIndent;
2608 /* Draw text and icon */
2610 /* Initialise the icon display area */
2611 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2612 rectIcon.top = pDIStruct->rcItem.top;
2613 rectIcon.right = rectIcon.left + ICONWIDTH;
2614 rectIcon.bottom = pDIStruct->rcItem.bottom;
2616 /* Initialise the text display area */
2617 GetTextMetricsA(pDIStruct->hDC, &tm);
2618 rectText.left = rectIcon.right;
2619 rectText.top =
2620 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2621 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2622 rectText.bottom =
2623 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2625 /* Draw the icon from the image list */
2626 ImageList_Draw(ilItemImage,
2627 sfi.iIcon,
2628 pDIStruct->hDC,
2629 rectIcon.left,
2630 rectIcon.top,
2631 ILD_TRANSPARENT );
2633 /* Draw the associated text */
2634 if(sfi.szDisplayName)
2635 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2638 return NOERROR;
2641 /***********************************************************************
2642 * FILEDLG95_LOOKIN_OnCommand
2644 * LookIn combo box WM_COMMAND message handler
2645 * If the function succeeds, the return value is nonzero.
2647 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2649 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2651 TRACE("%p\n", fodInfos);
2653 switch(wNotifyCode)
2655 case CBN_SELENDOK:
2657 LPSFOLDER tmpFolder;
2658 int iItem;
2660 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2662 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2663 iItem)))
2664 return FALSE;
2667 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2668 tmpFolder->pidlItem,
2669 SBSP_ABSOLUTE)))
2671 return TRUE;
2673 break;
2677 return FALSE;
2680 /***********************************************************************
2681 * FILEDLG95_LOOKIN_AddItem
2683 * Adds an absolute pidl item to the lookin combo box
2684 * returns the index of the inserted item
2686 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2688 LPITEMIDLIST pidlNext;
2689 SHFILEINFOA sfi;
2690 SFOLDER *tmpFolder;
2691 LookInInfos *liInfos;
2693 TRACE("%08x\n", iInsertId);
2695 if(!pidl)
2696 return -1;
2698 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2699 return -1;
2701 tmpFolder = MemAlloc(sizeof(SFOLDER));
2702 tmpFolder->m_iIndent = 0;
2704 /* Calculate the indentation of the item in the lookin*/
2705 pidlNext = pidl;
2706 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2708 tmpFolder->m_iIndent++;
2711 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2713 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2714 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2716 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2717 SHGetFileInfoA((LPSTR)pidl,
2719 &sfi,
2720 sizeof(sfi),
2721 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2722 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2724 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2726 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2728 int iItemID;
2730 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2732 /* Add the item at the end of the list */
2733 if(iInsertId < 0)
2735 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2737 /* Insert the item at the iInsertId position*/
2738 else
2740 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2743 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2744 return iItemID;
2747 COMDLG32_SHFree( tmpFolder->pidlItem );
2748 MemFree( tmpFolder );
2749 return -1;
2753 /***********************************************************************
2754 * FILEDLG95_LOOKIN_InsertItemAfterParent
2756 * Insert an item below its parent
2758 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2761 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2762 int iParentPos;
2764 TRACE("\n");
2766 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2768 if(iParentPos < 0)
2770 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2773 /* Free pidlParent memory */
2774 COMDLG32_SHFree((LPVOID)pidlParent);
2776 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2779 /***********************************************************************
2780 * FILEDLG95_LOOKIN_SelectItem
2782 * Adds an absolute pidl item to the lookin combo box
2783 * returns the index of the inserted item
2785 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2787 int iItemPos;
2788 LookInInfos *liInfos;
2790 TRACE("\n");
2792 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2794 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2796 if(iItemPos < 0)
2798 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2799 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2802 else
2804 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2805 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2807 int iRemovedItem;
2809 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2810 break;
2811 if(iRemovedItem < iItemPos)
2812 iItemPos--;
2816 CBSetCurSel(hwnd,iItemPos);
2817 liInfos->uSelectedItem = iItemPos;
2819 return 0;
2823 /***********************************************************************
2824 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2826 * Remove the item with an expansion level over iExpansionLevel
2828 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2830 int iItemPos;
2832 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2834 TRACE("\n");
2836 if(liInfos->iMaxIndentation <= 2)
2837 return -1;
2839 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2841 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2842 COMDLG32_SHFree(tmpFolder->pidlItem);
2843 MemFree(tmpFolder);
2844 CBDeleteString(hwnd,iItemPos);
2845 liInfos->iMaxIndentation--;
2847 return iItemPos;
2850 return -1;
2853 /***********************************************************************
2854 * FILEDLG95_LOOKIN_SearchItem
2856 * Search for pidl in the lookin combo box
2857 * returns the index of the found item
2859 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2861 int i = 0;
2862 int iCount = CBGetCount(hwnd);
2864 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2866 if (iCount != CB_ERR)
2868 for(;i<iCount;i++)
2870 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2872 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2873 return i;
2874 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2875 return i;
2879 return -1;
2882 /***********************************************************************
2883 * FILEDLG95_LOOKIN_Clean
2885 * Clean the memory used by the lookin combo box
2887 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2889 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2890 int iPos;
2891 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2893 TRACE("\n");
2895 /* Delete each string of the combo and their associated data */
2896 if (iCount != CB_ERR)
2898 for(iPos = iCount-1;iPos>=0;iPos--)
2900 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2901 COMDLG32_SHFree(tmpFolder->pidlItem);
2902 MemFree(tmpFolder);
2903 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2907 /* LookInInfos structure */
2908 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2911 /***********************************************************************
2912 * FILEDLG95_FILENAME_FillFromSelection
2914 * fills the edit box from the cached DataObject
2916 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2918 FileOpenDlgInfos *fodInfos;
2919 LPITEMIDLIST pidl;
2920 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2921 char lpstrTemp[MAX_PATH];
2922 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2924 TRACE("\n");
2925 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2927 /* Count how many files we have */
2928 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2930 /* calculate the string length, count files */
2931 if (nFileSelected >= 1)
2933 nLength += 3; /* first and last quotes, trailing \0 */
2934 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2936 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2938 if (pidl)
2940 /* get the total length of the selected file names */
2941 lpstrTemp[0] = '\0';
2942 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2944 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2946 nLength += strlen( lpstrTemp ) + 3;
2947 nFiles++;
2949 COMDLG32_SHFree( pidl );
2954 /* allocate the buffer */
2955 if (nFiles <= 1) nLength = MAX_PATH;
2956 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2957 lpstrAllFile[0] = '\0';
2959 /* Generate the string for the edit control */
2960 if(nFiles >= 1)
2962 lpstrCurrFile = lpstrAllFile;
2963 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2965 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2967 if (pidl)
2969 /* get the file name */
2970 lpstrTemp[0] = '\0';
2971 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2973 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2975 if ( nFiles > 1)
2977 *lpstrCurrFile++ = '\"';
2978 strcpy( lpstrCurrFile, lpstrTemp );
2979 lpstrCurrFile += strlen( lpstrTemp );
2980 strcpy( lpstrCurrFile, "\" " );
2981 lpstrCurrFile += 2;
2983 else
2985 strcpy( lpstrAllFile, lpstrTemp );
2988 COMDLG32_SHFree( (LPVOID) pidl );
2991 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2993 /* Select the file name like Windows does */
2994 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2996 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3000 /* copied from shell32 to avoid linking to it */
3001 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3003 switch (src->uType)
3005 case STRRET_WSTR:
3006 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3007 COMDLG32_SHFree(src->u.pOleStr);
3008 break;
3010 case STRRET_CSTR:
3011 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3012 break;
3014 case STRRET_OFFSET:
3015 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3016 break;
3018 default:
3019 FIXME("unknown type!\n");
3020 if (len)
3022 *(LPSTR)dest = '\0';
3024 return(FALSE);
3026 return S_OK;
3029 /***********************************************************************
3030 * FILEDLG95_FILENAME_GetFileNames
3032 * Copies the filenames to a delimited string list.
3033 * The delimiter is specified by the parameter 'separator',
3034 * usually either a space or a nul
3036 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3038 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3039 UINT nStrCharCount = 0; /* index in src buffer */
3040 UINT nFileIndex = 0; /* index in dest buffer */
3041 UINT nFileCount = 0; /* number of files */
3042 UINT nStrLen = 0; /* length of string in edit control */
3043 LPWSTR lpstrEdit; /* buffer for string from edit control */
3045 TRACE("\n");
3047 /* get the filenames from the edit control */
3048 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3049 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3050 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3052 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3054 /* we might get single filename without any '"',
3055 * so we need nStrLen + terminating \0 + end-of-list \0 */
3056 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3057 *sizeUsed = 0;
3059 /* build delimited file list from filenames */
3060 while ( nStrCharCount <= nStrLen )
3062 if ( lpstrEdit[nStrCharCount]=='"' )
3064 nStrCharCount++;
3065 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3067 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3068 (*sizeUsed)++;
3069 nStrCharCount++;
3071 (*lpstrFileList)[nFileIndex++] = separator;
3072 (*sizeUsed)++;
3073 nFileCount++;
3075 nStrCharCount++;
3078 /* single, unquoted string */
3079 if ((nStrLen > 0) && (*sizeUsed == 0) )
3081 strcpyW(*lpstrFileList, lpstrEdit);
3082 nFileIndex = strlenW(lpstrEdit) + 1;
3083 (*sizeUsed) = nFileIndex;
3084 nFileCount = 1;
3087 /* trailing \0 */
3088 (*lpstrFileList)[nFileIndex] = '\0';
3089 (*sizeUsed)++;
3091 MemFree(lpstrEdit);
3092 return nFileCount;
3095 #define SETDefFormatEtc(fe,cf,med) \
3097 (fe).cfFormat = cf;\
3098 (fe).dwAspect = DVASPECT_CONTENT; \
3099 (fe).ptd =NULL;\
3100 (fe).tymed = med;\
3101 (fe).lindex = -1;\
3105 * DATAOBJECT Helper functions
3108 /***********************************************************************
3109 * COMCTL32_ReleaseStgMedium
3111 * like ReleaseStgMedium from ole32
3113 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3115 if(medium.pUnkForRelease)
3117 IUnknown_Release(medium.pUnkForRelease);
3119 else
3121 GlobalUnlock(medium.u.hGlobal);
3122 GlobalFree(medium.u.hGlobal);
3126 /***********************************************************************
3127 * GetPidlFromDataObject
3129 * Return pidl(s) by number from the cached DataObject
3131 * nPidlIndex=0 gets the fully qualified root path
3133 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3136 STGMEDIUM medium;
3137 FORMATETC formatetc;
3138 LPITEMIDLIST pidl = NULL;
3140 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3142 /* Set the FORMATETC structure*/
3143 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3145 /* Get the pidls from IDataObject */
3146 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3148 LPIDA cida = GlobalLock(medium.u.hGlobal);
3149 if(nPidlIndex <= cida->cidl)
3151 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3153 COMCTL32_ReleaseStgMedium(medium);
3155 return pidl;
3158 /***********************************************************************
3159 * GetNumSelected
3161 * Return the number of selected items in the DataObject.
3164 UINT GetNumSelected( IDataObject *doSelected )
3166 UINT retVal = 0;
3167 STGMEDIUM medium;
3168 FORMATETC formatetc;
3170 TRACE("sv=%p\n", doSelected);
3172 if (!doSelected) return 0;
3174 /* Set the FORMATETC structure*/
3175 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3177 /* Get the pidls from IDataObject */
3178 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3180 LPIDA cida = GlobalLock(medium.u.hGlobal);
3181 retVal = cida->cidl;
3182 COMCTL32_ReleaseStgMedium(medium);
3183 return retVal;
3185 return 0;
3189 * TOOLS
3192 /***********************************************************************
3193 * GetName
3195 * Get the pidl's display name (relative to folder) and
3196 * put it in lpstrFileName.
3198 * Return NOERROR on success,
3199 * E_FAIL otherwise
3202 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3204 STRRET str;
3205 HRESULT hRes;
3207 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3209 if(!lpsf)
3211 HRESULT hRes;
3212 SHGetDesktopFolder(&lpsf);
3213 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3214 IShellFolder_Release(lpsf);
3215 return hRes;
3218 /* Get the display name of the pidl relative to the folder */
3219 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3221 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3223 return E_FAIL;
3226 /***********************************************************************
3227 * GetShellFolderFromPidl
3229 * pidlRel is the item pidl relative
3230 * Return the IShellFolder of the absolute pidl
3232 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3234 IShellFolder *psf = NULL,*psfParent;
3236 TRACE("%p\n", pidlAbs);
3238 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3240 psf = psfParent;
3241 if(pidlAbs && pidlAbs->mkid.cb)
3243 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3245 IShellFolder_Release(psfParent);
3246 return psf;
3249 /* return the desktop */
3250 return psfParent;
3252 return NULL;
3255 /***********************************************************************
3256 * GetParentPidl
3258 * Return the LPITEMIDLIST to the parent of the pidl in the list
3260 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3262 LPITEMIDLIST pidlParent;
3264 TRACE("%p\n", pidl);
3266 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3267 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3269 return pidlParent;
3272 /***********************************************************************
3273 * GetPidlFromName
3275 * returns the pidl of the file name relative to folder
3276 * NULL if an error occurred
3278 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3280 LPITEMIDLIST pidl = NULL;
3281 ULONG ulEaten;
3283 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3285 if(!lpcstrFileName) return NULL;
3286 if(!*lpcstrFileName) return NULL;
3288 if(!lpsf)
3290 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3291 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3292 IShellFolder_Release(lpsf);
3295 else
3297 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3299 return pidl;
3304 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3306 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3307 HRESULT ret;
3309 TRACE("%p, %p\n", psf, pidl);
3311 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3313 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3314 /* see documentation shell 4.1*/
3315 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3318 /***********************************************************************
3319 * BrowseSelectedFolder
3321 static BOOL BrowseSelectedFolder(HWND hwnd)
3323 BOOL bBrowseSelFolder = FALSE;
3324 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3326 TRACE("\n");
3328 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3330 LPITEMIDLIST pidlSelection;
3332 /* get the file selected */
3333 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3334 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3336 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3337 pidlSelection, SBSP_RELATIVE ) ) )
3339 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3340 ' ','n','o','t',' ','e','x','i','s','t',0};
3341 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3344 bBrowseSelFolder = TRUE;
3346 COMDLG32_SHFree( pidlSelection );
3349 return bBrowseSelFolder;
3353 * Memory allocation methods */
3354 static void *MemAlloc(UINT size)
3356 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3359 static void MemFree(void *mem)
3361 HeapFree(GetProcessHeap(),0,mem);
3365 * Old-style (win3.1) dialogs */
3367 /***********************************************************************
3368 * FD32_GetTemplate [internal]
3370 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3371 * by a 32 bits application
3374 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3376 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3377 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3378 HANDLE hDlgTmpl;
3380 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3382 if (!(lfs->template = LockResource( ofnW->hInstance )))
3384 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3385 return FALSE;
3388 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3390 HRSRC hResInfo;
3391 if (priv->ofnA)
3392 hResInfo = FindResourceA(priv->ofnA->hInstance,
3393 priv->ofnA->lpTemplateName,
3394 (LPSTR)RT_DIALOG);
3395 else
3396 hResInfo = FindResourceW(ofnW->hInstance,
3397 ofnW->lpTemplateName,
3398 (LPWSTR)RT_DIALOG);
3399 if (!hResInfo)
3401 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3402 return FALSE;
3404 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3405 hResInfo)) ||
3406 !(lfs->template = LockResource(hDlgTmpl)))
3408 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3409 return FALSE;
3411 } else { /* get it from internal Wine resource */
3412 HRSRC hResInfo;
3413 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3414 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3416 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3417 return FALSE;
3419 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3420 !(lfs->template = LockResource( hDlgTmpl )))
3422 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3423 return FALSE;
3426 return TRUE;
3430 /************************************************************************
3431 * FD32_Init [internal]
3432 * called from the common 16/32 code to initialize 32 bit data
3434 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3436 BOOL IsUnicode = (BOOL) data;
3437 PFD32_PRIVATE priv;
3439 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3440 lfs->private1632 = priv;
3441 if (NULL == lfs->private1632) return FALSE;
3442 if (IsUnicode)
3444 lfs->ofnW = *((LPOPENFILENAMEW) lParam);
3445 if (lfs->ofnW.Flags & OFN_ENABLEHOOK)
3446 if (lfs->ofnW.lpfnHook)
3447 lfs->hook = TRUE;
3449 else
3451 priv->ofnA = (LPOPENFILENAMEA) lParam;
3452 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3453 if (priv->ofnA->lpfnHook)
3454 lfs->hook = TRUE;
3455 FD31_MapOfnStructA(priv->ofnA, &lfs->ofnW, lfs->open);
3458 if (! FD32_GetTemplate(lfs)) return FALSE;
3460 return TRUE;
3463 /***********************************************************************
3464 * FD32_CallWindowProc [internal]
3466 * called from the common 16/32 code to call the appropriate hook
3468 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3469 LPARAM lParam)
3471 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3473 if (priv->ofnA)
3475 return (BOOL) CallWindowProcA(
3476 (WNDPROC)priv->ofnA->lpfnHook, lfs->hwnd,
3477 wMsg, wParam, lParam);
3480 return (BOOL) CallWindowProcW(
3481 (WNDPROC)lfs->ofnW.lpfnHook, lfs->hwnd,
3482 wMsg, wParam, lParam);
3485 /***********************************************************************
3486 * FD32_UpdateResult [internal]
3487 * update the real client structures if any
3489 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3491 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3492 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3494 if (priv->ofnA)
3496 if (ofnW->nMaxFile &&
3497 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3498 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3499 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3500 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3501 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3505 /***********************************************************************
3506 * FD32_UpdateFileTitle [internal]
3507 * update the real client structures if any
3509 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3511 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3512 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3514 if (priv->ofnA)
3516 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3517 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3518 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3523 /***********************************************************************
3524 * FD32_SendLbGetCurSel [internal]
3525 * retrieve selected listbox item
3527 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3529 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3533 /************************************************************************
3534 * FD32_Destroy [internal]
3535 * called from the common 16/32 code to cleanup 32 bit data
3537 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3539 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3541 /* if ofnW has been allocated, have to free everything in it */
3542 if (NULL != priv && NULL != priv->ofnA)
3543 FD31_FreeOfnW(&lfs->ofnW);
3546 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3548 callbacks->Init = FD32_Init;
3549 callbacks->CWP = FD32_CallWindowProc;
3550 callbacks->UpdateResult = FD32_UpdateResult;
3551 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3552 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3553 callbacks->Destroy = FD32_Destroy;
3556 /***********************************************************************
3557 * FD32_WMMeasureItem [internal]
3559 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3561 LPMEASUREITEMSTRUCT lpmeasure;
3563 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3564 lpmeasure->itemHeight = FD31_GetFldrHeight();
3565 return TRUE;
3569 /***********************************************************************
3570 * FileOpenDlgProc [internal]
3571 * Used for open and save, in fact.
3573 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3574 WPARAM wParam, LPARAM lParam)
3576 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3578 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3579 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3581 INT_PTR lRet;
3582 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3583 if (lRet)
3584 return lRet; /* else continue message processing */
3586 switch (wMsg)
3588 case WM_INITDIALOG:
3589 return FD31_WMInitDialog(hWnd, wParam, lParam);
3591 case WM_MEASUREITEM:
3592 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3594 case WM_DRAWITEM:
3595 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3597 case WM_COMMAND:
3598 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3599 #if 0
3600 case WM_CTLCOLOR:
3601 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3602 switch (HIWORD(lParam))
3604 case CTLCOLOR_BTN:
3605 SetTextColor((HDC16)wParam, 0x00000000);
3606 return hGRAYBrush;
3607 case CTLCOLOR_STATIC:
3608 SetTextColor((HDC16)wParam, 0x00000000);
3609 return hGRAYBrush;
3611 break;
3612 #endif
3614 return FALSE;
3618 /***********************************************************************
3619 * GetFileName31A [internal]
3621 * Creates a win31 style dialog box for the user to select a file to open/save.
3623 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3624 UINT dlgType /* type dialogue : open/save */
3627 HINSTANCE hInst;
3628 BOOL bRet = FALSE;
3629 PFD31_DATA lfs;
3630 FD31_CALLBACKS callbacks;
3632 if (!lpofn || !FD31_Init()) return FALSE;
3634 TRACE("ofn flags %08lx\n", lpofn->Flags);
3635 FD32_SetupCallbacks(&callbacks);
3636 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3637 if (lfs)
3639 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3640 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3641 FD32_FileOpenDlgProc, (LPARAM)lfs);
3642 FD31_DestroyPrivate(lfs);
3645 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3646 return bRet;
3649 /***********************************************************************
3650 * GetFileName31W [internal]
3652 * Creates a win31 style dialog box for the user to select a file to open/save
3654 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3655 UINT dlgType /* type dialogue : open/save */
3658 HINSTANCE hInst;
3659 BOOL bRet = FALSE;
3660 PFD31_DATA lfs;
3661 FD31_CALLBACKS callbacks;
3663 if (!lpofn || !FD31_Init()) return FALSE;
3665 FD32_SetupCallbacks(&callbacks);
3666 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3667 if (lfs)
3669 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3670 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3671 FD32_FileOpenDlgProc, (LPARAM)lfs);
3672 FD31_DestroyPrivate(lfs);
3675 TRACE("return lpstrFile=%s !\n", debugstr_w(lpofn->lpstrFile));
3676 return bRet;
3679 /* ------------------ APIs ---------------------- */
3681 /***********************************************************************
3682 * GetOpenFileNameA (COMDLG32.@)
3684 * Creates a dialog box for the user to select a file to open.
3686 * RETURNS
3687 * TRUE on success: user enters a valid file
3688 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3691 BOOL WINAPI GetOpenFileNameA(
3692 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3694 BOOL win16look = FALSE;
3696 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3697 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3699 if (win16look)
3700 return GetFileName31A(ofn, OPEN_DIALOG);
3701 else
3702 return GetFileDialog95A(ofn, OPEN_DIALOG);
3705 /***********************************************************************
3706 * GetOpenFileNameW (COMDLG32.@)
3708 * Creates a dialog box for the user to select a file to open.
3710 * RETURNS
3711 * TRUE on success: user enters a valid file
3712 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3715 BOOL WINAPI GetOpenFileNameW(
3716 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3718 BOOL win16look = FALSE;
3720 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3721 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3723 if (win16look)
3724 return GetFileName31W(ofn, OPEN_DIALOG);
3725 else
3726 return GetFileDialog95W(ofn, OPEN_DIALOG);
3730 /***********************************************************************
3731 * GetSaveFileNameA (COMDLG32.@)
3733 * Creates a dialog box for the user to select a file to save.
3735 * RETURNS
3736 * TRUE on success: user enters a valid file
3737 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3740 BOOL WINAPI GetSaveFileNameA(
3741 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3743 BOOL win16look = FALSE;
3745 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3746 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3748 if (win16look)
3749 return GetFileName31A(ofn, SAVE_DIALOG);
3750 else
3751 return GetFileDialog95A(ofn, SAVE_DIALOG);
3754 /***********************************************************************
3755 * GetSaveFileNameW (COMDLG32.@)
3757 * Creates a dialog box for the user to select a file to save.
3759 * RETURNS
3760 * TRUE on success: user enters a valid file
3761 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3764 BOOL WINAPI GetSaveFileNameW(
3765 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3767 BOOL win16look = FALSE;
3769 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3770 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3772 if (win16look)
3773 return GetFileName31W(ofn, SAVE_DIALOG);
3774 else
3775 return GetFileDialog95W(ofn, SAVE_DIALOG);