Add stub implementation of RtlAddAuditAccessAce.
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blob8d92e4505ffd3cd8d06f9293878a5f50d7b74597
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 EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
202 /* Functions used by the filetype combo box */
203 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
204 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
210 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
211 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
219 /* Miscellaneous tool functions */
220 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
221 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
222 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
223 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size);
227 static void MemFree(void *mem);
229 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
231 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
232 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
233 static BOOL BrowseSelectedFolder(HWND hwnd);
235 /***********************************************************************
236 * GetFileName95
238 * Creates an Open common dialog box that lets the user select
239 * the drive, directory, and the name of a file or set of files to open.
241 * IN : The FileOpenDlgInfos structure associated with the dialog
242 * OUT : TRUE on success
243 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
245 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
248 LRESULT lRes;
249 LPCVOID template;
250 HRSRC hRes;
251 HANDLE hDlgTmpl = 0;
253 /* test for missing functionality */
254 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 FIXME("Flags 0x%08lx not yet implemented\n",
257 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
260 /* Create the dialog from a template */
262 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
265 return FALSE;
267 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268 !(template = LockResource( hDlgTmpl )))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
271 return FALSE;
274 /* old style hook messages */
275 if (IsHooked(fodInfos))
277 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
278 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
279 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
280 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
283 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
284 (LPDLGTEMPLATEA) template,
285 fodInfos->ofnInfos->hwndOwner,
286 FileOpenDlgProc95,
287 (LPARAM) fodInfos);
289 /* Unable to create the dialog */
290 if( lRes == -1)
291 return FALSE;
293 return lRes;
296 /***********************************************************************
297 * GetFileDialog95A
299 * Call GetFileName95 with this structure and clean the memory.
301 * IN : The OPENFILENAMEA initialisation structure passed to
302 * GetOpenFileNameA win api function (see filedlg.c)
304 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
306 BOOL ret;
307 FileOpenDlgInfos fodInfos;
308 LPSTR lpstrSavDir = NULL;
309 LPWSTR title = NULL;
310 LPWSTR defext = NULL;
311 LPWSTR filter = NULL;
312 LPWSTR customfilter = NULL;
314 /* Initialize FileOpenDlgInfos structure */
315 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
317 /* Pass in the original ofn */
318 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
320 /* save current directory */
321 if (ofn->Flags & OFN_NOCHANGEDIR)
323 lpstrSavDir = MemAlloc(MAX_PATH);
324 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
327 fodInfos.unicode = FALSE;
329 /* convert all the input strings to unicode */
330 if(ofn->lpstrInitialDir)
332 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
333 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
334 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
336 else
337 fodInfos.initdir = NULL;
339 if(ofn->lpstrFile)
341 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
342 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
344 else
345 fodInfos.filename = NULL;
347 if(ofn->lpstrDefExt)
349 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
350 defext = MemAlloc((len+1)*sizeof(WCHAR));
351 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
353 fodInfos.defext = defext;
355 if(ofn->lpstrTitle)
357 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
358 title = MemAlloc((len+1)*sizeof(WCHAR));
359 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
361 fodInfos.title = title;
363 if (ofn->lpstrFilter)
365 LPCSTR s;
366 int n, len;
368 /* filter is a list... title\0ext\0......\0\0 */
369 s = ofn->lpstrFilter;
370 while (*s) s = s+strlen(s)+1;
371 s++;
372 n = s - ofn->lpstrFilter;
373 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
374 filter = MemAlloc(len*sizeof(WCHAR));
375 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
377 fodInfos.filter = filter;
379 /* convert lpstrCustomFilter */
380 if (ofn->lpstrCustomFilter)
382 LPCSTR s;
383 int n, len;
385 /* customfilter contains a pair of strings... title\0ext\0 */
386 s = ofn->lpstrCustomFilter;
387 if (*s) s = s+strlen(s)+1;
388 if (*s) s = s+strlen(s)+1;
389 n = s - ofn->lpstrCustomFilter;
390 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
391 customfilter = MemAlloc(len*sizeof(WCHAR));
392 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
394 fodInfos.customfilter = customfilter;
396 /* Initialize the dialog property */
397 fodInfos.DlgInfos.dwDlgProp = 0;
398 fodInfos.DlgInfos.hwndCustomDlg = NULL;
400 switch(iDlgType)
402 case OPEN_DIALOG :
403 ret = GetFileName95(&fodInfos);
404 break;
405 case SAVE_DIALOG :
406 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
407 ret = GetFileName95(&fodInfos);
408 break;
409 default :
410 ret = 0;
413 if (lpstrSavDir)
415 SetCurrentDirectoryA(lpstrSavDir);
416 MemFree(lpstrSavDir);
419 if(title)
420 MemFree(title);
421 if(defext)
422 MemFree(defext);
423 if(filter)
424 MemFree(filter);
425 if(customfilter)
426 MemFree(customfilter);
427 if(fodInfos.initdir)
428 MemFree(fodInfos.initdir);
430 if(fodInfos.filename)
431 MemFree(fodInfos.filename);
433 TRACE("selected file: %s\n",ofn->lpstrFile);
435 return ret;
438 /***********************************************************************
439 * GetFileDialog95W
441 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
442 * Call GetFileName95 with this structure and clean the memory.
445 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
447 BOOL ret;
448 FileOpenDlgInfos fodInfos;
449 LPWSTR lpstrSavDir = NULL;
451 /* Initialize FileOpenDlgInfos structure */
452 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
454 /* Pass in the original ofn */
455 fodInfos.ofnInfos = ofn;
457 fodInfos.title = ofn->lpstrTitle;
458 fodInfos.defext = ofn->lpstrDefExt;
459 fodInfos.filter = ofn->lpstrFilter;
460 fodInfos.customfilter = ofn->lpstrCustomFilter;
462 /* convert string arguments, save others */
463 if(ofn->lpstrFile)
465 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
466 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
468 else
469 fodInfos.filename = NULL;
471 if(ofn->lpstrInitialDir)
473 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
474 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
475 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
476 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
478 else
479 fodInfos.initdir = NULL;
481 /* save current directory */
482 if (ofn->Flags & OFN_NOCHANGEDIR)
484 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
485 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
488 fodInfos.unicode = TRUE;
490 switch(iDlgType)
492 case OPEN_DIALOG :
493 ret = GetFileName95(&fodInfos);
494 break;
495 case SAVE_DIALOG :
496 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
497 ret = GetFileName95(&fodInfos);
498 break;
499 default :
500 ret = 0;
503 if (lpstrSavDir)
505 SetCurrentDirectoryW(lpstrSavDir);
506 MemFree(lpstrSavDir);
509 /* restore saved IN arguments and convert OUT arguments back */
510 MemFree(fodInfos.filename);
511 MemFree(fodInfos.initdir);
512 return ret;
515 /******************************************************************************
516 * COMDLG32_GetDisplayNameOf [internal]
518 * Helper function to get the display name for a pidl.
520 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
521 LPSHELLFOLDER psfDesktop;
522 STRRET strret;
524 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
525 return FALSE;
527 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
528 IShellFolder_Release(psfDesktop);
529 return FALSE;
532 IShellFolder_Release(psfDesktop);
533 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
536 /***********************************************************************
537 * ArrangeCtrlPositions [internal]
539 * NOTE: Do not change anything here without a lot of testing.
541 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
543 HWND hwndChild, hwndStc32;
544 RECT rectParent, rectChild, rectStc32;
545 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
547 /* Take into account if open as read only checkbox and help button
548 * are hidden
550 if (hide_help)
552 RECT rectHelp, rectCancel;
553 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
554 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
555 /* subtract the height of the help button plus the space between
556 * the help button and the cancel button to the height of the dialog
558 help_fixup = rectHelp.bottom - rectCancel.bottom;
562 There are two possibilities to add components to the default file dialog box.
564 By default, all the new components are added below the standard dialog box (the else case).
566 However, if there is a static text component with the stc32 id, a special case happens.
567 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
568 in the window and the cx and cy indicate how to size the window.
569 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
570 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
574 GetClientRect(hwndParentDlg, &rectParent);
576 /* when arranging controls we have to use fixed parent size */
577 rectParent.bottom -= help_fixup;
579 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
580 if (hwndStc32)
582 GetWindowRect(hwndStc32, &rectStc32);
583 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
585 /* set the size of the stc32 control according to the size of
586 * client area of the parent dialog
588 SetWindowPos(hwndStc32, 0,
589 0, 0,
590 rectParent.right, rectParent.bottom,
591 SWP_NOMOVE | SWP_NOZORDER);
593 else
594 SetRectEmpty(&rectStc32);
596 /* this part moves controls of the child dialog */
597 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
598 while (hwndChild)
600 if (hwndChild != hwndStc32)
602 GetWindowRect(hwndChild, &rectChild);
603 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
605 /* move only if stc32 exist */
606 if (hwndStc32 && rectChild.left > rectStc32.right)
608 LONG old_left = rectChild.left;
610 /* move to the right of visible controls of the parent dialog */
611 rectChild.left += rectParent.right;
612 rectChild.left -= rectStc32.right;
614 child_width_fixup = rectChild.left - old_left;
616 /* move even if stc32 doesn't exist */
617 if (rectChild.top >= rectStc32.bottom)
619 LONG old_top = rectChild.top;
621 /* move below visible controls of the parent dialog */
622 rectChild.top += rectParent.bottom;
623 rectChild.top -= rectStc32.bottom - rectStc32.top;
625 child_height_fixup = rectChild.top - old_top;
628 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
629 0, 0, SWP_NOSIZE | SWP_NOZORDER);
631 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
634 /* this part moves controls of the parent dialog */
635 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
636 while (hwndChild)
638 if (hwndChild != hwndChildDlg)
640 GetWindowRect(hwndChild, &rectChild);
641 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
643 /* left,top of stc32 marks the position of controls
644 * from the parent dialog
646 rectChild.left += rectStc32.left;
647 rectChild.top += rectStc32.top;
649 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
650 0, 0, SWP_NOSIZE | SWP_NOZORDER);
652 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
655 /* calculate the size of the resulting dialog */
657 /* here we have to use original parent size */
658 GetClientRect(hwndParentDlg, &rectParent);
659 GetClientRect(hwndChildDlg, &rectChild);
661 if (hwndStc32)
663 rectChild.right += child_width_fixup;
664 rectChild.bottom += child_height_fixup;
666 if (rectParent.right > rectChild.right)
668 rectParent.right += rectChild.right;
669 rectParent.right -= rectStc32.right - rectStc32.left;
671 else
673 rectParent.right = rectChild.right;
676 if (rectParent.bottom > rectChild.bottom)
678 rectParent.bottom += rectChild.bottom;
679 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
681 else
683 /* child dialog is higher, unconditionally set new dialog
684 * height to its size (help_fixup will be subtracted below)
686 rectParent.bottom = rectChild.bottom + help_fixup;
689 else
691 rectParent.bottom += rectChild.bottom;
694 /* finally use fixed parent size */
695 rectParent.bottom -= help_fixup;
697 /* save the size of the parent's client area */
698 rectChild.right = rectParent.right;
699 rectChild.bottom = rectParent.bottom;
701 /* set the size of the parent dialog */
702 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
703 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
704 SetWindowPos(hwndParentDlg, 0,
705 0, 0,
706 rectParent.right - rectParent.left,
707 rectParent.bottom - rectParent.top,
708 SWP_NOMOVE | SWP_NOZORDER);
710 /* set the size of the child dialog */
711 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
712 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
715 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
717 switch(uMsg) {
718 case WM_INITDIALOG:
719 return TRUE;
721 return FALSE;
724 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
726 LPCVOID template;
727 HRSRC hRes;
728 HANDLE hDlgTmpl = 0;
729 HWND hChildDlg = 0;
731 TRACE("\n");
734 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
735 * structure's hInstance parameter is not a HINSTANCE, but
736 * instead a pointer to a template resource to use.
738 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
740 HINSTANCE hinst;
741 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
743 hinst = 0;
744 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
746 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
747 return NULL;
750 else
752 hinst = fodInfos->ofnInfos->hInstance;
753 if(fodInfos->unicode)
755 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
756 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
758 else
760 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
761 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
763 if (!hRes)
765 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
766 return NULL;
768 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
769 !(template = LockResource( hDlgTmpl )))
771 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
772 return NULL;
775 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
776 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
777 (LPARAM)fodInfos->ofnInfos);
778 if(hChildDlg)
780 ShowWindow(hChildDlg,SW_SHOW);
781 return hChildDlg;
784 else if( IsHooked(fodInfos))
786 RECT rectHwnd;
787 struct {
788 DLGTEMPLATE tmplate;
789 WORD menu,class,title;
790 } temp;
791 GetClientRect(hwnd,&rectHwnd);
792 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
793 temp.tmplate.dwExtendedStyle = 0;
794 temp.tmplate.cdit = 0;
795 temp.tmplate.x = 0;
796 temp.tmplate.y = 0;
797 temp.tmplate.cx = 0;
798 temp.tmplate.cy = 0;
799 temp.menu = temp.class = temp.title = 0;
801 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
802 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
804 return hChildDlg;
806 return NULL;
809 /***********************************************************************
810 * SendCustomDlgNotificationMessage
812 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
815 void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
817 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
819 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
821 if(!fodInfos) return;
823 if(fodInfos->DlgInfos.hwndCustomDlg)
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 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 SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
846 TRACE("RET NOTIFY\n");
850 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
852 INT_PTR sizeUsed = 0, n, total;
853 LPWSTR lpstrFileList = NULL;
854 WCHAR lpstrCurrentDir[MAX_PATH];
855 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
857 TRACE("CDM_GETFILEPATH:\n");
859 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
860 return -1;
862 /* get path and filenames */
863 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
864 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
866 TRACE("path >%s< filespec >%s< %d files\n",
867 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
869 if( fodInfos->unicode )
871 LPWSTR bufW = buffer;
872 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
874 /* Prepend the current path */
875 n = strlenW(lpstrCurrentDir) + 1;
876 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
877 if(n<size)
879 /* 'n' includes trailing \0 */
880 bufW[n-1] = '\\';
881 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
883 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
885 else
887 LPSTR bufA = buffer;
888 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
889 NULL, 0, NULL, NULL);
890 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
891 NULL, 0, NULL, NULL);
893 /* Prepend the current path */
894 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
895 bufA, size, NULL, NULL);
897 if(n<size)
899 /* 'n' includes trailing \0 */
900 bufA[n-1] = '\\';
901 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
902 &bufA[n], size-n, NULL, NULL);
905 TRACE("returned -> %s\n",debugstr_an(bufA, total));
907 MemFree(lpstrFileList);
909 return total;
912 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
914 INT_PTR sizeUsed = 0;
915 LPWSTR lpstrFileList = NULL;
916 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
918 TRACE("CDM_GETSPEC:\n");
920 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
921 if( fodInfos->unicode )
923 LPWSTR bufW = buffer;
924 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
926 else
928 LPSTR bufA = buffer;
929 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
930 NULL, 0, NULL, NULL);
931 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
932 bufA, size, NULL, NULL);
934 MemFree(lpstrFileList);
936 return sizeUsed;
939 /***********************************************************************
940 * FILEDLG95_HandleCustomDialogMessages
942 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
944 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
946 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
947 WCHAR lpstrPath[MAX_PATH];
948 INT_PTR retval;
950 if(!fodInfos) return FALSE;
952 switch(uMsg)
954 case CDM_GETFILEPATH:
955 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
956 break;
958 case CDM_GETFOLDERPATH:
959 TRACE("CDM_GETFOLDERPATH:\n");
960 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
961 if (lParam)
963 if (fodInfos->unicode)
964 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
965 else
966 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
967 (LPSTR)lParam, (int)wParam, NULL, NULL);
969 retval = strlenW(lpstrPath);
970 break;
972 case CDM_GETSPEC:
973 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
974 break;
976 case CDM_SETCONTROLTEXT:
977 TRACE("CDM_SETCONTROLTEXT:\n");
978 if ( lParam )
980 if( fodInfos->unicode )
981 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
982 else
983 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
985 retval = TRUE;
986 break;
988 case CDM_HIDECONTROL:
989 case CDM_SETDEFEXT:
990 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
991 retval = -1;
992 break;
994 default:
995 return FALSE;
997 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
998 return TRUE;
1001 /***********************************************************************
1002 * FileOpenDlgProc95
1004 * File open dialog procedure
1006 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1008 #if 0
1009 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1010 #endif
1012 switch(uMsg)
1014 case WM_INITDIALOG:
1016 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1018 /* Adds the FileOpenDlgInfos in the property list of the dialog
1019 so it will be easily accessible through a GetPropA(...) */
1020 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1022 fodInfos->DlgInfos.hwndCustomDlg =
1023 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1025 FILEDLG95_InitControls(hwnd);
1027 if (fodInfos->DlgInfos.hwndCustomDlg)
1028 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1029 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1031 FILEDLG95_FillControls(hwnd, wParam, lParam);
1033 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1034 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1035 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1036 return 0;
1038 case WM_COMMAND:
1039 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1040 case WM_DRAWITEM:
1042 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1044 case IDC_LOOKIN:
1045 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1046 return TRUE;
1049 return FALSE;
1051 case WM_GETISHELLBROWSER:
1052 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1054 case WM_DESTROY:
1055 RemovePropA(hwnd, FileOpenDlgInfosStr);
1056 return FALSE;
1058 case WM_NOTIFY:
1060 LPNMHDR lpnmh = (LPNMHDR)lParam;
1061 UINT stringId = -1;
1063 /* set up the button tooltips strings */
1064 if(TTN_GETDISPINFOA == lpnmh->code )
1066 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1067 switch(lpnmh->idFrom )
1069 /* Up folder button */
1070 case FCIDM_TB_UPFOLDER:
1071 stringId = IDS_UPFOLDER;
1072 break;
1073 /* New folder button */
1074 case FCIDM_TB_NEWFOLDER:
1075 stringId = IDS_NEWFOLDER;
1076 break;
1077 /* List option button */
1078 case FCIDM_TB_SMALLICON:
1079 stringId = IDS_LISTVIEW;
1080 break;
1081 /* Details option button */
1082 case FCIDM_TB_REPORTVIEW:
1083 stringId = IDS_REPORTVIEW;
1084 break;
1085 /* Desktop button */
1086 case FCIDM_TB_DESKTOP:
1087 stringId = IDS_TODESKTOP;
1088 break;
1089 default:
1090 stringId = 0;
1092 lpdi->hinst = COMDLG32_hInstance;
1093 lpdi->lpszText = (LPSTR) stringId;
1095 return FALSE;
1097 default :
1098 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1099 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1100 return FALSE;
1104 /***********************************************************************
1105 * FILEDLG95_InitControls
1107 * WM_INITDIALOG message handler (before hook notification)
1109 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1111 int win2000plus = 0;
1112 int win98plus = 0;
1113 int handledPath = FALSE;
1114 OSVERSIONINFOA osVi;
1115 static const WCHAR szwSlash[] = { '\\', 0 };
1116 static const WCHAR szwStar[] = { '*',0 };
1118 TBBUTTON tbb[] =
1120 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1121 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1122 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1123 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1124 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1125 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1126 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1127 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1128 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1130 TBADDBITMAP tba[2];
1131 RECT rectTB;
1132 RECT rectlook;
1133 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1135 tba[0].hInst = HINST_COMMCTRL;
1136 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1137 tba[1].hInst = COMDLG32_hInstance;
1138 tba[1].nID = 800;
1140 TRACE("%p\n", fodInfos);
1142 /* Get windows version emulating */
1143 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1144 GetVersionExA(&osVi);
1145 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1146 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1147 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1148 win2000plus = (osVi.dwMajorVersion > 4);
1149 if (win2000plus) win98plus = TRUE;
1151 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1153 /* Get the hwnd of the controls */
1154 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1155 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1156 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1158 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1159 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1161 /* construct the toolbar */
1162 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1163 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1165 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1166 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1167 rectTB.left = rectlook.right;
1168 rectTB.top = rectlook.top-1;
1170 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1171 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1172 rectTB.left, rectTB.top,
1173 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1174 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1176 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1178 /* FIXME: use TB_LOADIMAGES when implemented */
1179 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1180 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1181 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1183 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1184 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1186 /* Set the window text with the text specified in the OPENFILENAME structure */
1187 if(fodInfos->title)
1189 SetWindowTextW(hwnd,fodInfos->title);
1191 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1193 WCHAR buf[16];
1194 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1195 SetWindowTextW(hwnd, buf);
1198 /* Initialise the file name edit control */
1199 handledPath = FALSE;
1200 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1202 if(fodInfos->filename)
1204 /* 1. If win2000 or higher and filename contains a path, use it
1205 in preference over the lpstrInitialDir */
1206 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1207 WCHAR tmpBuf[MAX_PATH];
1208 WCHAR *nameBit;
1209 DWORD result;
1211 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1212 if (result) {
1214 /* nameBit is always shorter than the original filename */
1215 strcpyW(fodInfos->filename,nameBit);
1217 *nameBit = 0x00;
1218 if (fodInfos->initdir == NULL)
1219 MemFree(fodInfos->initdir);
1220 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1221 strcpyW(fodInfos->initdir, tmpBuf);
1222 handledPath = TRUE;
1223 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1224 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1226 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1228 } else {
1229 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1233 /* 2. (All platforms) If initdir is not null, then use it */
1234 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1235 (*fodInfos->initdir!=0x00))
1237 /* Work out the proper path as supplied one might be relative */
1238 /* (Here because supplying '.' as dir browses to My Computer) */
1239 if (handledPath==FALSE) {
1240 WCHAR tmpBuf[MAX_PATH];
1241 WCHAR tmpBuf2[MAX_PATH];
1242 WCHAR *nameBit;
1243 DWORD result;
1245 strcpyW(tmpBuf, fodInfos->initdir);
1246 if( PathFileExistsW(tmpBuf) ) {
1247 /* initdir does not have to be a directory. If a file is
1248 * specified, the dir part is taken */
1249 if( PathIsDirectoryW(tmpBuf)) {
1250 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1251 strcatW(tmpBuf, szwSlash);
1253 strcatW(tmpBuf, szwStar);
1255 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1256 if (result) {
1257 *nameBit = 0x00;
1258 if (fodInfos->initdir)
1259 MemFree(fodInfos->initdir);
1260 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1261 strcpyW(fodInfos->initdir, tmpBuf2);
1262 handledPath = TRUE;
1263 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1266 else if (fodInfos->initdir)
1268 MemFree(fodInfos->initdir);
1269 fodInfos->initdir = NULL;
1270 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1275 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1276 (*fodInfos->initdir==0x00)))
1278 /* 3. All except w2k+: if filename contains a path use it */
1279 if (!win2000plus && fodInfos->filename &&
1280 *fodInfos->filename &&
1281 strpbrkW(fodInfos->filename, szwSlash)) {
1282 WCHAR tmpBuf[MAX_PATH];
1283 WCHAR *nameBit;
1284 DWORD result;
1286 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1287 tmpBuf, &nameBit);
1288 if (result) {
1289 int len;
1291 /* nameBit is always shorter than the original filename */
1292 strcpyW(fodInfos->filename, nameBit);
1293 *nameBit = 0x00;
1295 len = strlenW(tmpBuf);
1296 if(fodInfos->initdir)
1297 MemFree(fodInfos->initdir);
1298 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1299 strcpyW(fodInfos->initdir, tmpBuf);
1301 handledPath = TRUE;
1302 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1303 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1305 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1308 /* 4. win98+ and win2000+ if any files of specified filter types in
1309 current directory, use it */
1310 if ( win98plus && handledPath == FALSE &&
1311 fodInfos->filter && *fodInfos->filter) {
1313 BOOL searchMore = TRUE;
1314 LPCWSTR lpstrPos = fodInfos->filter;
1315 WIN32_FIND_DATAW FindFileData;
1316 HANDLE hFind;
1318 while (searchMore)
1320 /* filter is a list... title\0ext\0......\0\0 */
1322 /* Skip the title */
1323 if(! *lpstrPos) break; /* end */
1324 lpstrPos += strlenW(lpstrPos) + 1;
1326 /* See if any files exist in the current dir with this extension */
1327 if(! *lpstrPos) break; /* end */
1329 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1331 if (hFind == INVALID_HANDLE_VALUE) {
1332 /* None found - continue search */
1333 lpstrPos += strlenW(lpstrPos) + 1;
1335 } else {
1336 searchMore = FALSE;
1338 if(fodInfos->initdir)
1339 MemFree(fodInfos->initdir);
1340 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1341 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1343 handledPath = TRUE;
1344 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1345 debugstr_w(lpstrPos));
1346 break;
1351 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1353 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1354 if (handledPath == FALSE && (win2000plus || win98plus)) {
1355 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1357 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1359 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1361 /* last fallback */
1362 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1363 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1364 } else {
1365 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1367 } else {
1368 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1370 handledPath = TRUE;
1371 } else if (handledPath==FALSE) {
1372 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1373 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1374 handledPath = TRUE;
1375 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1378 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1379 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1381 /* Must the open as read only check box be checked ?*/
1382 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1384 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1387 /* Must the open as read only check box be hidden? */
1388 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1390 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1391 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1394 /* Must the help button be hidden? */
1395 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1397 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1398 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1401 /* Resize the height, if open as read only checkbox ad help button
1402 are hidden and we are not using a custom template nor a customDialog
1404 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1405 (!(fodInfos->ofnInfos->Flags &
1406 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1407 (!fodInfos->DlgInfos.hwndCustomDlg ))
1409 RECT rectDlg, rectHelp, rectCancel;
1410 GetWindowRect(hwnd, &rectDlg);
1411 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1412 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1413 /* subtract the height of the help button plus the space between
1414 the help button and the cancel button to the height of the dialog */
1415 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1416 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1417 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1419 /* change Open to Save */
1420 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1422 WCHAR buf[16];
1423 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1424 SetDlgItemTextW(hwnd, IDOK, buf);
1425 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1426 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1428 return 0;
1431 /***********************************************************************
1432 * FILEDLG95_FillControls
1434 * WM_INITDIALOG message handler (after hook notification)
1436 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1438 LPITEMIDLIST pidlItemId = NULL;
1440 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1442 TRACE("dir=%s file=%s\n",
1443 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1445 /* Get the initial directory pidl */
1447 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1449 WCHAR path[MAX_PATH];
1451 GetCurrentDirectoryW(MAX_PATH,path);
1452 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1455 /* Initialise shell objects */
1456 FILEDLG95_SHELL_Init(hwnd);
1458 /* Initialize the Look In combo box */
1459 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1461 /* Initialize the filter combo box */
1462 FILEDLG95_FILETYPE_Init(hwnd);
1464 /* Browse to the initial directory */
1465 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1467 /* Free pidlItem memory */
1468 COMDLG32_SHFree(pidlItemId);
1470 return TRUE;
1472 /***********************************************************************
1473 * FILEDLG95_Clean
1475 * Regroups all the cleaning functions of the filedlg
1477 void FILEDLG95_Clean(HWND hwnd)
1479 FILEDLG95_FILETYPE_Clean(hwnd);
1480 FILEDLG95_LOOKIN_Clean(hwnd);
1481 FILEDLG95_SHELL_Clean(hwnd);
1483 /***********************************************************************
1484 * FILEDLG95_OnWMCommand
1486 * WM_COMMAND message handler
1488 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1490 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1491 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1492 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1494 switch(wID)
1496 /* OK button */
1497 case IDOK:
1498 FILEDLG95_OnOpen(hwnd);
1499 break;
1500 /* Cancel button */
1501 case IDCANCEL:
1502 FILEDLG95_Clean(hwnd);
1503 EndDialog(hwnd, FALSE);
1504 break;
1505 /* Filetype combo box */
1506 case IDC_FILETYPE:
1507 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1508 break;
1509 /* LookIn combo box */
1510 case IDC_LOOKIN:
1511 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1512 break;
1514 /* --- toolbar --- */
1515 /* Up folder button */
1516 case FCIDM_TB_UPFOLDER:
1517 FILEDLG95_SHELL_UpFolder(hwnd);
1518 break;
1519 /* New folder button */
1520 case FCIDM_TB_NEWFOLDER:
1521 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1522 break;
1523 /* List option button */
1524 case FCIDM_TB_SMALLICON:
1525 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1526 break;
1527 /* Details option button */
1528 case FCIDM_TB_REPORTVIEW:
1529 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1530 break;
1531 /* Details option button */
1532 case FCIDM_TB_DESKTOP:
1533 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1534 break;
1536 case IDC_FILENAME:
1537 break;
1540 /* Do not use the listview selection anymore */
1541 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1542 return 0;
1545 /***********************************************************************
1546 * FILEDLG95_OnWMGetIShellBrowser
1548 * WM_GETISHELLBROWSER message handler
1550 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1553 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1555 TRACE("\n");
1557 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1559 return TRUE;
1563 /***********************************************************************
1564 * FILEDLG95_SendFileOK
1566 * Sends the CDN_FILEOK notification if required
1568 * RETURNS
1569 * TRUE if the dialog should close
1570 * FALSE if the dialog should not be closed
1572 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1574 /* ask the hook if we can close */
1575 if(IsHooked(fodInfos))
1577 TRACE("---\n");
1578 /* First send CDN_FILEOK as MSDN doc says */
1579 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1580 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1582 TRACE("canceled\n");
1583 return FALSE;
1586 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1587 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1588 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1589 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1591 TRACE("canceled\n");
1592 return FALSE;
1595 return TRUE;
1598 /***********************************************************************
1599 * FILEDLG95_OnOpenMultipleFiles
1601 * Handles the opening of multiple files.
1603 * FIXME
1604 * check destination buffer size
1606 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1608 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1609 UINT nCount, nSizePath;
1610 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1612 TRACE("\n");
1614 if(fodInfos->unicode)
1616 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1617 ofn->lpstrFile[0] = '\0';
1619 else
1621 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1622 ofn->lpstrFile[0] = '\0';
1625 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1627 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1628 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1629 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1631 LPWSTR lpstrTemp = lpstrFileList;
1633 for ( nCount = 0; nCount < nFileCount; nCount++ )
1635 LPITEMIDLIST pidl;
1637 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1638 if (!pidl)
1640 WCHAR lpstrNotFound[100];
1641 WCHAR lpstrMsg[100];
1642 WCHAR tmp[400];
1643 static const WCHAR nl[] = {'\n',0};
1645 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1646 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1648 strcpyW(tmp, lpstrTemp);
1649 strcatW(tmp, nl);
1650 strcatW(tmp, lpstrNotFound);
1651 strcatW(tmp, nl);
1652 strcatW(tmp, lpstrMsg);
1654 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1655 return FALSE;
1658 /* move to the next file in the list of files */
1659 lpstrTemp += strlenW(lpstrTemp) + 1;
1660 COMDLG32_SHFree(pidl);
1664 nSizePath = strlenW(lpstrPathSpec) + 1;
1665 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1667 /* For "oldstyle" dialog the components have to
1668 be separated by blanks (not '\0'!) and short
1669 filenames have to be used! */
1670 FIXME("Components have to be separated by blanks\n");
1672 if(fodInfos->unicode)
1674 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1675 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1676 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1678 else
1680 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1682 if (ofn->lpstrFile != NULL)
1684 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1685 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1686 if (ofn->nMaxFile > nSizePath)
1688 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1689 ofn->lpstrFile + nSizePath,
1690 ofn->nMaxFile - nSizePath, NULL, NULL);
1695 fodInfos->ofnInfos->nFileOffset = nSizePath;
1696 fodInfos->ofnInfos->nFileExtension = 0;
1698 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1699 return FALSE;
1701 /* clean and exit */
1702 FILEDLG95_Clean(hwnd);
1703 return EndDialog(hwnd,TRUE);
1706 /***********************************************************************
1707 * FILEDLG95_OnOpen
1709 * Ok button WM_COMMAND message handler
1711 * If the function succeeds, the return value is nonzero.
1713 #define ONOPEN_OPEN 1
1714 #define ONOPEN_SEARCH 2
1715 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1717 WCHAR strMsgTitle[MAX_PATH];
1718 WCHAR strMsgText [MAX_PATH];
1719 if (idCaption)
1720 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1721 else
1722 strMsgTitle[0] = '\0';
1723 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1724 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1727 BOOL FILEDLG95_OnOpen(HWND hwnd)
1729 LPWSTR lpstrFileList;
1730 UINT nFileCount = 0;
1731 UINT sizeUsed = 0;
1732 BOOL ret = TRUE;
1733 WCHAR lpstrPathAndFile[MAX_PATH];
1734 WCHAR lpstrTemp[MAX_PATH];
1735 LPSHELLFOLDER lpsf = NULL;
1736 int nOpenAction;
1737 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1739 TRACE("hwnd=%p\n", hwnd);
1741 if(BrowseSelectedFolder(hwnd))
1742 return FALSE;
1744 /* get the files from the edit control */
1745 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1747 /* try if the user selected a folder in the shellview */
1748 if(nFileCount == 0)
1749 return FALSE;
1751 if(nFileCount > 1)
1753 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1754 goto ret;
1757 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1760 Step 1: Build a complete path name from the current folder and
1761 the filename or path in the edit box.
1762 Special cases:
1763 - the path in the edit box is a root path
1764 (with or without drive letter)
1765 - the edit box contains ".." (or a path with ".." in it)
1768 /* Get the current directory name */
1769 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1771 /* last fallback */
1772 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1774 PathAddBackslashW(lpstrPathAndFile);
1776 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1778 /* if the user specifyed a fully qualified path use it */
1779 if(PathIsRelativeW(lpstrFileList))
1781 strcatW(lpstrPathAndFile, lpstrFileList);
1783 else
1785 /* does the path have a drive letter? */
1786 if (PathGetDriveNumberW(lpstrFileList) == -1)
1787 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1788 else
1789 strcpyW(lpstrPathAndFile, lpstrFileList);
1792 /* resolve "." and ".." */
1793 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1794 strcpyW(lpstrPathAndFile, lpstrTemp);
1795 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1797 MemFree(lpstrFileList);
1800 Step 2: here we have a cleaned up path
1802 We have to parse the path step by step to see if we have to browse
1803 to a folder if the path points to a directory or the last
1804 valid element is a directory.
1806 valid variables:
1807 lpstrPathAndFile: cleaned up path
1810 nOpenAction = ONOPEN_OPEN;
1812 /* don't apply any checks with OFN_NOVALIDATE */
1814 LPWSTR lpszTemp, lpszTemp1;
1815 LPITEMIDLIST pidl = NULL;
1816 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1818 /* check for invalid chars */
1819 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1821 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1822 ret = FALSE;
1823 goto ret;
1826 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1828 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1829 while (lpszTemp1)
1831 LPSHELLFOLDER lpsfChild;
1832 WCHAR lpwstrTemp[MAX_PATH];
1833 DWORD dwEaten, dwAttributes;
1834 LPWSTR p;
1836 strcpyW(lpwstrTemp, lpszTemp);
1837 p = PathFindNextComponentW(lpwstrTemp);
1839 if (!p) break; /* end of path */
1841 *p = 0;
1842 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1844 if(*lpszTemp==0)
1846 static const WCHAR wszWild[] = { '*', '?', 0 };
1847 /* if the last element is a wildcard do a search */
1848 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1850 nOpenAction = ONOPEN_SEARCH;
1851 break;
1854 lpszTemp1 = lpszTemp;
1856 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1858 /* append a backslash to drive letters */
1859 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1860 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1861 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1863 PathAddBackslashW(lpwstrTemp);
1866 dwAttributes = SFGAO_FOLDER;
1867 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1869 /* the path component is valid, we have a pidl of the next path component */
1870 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1871 if(dwAttributes & SFGAO_FOLDER)
1873 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1875 ERR("bind to failed\n"); /* should not fail */
1876 break;
1878 IShellFolder_Release(lpsf);
1879 lpsf = lpsfChild;
1880 lpsfChild = NULL;
1882 else
1884 TRACE("value\n");
1886 /* end dialog, return value */
1887 nOpenAction = ONOPEN_OPEN;
1888 break;
1890 COMDLG32_SHFree(pidl);
1891 pidl = NULL;
1893 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1895 if(*lpszTemp) /* points to trailing null for last path element */
1897 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1899 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1900 break;
1903 else
1905 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1906 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1908 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1909 break;
1912 /* change to the current folder */
1913 nOpenAction = ONOPEN_OPEN;
1914 break;
1916 else
1918 nOpenAction = ONOPEN_OPEN;
1919 break;
1922 if(pidl) COMDLG32_SHFree(pidl);
1926 Step 3: here we have a cleaned up and validated path
1928 valid variables:
1929 lpsf: ShellFolder bound to the rightmost valid path component
1930 lpstrPathAndFile: cleaned up path
1931 nOpenAction: action to do
1933 TRACE("end validate sf=%p\n", lpsf);
1935 switch(nOpenAction)
1937 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1938 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1940 int iPos;
1941 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1942 DWORD len;
1943 IPersistFolder2 * ppf2;
1945 /* replace the current filter */
1946 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1947 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1948 len = strlenW(lpszTemp)+1;
1949 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1950 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1952 /* set the filter cb to the extension when possible */
1953 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1954 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1956 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1958 LPITEMIDLIST pidlCurrent;
1959 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1960 IPersistFolder2_Release(ppf2);
1961 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1963 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1965 else
1967 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1969 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1970 COMDLG32_SHFree(pidlCurrent);
1973 ret = FALSE;
1974 break;
1975 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1976 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1978 WCHAR *ext = NULL;
1980 /* update READONLY check box flag */
1981 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1982 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1983 else
1984 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1986 /* Attach the file extension with file name*/
1988 if(!PathIsDirectoryW(lpstrPathAndFile))
1990 if((ext = PathFindExtensionW(lpstrPathAndFile)) == NULL)
1992 /* if no extension is specified with file name, then */
1993 /* attach the extension from file filter or default one */
1995 WCHAR *filterExt = NULL;
1996 LPWSTR lpstrFilter = NULL;
1997 static const WCHAR szwDot[] = {'.',0};
1998 int PathLength = strlenW(lpstrPathAndFile);
2000 /* Attach the dot*/
2001 strcatW(lpstrPathAndFile, szwDot);
2003 /*Get the file extension from file type filter*/
2004 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2005 fodInfos->ofnInfos->nFilterIndex-1);
2007 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2008 filterExt = PathFindExtensionW(lpstrFilter);
2010 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2011 strcatW(lpstrPathAndFile, filterExt + 1);
2012 else if ( fodInfos->defext ) /* attach the default file extension*/
2013 strcatW(lpstrPathAndFile, fodInfos->defext);
2015 /* In Open dialog: if file does not exist try without extension */
2016 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2017 lpstrPathAndFile[PathLength] = '\0';
2020 if (fodInfos->defext) /* add default extension */
2022 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2023 if (*ext)
2024 ext++;
2025 if (!lstrcmpiW(fodInfos->defext, ext))
2026 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2027 else
2028 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2032 /* In Save dialog: check if the file already exists */
2033 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2034 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2035 && PathFileExistsW(lpstrPathAndFile))
2037 WCHAR lpstrOverwrite[100];
2038 int answer;
2040 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2041 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2042 MB_YESNO | MB_ICONEXCLAMATION);
2043 if (answer == IDNO)
2045 ret = FALSE;
2046 goto ret;
2050 /* Check that the size of the file does not exceed buffer size.
2051 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2052 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2053 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2055 LPWSTR lpszTemp;
2057 /* fill destination buffer */
2058 if (fodInfos->ofnInfos->lpstrFile)
2060 if(fodInfos->unicode)
2062 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2064 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2065 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2066 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2068 else
2070 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2072 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2073 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2074 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2075 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2079 /* set filename offset */
2080 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2081 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2083 /* set extension offset */
2084 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2085 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2087 /* set the lpstrFileTitle */
2088 if(fodInfos->ofnInfos->lpstrFileTitle)
2090 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2091 if(fodInfos->unicode)
2093 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2094 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2096 else
2098 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2099 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2100 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2104 /* copy currently selected filter to lpstrCustomFilter */
2105 if (fodInfos->ofnInfos->lpstrCustomFilter)
2107 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2108 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2109 NULL, 0, NULL, NULL);
2110 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2112 LPSTR s = ofn->lpstrCustomFilter;
2113 s += strlen(ofn->lpstrCustomFilter)+1;
2114 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2115 s, len, NULL, NULL);
2120 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2121 goto ret;
2123 TRACE("close\n");
2124 FILEDLG95_Clean(hwnd);
2125 ret = EndDialog(hwnd, TRUE);
2127 else
2129 WORD size;
2131 size = strlenW(lpstrPathAndFile) + 1;
2132 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2133 size += 1;
2134 /* return needed size in first two bytes of lpstrFile */
2135 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2136 FILEDLG95_Clean(hwnd);
2137 ret = EndDialog(hwnd, FALSE);
2138 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2140 goto ret;
2142 break;
2145 ret:
2146 if(lpsf) IShellFolder_Release(lpsf);
2147 return ret;
2150 /***********************************************************************
2151 * FILEDLG95_SHELL_Init
2153 * Initialisation of the shell objects
2155 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2157 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2159 TRACE("\n");
2162 * Initialisation of the FileOpenDialogInfos structure
2165 /* Shell */
2167 /*ShellInfos */
2168 fodInfos->ShellInfos.hwndOwner = hwnd;
2170 /* Disable multi-select if flag not set */
2171 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2173 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2175 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2176 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2178 /* Construct the IShellBrowser interface */
2179 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2181 return NOERROR;
2184 /***********************************************************************
2185 * FILEDLG95_SHELL_ExecuteCommand
2187 * Change the folder option and refresh the view
2188 * If the function succeeds, the return value is nonzero.
2190 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2192 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2194 IContextMenu * pcm;
2195 TRACE("(%p,%p)\n", hwnd, lpVerb);
2197 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2198 SVGIO_BACKGROUND,
2199 &IID_IContextMenu,
2200 (LPVOID*)&pcm)))
2202 CMINVOKECOMMANDINFO ci;
2203 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2204 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2205 ci.lpVerb = lpVerb;
2206 ci.hwnd = hwnd;
2208 IContextMenu_InvokeCommand(pcm, &ci);
2209 IContextMenu_Release(pcm);
2212 return FALSE;
2215 /***********************************************************************
2216 * FILEDLG95_SHELL_UpFolder
2218 * Browse to the specified object
2219 * If the function succeeds, the return value is nonzero.
2221 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2223 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2225 TRACE("\n");
2227 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2228 NULL,
2229 SBSP_PARENT)))
2231 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2232 return TRUE;
2234 return FALSE;
2237 /***********************************************************************
2238 * FILEDLG95_SHELL_BrowseToDesktop
2240 * Browse to the Desktop
2241 * If the function succeeds, the return value is nonzero.
2243 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2245 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2246 LPITEMIDLIST pidl;
2247 HRESULT hres;
2249 TRACE("\n");
2251 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2252 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2253 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2254 COMDLG32_SHFree(pidl);
2255 return SUCCEEDED(hres);
2257 /***********************************************************************
2258 * FILEDLG95_SHELL_Clean
2260 * Cleans the memory used by shell objects
2262 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2264 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2266 TRACE("\n");
2268 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2270 /* clean Shell interfaces */
2271 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2272 IShellView_Release(fodInfos->Shell.FOIShellView);
2273 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2274 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2275 if (fodInfos->Shell.FOIDataObject)
2276 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2279 /***********************************************************************
2280 * FILEDLG95_FILETYPE_Init
2282 * Initialisation of the file type combo box
2284 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2286 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2287 int nFilters = 0; /* number of filters */
2288 int nFilterIndexCB;
2290 TRACE("\n");
2292 if(fodInfos->customfilter)
2294 /* customfilter has one entry... title\0ext\0
2295 * Set first entry of combo box item with customfilter
2297 LPWSTR lpstrExt;
2298 LPCWSTR lpstrPos = fodInfos->customfilter;
2300 /* Get the title */
2301 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2303 /* Copy the extensions */
2304 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2305 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2306 strcpyW(lpstrExt,lpstrPos);
2308 /* Add the item at the end of the combo */
2309 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2310 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2311 nFilters++;
2313 if(fodInfos->filter)
2315 LPCWSTR lpstrPos = fodInfos->filter;
2317 for(;;)
2319 /* filter is a list... title\0ext\0......\0\0
2320 * Set the combo item text to the title and the item data
2321 * to the ext
2323 LPCWSTR lpstrDisplay;
2324 LPWSTR lpstrExt;
2326 /* Get the title */
2327 if(! *lpstrPos) break; /* end */
2328 lpstrDisplay = lpstrPos;
2329 lpstrPos += strlenW(lpstrPos) + 1;
2331 /* Copy the extensions */
2332 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2333 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2334 strcpyW(lpstrExt,lpstrPos);
2335 lpstrPos += strlenW(lpstrPos) + 1;
2337 /* Add the item at the end of the combo */
2338 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2339 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2340 nFilters++;
2345 * Set the current filter to the one specified
2346 * in the initialisation structure
2348 if (fodInfos->filter || fodInfos->customfilter)
2350 LPWSTR lpstrFilter;
2352 /* Check to make sure our index isn't out of bounds. */
2353 if ( fodInfos->ofnInfos->nFilterIndex >
2354 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2355 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2357 /* set default filter index */
2358 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2359 fodInfos->ofnInfos->nFilterIndex = 1;
2361 /* calculate index of Combo Box item */
2362 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2363 if (fodInfos->customfilter == NULL)
2364 nFilterIndexCB--;
2366 /* Set the current index selection. */
2367 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2369 /* Get the corresponding text string from the combo box. */
2370 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2371 nFilterIndexCB);
2373 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2374 lpstrFilter = NULL;
2376 if(lpstrFilter)
2378 DWORD len;
2379 CharLowerW(lpstrFilter); /* lowercase */
2380 len = strlenW(lpstrFilter)+1;
2381 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2382 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2384 } else
2385 fodInfos->ofnInfos->nFilterIndex = 0;
2386 return S_OK;
2389 /***********************************************************************
2390 * FILEDLG95_FILETYPE_OnCommand
2392 * WM_COMMAND of the file type combo box
2393 * If the function succeeds, the return value is nonzero.
2395 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2397 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2399 switch(wNotifyCode)
2401 case CBN_SELENDOK:
2403 LPWSTR lpstrFilter;
2405 /* Get the current item of the filetype combo box */
2406 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2408 /* set the current filter index */
2409 fodInfos->ofnInfos->nFilterIndex = iItem +
2410 (fodInfos->customfilter == NULL ? 1 : 0);
2412 /* Set the current filter with the current selection */
2413 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2414 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2416 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2417 iItem);
2418 if((int)lpstrFilter != CB_ERR)
2420 DWORD len;
2421 CharLowerW(lpstrFilter); /* lowercase */
2422 len = strlenW(lpstrFilter)+1;
2423 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2424 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2425 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2428 /* Refresh the actual view to display the included items*/
2429 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2432 return FALSE;
2434 /***********************************************************************
2435 * FILEDLG95_FILETYPE_SearchExt
2437 * searches for an extension in the filetype box
2439 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2441 int i, iCount = CBGetCount(hwnd);
2443 TRACE("%s\n", debugstr_w(lpstrExt));
2445 if(iCount != CB_ERR)
2447 for(i=0;i<iCount;i++)
2449 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2450 return i;
2453 return -1;
2456 /***********************************************************************
2457 * FILEDLG95_FILETYPE_Clean
2459 * Clean the memory used by the filetype combo box
2461 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2463 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2464 int iPos;
2465 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2467 TRACE("\n");
2469 /* Delete each string of the combo and their associated data */
2470 if(iCount != CB_ERR)
2472 for(iPos = iCount-1;iPos>=0;iPos--)
2474 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2475 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2478 /* Current filter */
2479 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2480 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2484 /***********************************************************************
2485 * FILEDLG95_LOOKIN_Init
2487 * Initialisation of the look in combo box
2489 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2491 IShellFolder *psfRoot, *psfDrives;
2492 IEnumIDList *lpeRoot, *lpeDrives;
2493 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2495 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2497 TRACE("\n");
2499 liInfos->iMaxIndentation = 0;
2501 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2503 /* set item height for both text field and listbox */
2504 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2505 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2507 /* Turn on the extended UI for the combo box like Windows does */
2508 CBSetExtendedUI(hwndCombo, TRUE);
2510 /* Initialise data of Desktop folder */
2511 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2512 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2513 COMDLG32_SHFree(pidlTmp);
2515 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2517 SHGetDesktopFolder(&psfRoot);
2519 if (psfRoot)
2521 /* enumerate the contents of the desktop */
2522 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2524 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2526 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2528 /* special handling for CSIDL_DRIVES */
2529 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2531 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2533 /* enumerate the drives */
2534 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2536 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2538 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2539 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2540 COMDLG32_SHFree(pidlAbsTmp);
2541 COMDLG32_SHFree(pidlTmp1);
2543 IEnumIDList_Release(lpeDrives);
2545 IShellFolder_Release(psfDrives);
2548 COMDLG32_SHFree(pidlTmp);
2550 IEnumIDList_Release(lpeRoot);
2552 IShellFolder_Release(psfRoot);
2555 COMDLG32_SHFree(pidlDrives);
2558 /***********************************************************************
2559 * FILEDLG95_LOOKIN_DrawItem
2561 * WM_DRAWITEM message handler
2563 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2565 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2566 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2567 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2568 RECT rectText;
2569 RECT rectIcon;
2570 SHFILEINFOA sfi;
2571 HIMAGELIST ilItemImage;
2572 int iIndentation;
2573 TEXTMETRICA tm;
2574 LPSFOLDER tmpFolder;
2577 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2579 TRACE("\n");
2581 if(pDIStruct->itemID == -1)
2582 return 0;
2584 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2585 pDIStruct->itemID)))
2586 return 0;
2589 if(pDIStruct->itemID == liInfos->uSelectedItem)
2591 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2593 &sfi,
2594 sizeof (SHFILEINFOA),
2595 SHGFI_PIDL | SHGFI_SMALLICON |
2596 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2597 SHGFI_DISPLAYNAME );
2599 else
2601 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2603 &sfi,
2604 sizeof (SHFILEINFOA),
2605 SHGFI_PIDL | SHGFI_SMALLICON |
2606 SHGFI_SYSICONINDEX |
2607 SHGFI_DISPLAYNAME);
2610 /* Is this item selected ? */
2611 if(pDIStruct->itemState & ODS_SELECTED)
2613 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2614 SetBkColor(pDIStruct->hDC,crHighLight);
2615 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2617 else
2619 SetTextColor(pDIStruct->hDC,crText);
2620 SetBkColor(pDIStruct->hDC,crWin);
2621 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2624 /* Do not indent item if drawing in the edit of the combo */
2625 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2627 iIndentation = 0;
2628 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2630 &sfi,
2631 sizeof (SHFILEINFOA),
2632 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2633 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2636 else
2638 iIndentation = tmpFolder->m_iIndent;
2640 /* Draw text and icon */
2642 /* Initialise the icon display area */
2643 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2644 rectIcon.top = pDIStruct->rcItem.top;
2645 rectIcon.right = rectIcon.left + ICONWIDTH;
2646 rectIcon.bottom = pDIStruct->rcItem.bottom;
2648 /* Initialise the text display area */
2649 GetTextMetricsA(pDIStruct->hDC, &tm);
2650 rectText.left = rectIcon.right;
2651 rectText.top =
2652 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2653 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2654 rectText.bottom =
2655 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2657 /* Draw the icon from the image list */
2658 ImageList_Draw(ilItemImage,
2659 sfi.iIcon,
2660 pDIStruct->hDC,
2661 rectIcon.left,
2662 rectIcon.top,
2663 ILD_TRANSPARENT );
2665 /* Draw the associated text */
2666 if(sfi.szDisplayName)
2667 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2670 return NOERROR;
2673 /***********************************************************************
2674 * FILEDLG95_LOOKIN_OnCommand
2676 * LookIn combo box WM_COMMAND message handler
2677 * If the function succeeds, the return value is nonzero.
2679 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2681 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2683 TRACE("%p\n", fodInfos);
2685 switch(wNotifyCode)
2687 case CBN_SELENDOK:
2689 LPSFOLDER tmpFolder;
2690 int iItem;
2692 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2694 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2695 iItem)))
2696 return FALSE;
2699 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2700 tmpFolder->pidlItem,
2701 SBSP_ABSOLUTE)))
2703 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2704 return TRUE;
2706 break;
2710 return FALSE;
2713 /***********************************************************************
2714 * FILEDLG95_LOOKIN_AddItem
2716 * Adds an absolute pidl item to the lookin combo box
2717 * returns the index of the inserted item
2719 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2721 LPITEMIDLIST pidlNext;
2722 SHFILEINFOA sfi;
2723 SFOLDER *tmpFolder;
2724 LookInInfos *liInfos;
2726 TRACE("%08x\n", iInsertId);
2728 if(!pidl)
2729 return -1;
2731 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2732 return -1;
2734 tmpFolder = MemAlloc(sizeof(SFOLDER));
2735 tmpFolder->m_iIndent = 0;
2737 /* Calculate the indentation of the item in the lookin*/
2738 pidlNext = pidl;
2739 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2741 tmpFolder->m_iIndent++;
2744 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2746 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2747 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2749 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2750 SHGetFileInfoA((LPSTR)pidl,
2752 &sfi,
2753 sizeof(sfi),
2754 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2755 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2757 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2759 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2761 int iItemID;
2763 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2765 /* Add the item at the end of the list */
2766 if(iInsertId < 0)
2768 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2770 /* Insert the item at the iInsertId position*/
2771 else
2773 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2776 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2777 return iItemID;
2780 COMDLG32_SHFree( tmpFolder->pidlItem );
2781 MemFree( tmpFolder );
2782 return -1;
2786 /***********************************************************************
2787 * FILEDLG95_LOOKIN_InsertItemAfterParent
2789 * Insert an item below its parent
2791 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2794 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2795 int iParentPos;
2797 TRACE("\n");
2799 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2801 if(iParentPos < 0)
2803 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2806 /* Free pidlParent memory */
2807 COMDLG32_SHFree((LPVOID)pidlParent);
2809 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2812 /***********************************************************************
2813 * FILEDLG95_LOOKIN_SelectItem
2815 * Adds an absolute pidl item to the lookin combo box
2816 * returns the index of the inserted item
2818 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2820 int iItemPos;
2821 LookInInfos *liInfos;
2823 TRACE("\n");
2825 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2827 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2829 if(iItemPos < 0)
2831 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2832 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2835 else
2837 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2838 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2840 int iRemovedItem;
2842 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2843 break;
2844 if(iRemovedItem < iItemPos)
2845 iItemPos--;
2849 CBSetCurSel(hwnd,iItemPos);
2850 liInfos->uSelectedItem = iItemPos;
2852 return 0;
2856 /***********************************************************************
2857 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2859 * Remove the item with an expansion level over iExpansionLevel
2861 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2863 int iItemPos;
2865 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2867 TRACE("\n");
2869 if(liInfos->iMaxIndentation <= 2)
2870 return -1;
2872 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2874 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2875 COMDLG32_SHFree(tmpFolder->pidlItem);
2876 MemFree(tmpFolder);
2877 CBDeleteString(hwnd,iItemPos);
2878 liInfos->iMaxIndentation--;
2880 return iItemPos;
2883 return -1;
2886 /***********************************************************************
2887 * FILEDLG95_LOOKIN_SearchItem
2889 * Search for pidl in the lookin combo box
2890 * returns the index of the found item
2892 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2894 int i = 0;
2895 int iCount = CBGetCount(hwnd);
2897 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2899 if (iCount != CB_ERR)
2901 for(;i<iCount;i++)
2903 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2905 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2906 return i;
2907 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2908 return i;
2912 return -1;
2915 /***********************************************************************
2916 * FILEDLG95_LOOKIN_Clean
2918 * Clean the memory used by the lookin combo box
2920 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2922 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2923 int iPos;
2924 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2926 TRACE("\n");
2928 /* Delete each string of the combo and their associated data */
2929 if (iCount != CB_ERR)
2931 for(iPos = iCount-1;iPos>=0;iPos--)
2933 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2934 COMDLG32_SHFree(tmpFolder->pidlItem);
2935 MemFree(tmpFolder);
2936 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2940 /* LookInInfos structure */
2941 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2944 /***********************************************************************
2945 * FILEDLG95_FILENAME_FillFromSelection
2947 * fills the edit box from the cached DataObject
2949 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2951 FileOpenDlgInfos *fodInfos;
2952 LPITEMIDLIST pidl;
2953 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2954 char lpstrTemp[MAX_PATH];
2955 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2957 TRACE("\n");
2958 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2960 /* Count how many files we have */
2961 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2963 /* calculate the string length, count files */
2964 if (nFileSelected >= 1)
2966 nLength += 3; /* first and last quotes, trailing \0 */
2967 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2969 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2971 if (pidl)
2973 /* get the total length of the selected file names */
2974 lpstrTemp[0] = '\0';
2975 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2977 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2979 nLength += strlen( lpstrTemp ) + 3;
2980 nFiles++;
2982 COMDLG32_SHFree( pidl );
2987 /* allocate the buffer */
2988 if (nFiles <= 1) nLength = MAX_PATH;
2989 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2990 lpstrAllFile[0] = '\0';
2992 /* Generate the string for the edit control */
2993 if(nFiles >= 1)
2995 lpstrCurrFile = lpstrAllFile;
2996 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2998 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3000 if (pidl)
3002 /* get the file name */
3003 lpstrTemp[0] = '\0';
3004 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3006 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3008 if ( nFiles > 1)
3010 *lpstrCurrFile++ = '\"';
3011 strcpy( lpstrCurrFile, lpstrTemp );
3012 lpstrCurrFile += strlen( lpstrTemp );
3013 strcpy( lpstrCurrFile, "\" " );
3014 lpstrCurrFile += 2;
3016 else
3018 strcpy( lpstrAllFile, lpstrTemp );
3021 COMDLG32_SHFree( (LPVOID) pidl );
3024 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3026 /* Select the file name like Windows does */
3027 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3029 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3033 /* copied from shell32 to avoid linking to it
3034 * FIXME: why? shell32 is already linked
3036 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3038 switch (src->uType)
3040 case STRRET_WSTR:
3041 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3042 COMDLG32_SHFree(src->u.pOleStr);
3043 break;
3045 case STRRET_CSTR:
3046 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3047 break;
3049 case STRRET_OFFSET:
3050 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3051 break;
3053 default:
3054 FIXME("unknown type!\n");
3055 if (len)
3057 *(LPSTR)dest = '\0';
3059 return(E_FAIL);
3061 return S_OK;
3064 /***********************************************************************
3065 * FILEDLG95_FILENAME_GetFileNames
3067 * Copies the filenames to a delimited string list.
3068 * The delimiter is specified by the parameter 'separator',
3069 * usually either a space or a nul
3071 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3073 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3074 UINT nStrCharCount = 0; /* index in src buffer */
3075 UINT nFileIndex = 0; /* index in dest buffer */
3076 UINT nFileCount = 0; /* number of files */
3077 UINT nStrLen = 0; /* length of string in edit control */
3078 LPWSTR lpstrEdit; /* buffer for string from edit control */
3080 TRACE("\n");
3082 /* get the filenames from the edit control */
3083 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3084 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3085 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3087 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3089 /* we might get single filename without any '"',
3090 * so we need nStrLen + terminating \0 + end-of-list \0 */
3091 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3092 *sizeUsed = 0;
3094 /* build delimited file list from filenames */
3095 while ( nStrCharCount <= nStrLen )
3097 if ( lpstrEdit[nStrCharCount]=='"' )
3099 nStrCharCount++;
3100 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3102 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3103 (*sizeUsed)++;
3104 nStrCharCount++;
3106 (*lpstrFileList)[nFileIndex++] = separator;
3107 (*sizeUsed)++;
3108 nFileCount++;
3110 nStrCharCount++;
3113 /* single, unquoted string */
3114 if ((nStrLen > 0) && (*sizeUsed == 0) )
3116 strcpyW(*lpstrFileList, lpstrEdit);
3117 nFileIndex = strlenW(lpstrEdit) + 1;
3118 (*sizeUsed) = nFileIndex;
3119 nFileCount = 1;
3122 /* trailing \0 */
3123 (*lpstrFileList)[nFileIndex] = '\0';
3124 (*sizeUsed)++;
3126 MemFree(lpstrEdit);
3127 return nFileCount;
3130 #define SETDefFormatEtc(fe,cf,med) \
3132 (fe).cfFormat = cf;\
3133 (fe).dwAspect = DVASPECT_CONTENT; \
3134 (fe).ptd =NULL;\
3135 (fe).tymed = med;\
3136 (fe).lindex = -1;\
3140 * DATAOBJECT Helper functions
3143 /***********************************************************************
3144 * COMCTL32_ReleaseStgMedium
3146 * like ReleaseStgMedium from ole32
3148 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3150 if(medium.pUnkForRelease)
3152 IUnknown_Release(medium.pUnkForRelease);
3154 else
3156 GlobalUnlock(medium.u.hGlobal);
3157 GlobalFree(medium.u.hGlobal);
3161 /***********************************************************************
3162 * GetPidlFromDataObject
3164 * Return pidl(s) by number from the cached DataObject
3166 * nPidlIndex=0 gets the fully qualified root path
3168 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3171 STGMEDIUM medium;
3172 FORMATETC formatetc;
3173 LPITEMIDLIST pidl = NULL;
3175 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3177 /* Set the FORMATETC structure*/
3178 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3180 /* Get the pidls from IDataObject */
3181 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3183 LPIDA cida = GlobalLock(medium.u.hGlobal);
3184 if(nPidlIndex <= cida->cidl)
3186 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3188 COMCTL32_ReleaseStgMedium(medium);
3190 return pidl;
3193 /***********************************************************************
3194 * GetNumSelected
3196 * Return the number of selected items in the DataObject.
3199 UINT GetNumSelected( IDataObject *doSelected )
3201 UINT retVal = 0;
3202 STGMEDIUM medium;
3203 FORMATETC formatetc;
3205 TRACE("sv=%p\n", doSelected);
3207 if (!doSelected) return 0;
3209 /* Set the FORMATETC structure*/
3210 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3212 /* Get the pidls from IDataObject */
3213 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3215 LPIDA cida = GlobalLock(medium.u.hGlobal);
3216 retVal = cida->cidl;
3217 COMCTL32_ReleaseStgMedium(medium);
3218 return retVal;
3220 return 0;
3224 * TOOLS
3227 /***********************************************************************
3228 * GetName
3230 * Get the pidl's display name (relative to folder) and
3231 * put it in lpstrFileName.
3233 * Return NOERROR on success,
3234 * E_FAIL otherwise
3237 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3239 STRRET str;
3240 HRESULT hRes;
3242 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3244 if(!lpsf)
3246 SHGetDesktopFolder(&lpsf);
3247 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3248 IShellFolder_Release(lpsf);
3249 return hRes;
3252 /* Get the display name of the pidl relative to the folder */
3253 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3255 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3257 return E_FAIL;
3260 /***********************************************************************
3261 * GetShellFolderFromPidl
3263 * pidlRel is the item pidl relative
3264 * Return the IShellFolder of the absolute pidl
3266 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3268 IShellFolder *psf = NULL,*psfParent;
3270 TRACE("%p\n", pidlAbs);
3272 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3274 psf = psfParent;
3275 if(pidlAbs && pidlAbs->mkid.cb)
3277 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3279 IShellFolder_Release(psfParent);
3280 return psf;
3283 /* return the desktop */
3284 return psfParent;
3286 return NULL;
3289 /***********************************************************************
3290 * GetParentPidl
3292 * Return the LPITEMIDLIST to the parent of the pidl in the list
3294 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3296 LPITEMIDLIST pidlParent;
3298 TRACE("%p\n", pidl);
3300 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3301 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3303 return pidlParent;
3306 /***********************************************************************
3307 * GetPidlFromName
3309 * returns the pidl of the file name relative to folder
3310 * NULL if an error occurred
3312 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3314 LPITEMIDLIST pidl = NULL;
3315 ULONG ulEaten;
3317 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3319 if(!lpcstrFileName) return NULL;
3320 if(!*lpcstrFileName) return NULL;
3322 if(!lpsf)
3324 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3325 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3326 IShellFolder_Release(lpsf);
3329 else
3331 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3333 return pidl;
3338 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3340 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3341 HRESULT ret;
3343 TRACE("%p, %p\n", psf, pidl);
3345 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3347 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3348 /* see documentation shell 4.1*/
3349 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3352 /***********************************************************************
3353 * BrowseSelectedFolder
3355 static BOOL BrowseSelectedFolder(HWND hwnd)
3357 BOOL bBrowseSelFolder = FALSE;
3358 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3360 TRACE("\n");
3362 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3364 LPITEMIDLIST pidlSelection;
3366 /* get the file selected */
3367 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3368 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3370 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3371 pidlSelection, SBSP_RELATIVE ) ) )
3373 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3374 ' ','n','o','t',' ','e','x','i','s','t',0};
3375 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3377 bBrowseSelFolder = TRUE;
3378 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3380 COMDLG32_SHFree( pidlSelection );
3383 return bBrowseSelFolder;
3387 * Memory allocation methods */
3388 static void *MemAlloc(UINT size)
3390 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3393 static void MemFree(void *mem)
3395 HeapFree(GetProcessHeap(),0,mem);
3399 * Old-style (win3.1) dialogs */
3401 /***********************************************************************
3402 * FD32_GetTemplate [internal]
3404 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3405 * by a 32 bits application
3408 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3410 LPOPENFILENAMEW ofnW = lfs->ofnW;
3411 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3412 HANDLE hDlgTmpl;
3414 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3416 if (!(lfs->template = LockResource( ofnW->hInstance )))
3418 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3419 return FALSE;
3422 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3424 HRSRC hResInfo;
3425 if (priv->ofnA)
3426 hResInfo = FindResourceA(priv->ofnA->hInstance,
3427 priv->ofnA->lpTemplateName,
3428 (LPSTR)RT_DIALOG);
3429 else
3430 hResInfo = FindResourceW(ofnW->hInstance,
3431 ofnW->lpTemplateName,
3432 (LPWSTR)RT_DIALOG);
3433 if (!hResInfo)
3435 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3436 return FALSE;
3438 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3439 hResInfo)) ||
3440 !(lfs->template = LockResource(hDlgTmpl)))
3442 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3443 return FALSE;
3445 } else { /* get it from internal Wine resource */
3446 HRSRC hResInfo;
3447 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3448 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3450 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3451 return FALSE;
3453 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3454 !(lfs->template = LockResource( hDlgTmpl )))
3456 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3457 return FALSE;
3460 return TRUE;
3464 /************************************************************************
3465 * FD32_Init [internal]
3466 * called from the common 16/32 code to initialize 32 bit data
3468 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3470 BOOL IsUnicode = (BOOL) data;
3471 PFD32_PRIVATE priv;
3473 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3474 lfs->private1632 = priv;
3475 if (NULL == lfs->private1632) return FALSE;
3476 if (IsUnicode)
3478 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3479 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3480 if (lfs->ofnW->lpfnHook)
3481 lfs->hook = TRUE;
3483 else
3485 priv->ofnA = (LPOPENFILENAMEA) lParam;
3486 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3487 if (priv->ofnA->lpfnHook)
3488 lfs->hook = TRUE;
3489 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3490 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3493 if (! FD32_GetTemplate(lfs)) return FALSE;
3495 return TRUE;
3498 /***********************************************************************
3499 * FD32_CallWindowProc [internal]
3501 * called from the common 16/32 code to call the appropriate hook
3503 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3504 LPARAM lParam)
3506 BOOL ret;
3507 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3509 if (priv->ofnA)
3511 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3512 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3513 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3514 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3515 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3516 return ret;
3519 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3520 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3521 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3522 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3523 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3524 return ret;
3527 /***********************************************************************
3528 * FD32_UpdateResult [internal]
3529 * update the real client structures if any
3531 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3533 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3534 LPOPENFILENAMEW ofnW = lfs->ofnW;
3536 if (priv->ofnA)
3538 if (ofnW->nMaxFile &&
3539 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3540 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3541 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3542 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3543 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3547 /***********************************************************************
3548 * FD32_UpdateFileTitle [internal]
3549 * update the real client structures if any
3551 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3553 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3554 LPOPENFILENAMEW ofnW = lfs->ofnW;
3556 if (priv->ofnA)
3558 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3559 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3560 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3565 /***********************************************************************
3566 * FD32_SendLbGetCurSel [internal]
3567 * retrieve selected listbox item
3569 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3571 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3575 /************************************************************************
3576 * FD32_Destroy [internal]
3577 * called from the common 16/32 code to cleanup 32 bit data
3579 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3581 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3583 /* if ofnW has been allocated, have to free everything in it */
3584 if (NULL != priv && NULL != priv->ofnA)
3586 FD31_FreeOfnW(lfs->ofnW);
3587 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3591 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3593 callbacks->Init = FD32_Init;
3594 callbacks->CWP = FD32_CallWindowProc;
3595 callbacks->UpdateResult = FD32_UpdateResult;
3596 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3597 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3598 callbacks->Destroy = FD32_Destroy;
3601 /***********************************************************************
3602 * FD32_WMMeasureItem [internal]
3604 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3606 LPMEASUREITEMSTRUCT lpmeasure;
3608 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3609 lpmeasure->itemHeight = FD31_GetFldrHeight();
3610 return TRUE;
3614 /***********************************************************************
3615 * FileOpenDlgProc [internal]
3616 * Used for open and save, in fact.
3618 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3619 WPARAM wParam, LPARAM lParam)
3621 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3623 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3624 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3626 INT_PTR lRet;
3627 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3628 if (lRet)
3629 return lRet; /* else continue message processing */
3631 switch (wMsg)
3633 case WM_INITDIALOG:
3634 return FD31_WMInitDialog(hWnd, wParam, lParam);
3636 case WM_MEASUREITEM:
3637 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3639 case WM_DRAWITEM:
3640 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3642 case WM_COMMAND:
3643 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3644 #if 0
3645 case WM_CTLCOLOR:
3646 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3647 switch (HIWORD(lParam))
3649 case CTLCOLOR_BTN:
3650 SetTextColor((HDC16)wParam, 0x00000000);
3651 return hGRAYBrush;
3652 case CTLCOLOR_STATIC:
3653 SetTextColor((HDC16)wParam, 0x00000000);
3654 return hGRAYBrush;
3656 break;
3657 #endif
3659 return FALSE;
3663 /***********************************************************************
3664 * GetFileName31A [internal]
3666 * Creates a win31 style dialog box for the user to select a file to open/save.
3668 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3669 UINT dlgType /* type dialogue : open/save */
3672 HINSTANCE hInst;
3673 BOOL bRet = FALSE;
3674 PFD31_DATA lfs;
3675 FD31_CALLBACKS callbacks;
3677 if (!lpofn || !FD31_Init()) return FALSE;
3679 TRACE("ofn flags %08lx\n", lpofn->Flags);
3680 FD32_SetupCallbacks(&callbacks);
3681 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3682 if (lfs)
3684 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3685 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3686 FD32_FileOpenDlgProc, (LPARAM)lfs);
3687 FD31_DestroyPrivate(lfs);
3690 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3691 return bRet;
3694 /***********************************************************************
3695 * GetFileName31W [internal]
3697 * Creates a win31 style dialog box for the user to select a file to open/save
3699 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3700 UINT dlgType /* type dialogue : open/save */
3703 HINSTANCE hInst;
3704 BOOL bRet = FALSE;
3705 PFD31_DATA lfs;
3706 FD31_CALLBACKS callbacks;
3708 if (!lpofn || !FD31_Init()) return FALSE;
3710 FD32_SetupCallbacks(&callbacks);
3711 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3712 if (lfs)
3714 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3715 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3716 FD32_FileOpenDlgProc, (LPARAM)lfs);
3717 FD31_DestroyPrivate(lfs);
3720 TRACE("file %s, file offset %d, ext offset %d\n",
3721 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3722 return bRet;
3725 /* ------------------ APIs ---------------------- */
3727 /***********************************************************************
3728 * GetOpenFileNameA (COMDLG32.@)
3730 * Creates a dialog box for the user to select a file to open.
3732 * RETURNS
3733 * TRUE on success: user enters a valid file
3734 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3737 BOOL WINAPI GetOpenFileNameA(
3738 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3740 BOOL win16look = FALSE;
3742 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3743 if (ofn->Flags & OFN_FILEMUSTEXIST)
3744 ofn->Flags |= OFN_PATHMUSTEXIST;
3746 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3747 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3749 if (win16look)
3750 return GetFileName31A(ofn, OPEN_DIALOG);
3751 else
3752 return GetFileDialog95A(ofn, OPEN_DIALOG);
3755 /***********************************************************************
3756 * GetOpenFileNameW (COMDLG32.@)
3758 * Creates a dialog box for the user to select a file to open.
3760 * RETURNS
3761 * TRUE on success: user enters a valid file
3762 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3765 BOOL WINAPI GetOpenFileNameW(
3766 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3768 BOOL win16look = FALSE;
3770 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3771 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3773 if (win16look)
3774 return GetFileName31W(ofn, OPEN_DIALOG);
3775 else
3776 return GetFileDialog95W(ofn, OPEN_DIALOG);
3780 /***********************************************************************
3781 * GetSaveFileNameA (COMDLG32.@)
3783 * Creates a dialog box for the user to select a file to save.
3785 * RETURNS
3786 * TRUE on success: user enters a valid file
3787 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3790 BOOL WINAPI GetSaveFileNameA(
3791 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3793 BOOL win16look = FALSE;
3795 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3796 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3798 if (win16look)
3799 return GetFileName31A(ofn, SAVE_DIALOG);
3800 else
3801 return GetFileDialog95A(ofn, SAVE_DIALOG);
3804 /***********************************************************************
3805 * GetSaveFileNameW (COMDLG32.@)
3807 * Creates a dialog box for the user to select a file to save.
3809 * RETURNS
3810 * TRUE on success: user enters a valid file
3811 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3814 BOOL WINAPI GetSaveFileNameW(
3815 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3817 BOOL win16look = FALSE;
3819 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3820 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3822 if (win16look)
3823 return GetFileName31W(ofn, SAVE_DIALOG);
3824 else
3825 return GetFileDialog95W(ofn, SAVE_DIALOG);