Use IShellFolder::GetDisplayNameOf instead of SHGetPathFromIDList to
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blob78cbe1ef60db7e19453d548669dc62c3ee011c48
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "commdlg.h"
71 #include "dlgs.h"
72 #include "cdlg.h"
73 #include "filedlg31.h"
74 #include "wine/debug.h"
75 #include "cderr.h"
76 #include "shellapi.h"
77 #include "shlguid.h"
78 #include "shlobj.h"
79 #include "filedlgbrowser.h"
80 #include "shlwapi.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
124 /* AddItem flags*/
125 #define LISTEND -1
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
135 /* NOTE
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBAddStringW(hwnd,str) \
144 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
146 #define CBInsertString(hwnd,str,pos) \
147 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
149 #define CBDeleteString(hwnd,pos) \
150 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
152 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
153 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
155 #define CBGetItemDataPtr(hwnd,iItemId) \
156 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
158 #define CBGetLBText(hwnd,iItemId,str) \
159 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
161 #define CBGetCurSel(hwnd) \
162 SendMessageA(hwnd,CB_GETCURSEL,0,0);
164 #define CBSetCurSel(hwnd,pos) \
165 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
167 #define CBGetCount(hwnd) \
168 SendMessageA(hwnd,CB_GETCOUNT,0,0);
169 #define CBShowDropDown(hwnd,show) \
170 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
171 #define CBSetItemHeight(hwnd,index,height) \
172 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
174 #define CBSetExtendedUI(hwnd,flag) \
175 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
177 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
178 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
180 /***********************************************************************
181 * Prototypes
184 /* Internal functions used by the dialog */
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Miscellaneous tool functions */
217 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
218 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
221 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
223 /* Shell memory allocation */
224 static void *MemAlloc(UINT size);
225 static void MemFree(void *mem);
227 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
228 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
230 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
235 * GetFileName95
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
247 LRESULT lRes;
248 LPCVOID template;
249 HRSRC hRes;
250 HANDLE hDlgTmpl = 0;
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08lx not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
282 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
283 (LPDLGTEMPLATEA) template,
284 fodInfos->ofnInfos->hwndOwner,
285 FileOpenDlgProc95,
286 (LPARAM) fodInfos);
288 /* Unable to create the dialog */
289 if( lRes == -1)
290 return FALSE;
292 return lRes;
295 /***********************************************************************
296 * GetFileDialog95A
298 * Call GetFileName95 with this structure and clean the memory.
300 * IN : The OPENFILENAMEA initialisation structure passed to
301 * GetOpenFileNameA win api function (see filedlg.c)
303 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
305 BOOL ret;
306 FileOpenDlgInfos fodInfos;
307 LPSTR lpstrSavDir = NULL;
308 LPWSTR title = NULL;
309 LPWSTR defext = NULL;
310 LPWSTR filter = NULL;
311 LPWSTR customfilter = NULL;
313 /* Initialize FileOpenDlgInfos structure */
314 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
316 /* Pass in the original ofn */
317 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
319 /* save current directory */
320 if (ofn->Flags & OFN_NOCHANGEDIR)
322 lpstrSavDir = MemAlloc(MAX_PATH);
323 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
326 fodInfos.unicode = FALSE;
328 /* convert all the input strings to unicode */
329 if(ofn->lpstrInitialDir)
331 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
332 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
333 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
335 else
336 fodInfos.initdir = NULL;
338 if(ofn->lpstrFile)
340 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
343 else
344 fodInfos.filename = NULL;
346 if(ofn->lpstrDefExt)
348 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
349 defext = MemAlloc((len+1)*sizeof(WCHAR));
350 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
352 fodInfos.defext = defext;
354 if(ofn->lpstrTitle)
356 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
357 title = MemAlloc((len+1)*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
360 fodInfos.title = title;
362 if (ofn->lpstrFilter)
364 LPCSTR s;
365 int n, len;
367 /* filter is a list... title\0ext\0......\0\0 */
368 s = ofn->lpstrFilter;
369 while (*s) s = s+strlen(s)+1;
370 s++;
371 n = s - ofn->lpstrFilter;
372 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
373 filter = MemAlloc(len*sizeof(WCHAR));
374 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
376 fodInfos.filter = filter;
378 /* convert lpstrCustomFilter */
379 if (ofn->lpstrCustomFilter)
381 LPCSTR s;
382 int n, len;
384 /* customfilter contains a pair of strings... title\0ext\0 */
385 s = ofn->lpstrCustomFilter;
386 if (*s) s = s+strlen(s)+1;
387 if (*s) s = s+strlen(s)+1;
388 n = s - ofn->lpstrCustomFilter;
389 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
390 customfilter = MemAlloc(len*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
393 fodInfos.customfilter = customfilter;
395 /* Initialize the dialog property */
396 fodInfos.DlgInfos.dwDlgProp = 0;
397 fodInfos.DlgInfos.hwndCustomDlg = NULL;
399 switch(iDlgType)
401 case OPEN_DIALOG :
402 ret = GetFileName95(&fodInfos);
403 break;
404 case SAVE_DIALOG :
405 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
406 ret = GetFileName95(&fodInfos);
407 break;
408 default :
409 ret = 0;
412 if (lpstrSavDir)
414 SetCurrentDirectoryA(lpstrSavDir);
415 MemFree(lpstrSavDir);
418 if(title)
419 MemFree(title);
420 if(defext)
421 MemFree(defext);
422 if(filter)
423 MemFree(filter);
424 if(customfilter)
425 MemFree(customfilter);
426 if(fodInfos.initdir)
427 MemFree(fodInfos.initdir);
429 if(fodInfos.filename)
430 MemFree(fodInfos.filename);
432 TRACE("selected file: %s\n",ofn->lpstrFile);
434 return ret;
437 /***********************************************************************
438 * GetFileDialog95W
440 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
441 * Call GetFileName95 with this structure and clean the memory.
444 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
446 BOOL ret;
447 FileOpenDlgInfos fodInfos;
448 LPWSTR lpstrSavDir = NULL;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
453 /* Pass in the original ofn */
454 fodInfos.ofnInfos = ofn;
456 fodInfos.title = ofn->lpstrTitle;
457 fodInfos.defext = ofn->lpstrDefExt;
458 fodInfos.filter = ofn->lpstrFilter;
459 fodInfos.customfilter = ofn->lpstrCustomFilter;
461 /* convert string arguments, save others */
462 if(ofn->lpstrFile)
464 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
467 else
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
473 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
474 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
475 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
477 else
478 fodInfos.initdir = NULL;
480 /* save current directory */
481 if (ofn->Flags & OFN_NOCHANGEDIR)
483 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
484 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
487 fodInfos.unicode = TRUE;
489 switch(iDlgType)
491 case OPEN_DIALOG :
492 ret = GetFileName95(&fodInfos);
493 break;
494 case SAVE_DIALOG :
495 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
496 ret = GetFileName95(&fodInfos);
497 break;
498 default :
499 ret = 0;
502 if (lpstrSavDir)
504 SetCurrentDirectoryW(lpstrSavDir);
505 MemFree(lpstrSavDir);
508 /* restore saved IN arguments and convert OUT arguments back */
509 MemFree(fodInfos.filename);
510 MemFree(fodInfos.initdir);
511 return ret;
514 /******************************************************************************
515 * COMDLG32_GetDisplayNameOf [internal]
517 * Helper function to get the display name for a pidl.
519 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
520 LPSHELLFOLDER psfDesktop;
521 STRRET strret;
523 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
524 return FALSE;
526 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
527 IShellFolder_Release(psfDesktop);
528 return FALSE;
531 IShellFolder_Release(psfDesktop);
532 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
535 /***********************************************************************
536 * ArrangeCtrlPositions [internal]
538 * NOTE: Do not change anything here without a lot of testing.
540 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
542 HWND hwndChild, hwndStc32;
543 RECT rectParent, rectChild, rectStc32;
544 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
546 /* Take into account if open as read only checkbox and help button
547 * are hidden
549 if (hide_help)
551 RECT rectHelp, rectCancel;
552 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
553 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
554 /* subtract the height of the help button plus the space between
555 * the help button and the cancel button to the height of the dialog
557 help_fixup = rectHelp.bottom - rectCancel.bottom;
561 There are two possibilities to add components to the default file dialog box.
563 By default, all the new components are added below the standard dialog box (the else case).
565 However, if there is a static text component with the stc32 id, a special case happens.
566 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
567 in the window and the cx and cy indicate how to size the window.
568 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
569 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
573 GetClientRect(hwndParentDlg, &rectParent);
575 /* when arranging controls we have to use fixed parent size */
576 rectParent.bottom -= help_fixup;
578 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
579 if (hwndStc32)
581 GetWindowRect(hwndStc32, &rectStc32);
582 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
584 /* set the size of the stc32 control according to the size of
585 * client area of the parent dialog
587 SetWindowPos(hwndStc32, 0,
588 0, 0,
589 rectParent.right, rectParent.bottom,
590 SWP_NOMOVE | SWP_NOZORDER);
592 else
593 SetRectEmpty(&rectStc32);
595 /* this part moves controls of the child dialog */
596 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
597 while (hwndChild)
599 if (hwndChild != hwndStc32)
601 GetWindowRect(hwndChild, &rectChild);
602 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
604 /* move only if stc32 exist */
605 if (hwndStc32 && rectChild.left > rectStc32.right)
607 LONG old_left = rectChild.left;
609 /* move to the right of visible controls of the parent dialog */
610 rectChild.left += rectParent.right;
611 rectChild.left -= rectStc32.right;
613 child_width_fixup = rectChild.left - old_left;
615 /* move even if stc32 doesn't exist */
616 if (rectChild.top >= rectStc32.bottom)
618 LONG old_top = rectChild.top;
620 /* move below visible controls of the parent dialog */
621 rectChild.top += rectParent.bottom;
622 rectChild.top -= rectStc32.bottom - rectStc32.top;
624 child_height_fixup = rectChild.top - old_top;
627 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
628 0, 0, SWP_NOSIZE | SWP_NOZORDER);
630 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
633 /* this part moves controls of the parent dialog */
634 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
635 while (hwndChild)
637 if (hwndChild != hwndChildDlg)
639 GetWindowRect(hwndChild, &rectChild);
640 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
642 /* left,top of stc32 marks the position of controls
643 * from the parent dialog
645 rectChild.left += rectStc32.left;
646 rectChild.top += rectStc32.top;
648 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
649 0, 0, SWP_NOSIZE | SWP_NOZORDER);
651 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
654 /* calculate the size of the resulting dialog */
656 /* here we have to use original parent size */
657 GetClientRect(hwndParentDlg, &rectParent);
658 GetClientRect(hwndChildDlg, &rectChild);
660 if (hwndStc32)
662 rectChild.right += child_width_fixup;
663 rectChild.bottom += child_height_fixup;
665 if (rectParent.right > rectChild.right)
667 rectParent.right += rectChild.right;
668 rectParent.right -= rectStc32.right - rectStc32.left;
670 else
672 rectParent.right = rectChild.right;
675 if (rectParent.bottom > rectChild.bottom)
677 rectParent.bottom += rectChild.bottom;
678 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
680 else
682 /* child dialog is higher, unconditionally set new dialog
683 * height to its size (help_fixup will be subtracted below)
685 rectParent.bottom = rectChild.bottom + help_fixup;
688 else
690 rectParent.bottom += rectChild.bottom;
693 /* finally use fixed parent size */
694 rectParent.bottom -= help_fixup;
696 /* save the size of the parent's client area */
697 rectChild.right = rectParent.right;
698 rectChild.bottom = rectParent.bottom;
700 /* set the size of the parent dialog */
701 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
702 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
703 SetWindowPos(hwndParentDlg, 0,
704 0, 0,
705 rectParent.right - rectParent.left,
706 rectParent.bottom - rectParent.top,
707 SWP_NOMOVE | SWP_NOZORDER);
709 /* set the size of the child dialog */
710 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
711 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
714 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 switch(uMsg) {
717 case WM_INITDIALOG:
718 return TRUE;
720 return FALSE;
723 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
725 LPCVOID template;
726 HRSRC hRes;
727 HANDLE hDlgTmpl = 0;
728 HWND hChildDlg = 0;
730 TRACE("\n");
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
739 HINSTANCE hinst;
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
742 hinst = 0;
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
746 return NULL;
749 else
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
757 else
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
762 if (!hRes)
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
765 return NULL;
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
771 return NULL;
774 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
775 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
776 (LPARAM)fodInfos->ofnInfos);
777 if(hChildDlg)
779 ShowWindow(hChildDlg,SW_SHOW);
780 return hChildDlg;
783 else if( IsHooked(fodInfos))
785 RECT rectHwnd;
786 struct {
787 DLGTEMPLATE tmplate;
788 WORD menu,class,title;
789 } temp;
790 GetClientRect(hwnd,&rectHwnd);
791 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
792 temp.tmplate.dwExtendedStyle = 0;
793 temp.tmplate.cdit = 0;
794 temp.tmplate.x = 0;
795 temp.tmplate.y = 0;
796 temp.tmplate.cx = 0;
797 temp.tmplate.cy = 0;
798 temp.menu = temp.class = temp.title = 0;
800 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
801 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
803 return hChildDlg;
805 return NULL;
808 /***********************************************************************
809 * SendCustomDlgNotificationMessage
811 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
814 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
816 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
818 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
820 if(!fodInfos) return 0;
822 if(fodInfos->DlgInfos.hwndCustomDlg)
824 HRESULT ret;
825 TRACE("CALL NOTIFY for %x\n", uCode);
826 if(fodInfos->unicode)
828 OFNOTIFYW ofnNotify;
829 ofnNotify.hdr.hwndFrom=hwndParentDlg;
830 ofnNotify.hdr.idFrom=0;
831 ofnNotify.hdr.code = uCode;
832 ofnNotify.lpOFN = fodInfos->ofnInfos;
833 ofnNotify.pszFile = NULL;
834 ret = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
836 else
838 OFNOTIFYA ofnNotify;
839 ofnNotify.hdr.hwndFrom=hwndParentDlg;
840 ofnNotify.hdr.idFrom=0;
841 ofnNotify.hdr.code = uCode;
842 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
843 ofnNotify.pszFile = NULL;
844 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
846 TRACE("RET NOTIFY\n");
847 return ret;
849 return TRUE;
852 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
854 UINT sizeUsed = 0, n, total;
855 LPWSTR lpstrFileList = NULL;
856 WCHAR lpstrCurrentDir[MAX_PATH];
857 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
859 TRACE("CDM_GETFILEPATH:\n");
861 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
862 return -1;
864 /* get path and filenames */
865 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
866 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
868 TRACE("path >%s< filespec >%s< %d files\n",
869 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
871 if( fodInfos->unicode )
873 LPWSTR bufW = buffer;
874 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
876 /* Prepend the current path */
877 n = strlenW(lpstrCurrentDir) + 1;
878 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
879 if(n<size)
881 /* 'n' includes trailing \0 */
882 bufW[n-1] = '\\';
883 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
885 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
887 else
889 LPSTR bufA = buffer;
890 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
891 NULL, 0, NULL, NULL);
892 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
893 NULL, 0, NULL, NULL);
895 /* Prepend the current path */
896 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
897 bufA, size, NULL, NULL);
899 if(n<size)
901 /* 'n' includes trailing \0 */
902 bufA[n-1] = '\\';
903 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
904 &bufA[n], size-n, NULL, NULL);
907 TRACE("returned -> %s\n",debugstr_an(bufA, total));
909 MemFree(lpstrFileList);
911 return total;
914 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
916 UINT sizeUsed = 0;
917 LPWSTR lpstrFileList = NULL;
918 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
920 TRACE("CDM_GETSPEC:\n");
922 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
923 if( fodInfos->unicode )
925 LPWSTR bufW = buffer;
926 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
928 else
930 LPSTR bufA = buffer;
931 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
932 NULL, 0, NULL, NULL);
933 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
934 bufA, size, NULL, NULL);
936 MemFree(lpstrFileList);
938 return sizeUsed;
941 /***********************************************************************
942 * FILEDLG95_HandleCustomDialogMessages
944 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
946 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
948 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
949 WCHAR lpstrPath[MAX_PATH];
950 if(!fodInfos) return -1;
952 switch(uMsg)
954 case CDM_GETFILEPATH:
955 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
957 case CDM_GETFOLDERPATH:
958 TRACE("CDM_GETFOLDERPATH:\n");
959 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
960 if (lParam)
962 if (fodInfos->unicode)
963 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
964 else
965 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
966 (LPSTR)lParam, (int)wParam, NULL, NULL);
968 return strlenW(lpstrPath);
970 case CDM_GETSPEC:
971 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
973 case CDM_SETCONTROLTEXT:
974 TRACE("CDM_SETCONTROLTEXT:\n");
975 if ( lParam )
977 if( fodInfos->unicode )
978 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
979 else
980 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
982 return TRUE;
984 case CDM_HIDECONTROL:
985 case CDM_SETDEFEXT:
986 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
987 return -1;
989 return TRUE;
992 /***********************************************************************
993 * FileOpenDlgProc95
995 * File open dialog procedure
997 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
999 #if 0
1000 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1001 #endif
1003 switch(uMsg)
1005 case WM_INITDIALOG:
1007 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1009 /* Adds the FileOpenDlgInfos in the property list of the dialog
1010 so it will be easily accessible through a GetPropA(...) */
1011 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1013 fodInfos->DlgInfos.hwndCustomDlg =
1014 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1016 FILEDLG95_InitControls(hwnd);
1018 if (fodInfos->DlgInfos.hwndCustomDlg)
1019 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1020 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1022 FILEDLG95_FillControls(hwnd, wParam, lParam);
1024 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1025 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1026 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1027 return 0;
1029 case WM_COMMAND:
1030 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1031 case WM_DRAWITEM:
1033 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1035 case IDC_LOOKIN:
1036 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1037 return TRUE;
1040 return FALSE;
1042 case WM_GETISHELLBROWSER:
1043 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1045 case WM_DESTROY:
1046 RemovePropA(hwnd, FileOpenDlgInfosStr);
1047 return FALSE;
1049 case WM_NOTIFY:
1051 LPNMHDR lpnmh = (LPNMHDR)lParam;
1052 UINT stringId = -1;
1054 /* set up the button tooltips strings */
1055 if(TTN_GETDISPINFOA == lpnmh->code )
1057 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1058 switch(lpnmh->idFrom )
1060 /* Up folder button */
1061 case FCIDM_TB_UPFOLDER:
1062 stringId = IDS_UPFOLDER;
1063 break;
1064 /* New folder button */
1065 case FCIDM_TB_NEWFOLDER:
1066 stringId = IDS_NEWFOLDER;
1067 break;
1068 /* List option button */
1069 case FCIDM_TB_SMALLICON:
1070 stringId = IDS_LISTVIEW;
1071 break;
1072 /* Details option button */
1073 case FCIDM_TB_REPORTVIEW:
1074 stringId = IDS_REPORTVIEW;
1075 break;
1076 /* Desktop button */
1077 case FCIDM_TB_DESKTOP:
1078 stringId = IDS_TODESKTOP;
1079 break;
1080 default:
1081 stringId = 0;
1083 lpdi->hinst = COMDLG32_hInstance;
1084 lpdi->lpszText = (LPSTR) stringId;
1086 return FALSE;
1088 default :
1089 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1090 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1091 return FALSE;
1095 /***********************************************************************
1096 * FILEDLG95_InitControls
1098 * WM_INITDIALOG message handler (before hook notification)
1100 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1102 int win2000plus = 0;
1103 int win98plus = 0;
1104 int handledPath = FALSE;
1105 OSVERSIONINFOA osVi;
1106 static const WCHAR szwSlash[] = { '\\', 0 };
1107 static const WCHAR szwStar[] = { '*',0 };
1109 TBBUTTON tbb[] =
1111 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1112 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1113 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1114 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1115 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1116 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1117 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1118 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1119 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1121 TBADDBITMAP tba[2];
1122 RECT rectTB;
1123 RECT rectlook;
1124 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1126 tba[0].hInst = HINST_COMMCTRL;
1127 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1128 tba[1].hInst = COMDLG32_hInstance;
1129 tba[1].nID = 800;
1131 TRACE("%p\n", fodInfos);
1133 /* Get windows version emulating */
1134 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1135 GetVersionExA(&osVi);
1136 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1137 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1138 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1139 win2000plus = (osVi.dwMajorVersion > 4);
1140 if (win2000plus) win98plus = TRUE;
1142 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1144 /* Get the hwnd of the controls */
1145 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1146 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1147 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1149 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1150 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1152 /* construct the toolbar */
1153 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1154 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1156 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1157 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1158 rectTB.left = rectlook.right;
1159 rectTB.top = rectlook.top-1;
1161 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1162 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1163 rectTB.left, rectTB.top,
1164 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1165 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1167 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1169 /* FIXME: use TB_LOADIMAGES when implemented */
1170 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1171 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1172 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1174 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1175 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1177 /* Set the window text with the text specified in the OPENFILENAME structure */
1178 if(fodInfos->title)
1180 SetWindowTextW(hwnd,fodInfos->title);
1182 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1184 WCHAR buf[16];
1185 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1186 SetWindowTextW(hwnd, buf);
1189 /* Initialise the file name edit control */
1190 handledPath = FALSE;
1191 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1193 if(fodInfos->filename)
1195 /* 1. If win2000 or higher and filename contains a path, use it
1196 in preference over the lpstrInitialDir */
1197 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1198 WCHAR tmpBuf[MAX_PATH];
1199 WCHAR *nameBit;
1200 DWORD result;
1202 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1203 if (result) {
1205 /* nameBit is always shorter than the original filename */
1206 strcpyW(fodInfos->filename,nameBit);
1208 *nameBit = 0x00;
1209 if (fodInfos->initdir == NULL)
1210 MemFree(fodInfos->initdir);
1211 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1212 strcpyW(fodInfos->initdir, tmpBuf);
1213 handledPath = TRUE;
1214 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1215 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1217 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1219 } else {
1220 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1224 /* 2. (All platforms) If initdir is not null, then use it */
1225 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1226 (*fodInfos->initdir!=0x00))
1228 /* Work out the proper path as supplied one might be relative */
1229 /* (Here because supplying '.' as dir browses to My Computer) */
1230 if (handledPath==FALSE) {
1231 WCHAR tmpBuf[MAX_PATH];
1232 WCHAR tmpBuf2[MAX_PATH];
1233 WCHAR *nameBit;
1234 DWORD result;
1236 strcpyW(tmpBuf, fodInfos->initdir);
1237 if( PathFileExistsW(tmpBuf) ) {
1238 /* initdir does not have to be a directory. If a file is
1239 * specified, the dir part is taken */
1240 if( PathIsDirectoryW(tmpBuf)) {
1241 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1242 strcatW(tmpBuf, szwSlash);
1244 strcatW(tmpBuf, szwStar);
1246 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1247 if (result) {
1248 *nameBit = 0x00;
1249 if (fodInfos->initdir)
1250 MemFree(fodInfos->initdir);
1251 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1252 strcpyW(fodInfos->initdir, tmpBuf2);
1253 handledPath = TRUE;
1254 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1257 else if (fodInfos->initdir)
1259 MemFree(fodInfos->initdir);
1260 fodInfos->initdir = NULL;
1261 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1266 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1267 (*fodInfos->initdir==0x00)))
1269 /* 3. All except w2k+: if filename contains a path use it */
1270 if (!win2000plus && fodInfos->filename &&
1271 *fodInfos->filename &&
1272 strpbrkW(fodInfos->filename, szwSlash)) {
1273 WCHAR tmpBuf[MAX_PATH];
1274 WCHAR *nameBit;
1275 DWORD result;
1277 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1278 tmpBuf, &nameBit);
1279 if (result) {
1280 int len;
1282 /* nameBit is always shorter than the original filename */
1283 strcpyW(fodInfos->filename, nameBit);
1284 *nameBit = 0x00;
1286 len = strlenW(tmpBuf);
1287 if(fodInfos->initdir)
1288 MemFree(fodInfos->initdir);
1289 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1290 strcpyW(fodInfos->initdir, tmpBuf);
1292 handledPath = TRUE;
1293 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1294 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1296 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1299 /* 4. win98+ and win2000+ if any files of specified filter types in
1300 current directory, use it */
1301 if ( win98plus && handledPath == FALSE &&
1302 fodInfos->filter && *fodInfos->filter) {
1304 BOOL searchMore = TRUE;
1305 LPCWSTR lpstrPos = fodInfos->filter;
1306 WIN32_FIND_DATAW FindFileData;
1307 HANDLE hFind;
1309 while (searchMore)
1311 /* filter is a list... title\0ext\0......\0\0 */
1313 /* Skip the title */
1314 if(! *lpstrPos) break; /* end */
1315 lpstrPos += strlenW(lpstrPos) + 1;
1317 /* See if any files exist in the current dir with this extension */
1318 if(! *lpstrPos) break; /* end */
1320 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1322 if (hFind == INVALID_HANDLE_VALUE) {
1323 /* None found - continue search */
1324 lpstrPos += strlenW(lpstrPos) + 1;
1326 } else {
1327 searchMore = FALSE;
1329 if(fodInfos->initdir)
1330 MemFree(fodInfos->initdir);
1331 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1332 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1334 handledPath = TRUE;
1335 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1336 debugstr_w(lpstrPos));
1337 break;
1342 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1344 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1345 if (handledPath == FALSE && (win2000plus || win98plus)) {
1346 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1348 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1350 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1352 /* last fallback */
1353 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1354 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1355 } else {
1356 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1358 } else {
1359 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1361 handledPath = TRUE;
1362 } else if (handledPath==FALSE) {
1363 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1364 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1365 handledPath = TRUE;
1366 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1369 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1370 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1372 /* Must the open as read only check box be checked ?*/
1373 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1375 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1378 /* Must the open as read only check box be hidden? */
1379 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1381 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1382 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1385 /* Must the help button be hidden? */
1386 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1388 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1389 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1392 /* Resize the height, if open as read only checkbox ad help button
1393 are hidden and we are not using a custom template nor a customDialog
1395 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1396 (!(fodInfos->ofnInfos->Flags &
1397 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1398 (!fodInfos->DlgInfos.hwndCustomDlg ))
1400 RECT rectDlg, rectHelp, rectCancel;
1401 GetWindowRect(hwnd, &rectDlg);
1402 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1403 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1404 /* subtract the height of the help button plus the space between
1405 the help button and the cancel button to the height of the dialog */
1406 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1407 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1408 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1410 /* change Open to Save */
1411 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1413 WCHAR buf[16];
1414 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1415 SetDlgItemTextW(hwnd, IDOK, buf);
1416 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1417 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1419 return 0;
1422 /***********************************************************************
1423 * FILEDLG95_FillControls
1425 * WM_INITDIALOG message handler (after hook notification)
1427 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1429 LPITEMIDLIST pidlItemId = NULL;
1431 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1433 TRACE("dir=%s file=%s\n",
1434 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1436 /* Get the initial directory pidl */
1438 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1440 WCHAR path[MAX_PATH];
1442 GetCurrentDirectoryW(MAX_PATH,path);
1443 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1446 /* Initialise shell objects */
1447 FILEDLG95_SHELL_Init(hwnd);
1449 /* Initialize the Look In combo box */
1450 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1452 /* Initialize the filter combo box */
1453 FILEDLG95_FILETYPE_Init(hwnd);
1455 /* Browse to the initial directory */
1456 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1458 /* Free pidlItem memory */
1459 COMDLG32_SHFree(pidlItemId);
1461 return TRUE;
1463 /***********************************************************************
1464 * FILEDLG95_Clean
1466 * Regroups all the cleaning functions of the filedlg
1468 void FILEDLG95_Clean(HWND hwnd)
1470 FILEDLG95_FILETYPE_Clean(hwnd);
1471 FILEDLG95_LOOKIN_Clean(hwnd);
1472 FILEDLG95_SHELL_Clean(hwnd);
1474 /***********************************************************************
1475 * FILEDLG95_OnWMCommand
1477 * WM_COMMAND message handler
1479 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1481 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1482 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1483 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1485 switch(wID)
1487 /* OK button */
1488 case IDOK:
1489 FILEDLG95_OnOpen(hwnd);
1490 break;
1491 /* Cancel button */
1492 case IDCANCEL:
1493 FILEDLG95_Clean(hwnd);
1494 EndDialog(hwnd, FALSE);
1495 break;
1496 /* Filetype combo box */
1497 case IDC_FILETYPE:
1498 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1499 break;
1500 /* LookIn combo box */
1501 case IDC_LOOKIN:
1502 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1503 break;
1505 /* --- toolbar --- */
1506 /* Up folder button */
1507 case FCIDM_TB_UPFOLDER:
1508 FILEDLG95_SHELL_UpFolder(hwnd);
1509 break;
1510 /* New folder button */
1511 case FCIDM_TB_NEWFOLDER:
1512 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1513 break;
1514 /* List option button */
1515 case FCIDM_TB_SMALLICON:
1516 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1517 break;
1518 /* Details option button */
1519 case FCIDM_TB_REPORTVIEW:
1520 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1521 break;
1522 /* Details option button */
1523 case FCIDM_TB_DESKTOP:
1524 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1525 break;
1527 case IDC_FILENAME:
1528 break;
1531 /* Do not use the listview selection anymore */
1532 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1533 return 0;
1536 /***********************************************************************
1537 * FILEDLG95_OnWMGetIShellBrowser
1539 * WM_GETISHELLBROWSER message handler
1541 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1544 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1546 TRACE("\n");
1548 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1550 return TRUE;
1554 /***********************************************************************
1555 * FILEDLG95_SendFileOK
1557 * Sends the CDN_FILEOK notification if required
1559 * RETURNS
1560 * TRUE if the dialog should close
1561 * FALSE if the dialog should not be closed
1563 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1565 /* ask the hook if we can close */
1566 if(IsHooked(fodInfos))
1568 TRACE("---\n");
1569 /* First send CDN_FILEOK as MSDN doc says */
1570 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1571 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1573 TRACE("canceled\n");
1574 return FALSE;
1577 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1578 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1579 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1580 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1582 TRACE("canceled\n");
1583 return FALSE;
1586 return TRUE;
1589 /***********************************************************************
1590 * FILEDLG95_OnOpenMultipleFiles
1592 * Handles the opening of multiple files.
1594 * FIXME
1595 * check destination buffer size
1597 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1599 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1600 UINT nCount, nSizePath;
1601 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1603 TRACE("\n");
1605 if(fodInfos->unicode)
1607 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1608 ofn->lpstrFile[0] = '\0';
1610 else
1612 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1613 ofn->lpstrFile[0] = '\0';
1616 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1618 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1619 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1620 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1622 LPWSTR lpstrTemp = lpstrFileList;
1624 for ( nCount = 0; nCount < nFileCount; nCount++ )
1626 LPITEMIDLIST pidl;
1628 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1629 if (!pidl)
1631 WCHAR lpstrNotFound[100];
1632 WCHAR lpstrMsg[100];
1633 WCHAR tmp[400];
1634 static const WCHAR nl[] = {'\n',0};
1636 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1637 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1639 strcpyW(tmp, lpstrTemp);
1640 strcatW(tmp, nl);
1641 strcatW(tmp, lpstrNotFound);
1642 strcatW(tmp, nl);
1643 strcatW(tmp, lpstrMsg);
1645 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1646 return FALSE;
1649 /* move to the next file in the list of files */
1650 lpstrTemp += strlenW(lpstrTemp) + 1;
1651 COMDLG32_SHFree(pidl);
1655 nSizePath = strlenW(lpstrPathSpec) + 1;
1656 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1658 /* For "oldstyle" dialog the components have to
1659 be separated by blanks (not '\0'!) and short
1660 filenames have to be used! */
1661 FIXME("Components have to be separated by blanks\n");
1663 if(fodInfos->unicode)
1665 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1666 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1667 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1669 else
1671 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1673 if (ofn->lpstrFile != NULL)
1675 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1676 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1677 if (ofn->nMaxFile > nSizePath)
1679 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1680 ofn->lpstrFile + nSizePath,
1681 ofn->nMaxFile - nSizePath, NULL, NULL);
1686 fodInfos->ofnInfos->nFileOffset = nSizePath;
1687 fodInfos->ofnInfos->nFileExtension = 0;
1689 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1690 return FALSE;
1692 /* clean and exit */
1693 FILEDLG95_Clean(hwnd);
1694 return EndDialog(hwnd,TRUE);
1697 /***********************************************************************
1698 * FILEDLG95_OnOpen
1700 * Ok button WM_COMMAND message handler
1702 * If the function succeeds, the return value is nonzero.
1704 #define ONOPEN_BROWSE 1
1705 #define ONOPEN_OPEN 2
1706 #define ONOPEN_SEARCH 3
1707 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1709 WCHAR strMsgTitle[MAX_PATH];
1710 WCHAR strMsgText [MAX_PATH];
1711 if (idCaption)
1712 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1713 else
1714 strMsgTitle[0] = '\0';
1715 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1716 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1719 BOOL FILEDLG95_OnOpen(HWND hwnd)
1721 LPWSTR lpstrFileList;
1722 UINT nFileCount = 0;
1723 UINT sizeUsed = 0;
1724 BOOL ret = TRUE;
1725 WCHAR lpstrPathAndFile[MAX_PATH];
1726 WCHAR lpstrTemp[MAX_PATH];
1727 LPSHELLFOLDER lpsf = NULL;
1728 int nOpenAction;
1729 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1731 TRACE("hwnd=%p\n", hwnd);
1733 /* get the files from the edit control */
1734 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1736 /* try if the user selected a folder in the shellview */
1737 if(nFileCount == 0)
1739 BrowseSelectedFolder(hwnd);
1740 return FALSE;
1743 if(nFileCount > 1)
1745 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1746 goto ret;
1749 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1752 Step 1: Build a complete path name from the current folder and
1753 the filename or path in the edit box.
1754 Special cases:
1755 - the path in the edit box is a root path
1756 (with or without drive letter)
1757 - the edit box contains ".." (or a path with ".." in it)
1760 /* Get the current directory name */
1761 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1763 /* last fallback */
1764 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1766 PathAddBackslashW(lpstrPathAndFile);
1768 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1770 /* if the user specifyed a fully qualified path use it */
1771 if(PathIsRelativeW(lpstrFileList))
1773 strcatW(lpstrPathAndFile, lpstrFileList);
1775 else
1777 /* does the path have a drive letter? */
1778 if (PathGetDriveNumberW(lpstrFileList) == -1)
1779 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1780 else
1781 strcpyW(lpstrPathAndFile, lpstrFileList);
1784 /* resolve "." and ".." */
1785 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1786 strcpyW(lpstrPathAndFile, lpstrTemp);
1787 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1789 MemFree(lpstrFileList);
1792 Step 2: here we have a cleaned up path
1794 We have to parse the path step by step to see if we have to browse
1795 to a folder if the path points to a directory or the last
1796 valid element is a directory.
1798 valid variables:
1799 lpstrPathAndFile: cleaned up path
1802 nOpenAction = ONOPEN_BROWSE;
1804 /* don't apply any checks with OFN_NOVALIDATE */
1806 LPWSTR lpszTemp, lpszTemp1;
1807 LPITEMIDLIST pidl = NULL;
1808 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1810 /* check for invalid chars */
1811 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1813 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1814 ret = FALSE;
1815 goto ret;
1818 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1820 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1821 while (lpszTemp1)
1823 LPSHELLFOLDER lpsfChild;
1824 WCHAR lpwstrTemp[MAX_PATH];
1825 DWORD dwEaten, dwAttributes;
1826 LPWSTR p;
1828 strcpyW(lpwstrTemp, lpszTemp);
1829 p = PathFindNextComponentW(lpwstrTemp);
1831 if (!p) break; /* end of path */
1833 *p = 0;
1834 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1836 if(*lpszTemp==0)
1838 static const WCHAR wszWild[] = { '*', '?', 0 };
1839 /* if the last element is a wildcard do a search */
1840 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1842 nOpenAction = ONOPEN_SEARCH;
1843 break;
1846 lpszTemp1 = lpszTemp;
1848 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1850 /* append a backslash to drive letters */
1851 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1852 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1853 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1855 PathAddBackslashW(lpwstrTemp);
1858 dwAttributes = SFGAO_FOLDER;
1859 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1861 /* the path component is valid, we have a pidl of the next path component */
1862 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1863 if(dwAttributes & SFGAO_FOLDER)
1865 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1867 ERR("bind to failed\n"); /* should not fail */
1868 break;
1870 IShellFolder_Release(lpsf);
1871 lpsf = lpsfChild;
1872 lpsfChild = NULL;
1874 else
1876 TRACE("value\n");
1878 /* end dialog, return value */
1879 nOpenAction = ONOPEN_OPEN;
1880 break;
1882 COMDLG32_SHFree(pidl);
1883 pidl = NULL;
1885 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1887 if(*lpszTemp) /* points to trailing null for last path element */
1889 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1891 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1892 break;
1895 else
1897 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1898 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1900 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1901 break;
1904 /* change to the current folder */
1905 nOpenAction = ONOPEN_OPEN;
1906 break;
1908 else
1910 nOpenAction = ONOPEN_OPEN;
1911 break;
1914 if(pidl) COMDLG32_SHFree(pidl);
1918 Step 3: here we have a cleaned up and validated path
1920 valid variables:
1921 lpsf: ShellFolder bound to the rightmost valid path component
1922 lpstrPathAndFile: cleaned up path
1923 nOpenAction: action to do
1925 TRACE("end validate sf=%p\n", lpsf);
1927 switch(nOpenAction)
1929 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1930 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1932 int iPos;
1933 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1934 DWORD len;
1936 /* replace the current filter */
1937 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1938 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1939 len = strlenW(lpszTemp)+1;
1940 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1941 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1943 /* set the filter cb to the extension when possible */
1944 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1945 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1947 /* fall through */
1948 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1949 TRACE("ONOPEN_BROWSE\n");
1951 IPersistFolder2 * ppf2;
1952 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1954 LPITEMIDLIST pidlCurrent;
1955 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1956 IPersistFolder2_Release(ppf2);
1957 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1959 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1961 else if( nOpenAction == ONOPEN_SEARCH )
1963 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1965 COMDLG32_SHFree(pidlCurrent);
1968 ret = FALSE;
1969 break;
1970 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1971 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1973 WCHAR *ext = NULL;
1975 /* update READONLY check box flag */
1976 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1977 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1978 else
1979 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1981 /* Attach the file extension with file name*/
1982 ext = PathFindExtensionW(lpstrPathAndFile);
1983 if (! *ext)
1985 /* if no extension is specified with file name, then */
1986 /* attach the extension from file filter or default one */
1988 WCHAR *filterExt = NULL;
1989 LPWSTR lpstrFilter = NULL;
1990 static const WCHAR szwDot[] = {'.',0};
1991 int PathLength = strlenW(lpstrPathAndFile);
1993 /* Attach the dot*/
1994 strcatW(lpstrPathAndFile, szwDot);
1996 /*Get the file extension from file type filter*/
1997 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1998 fodInfos->ofnInfos->nFilterIndex-1);
2000 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2001 filterExt = PathFindExtensionW(lpstrFilter);
2003 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2004 strcatW(lpstrPathAndFile, filterExt + 1);
2005 else if ( fodInfos->defext ) /* attach the default file extension*/
2006 strcatW(lpstrPathAndFile, fodInfos->defext);
2008 /* In Open dialog: if file does not exist try without extension */
2009 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2010 lpstrPathAndFile[PathLength] = '\0';
2013 if (fodInfos->defext) /* add default extension */
2015 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2016 if (*ext)
2017 ext++;
2018 if (!lstrcmpiW(fodInfos->defext, ext))
2019 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2020 else
2021 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2024 /* In Save dialog: check if the file already exists */
2025 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2026 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2027 && PathFileExistsW(lpstrPathAndFile))
2029 WCHAR lpstrOverwrite[100];
2030 int answer;
2032 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2033 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2034 MB_YESNO | MB_ICONEXCLAMATION);
2035 if (answer == IDNO)
2037 ret = FALSE;
2038 goto ret;
2042 /* Check that the size of the file does not exceed buffer size.
2043 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2044 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2045 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2047 LPWSTR lpszTemp;
2049 /* fill destination buffer */
2050 if (fodInfos->ofnInfos->lpstrFile)
2052 if(fodInfos->unicode)
2054 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2056 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2057 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2058 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2060 else
2062 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2064 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2065 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2066 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2067 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2071 /* set filename offset */
2072 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2073 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2075 /* set extension offset */
2076 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2077 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2079 /* set the lpstrFileTitle */
2080 if(fodInfos->ofnInfos->lpstrFileTitle)
2082 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2083 if(fodInfos->unicode)
2085 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2086 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2088 else
2090 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2091 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2092 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2096 /* copy currently selected filter to lpstrCustomFilter */
2097 if (fodInfos->ofnInfos->lpstrCustomFilter)
2099 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2100 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2101 NULL, 0, NULL, NULL);
2102 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2104 LPSTR s = ofn->lpstrCustomFilter;
2105 s += strlen(ofn->lpstrCustomFilter)+1;
2106 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2107 s, len, NULL, NULL);
2112 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2113 goto ret;
2115 TRACE("close\n");
2116 FILEDLG95_Clean(hwnd);
2117 ret = EndDialog(hwnd, TRUE);
2119 else
2121 WORD size;
2123 size = strlenW(lpstrPathAndFile) + 1;
2124 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2125 size += 1;
2126 /* return needed size in first two bytes of lpstrFile */
2127 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2128 FILEDLG95_Clean(hwnd);
2129 ret = EndDialog(hwnd, FALSE);
2130 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2132 goto ret;
2134 break;
2137 ret:
2138 if(lpsf) IShellFolder_Release(lpsf);
2139 return ret;
2142 /***********************************************************************
2143 * FILEDLG95_SHELL_Init
2145 * Initialisation of the shell objects
2147 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2149 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2151 TRACE("\n");
2154 * Initialisation of the FileOpenDialogInfos structure
2157 /* Shell */
2159 /*ShellInfos */
2160 fodInfos->ShellInfos.hwndOwner = hwnd;
2162 /* Disable multi-select if flag not set */
2163 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2165 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2167 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2168 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2170 /* Construct the IShellBrowser interface */
2171 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2173 return NOERROR;
2176 /***********************************************************************
2177 * FILEDLG95_SHELL_ExecuteCommand
2179 * Change the folder option and refresh the view
2180 * If the function succeeds, the return value is nonzero.
2182 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2184 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2186 IContextMenu * pcm;
2187 TRACE("(%p,%p)\n", hwnd, lpVerb);
2189 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2190 SVGIO_BACKGROUND,
2191 &IID_IContextMenu,
2192 (LPVOID*)&pcm)))
2194 CMINVOKECOMMANDINFO ci;
2195 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2196 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2197 ci.lpVerb = lpVerb;
2198 ci.hwnd = hwnd;
2200 IContextMenu_InvokeCommand(pcm, &ci);
2201 IContextMenu_Release(pcm);
2204 return FALSE;
2207 /***********************************************************************
2208 * FILEDLG95_SHELL_UpFolder
2210 * Browse to the specified object
2211 * If the function succeeds, the return value is nonzero.
2213 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2215 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2217 TRACE("\n");
2219 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2220 NULL,
2221 SBSP_PARENT)))
2223 return TRUE;
2225 return FALSE;
2228 /***********************************************************************
2229 * FILEDLG95_SHELL_BrowseToDesktop
2231 * Browse to the Desktop
2232 * If the function succeeds, the return value is nonzero.
2234 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2236 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2237 LPITEMIDLIST pidl;
2238 HRESULT hres;
2240 TRACE("\n");
2242 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2243 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2244 COMDLG32_SHFree(pidl);
2245 return SUCCEEDED(hres);
2247 /***********************************************************************
2248 * FILEDLG95_SHELL_Clean
2250 * Cleans the memory used by shell objects
2252 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2254 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2256 TRACE("\n");
2258 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2260 /* clean Shell interfaces */
2261 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2262 IShellView_Release(fodInfos->Shell.FOIShellView);
2263 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2264 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2265 if (fodInfos->Shell.FOIDataObject)
2266 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2269 /***********************************************************************
2270 * FILEDLG95_FILETYPE_Init
2272 * Initialisation of the file type combo box
2274 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2276 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2277 int nFilters = 0; /* number of filters */
2278 int nFilterIndexCB;
2280 TRACE("\n");
2282 if(fodInfos->customfilter)
2284 /* customfilter has one entry... title\0ext\0
2285 * Set first entry of combo box item with customfilter
2287 LPWSTR lpstrExt;
2288 LPCWSTR lpstrPos = fodInfos->customfilter;
2290 /* Get the title */
2291 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2293 /* Copy the extensions */
2294 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2295 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2296 strcpyW(lpstrExt,lpstrPos);
2298 /* Add the item at the end of the combo */
2299 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2300 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2301 nFilters++;
2303 if(fodInfos->filter)
2305 LPCWSTR lpstrPos = fodInfos->filter;
2307 for(;;)
2309 /* filter is a list... title\0ext\0......\0\0
2310 * Set the combo item text to the title and the item data
2311 * to the ext
2313 LPCWSTR lpstrDisplay;
2314 LPWSTR lpstrExt;
2316 /* Get the title */
2317 if(! *lpstrPos) break; /* end */
2318 lpstrDisplay = lpstrPos;
2319 lpstrPos += strlenW(lpstrPos) + 1;
2321 /* Copy the extensions */
2322 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2323 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2324 strcpyW(lpstrExt,lpstrPos);
2325 lpstrPos += strlenW(lpstrPos) + 1;
2327 /* Add the item at the end of the combo */
2328 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2329 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2330 nFilters++;
2335 * Set the current filter to the one specified
2336 * in the initialisation structure
2338 if (fodInfos->filter || fodInfos->customfilter)
2340 LPWSTR lpstrFilter;
2342 /* Check to make sure our index isn't out of bounds. */
2343 if ( fodInfos->ofnInfos->nFilterIndex >
2344 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2345 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2347 /* set default filter index */
2348 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2349 fodInfos->ofnInfos->nFilterIndex = 1;
2351 /* calculate index of Combo Box item */
2352 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2353 if (fodInfos->customfilter == NULL)
2354 nFilterIndexCB--;
2356 /* Set the current index selection. */
2357 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2359 /* Get the corresponding text string from the combo box. */
2360 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2361 nFilterIndexCB);
2363 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2364 lpstrFilter = NULL;
2366 if(lpstrFilter)
2368 DWORD len;
2369 CharLowerW(lpstrFilter); /* lowercase */
2370 len = strlenW(lpstrFilter)+1;
2371 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2372 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2374 } else
2375 fodInfos->ofnInfos->nFilterIndex = 0;
2377 return NOERROR;
2380 /***********************************************************************
2381 * FILEDLG95_FILETYPE_OnCommand
2383 * WM_COMMAND of the file type combo box
2384 * If the function succeeds, the return value is nonzero.
2386 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2388 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2390 switch(wNotifyCode)
2392 case CBN_SELENDOK:
2394 LPWSTR lpstrFilter;
2396 /* Get the current item of the filetype combo box */
2397 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2399 /* set the current filter index */
2400 fodInfos->ofnInfos->nFilterIndex = iItem +
2401 (fodInfos->customfilter == NULL ? 1 : 0);
2403 /* Set the current filter with the current selection */
2404 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2405 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2407 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2408 iItem);
2409 if((int)lpstrFilter != CB_ERR)
2411 DWORD len;
2412 CharLowerW(lpstrFilter); /* lowercase */
2413 len = strlenW(lpstrFilter)+1;
2414 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2415 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2416 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2419 /* Refresh the actual view to display the included items*/
2420 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2423 return FALSE;
2425 /***********************************************************************
2426 * FILEDLG95_FILETYPE_SearchExt
2428 * searches for an extension in the filetype box
2430 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2432 int i, iCount = CBGetCount(hwnd);
2434 TRACE("%s\n", debugstr_w(lpstrExt));
2436 if(iCount != CB_ERR)
2438 for(i=0;i<iCount;i++)
2440 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2441 return i;
2444 return -1;
2447 /***********************************************************************
2448 * FILEDLG95_FILETYPE_Clean
2450 * Clean the memory used by the filetype combo box
2452 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2454 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2455 int iPos;
2456 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2458 TRACE("\n");
2460 /* Delete each string of the combo and their associated data */
2461 if(iCount != CB_ERR)
2463 for(iPos = iCount-1;iPos>=0;iPos--)
2465 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2466 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2469 /* Current filter */
2470 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2471 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2475 /***********************************************************************
2476 * FILEDLG95_LOOKIN_Init
2478 * Initialisation of the look in combo box
2480 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2482 IShellFolder *psfRoot, *psfDrives;
2483 IEnumIDList *lpeRoot, *lpeDrives;
2484 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2486 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2488 TRACE("\n");
2490 liInfos->iMaxIndentation = 0;
2492 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2494 /* set item height for both text field and listbox */
2495 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2496 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2498 /* Turn on the extended UI for the combo box like Windows does */
2499 CBSetExtendedUI(hwndCombo, TRUE);
2501 /* Initialise data of Desktop folder */
2502 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2503 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2504 COMDLG32_SHFree(pidlTmp);
2506 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2508 SHGetDesktopFolder(&psfRoot);
2510 if (psfRoot)
2512 /* enumerate the contents of the desktop */
2513 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2515 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2517 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2519 /* special handling for CSIDL_DRIVES */
2520 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2522 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2524 /* enumerate the drives */
2525 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2527 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2529 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2530 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2531 COMDLG32_SHFree(pidlAbsTmp);
2532 COMDLG32_SHFree(pidlTmp1);
2534 IEnumIDList_Release(lpeDrives);
2536 IShellFolder_Release(psfDrives);
2539 COMDLG32_SHFree(pidlTmp);
2541 IEnumIDList_Release(lpeRoot);
2543 IShellFolder_Release(psfRoot);
2546 COMDLG32_SHFree(pidlDrives);
2547 return NOERROR;
2550 /***********************************************************************
2551 * FILEDLG95_LOOKIN_DrawItem
2553 * WM_DRAWITEM message handler
2555 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2557 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2558 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2559 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2560 RECT rectText;
2561 RECT rectIcon;
2562 SHFILEINFOA sfi;
2563 HIMAGELIST ilItemImage;
2564 int iIndentation;
2565 TEXTMETRICA tm;
2566 LPSFOLDER tmpFolder;
2569 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2571 TRACE("\n");
2573 if(pDIStruct->itemID == -1)
2574 return 0;
2576 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2577 pDIStruct->itemID)))
2578 return 0;
2581 if(pDIStruct->itemID == liInfos->uSelectedItem)
2583 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2585 &sfi,
2586 sizeof (SHFILEINFOA),
2587 SHGFI_PIDL | SHGFI_SMALLICON |
2588 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2589 SHGFI_DISPLAYNAME );
2591 else
2593 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2595 &sfi,
2596 sizeof (SHFILEINFOA),
2597 SHGFI_PIDL | SHGFI_SMALLICON |
2598 SHGFI_SYSICONINDEX |
2599 SHGFI_DISPLAYNAME);
2602 /* Is this item selected ? */
2603 if(pDIStruct->itemState & ODS_SELECTED)
2605 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2606 SetBkColor(pDIStruct->hDC,crHighLight);
2607 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2609 else
2611 SetTextColor(pDIStruct->hDC,crText);
2612 SetBkColor(pDIStruct->hDC,crWin);
2613 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2616 /* Do not indent item if drawing in the edit of the combo */
2617 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2619 iIndentation = 0;
2620 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2622 &sfi,
2623 sizeof (SHFILEINFOA),
2624 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2625 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2628 else
2630 iIndentation = tmpFolder->m_iIndent;
2632 /* Draw text and icon */
2634 /* Initialise the icon display area */
2635 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2636 rectIcon.top = pDIStruct->rcItem.top;
2637 rectIcon.right = rectIcon.left + ICONWIDTH;
2638 rectIcon.bottom = pDIStruct->rcItem.bottom;
2640 /* Initialise the text display area */
2641 GetTextMetricsA(pDIStruct->hDC, &tm);
2642 rectText.left = rectIcon.right;
2643 rectText.top =
2644 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2645 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2646 rectText.bottom =
2647 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2649 /* Draw the icon from the image list */
2650 ImageList_Draw(ilItemImage,
2651 sfi.iIcon,
2652 pDIStruct->hDC,
2653 rectIcon.left,
2654 rectIcon.top,
2655 ILD_TRANSPARENT );
2657 /* Draw the associated text */
2658 if(sfi.szDisplayName)
2659 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2662 return NOERROR;
2665 /***********************************************************************
2666 * FILEDLG95_LOOKIN_OnCommand
2668 * LookIn combo box WM_COMMAND message handler
2669 * If the function succeeds, the return value is nonzero.
2671 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2673 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2675 TRACE("%p\n", fodInfos);
2677 switch(wNotifyCode)
2679 case CBN_SELENDOK:
2681 LPSFOLDER tmpFolder;
2682 int iItem;
2684 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2686 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2687 iItem)))
2688 return FALSE;
2691 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2692 tmpFolder->pidlItem,
2693 SBSP_ABSOLUTE)))
2695 return TRUE;
2697 break;
2701 return FALSE;
2704 /***********************************************************************
2705 * FILEDLG95_LOOKIN_AddItem
2707 * Adds an absolute pidl item to the lookin combo box
2708 * returns the index of the inserted item
2710 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2712 LPITEMIDLIST pidlNext;
2713 SHFILEINFOA sfi;
2714 SFOLDER *tmpFolder;
2715 LookInInfos *liInfos;
2717 TRACE("%08x\n", iInsertId);
2719 if(!pidl)
2720 return -1;
2722 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2723 return -1;
2725 tmpFolder = MemAlloc(sizeof(SFOLDER));
2726 tmpFolder->m_iIndent = 0;
2728 /* Calculate the indentation of the item in the lookin*/
2729 pidlNext = pidl;
2730 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2732 tmpFolder->m_iIndent++;
2735 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2737 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2738 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2740 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2741 SHGetFileInfoA((LPSTR)pidl,
2743 &sfi,
2744 sizeof(sfi),
2745 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2746 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2748 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2750 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2752 int iItemID;
2754 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2756 /* Add the item at the end of the list */
2757 if(iInsertId < 0)
2759 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2761 /* Insert the item at the iInsertId position*/
2762 else
2764 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2767 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2768 return iItemID;
2771 COMDLG32_SHFree( tmpFolder->pidlItem );
2772 MemFree( tmpFolder );
2773 return -1;
2777 /***********************************************************************
2778 * FILEDLG95_LOOKIN_InsertItemAfterParent
2780 * Insert an item below its parent
2782 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2785 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2786 int iParentPos;
2788 TRACE("\n");
2790 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2792 if(iParentPos < 0)
2794 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2797 /* Free pidlParent memory */
2798 COMDLG32_SHFree((LPVOID)pidlParent);
2800 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2803 /***********************************************************************
2804 * FILEDLG95_LOOKIN_SelectItem
2806 * Adds an absolute pidl item to the lookin combo box
2807 * returns the index of the inserted item
2809 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2811 int iItemPos;
2812 LookInInfos *liInfos;
2814 TRACE("\n");
2816 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2818 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2820 if(iItemPos < 0)
2822 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2823 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2826 else
2828 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2829 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2831 int iRemovedItem;
2833 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2834 break;
2835 if(iRemovedItem < iItemPos)
2836 iItemPos--;
2840 CBSetCurSel(hwnd,iItemPos);
2841 liInfos->uSelectedItem = iItemPos;
2843 return 0;
2847 /***********************************************************************
2848 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2850 * Remove the item with an expansion level over iExpansionLevel
2852 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2854 int iItemPos;
2856 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2858 TRACE("\n");
2860 if(liInfos->iMaxIndentation <= 2)
2861 return -1;
2863 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2865 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2866 COMDLG32_SHFree(tmpFolder->pidlItem);
2867 MemFree(tmpFolder);
2868 CBDeleteString(hwnd,iItemPos);
2869 liInfos->iMaxIndentation--;
2871 return iItemPos;
2874 return -1;
2877 /***********************************************************************
2878 * FILEDLG95_LOOKIN_SearchItem
2880 * Search for pidl in the lookin combo box
2881 * returns the index of the found item
2883 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2885 int i = 0;
2886 int iCount = CBGetCount(hwnd);
2888 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2890 if (iCount != CB_ERR)
2892 for(;i<iCount;i++)
2894 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2896 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2897 return i;
2898 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2899 return i;
2903 return -1;
2906 /***********************************************************************
2907 * FILEDLG95_LOOKIN_Clean
2909 * Clean the memory used by the lookin combo box
2911 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2913 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2914 int iPos;
2915 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2917 TRACE("\n");
2919 /* Delete each string of the combo and their associated data */
2920 if (iCount != CB_ERR)
2922 for(iPos = iCount-1;iPos>=0;iPos--)
2924 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2925 COMDLG32_SHFree(tmpFolder->pidlItem);
2926 MemFree(tmpFolder);
2927 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2931 /* LookInInfos structure */
2932 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2935 /***********************************************************************
2936 * FILEDLG95_FILENAME_FillFromSelection
2938 * fills the edit box from the cached DataObject
2940 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2942 FileOpenDlgInfos *fodInfos;
2943 LPITEMIDLIST pidl;
2944 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2945 char lpstrTemp[MAX_PATH];
2946 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2948 TRACE("\n");
2949 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2951 /* Count how many files we have */
2952 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2954 /* calculate the string length, count files */
2955 if (nFileSelected >= 1)
2957 nLength += 3; /* first and last quotes, trailing \0 */
2958 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2960 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2962 if (pidl)
2964 /* get the total length of the selected file names */
2965 lpstrTemp[0] = '\0';
2966 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2968 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2970 nLength += strlen( lpstrTemp ) + 3;
2971 nFiles++;
2973 COMDLG32_SHFree( pidl );
2978 /* allocate the buffer */
2979 if (nFiles <= 1) nLength = MAX_PATH;
2980 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2981 lpstrAllFile[0] = '\0';
2983 /* Generate the string for the edit control */
2984 if(nFiles >= 1)
2986 lpstrCurrFile = lpstrAllFile;
2987 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2989 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2991 if (pidl)
2993 /* get the file name */
2994 lpstrTemp[0] = '\0';
2995 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2997 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2999 if ( nFiles > 1)
3001 *lpstrCurrFile++ = '\"';
3002 strcpy( lpstrCurrFile, lpstrTemp );
3003 lpstrCurrFile += strlen( lpstrTemp );
3004 strcpy( lpstrCurrFile, "\" " );
3005 lpstrCurrFile += 2;
3007 else
3009 strcpy( lpstrAllFile, lpstrTemp );
3012 COMDLG32_SHFree( (LPVOID) pidl );
3015 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3017 /* Select the file name like Windows does */
3018 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3020 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3024 /* copied from shell32 to avoid linking to it */
3025 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3027 switch (src->uType)
3029 case STRRET_WSTR:
3030 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3031 COMDLG32_SHFree(src->u.pOleStr);
3032 break;
3034 case STRRET_CSTR:
3035 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3036 break;
3038 case STRRET_OFFSET:
3039 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3040 break;
3042 default:
3043 FIXME("unknown type!\n");
3044 if (len)
3046 *(LPSTR)dest = '\0';
3048 return(FALSE);
3050 return S_OK;
3053 /***********************************************************************
3054 * FILEDLG95_FILENAME_GetFileNames
3056 * Copies the filenames to a delimited string list.
3057 * The delimiter is specified by the parameter 'separator',
3058 * usually either a space or a nul
3060 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3062 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3063 UINT nStrCharCount = 0; /* index in src buffer */
3064 UINT nFileIndex = 0; /* index in dest buffer */
3065 UINT nFileCount = 0; /* number of files */
3066 UINT nStrLen = 0; /* length of string in edit control */
3067 LPWSTR lpstrEdit; /* buffer for string from edit control */
3069 TRACE("\n");
3071 /* get the filenames from the edit control */
3072 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3073 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3074 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3076 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3078 /* we might get single filename without any '"',
3079 * so we need nStrLen + terminating \0 + end-of-list \0 */
3080 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3081 *sizeUsed = 0;
3083 /* build delimited file list from filenames */
3084 while ( nStrCharCount <= nStrLen )
3086 if ( lpstrEdit[nStrCharCount]=='"' )
3088 nStrCharCount++;
3089 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3091 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3092 (*sizeUsed)++;
3093 nStrCharCount++;
3095 (*lpstrFileList)[nFileIndex++] = separator;
3096 (*sizeUsed)++;
3097 nFileCount++;
3099 nStrCharCount++;
3102 /* single, unquoted string */
3103 if ((nStrLen > 0) && (*sizeUsed == 0) )
3105 strcpyW(*lpstrFileList, lpstrEdit);
3106 nFileIndex = strlenW(lpstrEdit) + 1;
3107 (*sizeUsed) = nFileIndex;
3108 nFileCount = 1;
3111 /* trailing \0 */
3112 (*lpstrFileList)[nFileIndex] = '\0';
3113 (*sizeUsed)++;
3115 MemFree(lpstrEdit);
3116 return nFileCount;
3119 #define SETDefFormatEtc(fe,cf,med) \
3121 (fe).cfFormat = cf;\
3122 (fe).dwAspect = DVASPECT_CONTENT; \
3123 (fe).ptd =NULL;\
3124 (fe).tymed = med;\
3125 (fe).lindex = -1;\
3129 * DATAOBJECT Helper functions
3132 /***********************************************************************
3133 * COMCTL32_ReleaseStgMedium
3135 * like ReleaseStgMedium from ole32
3137 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3139 if(medium.pUnkForRelease)
3141 IUnknown_Release(medium.pUnkForRelease);
3143 else
3145 GlobalUnlock(medium.u.hGlobal);
3146 GlobalFree(medium.u.hGlobal);
3150 /***********************************************************************
3151 * GetPidlFromDataObject
3153 * Return pidl(s) by number from the cached DataObject
3155 * nPidlIndex=0 gets the fully qualified root path
3157 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3160 STGMEDIUM medium;
3161 FORMATETC formatetc;
3162 LPITEMIDLIST pidl = NULL;
3164 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3166 /* Set the FORMATETC structure*/
3167 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3169 /* Get the pidls from IDataObject */
3170 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3172 LPIDA cida = GlobalLock(medium.u.hGlobal);
3173 if(nPidlIndex <= cida->cidl)
3175 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3177 COMCTL32_ReleaseStgMedium(medium);
3179 return pidl;
3182 /***********************************************************************
3183 * GetNumSelected
3185 * Return the number of selected items in the DataObject.
3188 UINT GetNumSelected( IDataObject *doSelected )
3190 UINT retVal = 0;
3191 STGMEDIUM medium;
3192 FORMATETC formatetc;
3194 TRACE("sv=%p\n", doSelected);
3196 if (!doSelected) return 0;
3198 /* Set the FORMATETC structure*/
3199 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3201 /* Get the pidls from IDataObject */
3202 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3204 LPIDA cida = GlobalLock(medium.u.hGlobal);
3205 retVal = cida->cidl;
3206 COMCTL32_ReleaseStgMedium(medium);
3207 return retVal;
3209 return 0;
3213 * TOOLS
3216 /***********************************************************************
3217 * GetName
3219 * Get the pidl's display name (relative to folder) and
3220 * put it in lpstrFileName.
3222 * Return NOERROR on success,
3223 * E_FAIL otherwise
3226 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3228 STRRET str;
3229 HRESULT hRes;
3231 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3233 if(!lpsf)
3235 SHGetDesktopFolder(&lpsf);
3236 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3237 IShellFolder_Release(lpsf);
3238 return hRes;
3241 /* Get the display name of the pidl relative to the folder */
3242 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3244 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3246 return E_FAIL;
3249 /***********************************************************************
3250 * GetShellFolderFromPidl
3252 * pidlRel is the item pidl relative
3253 * Return the IShellFolder of the absolute pidl
3255 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3257 IShellFolder *psf = NULL,*psfParent;
3259 TRACE("%p\n", pidlAbs);
3261 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3263 psf = psfParent;
3264 if(pidlAbs && pidlAbs->mkid.cb)
3266 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3268 IShellFolder_Release(psfParent);
3269 return psf;
3272 /* return the desktop */
3273 return psfParent;
3275 return NULL;
3278 /***********************************************************************
3279 * GetParentPidl
3281 * Return the LPITEMIDLIST to the parent of the pidl in the list
3283 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3285 LPITEMIDLIST pidlParent;
3287 TRACE("%p\n", pidl);
3289 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3290 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3292 return pidlParent;
3295 /***********************************************************************
3296 * GetPidlFromName
3298 * returns the pidl of the file name relative to folder
3299 * NULL if an error occurred
3301 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3303 LPITEMIDLIST pidl = NULL;
3304 ULONG ulEaten;
3306 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3308 if(!lpcstrFileName) return NULL;
3309 if(!*lpcstrFileName) return NULL;
3311 if(!lpsf)
3313 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3314 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3315 IShellFolder_Release(lpsf);
3318 else
3320 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3322 return pidl;
3327 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3329 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3330 HRESULT ret;
3332 TRACE("%p, %p\n", psf, pidl);
3334 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3336 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3337 /* see documentation shell 4.1*/
3338 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3341 /***********************************************************************
3342 * BrowseSelectedFolder
3344 static BOOL BrowseSelectedFolder(HWND hwnd)
3346 BOOL bBrowseSelFolder = FALSE;
3347 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3349 TRACE("\n");
3351 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3353 LPITEMIDLIST pidlSelection;
3355 /* get the file selected */
3356 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3357 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3359 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3360 pidlSelection, SBSP_RELATIVE ) ) )
3362 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3363 ' ','n','o','t',' ','e','x','i','s','t',0};
3364 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3367 bBrowseSelFolder = TRUE;
3369 COMDLG32_SHFree( pidlSelection );
3372 return bBrowseSelFolder;
3376 * Memory allocation methods */
3377 static void *MemAlloc(UINT size)
3379 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3382 static void MemFree(void *mem)
3384 HeapFree(GetProcessHeap(),0,mem);
3388 * Old-style (win3.1) dialogs */
3390 /***********************************************************************
3391 * FD32_GetTemplate [internal]
3393 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3394 * by a 32 bits application
3397 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3399 LPOPENFILENAMEW ofnW = lfs->ofnW;
3400 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3401 HANDLE hDlgTmpl;
3403 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3405 if (!(lfs->template = LockResource( ofnW->hInstance )))
3407 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3408 return FALSE;
3411 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3413 HRSRC hResInfo;
3414 if (priv->ofnA)
3415 hResInfo = FindResourceA(priv->ofnA->hInstance,
3416 priv->ofnA->lpTemplateName,
3417 (LPSTR)RT_DIALOG);
3418 else
3419 hResInfo = FindResourceW(ofnW->hInstance,
3420 ofnW->lpTemplateName,
3421 (LPWSTR)RT_DIALOG);
3422 if (!hResInfo)
3424 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3425 return FALSE;
3427 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3428 hResInfo)) ||
3429 !(lfs->template = LockResource(hDlgTmpl)))
3431 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3432 return FALSE;
3434 } else { /* get it from internal Wine resource */
3435 HRSRC hResInfo;
3436 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3437 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3439 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3440 return FALSE;
3442 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3443 !(lfs->template = LockResource( hDlgTmpl )))
3445 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3446 return FALSE;
3449 return TRUE;
3453 /************************************************************************
3454 * FD32_Init [internal]
3455 * called from the common 16/32 code to initialize 32 bit data
3457 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3459 BOOL IsUnicode = (BOOL) data;
3460 PFD32_PRIVATE priv;
3462 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3463 lfs->private1632 = priv;
3464 if (NULL == lfs->private1632) return FALSE;
3465 if (IsUnicode)
3467 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3468 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3469 if (lfs->ofnW->lpfnHook)
3470 lfs->hook = TRUE;
3472 else
3474 priv->ofnA = (LPOPENFILENAMEA) lParam;
3475 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3476 if (priv->ofnA->lpfnHook)
3477 lfs->hook = TRUE;
3478 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3479 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3482 if (! FD32_GetTemplate(lfs)) return FALSE;
3484 return TRUE;
3487 /***********************************************************************
3488 * FD32_CallWindowProc [internal]
3490 * called from the common 16/32 code to call the appropriate hook
3492 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3493 LPARAM lParam)
3495 BOOL ret;
3496 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3498 if (priv->ofnA)
3500 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3501 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3502 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3503 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3504 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3505 return ret;
3508 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3509 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3510 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3511 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3512 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3513 return ret;
3516 /***********************************************************************
3517 * FD32_UpdateResult [internal]
3518 * update the real client structures if any
3520 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3522 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3523 LPOPENFILENAMEW ofnW = lfs->ofnW;
3525 if (priv->ofnA)
3527 if (ofnW->nMaxFile &&
3528 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3529 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3530 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3531 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3532 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3536 /***********************************************************************
3537 * FD32_UpdateFileTitle [internal]
3538 * update the real client structures if any
3540 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3542 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3543 LPOPENFILENAMEW ofnW = lfs->ofnW;
3545 if (priv->ofnA)
3547 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3548 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3549 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3554 /***********************************************************************
3555 * FD32_SendLbGetCurSel [internal]
3556 * retrieve selected listbox item
3558 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3560 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3564 /************************************************************************
3565 * FD32_Destroy [internal]
3566 * called from the common 16/32 code to cleanup 32 bit data
3568 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3570 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3572 /* if ofnW has been allocated, have to free everything in it */
3573 if (NULL != priv && NULL != priv->ofnA)
3575 FD31_FreeOfnW(lfs->ofnW);
3576 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3580 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3582 callbacks->Init = FD32_Init;
3583 callbacks->CWP = FD32_CallWindowProc;
3584 callbacks->UpdateResult = FD32_UpdateResult;
3585 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3586 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3587 callbacks->Destroy = FD32_Destroy;
3590 /***********************************************************************
3591 * FD32_WMMeasureItem [internal]
3593 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3595 LPMEASUREITEMSTRUCT lpmeasure;
3597 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3598 lpmeasure->itemHeight = FD31_GetFldrHeight();
3599 return TRUE;
3603 /***********************************************************************
3604 * FileOpenDlgProc [internal]
3605 * Used for open and save, in fact.
3607 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3608 WPARAM wParam, LPARAM lParam)
3610 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3612 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3613 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3615 INT_PTR lRet;
3616 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3617 if (lRet)
3618 return lRet; /* else continue message processing */
3620 switch (wMsg)
3622 case WM_INITDIALOG:
3623 return FD31_WMInitDialog(hWnd, wParam, lParam);
3625 case WM_MEASUREITEM:
3626 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3628 case WM_DRAWITEM:
3629 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3631 case WM_COMMAND:
3632 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3633 #if 0
3634 case WM_CTLCOLOR:
3635 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3636 switch (HIWORD(lParam))
3638 case CTLCOLOR_BTN:
3639 SetTextColor((HDC16)wParam, 0x00000000);
3640 return hGRAYBrush;
3641 case CTLCOLOR_STATIC:
3642 SetTextColor((HDC16)wParam, 0x00000000);
3643 return hGRAYBrush;
3645 break;
3646 #endif
3648 return FALSE;
3652 /***********************************************************************
3653 * GetFileName31A [internal]
3655 * Creates a win31 style dialog box for the user to select a file to open/save.
3657 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3658 UINT dlgType /* type dialogue : open/save */
3661 HINSTANCE hInst;
3662 BOOL bRet = FALSE;
3663 PFD31_DATA lfs;
3664 FD31_CALLBACKS callbacks;
3666 if (!lpofn || !FD31_Init()) return FALSE;
3668 TRACE("ofn flags %08lx\n", lpofn->Flags);
3669 FD32_SetupCallbacks(&callbacks);
3670 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3671 if (lfs)
3673 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3674 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3675 FD32_FileOpenDlgProc, (LPARAM)lfs);
3676 FD31_DestroyPrivate(lfs);
3679 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3680 return bRet;
3683 /***********************************************************************
3684 * GetFileName31W [internal]
3686 * Creates a win31 style dialog box for the user to select a file to open/save
3688 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3689 UINT dlgType /* type dialogue : open/save */
3692 HINSTANCE hInst;
3693 BOOL bRet = FALSE;
3694 PFD31_DATA lfs;
3695 FD31_CALLBACKS callbacks;
3697 if (!lpofn || !FD31_Init()) return FALSE;
3699 FD32_SetupCallbacks(&callbacks);
3700 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3701 if (lfs)
3703 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3704 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3705 FD32_FileOpenDlgProc, (LPARAM)lfs);
3706 FD31_DestroyPrivate(lfs);
3709 TRACE("file %s, file offset %d, ext offset %d\n",
3710 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3711 return bRet;
3714 /* ------------------ APIs ---------------------- */
3716 /***********************************************************************
3717 * GetOpenFileNameA (COMDLG32.@)
3719 * Creates a dialog box for the user to select a file to open.
3721 * RETURNS
3722 * TRUE on success: user enters a valid file
3723 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3726 BOOL WINAPI GetOpenFileNameA(
3727 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3729 BOOL win16look = FALSE;
3731 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3732 if (ofn->Flags & OFN_FILEMUSTEXIST)
3733 ofn->Flags |= OFN_PATHMUSTEXIST;
3735 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3736 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3738 if (win16look)
3739 return GetFileName31A(ofn, OPEN_DIALOG);
3740 else
3741 return GetFileDialog95A(ofn, OPEN_DIALOG);
3744 /***********************************************************************
3745 * GetOpenFileNameW (COMDLG32.@)
3747 * Creates a dialog box for the user to select a file to open.
3749 * RETURNS
3750 * TRUE on success: user enters a valid file
3751 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3754 BOOL WINAPI GetOpenFileNameW(
3755 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3757 BOOL win16look = FALSE;
3759 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3760 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3762 if (win16look)
3763 return GetFileName31W(ofn, OPEN_DIALOG);
3764 else
3765 return GetFileDialog95W(ofn, OPEN_DIALOG);
3769 /***********************************************************************
3770 * GetSaveFileNameA (COMDLG32.@)
3772 * Creates a dialog box for the user to select a file to save.
3774 * RETURNS
3775 * TRUE on success: user enters a valid file
3776 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3779 BOOL WINAPI GetSaveFileNameA(
3780 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3782 BOOL win16look = FALSE;
3784 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3785 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3787 if (win16look)
3788 return GetFileName31A(ofn, SAVE_DIALOG);
3789 else
3790 return GetFileDialog95A(ofn, SAVE_DIALOG);
3793 /***********************************************************************
3794 * GetSaveFileNameW (COMDLG32.@)
3796 * Creates a dialog box for the user to select a file to save.
3798 * RETURNS
3799 * TRUE on success: user enters a valid file
3800 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3803 BOOL WINAPI GetSaveFileNameW(
3804 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3806 BOOL win16look = FALSE;
3808 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3809 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3811 if (win16look)
3812 return GetFileName31W(ofn, SAVE_DIALOG);
3813 else
3814 return GetFileDialog95W(ofn, SAVE_DIALOG);