If a folder is selected on Open then browse into it, otherwise we
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blobcbfbe88bb8303ff3d5987343a00f2879c8fda397
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 HRESULT retval;
952 if(!fodInfos) return FALSE;
954 switch(uMsg)
956 case CDM_GETFILEPATH:
957 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
958 break;
960 case CDM_GETFOLDERPATH:
961 TRACE("CDM_GETFOLDERPATH:\n");
962 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
963 if (lParam)
965 if (fodInfos->unicode)
966 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
967 else
968 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
969 (LPSTR)lParam, (int)wParam, NULL, NULL);
971 retval = strlenW(lpstrPath);
972 break;
974 case CDM_GETSPEC:
975 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
976 break;
978 case CDM_SETCONTROLTEXT:
979 TRACE("CDM_SETCONTROLTEXT:\n");
980 if ( lParam )
982 if( fodInfos->unicode )
983 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
984 else
985 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
987 retval = TRUE;
988 break;
990 case CDM_HIDECONTROL:
991 case CDM_SETDEFEXT:
992 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
993 retval = -1;
994 break;
996 default:
997 return FALSE;
999 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1000 return TRUE;
1003 /***********************************************************************
1004 * FileOpenDlgProc95
1006 * File open dialog procedure
1008 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1010 #if 0
1011 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1012 #endif
1014 switch(uMsg)
1016 case WM_INITDIALOG:
1018 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1020 /* Adds the FileOpenDlgInfos in the property list of the dialog
1021 so it will be easily accessible through a GetPropA(...) */
1022 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1024 fodInfos->DlgInfos.hwndCustomDlg =
1025 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1027 FILEDLG95_InitControls(hwnd);
1029 if (fodInfos->DlgInfos.hwndCustomDlg)
1030 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1031 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1033 FILEDLG95_FillControls(hwnd, wParam, lParam);
1035 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1036 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1037 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1038 return 0;
1040 case WM_COMMAND:
1041 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1042 case WM_DRAWITEM:
1044 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1046 case IDC_LOOKIN:
1047 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1048 return TRUE;
1051 return FALSE;
1053 case WM_GETISHELLBROWSER:
1054 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1056 case WM_DESTROY:
1057 RemovePropA(hwnd, FileOpenDlgInfosStr);
1058 return FALSE;
1060 case WM_NOTIFY:
1062 LPNMHDR lpnmh = (LPNMHDR)lParam;
1063 UINT stringId = -1;
1065 /* set up the button tooltips strings */
1066 if(TTN_GETDISPINFOA == lpnmh->code )
1068 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1069 switch(lpnmh->idFrom )
1071 /* Up folder button */
1072 case FCIDM_TB_UPFOLDER:
1073 stringId = IDS_UPFOLDER;
1074 break;
1075 /* New folder button */
1076 case FCIDM_TB_NEWFOLDER:
1077 stringId = IDS_NEWFOLDER;
1078 break;
1079 /* List option button */
1080 case FCIDM_TB_SMALLICON:
1081 stringId = IDS_LISTVIEW;
1082 break;
1083 /* Details option button */
1084 case FCIDM_TB_REPORTVIEW:
1085 stringId = IDS_REPORTVIEW;
1086 break;
1087 /* Desktop button */
1088 case FCIDM_TB_DESKTOP:
1089 stringId = IDS_TODESKTOP;
1090 break;
1091 default:
1092 stringId = 0;
1094 lpdi->hinst = COMDLG32_hInstance;
1095 lpdi->lpszText = (LPSTR) stringId;
1097 return FALSE;
1099 default :
1100 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1101 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1102 return FALSE;
1106 /***********************************************************************
1107 * FILEDLG95_InitControls
1109 * WM_INITDIALOG message handler (before hook notification)
1111 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1113 int win2000plus = 0;
1114 int win98plus = 0;
1115 int handledPath = FALSE;
1116 OSVERSIONINFOA osVi;
1117 static const WCHAR szwSlash[] = { '\\', 0 };
1118 static const WCHAR szwStar[] = { '*',0 };
1120 TBBUTTON tbb[] =
1122 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1123 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1124 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1125 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1126 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1127 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1128 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1129 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1130 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1132 TBADDBITMAP tba[2];
1133 RECT rectTB;
1134 RECT rectlook;
1135 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1137 tba[0].hInst = HINST_COMMCTRL;
1138 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1139 tba[1].hInst = COMDLG32_hInstance;
1140 tba[1].nID = 800;
1142 TRACE("%p\n", fodInfos);
1144 /* Get windows version emulating */
1145 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1146 GetVersionExA(&osVi);
1147 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1148 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1149 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1150 win2000plus = (osVi.dwMajorVersion > 4);
1151 if (win2000plus) win98plus = TRUE;
1153 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1155 /* Get the hwnd of the controls */
1156 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1157 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1158 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1160 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1161 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1163 /* construct the toolbar */
1164 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1165 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1167 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1168 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1169 rectTB.left = rectlook.right;
1170 rectTB.top = rectlook.top-1;
1172 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1173 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1174 rectTB.left, rectTB.top,
1175 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1176 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1178 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1180 /* FIXME: use TB_LOADIMAGES when implemented */
1181 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1182 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1183 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1185 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1186 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1188 /* Set the window text with the text specified in the OPENFILENAME structure */
1189 if(fodInfos->title)
1191 SetWindowTextW(hwnd,fodInfos->title);
1193 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1195 WCHAR buf[16];
1196 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1197 SetWindowTextW(hwnd, buf);
1200 /* Initialise the file name edit control */
1201 handledPath = FALSE;
1202 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1204 if(fodInfos->filename)
1206 /* 1. If win2000 or higher and filename contains a path, use it
1207 in preference over the lpstrInitialDir */
1208 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1209 WCHAR tmpBuf[MAX_PATH];
1210 WCHAR *nameBit;
1211 DWORD result;
1213 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1214 if (result) {
1216 /* nameBit is always shorter than the original filename */
1217 strcpyW(fodInfos->filename,nameBit);
1219 *nameBit = 0x00;
1220 if (fodInfos->initdir == NULL)
1221 MemFree(fodInfos->initdir);
1222 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1223 strcpyW(fodInfos->initdir, tmpBuf);
1224 handledPath = TRUE;
1225 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1226 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1228 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1230 } else {
1231 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1235 /* 2. (All platforms) If initdir is not null, then use it */
1236 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1237 (*fodInfos->initdir!=0x00))
1239 /* Work out the proper path as supplied one might be relative */
1240 /* (Here because supplying '.' as dir browses to My Computer) */
1241 if (handledPath==FALSE) {
1242 WCHAR tmpBuf[MAX_PATH];
1243 WCHAR tmpBuf2[MAX_PATH];
1244 WCHAR *nameBit;
1245 DWORD result;
1247 strcpyW(tmpBuf, fodInfos->initdir);
1248 if( PathFileExistsW(tmpBuf) ) {
1249 /* initdir does not have to be a directory. If a file is
1250 * specified, the dir part is taken */
1251 if( PathIsDirectoryW(tmpBuf)) {
1252 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1253 strcatW(tmpBuf, szwSlash);
1255 strcatW(tmpBuf, szwStar);
1257 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1258 if (result) {
1259 *nameBit = 0x00;
1260 if (fodInfos->initdir)
1261 MemFree(fodInfos->initdir);
1262 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1263 strcpyW(fodInfos->initdir, tmpBuf2);
1264 handledPath = TRUE;
1265 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1268 else if (fodInfos->initdir)
1270 MemFree(fodInfos->initdir);
1271 fodInfos->initdir = NULL;
1272 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1277 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1278 (*fodInfos->initdir==0x00)))
1280 /* 3. All except w2k+: if filename contains a path use it */
1281 if (!win2000plus && fodInfos->filename &&
1282 *fodInfos->filename &&
1283 strpbrkW(fodInfos->filename, szwSlash)) {
1284 WCHAR tmpBuf[MAX_PATH];
1285 WCHAR *nameBit;
1286 DWORD result;
1288 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1289 tmpBuf, &nameBit);
1290 if (result) {
1291 int len;
1293 /* nameBit is always shorter than the original filename */
1294 strcpyW(fodInfos->filename, nameBit);
1295 *nameBit = 0x00;
1297 len = strlenW(tmpBuf);
1298 if(fodInfos->initdir)
1299 MemFree(fodInfos->initdir);
1300 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1301 strcpyW(fodInfos->initdir, tmpBuf);
1303 handledPath = TRUE;
1304 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1305 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1307 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1310 /* 4. win98+ and win2000+ if any files of specified filter types in
1311 current directory, use it */
1312 if ( win98plus && handledPath == FALSE &&
1313 fodInfos->filter && *fodInfos->filter) {
1315 BOOL searchMore = TRUE;
1316 LPCWSTR lpstrPos = fodInfos->filter;
1317 WIN32_FIND_DATAW FindFileData;
1318 HANDLE hFind;
1320 while (searchMore)
1322 /* filter is a list... title\0ext\0......\0\0 */
1324 /* Skip the title */
1325 if(! *lpstrPos) break; /* end */
1326 lpstrPos += strlenW(lpstrPos) + 1;
1328 /* See if any files exist in the current dir with this extension */
1329 if(! *lpstrPos) break; /* end */
1331 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1333 if (hFind == INVALID_HANDLE_VALUE) {
1334 /* None found - continue search */
1335 lpstrPos += strlenW(lpstrPos) + 1;
1337 } else {
1338 searchMore = FALSE;
1340 if(fodInfos->initdir)
1341 MemFree(fodInfos->initdir);
1342 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1343 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1345 handledPath = TRUE;
1346 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1347 debugstr_w(lpstrPos));
1348 break;
1353 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1355 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1356 if (handledPath == FALSE && (win2000plus || win98plus)) {
1357 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1359 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1361 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1363 /* last fallback */
1364 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1365 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1366 } else {
1367 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1369 } else {
1370 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1372 handledPath = TRUE;
1373 } else if (handledPath==FALSE) {
1374 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1375 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1376 handledPath = TRUE;
1377 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1380 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1381 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1383 /* Must the open as read only check box be checked ?*/
1384 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1386 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1389 /* Must the open as read only check box be hidden? */
1390 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1392 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1393 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1396 /* Must the help button be hidden? */
1397 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1399 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1400 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1403 /* Resize the height, if open as read only checkbox ad help button
1404 are hidden and we are not using a custom template nor a customDialog
1406 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1407 (!(fodInfos->ofnInfos->Flags &
1408 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1409 (!fodInfos->DlgInfos.hwndCustomDlg ))
1411 RECT rectDlg, rectHelp, rectCancel;
1412 GetWindowRect(hwnd, &rectDlg);
1413 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1414 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1415 /* subtract the height of the help button plus the space between
1416 the help button and the cancel button to the height of the dialog */
1417 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1418 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1419 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1421 /* change Open to Save */
1422 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1424 WCHAR buf[16];
1425 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1426 SetDlgItemTextW(hwnd, IDOK, buf);
1427 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1428 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1430 return 0;
1433 /***********************************************************************
1434 * FILEDLG95_FillControls
1436 * WM_INITDIALOG message handler (after hook notification)
1438 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1440 LPITEMIDLIST pidlItemId = NULL;
1442 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1444 TRACE("dir=%s file=%s\n",
1445 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1447 /* Get the initial directory pidl */
1449 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1451 WCHAR path[MAX_PATH];
1453 GetCurrentDirectoryW(MAX_PATH,path);
1454 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1457 /* Initialise shell objects */
1458 FILEDLG95_SHELL_Init(hwnd);
1460 /* Initialize the Look In combo box */
1461 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1463 /* Initialize the filter combo box */
1464 FILEDLG95_FILETYPE_Init(hwnd);
1466 /* Browse to the initial directory */
1467 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1469 /* Free pidlItem memory */
1470 COMDLG32_SHFree(pidlItemId);
1472 return TRUE;
1474 /***********************************************************************
1475 * FILEDLG95_Clean
1477 * Regroups all the cleaning functions of the filedlg
1479 void FILEDLG95_Clean(HWND hwnd)
1481 FILEDLG95_FILETYPE_Clean(hwnd);
1482 FILEDLG95_LOOKIN_Clean(hwnd);
1483 FILEDLG95_SHELL_Clean(hwnd);
1485 /***********************************************************************
1486 * FILEDLG95_OnWMCommand
1488 * WM_COMMAND message handler
1490 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1492 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1493 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1494 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1496 switch(wID)
1498 /* OK button */
1499 case IDOK:
1500 FILEDLG95_OnOpen(hwnd);
1501 break;
1502 /* Cancel button */
1503 case IDCANCEL:
1504 FILEDLG95_Clean(hwnd);
1505 EndDialog(hwnd, FALSE);
1506 break;
1507 /* Filetype combo box */
1508 case IDC_FILETYPE:
1509 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1510 break;
1511 /* LookIn combo box */
1512 case IDC_LOOKIN:
1513 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1514 break;
1516 /* --- toolbar --- */
1517 /* Up folder button */
1518 case FCIDM_TB_UPFOLDER:
1519 FILEDLG95_SHELL_UpFolder(hwnd);
1520 break;
1521 /* New folder button */
1522 case FCIDM_TB_NEWFOLDER:
1523 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1524 break;
1525 /* List option button */
1526 case FCIDM_TB_SMALLICON:
1527 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1528 break;
1529 /* Details option button */
1530 case FCIDM_TB_REPORTVIEW:
1531 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1532 break;
1533 /* Details option button */
1534 case FCIDM_TB_DESKTOP:
1535 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1536 break;
1538 case IDC_FILENAME:
1539 break;
1542 /* Do not use the listview selection anymore */
1543 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1544 return 0;
1547 /***********************************************************************
1548 * FILEDLG95_OnWMGetIShellBrowser
1550 * WM_GETISHELLBROWSER message handler
1552 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1555 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1557 TRACE("\n");
1559 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1561 return TRUE;
1565 /***********************************************************************
1566 * FILEDLG95_SendFileOK
1568 * Sends the CDN_FILEOK notification if required
1570 * RETURNS
1571 * TRUE if the dialog should close
1572 * FALSE if the dialog should not be closed
1574 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1576 /* ask the hook if we can close */
1577 if(IsHooked(fodInfos))
1579 TRACE("---\n");
1580 /* First send CDN_FILEOK as MSDN doc says */
1581 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1582 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1584 TRACE("canceled\n");
1585 return FALSE;
1588 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1589 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1590 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1591 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1593 TRACE("canceled\n");
1594 return FALSE;
1597 return TRUE;
1600 /***********************************************************************
1601 * FILEDLG95_OnOpenMultipleFiles
1603 * Handles the opening of multiple files.
1605 * FIXME
1606 * check destination buffer size
1608 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1610 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1611 UINT nCount, nSizePath;
1612 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1614 TRACE("\n");
1616 if(fodInfos->unicode)
1618 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1619 ofn->lpstrFile[0] = '\0';
1621 else
1623 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1624 ofn->lpstrFile[0] = '\0';
1627 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1629 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1630 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1631 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1633 LPWSTR lpstrTemp = lpstrFileList;
1635 for ( nCount = 0; nCount < nFileCount; nCount++ )
1637 LPITEMIDLIST pidl;
1639 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1640 if (!pidl)
1642 WCHAR lpstrNotFound[100];
1643 WCHAR lpstrMsg[100];
1644 WCHAR tmp[400];
1645 static const WCHAR nl[] = {'\n',0};
1647 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1648 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1650 strcpyW(tmp, lpstrTemp);
1651 strcatW(tmp, nl);
1652 strcatW(tmp, lpstrNotFound);
1653 strcatW(tmp, nl);
1654 strcatW(tmp, lpstrMsg);
1656 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1657 return FALSE;
1660 /* move to the next file in the list of files */
1661 lpstrTemp += strlenW(lpstrTemp) + 1;
1662 COMDLG32_SHFree(pidl);
1666 nSizePath = strlenW(lpstrPathSpec) + 1;
1667 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1669 /* For "oldstyle" dialog the components have to
1670 be separated by blanks (not '\0'!) and short
1671 filenames have to be used! */
1672 FIXME("Components have to be separated by blanks\n");
1674 if(fodInfos->unicode)
1676 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1677 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1678 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1680 else
1682 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1684 if (ofn->lpstrFile != NULL)
1686 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1687 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1688 if (ofn->nMaxFile > nSizePath)
1690 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1691 ofn->lpstrFile + nSizePath,
1692 ofn->nMaxFile - nSizePath, NULL, NULL);
1697 fodInfos->ofnInfos->nFileOffset = nSizePath;
1698 fodInfos->ofnInfos->nFileExtension = 0;
1700 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1701 return FALSE;
1703 /* clean and exit */
1704 FILEDLG95_Clean(hwnd);
1705 return EndDialog(hwnd,TRUE);
1708 /***********************************************************************
1709 * FILEDLG95_OnOpen
1711 * Ok button WM_COMMAND message handler
1713 * If the function succeeds, the return value is nonzero.
1715 #define ONOPEN_OPEN 1
1716 #define ONOPEN_SEARCH 2
1717 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1719 WCHAR strMsgTitle[MAX_PATH];
1720 WCHAR strMsgText [MAX_PATH];
1721 if (idCaption)
1722 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1723 else
1724 strMsgTitle[0] = '\0';
1725 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1726 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1729 BOOL FILEDLG95_OnOpen(HWND hwnd)
1731 LPWSTR lpstrFileList;
1732 UINT nFileCount = 0;
1733 UINT sizeUsed = 0;
1734 BOOL ret = TRUE;
1735 WCHAR lpstrPathAndFile[MAX_PATH];
1736 WCHAR lpstrTemp[MAX_PATH];
1737 LPSHELLFOLDER lpsf = NULL;
1738 int nOpenAction;
1739 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1741 TRACE("hwnd=%p\n", hwnd);
1743 if(BrowseSelectedFolder(hwnd))
1744 return FALSE;
1746 /* get the files from the edit control */
1747 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1749 /* try if the user selected a folder in the shellview */
1750 if(nFileCount == 0)
1751 return FALSE;
1753 if(nFileCount > 1)
1755 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1756 goto ret;
1759 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1762 Step 1: Build a complete path name from the current folder and
1763 the filename or path in the edit box.
1764 Special cases:
1765 - the path in the edit box is a root path
1766 (with or without drive letter)
1767 - the edit box contains ".." (or a path with ".." in it)
1770 /* Get the current directory name */
1771 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1773 /* last fallback */
1774 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1776 PathAddBackslashW(lpstrPathAndFile);
1778 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1780 /* if the user specifyed a fully qualified path use it */
1781 if(PathIsRelativeW(lpstrFileList))
1783 strcatW(lpstrPathAndFile, lpstrFileList);
1785 else
1787 /* does the path have a drive letter? */
1788 if (PathGetDriveNumberW(lpstrFileList) == -1)
1789 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1790 else
1791 strcpyW(lpstrPathAndFile, lpstrFileList);
1794 /* resolve "." and ".." */
1795 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1796 strcpyW(lpstrPathAndFile, lpstrTemp);
1797 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1799 MemFree(lpstrFileList);
1802 Step 2: here we have a cleaned up path
1804 We have to parse the path step by step to see if we have to browse
1805 to a folder if the path points to a directory or the last
1806 valid element is a directory.
1808 valid variables:
1809 lpstrPathAndFile: cleaned up path
1812 nOpenAction = ONOPEN_OPEN;
1814 /* don't apply any checks with OFN_NOVALIDATE */
1816 LPWSTR lpszTemp, lpszTemp1;
1817 LPITEMIDLIST pidl = NULL;
1818 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1820 /* check for invalid chars */
1821 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1823 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1824 ret = FALSE;
1825 goto ret;
1828 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1830 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1831 while (lpszTemp1)
1833 LPSHELLFOLDER lpsfChild;
1834 WCHAR lpwstrTemp[MAX_PATH];
1835 DWORD dwEaten, dwAttributes;
1836 LPWSTR p;
1838 strcpyW(lpwstrTemp, lpszTemp);
1839 p = PathFindNextComponentW(lpwstrTemp);
1841 if (!p) break; /* end of path */
1843 *p = 0;
1844 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1846 if(*lpszTemp==0)
1848 static const WCHAR wszWild[] = { '*', '?', 0 };
1849 /* if the last element is a wildcard do a search */
1850 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1852 nOpenAction = ONOPEN_SEARCH;
1853 break;
1856 lpszTemp1 = lpszTemp;
1858 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1860 /* append a backslash to drive letters */
1861 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1862 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1863 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1865 PathAddBackslashW(lpwstrTemp);
1868 dwAttributes = SFGAO_FOLDER;
1869 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1871 /* the path component is valid, we have a pidl of the next path component */
1872 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1873 if(dwAttributes & SFGAO_FOLDER)
1875 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1877 ERR("bind to failed\n"); /* should not fail */
1878 break;
1880 IShellFolder_Release(lpsf);
1881 lpsf = lpsfChild;
1882 lpsfChild = NULL;
1884 else
1886 TRACE("value\n");
1888 /* end dialog, return value */
1889 nOpenAction = ONOPEN_OPEN;
1890 break;
1892 COMDLG32_SHFree(pidl);
1893 pidl = NULL;
1895 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1897 if(*lpszTemp) /* points to trailing null for last path element */
1899 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1901 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1902 break;
1905 else
1907 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1908 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1910 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1911 break;
1914 /* change to the current folder */
1915 nOpenAction = ONOPEN_OPEN;
1916 break;
1918 else
1920 nOpenAction = ONOPEN_OPEN;
1921 break;
1924 if(pidl) COMDLG32_SHFree(pidl);
1928 Step 3: here we have a cleaned up and validated path
1930 valid variables:
1931 lpsf: ShellFolder bound to the rightmost valid path component
1932 lpstrPathAndFile: cleaned up path
1933 nOpenAction: action to do
1935 TRACE("end validate sf=%p\n", lpsf);
1937 switch(nOpenAction)
1939 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1940 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1942 int iPos;
1943 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1944 DWORD len;
1945 IPersistFolder2 * ppf2;
1947 /* replace the current filter */
1948 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1949 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1950 len = strlenW(lpszTemp)+1;
1951 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1952 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1954 /* set the filter cb to the extension when possible */
1955 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1956 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1958 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1960 LPITEMIDLIST pidlCurrent;
1961 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1962 IPersistFolder2_Release(ppf2);
1963 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1965 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1967 else
1969 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1971 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1972 COMDLG32_SHFree(pidlCurrent);
1975 ret = FALSE;
1976 break;
1977 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1978 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1980 WCHAR *ext = NULL;
1982 /* update READONLY check box flag */
1983 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1984 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1985 else
1986 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1988 /* Attach the file extension with file name*/
1990 if(!PathIsDirectoryW(lpstrPathAndFile))
1992 if((ext = PathFindExtensionW(lpstrPathAndFile)) == NULL)
1994 /* if no extension is specified with file name, then */
1995 /* attach the extension from file filter or default one */
1997 WCHAR *filterExt = NULL;
1998 LPWSTR lpstrFilter = NULL;
1999 static const WCHAR szwDot[] = {'.',0};
2000 int PathLength = strlenW(lpstrPathAndFile);
2002 /* Attach the dot*/
2003 strcatW(lpstrPathAndFile, szwDot);
2005 /*Get the file extension from file type filter*/
2006 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2007 fodInfos->ofnInfos->nFilterIndex-1);
2009 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2010 filterExt = PathFindExtensionW(lpstrFilter);
2012 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2013 strcatW(lpstrPathAndFile, filterExt + 1);
2014 else if ( fodInfos->defext ) /* attach the default file extension*/
2015 strcatW(lpstrPathAndFile, fodInfos->defext);
2017 /* In Open dialog: if file does not exist try without extension */
2018 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2019 lpstrPathAndFile[PathLength] = '\0';
2022 if (fodInfos->defext) /* add default extension */
2024 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2025 if (*ext)
2026 ext++;
2027 if (!lstrcmpiW(fodInfos->defext, ext))
2028 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2029 else
2030 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2034 /* In Save dialog: check if the file already exists */
2035 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2036 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2037 && PathFileExistsW(lpstrPathAndFile))
2039 WCHAR lpstrOverwrite[100];
2040 int answer;
2042 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2043 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2044 MB_YESNO | MB_ICONEXCLAMATION);
2045 if (answer == IDNO)
2047 ret = FALSE;
2048 goto ret;
2052 /* Check that the size of the file does not exceed buffer size.
2053 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2054 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2055 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2057 LPWSTR lpszTemp;
2059 /* fill destination buffer */
2060 if (fodInfos->ofnInfos->lpstrFile)
2062 if(fodInfos->unicode)
2064 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2066 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2067 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2068 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2070 else
2072 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2074 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2075 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2076 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2077 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2081 /* set filename offset */
2082 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2083 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2085 /* set extension offset */
2086 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2087 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2089 /* set the lpstrFileTitle */
2090 if(fodInfos->ofnInfos->lpstrFileTitle)
2092 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2093 if(fodInfos->unicode)
2095 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2096 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2098 else
2100 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2101 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2102 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2106 /* copy currently selected filter to lpstrCustomFilter */
2107 if (fodInfos->ofnInfos->lpstrCustomFilter)
2109 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2110 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2111 NULL, 0, NULL, NULL);
2112 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2114 LPSTR s = ofn->lpstrCustomFilter;
2115 s += strlen(ofn->lpstrCustomFilter)+1;
2116 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2117 s, len, NULL, NULL);
2122 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2123 goto ret;
2125 TRACE("close\n");
2126 FILEDLG95_Clean(hwnd);
2127 ret = EndDialog(hwnd, TRUE);
2129 else
2131 WORD size;
2133 size = strlenW(lpstrPathAndFile) + 1;
2134 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2135 size += 1;
2136 /* return needed size in first two bytes of lpstrFile */
2137 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2138 FILEDLG95_Clean(hwnd);
2139 ret = EndDialog(hwnd, FALSE);
2140 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2142 goto ret;
2144 break;
2147 ret:
2148 if(lpsf) IShellFolder_Release(lpsf);
2149 return ret;
2152 /***********************************************************************
2153 * FILEDLG95_SHELL_Init
2155 * Initialisation of the shell objects
2157 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2159 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2161 TRACE("\n");
2164 * Initialisation of the FileOpenDialogInfos structure
2167 /* Shell */
2169 /*ShellInfos */
2170 fodInfos->ShellInfos.hwndOwner = hwnd;
2172 /* Disable multi-select if flag not set */
2173 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2175 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2177 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2178 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2180 /* Construct the IShellBrowser interface */
2181 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2183 return NOERROR;
2186 /***********************************************************************
2187 * FILEDLG95_SHELL_ExecuteCommand
2189 * Change the folder option and refresh the view
2190 * If the function succeeds, the return value is nonzero.
2192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2194 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2196 IContextMenu * pcm;
2197 TRACE("(%p,%p)\n", hwnd, lpVerb);
2199 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2200 SVGIO_BACKGROUND,
2201 &IID_IContextMenu,
2202 (LPVOID*)&pcm)))
2204 CMINVOKECOMMANDINFO ci;
2205 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2206 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2207 ci.lpVerb = lpVerb;
2208 ci.hwnd = hwnd;
2210 IContextMenu_InvokeCommand(pcm, &ci);
2211 IContextMenu_Release(pcm);
2214 return FALSE;
2217 /***********************************************************************
2218 * FILEDLG95_SHELL_UpFolder
2220 * Browse to the specified object
2221 * If the function succeeds, the return value is nonzero.
2223 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2225 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2227 TRACE("\n");
2229 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2230 NULL,
2231 SBSP_PARENT)))
2233 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2234 return TRUE;
2236 return FALSE;
2239 /***********************************************************************
2240 * FILEDLG95_SHELL_BrowseToDesktop
2242 * Browse to the Desktop
2243 * If the function succeeds, the return value is nonzero.
2245 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2247 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2248 LPITEMIDLIST pidl;
2249 HRESULT hres;
2251 TRACE("\n");
2253 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2254 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2255 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2256 COMDLG32_SHFree(pidl);
2257 return SUCCEEDED(hres);
2259 /***********************************************************************
2260 * FILEDLG95_SHELL_Clean
2262 * Cleans the memory used by shell objects
2264 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2266 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2268 TRACE("\n");
2270 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2272 /* clean Shell interfaces */
2273 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2274 IShellView_Release(fodInfos->Shell.FOIShellView);
2275 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2276 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2277 if (fodInfos->Shell.FOIDataObject)
2278 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2281 /***********************************************************************
2282 * FILEDLG95_FILETYPE_Init
2284 * Initialisation of the file type combo box
2286 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2288 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2289 int nFilters = 0; /* number of filters */
2290 int nFilterIndexCB;
2292 TRACE("\n");
2294 if(fodInfos->customfilter)
2296 /* customfilter has one entry... title\0ext\0
2297 * Set first entry of combo box item with customfilter
2299 LPWSTR lpstrExt;
2300 LPCWSTR lpstrPos = fodInfos->customfilter;
2302 /* Get the title */
2303 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2305 /* Copy the extensions */
2306 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2307 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2308 strcpyW(lpstrExt,lpstrPos);
2310 /* Add the item at the end of the combo */
2311 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2312 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2313 nFilters++;
2315 if(fodInfos->filter)
2317 LPCWSTR lpstrPos = fodInfos->filter;
2319 for(;;)
2321 /* filter is a list... title\0ext\0......\0\0
2322 * Set the combo item text to the title and the item data
2323 * to the ext
2325 LPCWSTR lpstrDisplay;
2326 LPWSTR lpstrExt;
2328 /* Get the title */
2329 if(! *lpstrPos) break; /* end */
2330 lpstrDisplay = lpstrPos;
2331 lpstrPos += strlenW(lpstrPos) + 1;
2333 /* Copy the extensions */
2334 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2335 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2336 strcpyW(lpstrExt,lpstrPos);
2337 lpstrPos += strlenW(lpstrPos) + 1;
2339 /* Add the item at the end of the combo */
2340 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2341 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2342 nFilters++;
2347 * Set the current filter to the one specified
2348 * in the initialisation structure
2350 if (fodInfos->filter || fodInfos->customfilter)
2352 LPWSTR lpstrFilter;
2354 /* Check to make sure our index isn't out of bounds. */
2355 if ( fodInfos->ofnInfos->nFilterIndex >
2356 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2357 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2359 /* set default filter index */
2360 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2361 fodInfos->ofnInfos->nFilterIndex = 1;
2363 /* calculate index of Combo Box item */
2364 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2365 if (fodInfos->customfilter == NULL)
2366 nFilterIndexCB--;
2368 /* Set the current index selection. */
2369 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2371 /* Get the corresponding text string from the combo box. */
2372 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2373 nFilterIndexCB);
2375 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2376 lpstrFilter = NULL;
2378 if(lpstrFilter)
2380 DWORD len;
2381 CharLowerW(lpstrFilter); /* lowercase */
2382 len = strlenW(lpstrFilter)+1;
2383 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2384 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2386 } else
2387 fodInfos->ofnInfos->nFilterIndex = 0;
2389 return NOERROR;
2392 /***********************************************************************
2393 * FILEDLG95_FILETYPE_OnCommand
2395 * WM_COMMAND of the file type combo box
2396 * If the function succeeds, the return value is nonzero.
2398 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2400 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2402 switch(wNotifyCode)
2404 case CBN_SELENDOK:
2406 LPWSTR lpstrFilter;
2408 /* Get the current item of the filetype combo box */
2409 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2411 /* set the current filter index */
2412 fodInfos->ofnInfos->nFilterIndex = iItem +
2413 (fodInfos->customfilter == NULL ? 1 : 0);
2415 /* Set the current filter with the current selection */
2416 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2417 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2419 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2420 iItem);
2421 if((int)lpstrFilter != CB_ERR)
2423 DWORD len;
2424 CharLowerW(lpstrFilter); /* lowercase */
2425 len = strlenW(lpstrFilter)+1;
2426 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2427 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2428 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2431 /* Refresh the actual view to display the included items*/
2432 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2435 return FALSE;
2437 /***********************************************************************
2438 * FILEDLG95_FILETYPE_SearchExt
2440 * searches for an extension in the filetype box
2442 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2444 int i, iCount = CBGetCount(hwnd);
2446 TRACE("%s\n", debugstr_w(lpstrExt));
2448 if(iCount != CB_ERR)
2450 for(i=0;i<iCount;i++)
2452 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2453 return i;
2456 return -1;
2459 /***********************************************************************
2460 * FILEDLG95_FILETYPE_Clean
2462 * Clean the memory used by the filetype combo box
2464 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2466 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2467 int iPos;
2468 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2470 TRACE("\n");
2472 /* Delete each string of the combo and their associated data */
2473 if(iCount != CB_ERR)
2475 for(iPos = iCount-1;iPos>=0;iPos--)
2477 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2478 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2481 /* Current filter */
2482 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2483 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2487 /***********************************************************************
2488 * FILEDLG95_LOOKIN_Init
2490 * Initialisation of the look in combo box
2492 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2494 IShellFolder *psfRoot, *psfDrives;
2495 IEnumIDList *lpeRoot, *lpeDrives;
2496 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2498 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2500 TRACE("\n");
2502 liInfos->iMaxIndentation = 0;
2504 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2506 /* set item height for both text field and listbox */
2507 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2508 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2510 /* Turn on the extended UI for the combo box like Windows does */
2511 CBSetExtendedUI(hwndCombo, TRUE);
2513 /* Initialise data of Desktop folder */
2514 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2515 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2516 COMDLG32_SHFree(pidlTmp);
2518 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2520 SHGetDesktopFolder(&psfRoot);
2522 if (psfRoot)
2524 /* enumerate the contents of the desktop */
2525 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2527 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2529 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2531 /* special handling for CSIDL_DRIVES */
2532 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2534 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2536 /* enumerate the drives */
2537 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2539 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2541 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2542 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2543 COMDLG32_SHFree(pidlAbsTmp);
2544 COMDLG32_SHFree(pidlTmp1);
2546 IEnumIDList_Release(lpeDrives);
2548 IShellFolder_Release(psfDrives);
2551 COMDLG32_SHFree(pidlTmp);
2553 IEnumIDList_Release(lpeRoot);
2555 IShellFolder_Release(psfRoot);
2558 COMDLG32_SHFree(pidlDrives);
2559 return NOERROR;
2562 /***********************************************************************
2563 * FILEDLG95_LOOKIN_DrawItem
2565 * WM_DRAWITEM message handler
2567 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2569 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2570 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2571 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2572 RECT rectText;
2573 RECT rectIcon;
2574 SHFILEINFOA sfi;
2575 HIMAGELIST ilItemImage;
2576 int iIndentation;
2577 TEXTMETRICA tm;
2578 LPSFOLDER tmpFolder;
2581 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2583 TRACE("\n");
2585 if(pDIStruct->itemID == -1)
2586 return 0;
2588 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2589 pDIStruct->itemID)))
2590 return 0;
2593 if(pDIStruct->itemID == liInfos->uSelectedItem)
2595 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2597 &sfi,
2598 sizeof (SHFILEINFOA),
2599 SHGFI_PIDL | SHGFI_SMALLICON |
2600 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2601 SHGFI_DISPLAYNAME );
2603 else
2605 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2607 &sfi,
2608 sizeof (SHFILEINFOA),
2609 SHGFI_PIDL | SHGFI_SMALLICON |
2610 SHGFI_SYSICONINDEX |
2611 SHGFI_DISPLAYNAME);
2614 /* Is this item selected ? */
2615 if(pDIStruct->itemState & ODS_SELECTED)
2617 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2618 SetBkColor(pDIStruct->hDC,crHighLight);
2619 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2621 else
2623 SetTextColor(pDIStruct->hDC,crText);
2624 SetBkColor(pDIStruct->hDC,crWin);
2625 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2628 /* Do not indent item if drawing in the edit of the combo */
2629 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2631 iIndentation = 0;
2632 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2634 &sfi,
2635 sizeof (SHFILEINFOA),
2636 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2637 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2640 else
2642 iIndentation = tmpFolder->m_iIndent;
2644 /* Draw text and icon */
2646 /* Initialise the icon display area */
2647 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2648 rectIcon.top = pDIStruct->rcItem.top;
2649 rectIcon.right = rectIcon.left + ICONWIDTH;
2650 rectIcon.bottom = pDIStruct->rcItem.bottom;
2652 /* Initialise the text display area */
2653 GetTextMetricsA(pDIStruct->hDC, &tm);
2654 rectText.left = rectIcon.right;
2655 rectText.top =
2656 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2657 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2658 rectText.bottom =
2659 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2661 /* Draw the icon from the image list */
2662 ImageList_Draw(ilItemImage,
2663 sfi.iIcon,
2664 pDIStruct->hDC,
2665 rectIcon.left,
2666 rectIcon.top,
2667 ILD_TRANSPARENT );
2669 /* Draw the associated text */
2670 if(sfi.szDisplayName)
2671 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2674 return NOERROR;
2677 /***********************************************************************
2678 * FILEDLG95_LOOKIN_OnCommand
2680 * LookIn combo box WM_COMMAND message handler
2681 * If the function succeeds, the return value is nonzero.
2683 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2685 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2687 TRACE("%p\n", fodInfos);
2689 switch(wNotifyCode)
2691 case CBN_SELENDOK:
2693 LPSFOLDER tmpFolder;
2694 int iItem;
2696 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2698 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2699 iItem)))
2700 return FALSE;
2703 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2704 tmpFolder->pidlItem,
2705 SBSP_ABSOLUTE)))
2707 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2708 return TRUE;
2710 break;
2714 return FALSE;
2717 /***********************************************************************
2718 * FILEDLG95_LOOKIN_AddItem
2720 * Adds an absolute pidl item to the lookin combo box
2721 * returns the index of the inserted item
2723 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2725 LPITEMIDLIST pidlNext;
2726 SHFILEINFOA sfi;
2727 SFOLDER *tmpFolder;
2728 LookInInfos *liInfos;
2730 TRACE("%08x\n", iInsertId);
2732 if(!pidl)
2733 return -1;
2735 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2736 return -1;
2738 tmpFolder = MemAlloc(sizeof(SFOLDER));
2739 tmpFolder->m_iIndent = 0;
2741 /* Calculate the indentation of the item in the lookin*/
2742 pidlNext = pidl;
2743 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2745 tmpFolder->m_iIndent++;
2748 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2750 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2751 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2753 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2754 SHGetFileInfoA((LPSTR)pidl,
2756 &sfi,
2757 sizeof(sfi),
2758 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2759 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2761 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2763 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2765 int iItemID;
2767 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2769 /* Add the item at the end of the list */
2770 if(iInsertId < 0)
2772 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2774 /* Insert the item at the iInsertId position*/
2775 else
2777 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2780 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2781 return iItemID;
2784 COMDLG32_SHFree( tmpFolder->pidlItem );
2785 MemFree( tmpFolder );
2786 return -1;
2790 /***********************************************************************
2791 * FILEDLG95_LOOKIN_InsertItemAfterParent
2793 * Insert an item below its parent
2795 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2798 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2799 int iParentPos;
2801 TRACE("\n");
2803 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2805 if(iParentPos < 0)
2807 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2810 /* Free pidlParent memory */
2811 COMDLG32_SHFree((LPVOID)pidlParent);
2813 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2816 /***********************************************************************
2817 * FILEDLG95_LOOKIN_SelectItem
2819 * Adds an absolute pidl item to the lookin combo box
2820 * returns the index of the inserted item
2822 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2824 int iItemPos;
2825 LookInInfos *liInfos;
2827 TRACE("\n");
2829 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2831 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2833 if(iItemPos < 0)
2835 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2836 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2839 else
2841 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2842 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2844 int iRemovedItem;
2846 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2847 break;
2848 if(iRemovedItem < iItemPos)
2849 iItemPos--;
2853 CBSetCurSel(hwnd,iItemPos);
2854 liInfos->uSelectedItem = iItemPos;
2856 return 0;
2860 /***********************************************************************
2861 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2863 * Remove the item with an expansion level over iExpansionLevel
2865 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2867 int iItemPos;
2869 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2871 TRACE("\n");
2873 if(liInfos->iMaxIndentation <= 2)
2874 return -1;
2876 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2878 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2879 COMDLG32_SHFree(tmpFolder->pidlItem);
2880 MemFree(tmpFolder);
2881 CBDeleteString(hwnd,iItemPos);
2882 liInfos->iMaxIndentation--;
2884 return iItemPos;
2887 return -1;
2890 /***********************************************************************
2891 * FILEDLG95_LOOKIN_SearchItem
2893 * Search for pidl in the lookin combo box
2894 * returns the index of the found item
2896 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2898 int i = 0;
2899 int iCount = CBGetCount(hwnd);
2901 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2903 if (iCount != CB_ERR)
2905 for(;i<iCount;i++)
2907 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2909 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2910 return i;
2911 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2912 return i;
2916 return -1;
2919 /***********************************************************************
2920 * FILEDLG95_LOOKIN_Clean
2922 * Clean the memory used by the lookin combo box
2924 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2926 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2927 int iPos;
2928 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2930 TRACE("\n");
2932 /* Delete each string of the combo and their associated data */
2933 if (iCount != CB_ERR)
2935 for(iPos = iCount-1;iPos>=0;iPos--)
2937 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2938 COMDLG32_SHFree(tmpFolder->pidlItem);
2939 MemFree(tmpFolder);
2940 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2944 /* LookInInfos structure */
2945 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2948 /***********************************************************************
2949 * FILEDLG95_FILENAME_FillFromSelection
2951 * fills the edit box from the cached DataObject
2953 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2955 FileOpenDlgInfos *fodInfos;
2956 LPITEMIDLIST pidl;
2957 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2958 char lpstrTemp[MAX_PATH];
2959 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2961 TRACE("\n");
2962 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2964 /* Count how many files we have */
2965 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2967 /* calculate the string length, count files */
2968 if (nFileSelected >= 1)
2970 nLength += 3; /* first and last quotes, trailing \0 */
2971 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2973 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2975 if (pidl)
2977 /* get the total length of the selected file names */
2978 lpstrTemp[0] = '\0';
2979 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2981 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2983 nLength += strlen( lpstrTemp ) + 3;
2984 nFiles++;
2986 COMDLG32_SHFree( pidl );
2991 /* allocate the buffer */
2992 if (nFiles <= 1) nLength = MAX_PATH;
2993 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2994 lpstrAllFile[0] = '\0';
2996 /* Generate the string for the edit control */
2997 if(nFiles >= 1)
2999 lpstrCurrFile = lpstrAllFile;
3000 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3002 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3004 if (pidl)
3006 /* get the file name */
3007 lpstrTemp[0] = '\0';
3008 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3010 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3012 if ( nFiles > 1)
3014 *lpstrCurrFile++ = '\"';
3015 strcpy( lpstrCurrFile, lpstrTemp );
3016 lpstrCurrFile += strlen( lpstrTemp );
3017 strcpy( lpstrCurrFile, "\" " );
3018 lpstrCurrFile += 2;
3020 else
3022 strcpy( lpstrAllFile, lpstrTemp );
3025 COMDLG32_SHFree( (LPVOID) pidl );
3028 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3030 /* Select the file name like Windows does */
3031 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3033 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3037 /* copied from shell32 to avoid linking to it */
3038 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3040 switch (src->uType)
3042 case STRRET_WSTR:
3043 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3044 COMDLG32_SHFree(src->u.pOleStr);
3045 break;
3047 case STRRET_CSTR:
3048 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3049 break;
3051 case STRRET_OFFSET:
3052 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3053 break;
3055 default:
3056 FIXME("unknown type!\n");
3057 if (len)
3059 *(LPSTR)dest = '\0';
3061 return(FALSE);
3063 return S_OK;
3066 /***********************************************************************
3067 * FILEDLG95_FILENAME_GetFileNames
3069 * Copies the filenames to a delimited string list.
3070 * The delimiter is specified by the parameter 'separator',
3071 * usually either a space or a nul
3073 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3075 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3076 UINT nStrCharCount = 0; /* index in src buffer */
3077 UINT nFileIndex = 0; /* index in dest buffer */
3078 UINT nFileCount = 0; /* number of files */
3079 UINT nStrLen = 0; /* length of string in edit control */
3080 LPWSTR lpstrEdit; /* buffer for string from edit control */
3082 TRACE("\n");
3084 /* get the filenames from the edit control */
3085 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3086 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3087 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3089 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3091 /* we might get single filename without any '"',
3092 * so we need nStrLen + terminating \0 + end-of-list \0 */
3093 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3094 *sizeUsed = 0;
3096 /* build delimited file list from filenames */
3097 while ( nStrCharCount <= nStrLen )
3099 if ( lpstrEdit[nStrCharCount]=='"' )
3101 nStrCharCount++;
3102 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3104 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3105 (*sizeUsed)++;
3106 nStrCharCount++;
3108 (*lpstrFileList)[nFileIndex++] = separator;
3109 (*sizeUsed)++;
3110 nFileCount++;
3112 nStrCharCount++;
3115 /* single, unquoted string */
3116 if ((nStrLen > 0) && (*sizeUsed == 0) )
3118 strcpyW(*lpstrFileList, lpstrEdit);
3119 nFileIndex = strlenW(lpstrEdit) + 1;
3120 (*sizeUsed) = nFileIndex;
3121 nFileCount = 1;
3124 /* trailing \0 */
3125 (*lpstrFileList)[nFileIndex] = '\0';
3126 (*sizeUsed)++;
3128 MemFree(lpstrEdit);
3129 return nFileCount;
3132 #define SETDefFormatEtc(fe,cf,med) \
3134 (fe).cfFormat = cf;\
3135 (fe).dwAspect = DVASPECT_CONTENT; \
3136 (fe).ptd =NULL;\
3137 (fe).tymed = med;\
3138 (fe).lindex = -1;\
3142 * DATAOBJECT Helper functions
3145 /***********************************************************************
3146 * COMCTL32_ReleaseStgMedium
3148 * like ReleaseStgMedium from ole32
3150 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3152 if(medium.pUnkForRelease)
3154 IUnknown_Release(medium.pUnkForRelease);
3156 else
3158 GlobalUnlock(medium.u.hGlobal);
3159 GlobalFree(medium.u.hGlobal);
3163 /***********************************************************************
3164 * GetPidlFromDataObject
3166 * Return pidl(s) by number from the cached DataObject
3168 * nPidlIndex=0 gets the fully qualified root path
3170 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3173 STGMEDIUM medium;
3174 FORMATETC formatetc;
3175 LPITEMIDLIST pidl = NULL;
3177 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3179 /* Set the FORMATETC structure*/
3180 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3182 /* Get the pidls from IDataObject */
3183 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3185 LPIDA cida = GlobalLock(medium.u.hGlobal);
3186 if(nPidlIndex <= cida->cidl)
3188 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3190 COMCTL32_ReleaseStgMedium(medium);
3192 return pidl;
3195 /***********************************************************************
3196 * GetNumSelected
3198 * Return the number of selected items in the DataObject.
3201 UINT GetNumSelected( IDataObject *doSelected )
3203 UINT retVal = 0;
3204 STGMEDIUM medium;
3205 FORMATETC formatetc;
3207 TRACE("sv=%p\n", doSelected);
3209 if (!doSelected) return 0;
3211 /* Set the FORMATETC structure*/
3212 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3214 /* Get the pidls from IDataObject */
3215 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3217 LPIDA cida = GlobalLock(medium.u.hGlobal);
3218 retVal = cida->cidl;
3219 COMCTL32_ReleaseStgMedium(medium);
3220 return retVal;
3222 return 0;
3226 * TOOLS
3229 /***********************************************************************
3230 * GetName
3232 * Get the pidl's display name (relative to folder) and
3233 * put it in lpstrFileName.
3235 * Return NOERROR on success,
3236 * E_FAIL otherwise
3239 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3241 STRRET str;
3242 HRESULT hRes;
3244 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3246 if(!lpsf)
3248 SHGetDesktopFolder(&lpsf);
3249 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3250 IShellFolder_Release(lpsf);
3251 return hRes;
3254 /* Get the display name of the pidl relative to the folder */
3255 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3257 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3259 return E_FAIL;
3262 /***********************************************************************
3263 * GetShellFolderFromPidl
3265 * pidlRel is the item pidl relative
3266 * Return the IShellFolder of the absolute pidl
3268 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3270 IShellFolder *psf = NULL,*psfParent;
3272 TRACE("%p\n", pidlAbs);
3274 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3276 psf = psfParent;
3277 if(pidlAbs && pidlAbs->mkid.cb)
3279 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3281 IShellFolder_Release(psfParent);
3282 return psf;
3285 /* return the desktop */
3286 return psfParent;
3288 return NULL;
3291 /***********************************************************************
3292 * GetParentPidl
3294 * Return the LPITEMIDLIST to the parent of the pidl in the list
3296 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3298 LPITEMIDLIST pidlParent;
3300 TRACE("%p\n", pidl);
3302 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3303 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3305 return pidlParent;
3308 /***********************************************************************
3309 * GetPidlFromName
3311 * returns the pidl of the file name relative to folder
3312 * NULL if an error occurred
3314 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3316 LPITEMIDLIST pidl = NULL;
3317 ULONG ulEaten;
3319 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3321 if(!lpcstrFileName) return NULL;
3322 if(!*lpcstrFileName) return NULL;
3324 if(!lpsf)
3326 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3327 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3328 IShellFolder_Release(lpsf);
3331 else
3333 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3335 return pidl;
3340 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3342 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3343 HRESULT ret;
3345 TRACE("%p, %p\n", psf, pidl);
3347 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3349 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3350 /* see documentation shell 4.1*/
3351 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3354 /***********************************************************************
3355 * BrowseSelectedFolder
3357 static BOOL BrowseSelectedFolder(HWND hwnd)
3359 BOOL bBrowseSelFolder = FALSE;
3360 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3362 TRACE("\n");
3364 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3366 LPITEMIDLIST pidlSelection;
3368 /* get the file selected */
3369 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3370 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3372 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3373 pidlSelection, SBSP_RELATIVE ) ) )
3375 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3376 ' ','n','o','t',' ','e','x','i','s','t',0};
3377 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3379 bBrowseSelFolder = TRUE;
3380 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3382 COMDLG32_SHFree( pidlSelection );
3385 return bBrowseSelFolder;
3389 * Memory allocation methods */
3390 static void *MemAlloc(UINT size)
3392 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3395 static void MemFree(void *mem)
3397 HeapFree(GetProcessHeap(),0,mem);
3401 * Old-style (win3.1) dialogs */
3403 /***********************************************************************
3404 * FD32_GetTemplate [internal]
3406 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3407 * by a 32 bits application
3410 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3412 LPOPENFILENAMEW ofnW = lfs->ofnW;
3413 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3414 HANDLE hDlgTmpl;
3416 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3418 if (!(lfs->template = LockResource( ofnW->hInstance )))
3420 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3421 return FALSE;
3424 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3426 HRSRC hResInfo;
3427 if (priv->ofnA)
3428 hResInfo = FindResourceA(priv->ofnA->hInstance,
3429 priv->ofnA->lpTemplateName,
3430 (LPSTR)RT_DIALOG);
3431 else
3432 hResInfo = FindResourceW(ofnW->hInstance,
3433 ofnW->lpTemplateName,
3434 (LPWSTR)RT_DIALOG);
3435 if (!hResInfo)
3437 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3438 return FALSE;
3440 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3441 hResInfo)) ||
3442 !(lfs->template = LockResource(hDlgTmpl)))
3444 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3445 return FALSE;
3447 } else { /* get it from internal Wine resource */
3448 HRSRC hResInfo;
3449 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3450 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3452 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3453 return FALSE;
3455 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3456 !(lfs->template = LockResource( hDlgTmpl )))
3458 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3459 return FALSE;
3462 return TRUE;
3466 /************************************************************************
3467 * FD32_Init [internal]
3468 * called from the common 16/32 code to initialize 32 bit data
3470 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3472 BOOL IsUnicode = (BOOL) data;
3473 PFD32_PRIVATE priv;
3475 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3476 lfs->private1632 = priv;
3477 if (NULL == lfs->private1632) return FALSE;
3478 if (IsUnicode)
3480 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3481 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3482 if (lfs->ofnW->lpfnHook)
3483 lfs->hook = TRUE;
3485 else
3487 priv->ofnA = (LPOPENFILENAMEA) lParam;
3488 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3489 if (priv->ofnA->lpfnHook)
3490 lfs->hook = TRUE;
3491 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3492 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3495 if (! FD32_GetTemplate(lfs)) return FALSE;
3497 return TRUE;
3500 /***********************************************************************
3501 * FD32_CallWindowProc [internal]
3503 * called from the common 16/32 code to call the appropriate hook
3505 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3506 LPARAM lParam)
3508 BOOL ret;
3509 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3511 if (priv->ofnA)
3513 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3514 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3515 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3516 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3517 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3518 return ret;
3521 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3522 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3523 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3524 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3525 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3526 return ret;
3529 /***********************************************************************
3530 * FD32_UpdateResult [internal]
3531 * update the real client structures if any
3533 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3535 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3536 LPOPENFILENAMEW ofnW = lfs->ofnW;
3538 if (priv->ofnA)
3540 if (ofnW->nMaxFile &&
3541 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3542 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3543 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3544 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3545 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3549 /***********************************************************************
3550 * FD32_UpdateFileTitle [internal]
3551 * update the real client structures if any
3553 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3555 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3556 LPOPENFILENAMEW ofnW = lfs->ofnW;
3558 if (priv->ofnA)
3560 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3561 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3562 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3567 /***********************************************************************
3568 * FD32_SendLbGetCurSel [internal]
3569 * retrieve selected listbox item
3571 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3573 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3577 /************************************************************************
3578 * FD32_Destroy [internal]
3579 * called from the common 16/32 code to cleanup 32 bit data
3581 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3583 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3585 /* if ofnW has been allocated, have to free everything in it */
3586 if (NULL != priv && NULL != priv->ofnA)
3588 FD31_FreeOfnW(lfs->ofnW);
3589 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3593 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3595 callbacks->Init = FD32_Init;
3596 callbacks->CWP = FD32_CallWindowProc;
3597 callbacks->UpdateResult = FD32_UpdateResult;
3598 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3599 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3600 callbacks->Destroy = FD32_Destroy;
3603 /***********************************************************************
3604 * FD32_WMMeasureItem [internal]
3606 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3608 LPMEASUREITEMSTRUCT lpmeasure;
3610 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3611 lpmeasure->itemHeight = FD31_GetFldrHeight();
3612 return TRUE;
3616 /***********************************************************************
3617 * FileOpenDlgProc [internal]
3618 * Used for open and save, in fact.
3620 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3621 WPARAM wParam, LPARAM lParam)
3623 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3625 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3626 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3628 INT_PTR lRet;
3629 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3630 if (lRet)
3631 return lRet; /* else continue message processing */
3633 switch (wMsg)
3635 case WM_INITDIALOG:
3636 return FD31_WMInitDialog(hWnd, wParam, lParam);
3638 case WM_MEASUREITEM:
3639 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3641 case WM_DRAWITEM:
3642 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3644 case WM_COMMAND:
3645 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3646 #if 0
3647 case WM_CTLCOLOR:
3648 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3649 switch (HIWORD(lParam))
3651 case CTLCOLOR_BTN:
3652 SetTextColor((HDC16)wParam, 0x00000000);
3653 return hGRAYBrush;
3654 case CTLCOLOR_STATIC:
3655 SetTextColor((HDC16)wParam, 0x00000000);
3656 return hGRAYBrush;
3658 break;
3659 #endif
3661 return FALSE;
3665 /***********************************************************************
3666 * GetFileName31A [internal]
3668 * Creates a win31 style dialog box for the user to select a file to open/save.
3670 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3671 UINT dlgType /* type dialogue : open/save */
3674 HINSTANCE hInst;
3675 BOOL bRet = FALSE;
3676 PFD31_DATA lfs;
3677 FD31_CALLBACKS callbacks;
3679 if (!lpofn || !FD31_Init()) return FALSE;
3681 TRACE("ofn flags %08lx\n", lpofn->Flags);
3682 FD32_SetupCallbacks(&callbacks);
3683 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3684 if (lfs)
3686 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3687 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3688 FD32_FileOpenDlgProc, (LPARAM)lfs);
3689 FD31_DestroyPrivate(lfs);
3692 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3693 return bRet;
3696 /***********************************************************************
3697 * GetFileName31W [internal]
3699 * Creates a win31 style dialog box for the user to select a file to open/save
3701 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3702 UINT dlgType /* type dialogue : open/save */
3705 HINSTANCE hInst;
3706 BOOL bRet = FALSE;
3707 PFD31_DATA lfs;
3708 FD31_CALLBACKS callbacks;
3710 if (!lpofn || !FD31_Init()) return FALSE;
3712 FD32_SetupCallbacks(&callbacks);
3713 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3714 if (lfs)
3716 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3717 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3718 FD32_FileOpenDlgProc, (LPARAM)lfs);
3719 FD31_DestroyPrivate(lfs);
3722 TRACE("file %s, file offset %d, ext offset %d\n",
3723 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3724 return bRet;
3727 /* ------------------ APIs ---------------------- */
3729 /***********************************************************************
3730 * GetOpenFileNameA (COMDLG32.@)
3732 * Creates a dialog box for the user to select a file to open.
3734 * RETURNS
3735 * TRUE on success: user enters a valid file
3736 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3739 BOOL WINAPI GetOpenFileNameA(
3740 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3742 BOOL win16look = FALSE;
3744 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3745 if (ofn->Flags & OFN_FILEMUSTEXIST)
3746 ofn->Flags |= OFN_PATHMUSTEXIST;
3748 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3749 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3751 if (win16look)
3752 return GetFileName31A(ofn, OPEN_DIALOG);
3753 else
3754 return GetFileDialog95A(ofn, OPEN_DIALOG);
3757 /***********************************************************************
3758 * GetOpenFileNameW (COMDLG32.@)
3760 * Creates a dialog box for the user to select a file to open.
3762 * RETURNS
3763 * TRUE on success: user enters a valid file
3764 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3767 BOOL WINAPI GetOpenFileNameW(
3768 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3770 BOOL win16look = FALSE;
3772 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3773 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3775 if (win16look)
3776 return GetFileName31W(ofn, OPEN_DIALOG);
3777 else
3778 return GetFileDialog95W(ofn, OPEN_DIALOG);
3782 /***********************************************************************
3783 * GetSaveFileNameA (COMDLG32.@)
3785 * Creates a dialog box for the user to select a file to save.
3787 * RETURNS
3788 * TRUE on success: user enters a valid file
3789 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3792 BOOL WINAPI GetSaveFileNameA(
3793 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3795 BOOL win16look = FALSE;
3797 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3798 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3800 if (win16look)
3801 return GetFileName31A(ofn, SAVE_DIALOG);
3802 else
3803 return GetFileDialog95A(ofn, SAVE_DIALOG);
3806 /***********************************************************************
3807 * GetSaveFileNameW (COMDLG32.@)
3809 * Creates a dialog box for the user to select a file to save.
3811 * RETURNS
3812 * TRUE on success: user enters a valid file
3813 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3816 BOOL WINAPI GetSaveFileNameW(
3817 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3819 BOOL win16look = FALSE;
3821 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3822 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3824 if (win16look)
3825 return GetFileName31W(ofn, SAVE_DIALOG);
3826 else
3827 return GetFileDialog95W(ofn, SAVE_DIALOG);