Implement NtAccessCheck.
[wine/gsoc-2012-control.git] / dlls / commdlg / filedlg.c
blob0c8f6e610aab6a4f3a590aa4f55c28e76981c2da
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "commdlg.h"
71 #include "dlgs.h"
72 #include "cdlg.h"
73 #include "filedlg31.h"
74 #include "wine/debug.h"
75 #include "cderr.h"
76 #include "shellapi.h"
77 #include "shlguid.h"
78 #include "shlobj.h"
79 #include "filedlgbrowser.h"
80 #include "shlwapi.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
124 /* AddItem flags*/
125 #define LISTEND -1
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
135 /* NOTE
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBAddStringW(hwnd,str) \
144 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
146 #define CBInsertString(hwnd,str,pos) \
147 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
149 #define CBDeleteString(hwnd,pos) \
150 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
152 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
153 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
155 #define CBGetItemDataPtr(hwnd,iItemId) \
156 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
158 #define CBGetLBText(hwnd,iItemId,str) \
159 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
161 #define CBGetCurSel(hwnd) \
162 SendMessageA(hwnd,CB_GETCURSEL,0,0);
164 #define CBSetCurSel(hwnd,pos) \
165 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
167 #define CBGetCount(hwnd) \
168 SendMessageA(hwnd,CB_GETCOUNT,0,0);
169 #define CBShowDropDown(hwnd,show) \
170 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
171 #define CBSetItemHeight(hwnd,index,height) \
172 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
174 #define CBSetExtendedUI(hwnd,flag) \
175 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
177 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
178 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
180 /***********************************************************************
181 * Prototypes
184 /* Internal functions used by the dialog */
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Miscellaneous tool functions */
217 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
218 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
221 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
223 /* Shell memory allocation */
224 static void *MemAlloc(UINT size);
225 static void MemFree(void *mem);
227 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
228 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
230 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
235 * GetFileName95
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
247 LRESULT lRes;
248 LPCVOID template;
249 HRSRC hRes;
250 HANDLE hDlgTmpl = 0;
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08lx not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
282 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
283 (LPDLGTEMPLATEA) template,
284 fodInfos->ofnInfos->hwndOwner,
285 FileOpenDlgProc95,
286 (LPARAM) fodInfos);
288 /* Unable to create the dialog */
289 if( lRes == -1)
290 return FALSE;
292 return lRes;
295 /***********************************************************************
296 * GetFileDialog95A
298 * Call GetFileName95 with this structure and clean the memory.
300 * IN : The OPENFILENAMEA initialisation structure passed to
301 * GetOpenFileNameA win api function (see filedlg.c)
303 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
305 BOOL ret;
306 FileOpenDlgInfos fodInfos;
307 LPSTR lpstrSavDir = NULL;
308 LPWSTR title = NULL;
309 LPWSTR defext = NULL;
310 LPWSTR filter = NULL;
311 LPWSTR customfilter = NULL;
313 /* Initialize FileOpenDlgInfos structure */
314 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
316 /* Pass in the original ofn */
317 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
319 /* save current directory */
320 if (ofn->Flags & OFN_NOCHANGEDIR)
322 lpstrSavDir = MemAlloc(MAX_PATH);
323 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
326 fodInfos.unicode = FALSE;
328 /* convert all the input strings to unicode */
329 if(ofn->lpstrInitialDir)
331 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
332 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
333 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
335 else
336 fodInfos.initdir = NULL;
338 if(ofn->lpstrFile)
340 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
343 else
344 fodInfos.filename = NULL;
346 if(ofn->lpstrDefExt)
348 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
349 defext = MemAlloc((len+1)*sizeof(WCHAR));
350 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
352 fodInfos.defext = defext;
354 if(ofn->lpstrTitle)
356 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
357 title = MemAlloc((len+1)*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
360 fodInfos.title = title;
362 if (ofn->lpstrFilter)
364 LPCSTR s;
365 int n, len;
367 /* filter is a list... title\0ext\0......\0\0 */
368 s = ofn->lpstrFilter;
369 while (*s) s = s+strlen(s)+1;
370 s++;
371 n = s - ofn->lpstrFilter;
372 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
373 filter = MemAlloc(len*sizeof(WCHAR));
374 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
376 fodInfos.filter = filter;
378 /* convert lpstrCustomFilter */
379 if (ofn->lpstrCustomFilter)
381 LPCSTR s;
382 int n, len;
384 /* customfilter contains a pair of strings... title\0ext\0 */
385 s = ofn->lpstrCustomFilter;
386 if (*s) s = s+strlen(s)+1;
387 if (*s) s = s+strlen(s)+1;
388 n = s - ofn->lpstrCustomFilter;
389 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
390 customfilter = MemAlloc(len*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
393 fodInfos.customfilter = customfilter;
395 /* Initialize the dialog property */
396 fodInfos.DlgInfos.dwDlgProp = 0;
397 fodInfos.DlgInfos.hwndCustomDlg = NULL;
399 switch(iDlgType)
401 case OPEN_DIALOG :
402 ret = GetFileName95(&fodInfos);
403 break;
404 case SAVE_DIALOG :
405 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
406 ret = GetFileName95(&fodInfos);
407 break;
408 default :
409 ret = 0;
412 if (lpstrSavDir)
414 SetCurrentDirectoryA(lpstrSavDir);
415 MemFree(lpstrSavDir);
418 if(title)
419 MemFree(title);
420 if(defext)
421 MemFree(defext);
422 if(filter)
423 MemFree(filter);
424 if(customfilter)
425 MemFree(customfilter);
426 if(fodInfos.initdir)
427 MemFree(fodInfos.initdir);
429 if(fodInfos.filename)
430 MemFree(fodInfos.filename);
432 TRACE("selected file: %s\n",ofn->lpstrFile);
434 return ret;
437 /***********************************************************************
438 * GetFileDialog95W
440 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
441 * Call GetFileName95 with this structure and clean the memory.
444 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
446 BOOL ret;
447 FileOpenDlgInfos fodInfos;
448 LPWSTR lpstrSavDir = NULL;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
453 /* Pass in the original ofn */
454 fodInfos.ofnInfos = ofn;
456 fodInfos.title = ofn->lpstrTitle;
457 fodInfos.defext = ofn->lpstrDefExt;
458 fodInfos.filter = ofn->lpstrFilter;
459 fodInfos.customfilter = ofn->lpstrCustomFilter;
461 /* convert string arguments, save others */
462 if(ofn->lpstrFile)
464 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
467 else
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
473 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
474 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
475 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
477 else
478 fodInfos.initdir = NULL;
480 /* save current directory */
481 if (ofn->Flags & OFN_NOCHANGEDIR)
483 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
484 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
487 fodInfos.unicode = TRUE;
489 switch(iDlgType)
491 case OPEN_DIALOG :
492 ret = GetFileName95(&fodInfos);
493 break;
494 case SAVE_DIALOG :
495 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
496 ret = GetFileName95(&fodInfos);
497 break;
498 default :
499 ret = 0;
502 if (lpstrSavDir)
504 SetCurrentDirectoryW(lpstrSavDir);
505 MemFree(lpstrSavDir);
508 /* restore saved IN arguments and convert OUT arguments back */
509 MemFree(fodInfos.filename);
510 MemFree(fodInfos.initdir);
511 return ret;
514 /***********************************************************************
515 * ArrangeCtrlPositions [internal]
517 * NOTE: Do not change anything here without a lot of testing.
519 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
521 HWND hwndChild, hwndStc32;
522 RECT rectParent, rectChild, rectStc32;
523 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
525 /* Take into account if open as read only checkbox and help button
526 * are hidden
528 if (hide_help)
530 RECT rectHelp, rectCancel;
531 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
532 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
533 /* subtract the height of the help button plus the space between
534 * the help button and the cancel button to the height of the dialog
536 help_fixup = rectHelp.bottom - rectCancel.bottom;
540 There are two possibilities to add components to the default file dialog box.
542 By default, all the new components are added below the standard dialog box (the else case).
544 However, if there is a static text component with the stc32 id, a special case happens.
545 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
546 in the window and the cx and cy indicate how to size the window.
547 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
548 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
552 GetClientRect(hwndParentDlg, &rectParent);
554 /* when arranging controls we have to use fixed parent size */
555 rectParent.bottom -= help_fixup;
557 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
558 if (hwndStc32)
560 GetWindowRect(hwndStc32, &rectStc32);
561 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
563 /* set the size of the stc32 control according to the size of
564 * client area of the parent dialog
566 SetWindowPos(hwndStc32, 0,
567 0, 0,
568 rectParent.right, rectParent.bottom,
569 SWP_NOMOVE | SWP_NOZORDER);
571 else
572 SetRectEmpty(&rectStc32);
574 /* this part moves controls of the child dialog */
575 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
576 while (hwndChild)
578 if (hwndChild != hwndStc32)
580 GetWindowRect(hwndChild, &rectChild);
581 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
583 /* move only if stc32 exist */
584 if (hwndStc32 && rectChild.left > rectStc32.right)
586 LONG old_left = rectChild.left;
588 /* move to the right of visible controls of the parent dialog */
589 rectChild.left += rectParent.right;
590 rectChild.left -= rectStc32.right;
592 child_width_fixup = rectChild.left - old_left;
594 /* move even if stc32 doesn't exist */
595 if (rectChild.top >= rectStc32.bottom)
597 LONG old_top = rectChild.top;
599 /* move below visible controls of the parent dialog */
600 rectChild.top += rectParent.bottom;
601 rectChild.top -= rectStc32.bottom - rectStc32.top;
603 child_height_fixup = rectChild.top - old_top;
606 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
607 0, 0, SWP_NOSIZE | SWP_NOZORDER);
609 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
612 /* this part moves controls of the parent dialog */
613 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
614 while (hwndChild)
616 if (hwndChild != hwndChildDlg)
618 GetWindowRect(hwndChild, &rectChild);
619 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
621 /* left,top of stc32 marks the position of controls
622 * from the parent dialog
624 rectChild.left += rectStc32.left;
625 rectChild.top += rectStc32.top;
627 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
628 0, 0, SWP_NOSIZE | SWP_NOZORDER);
630 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
633 /* calculate the size of the resulting dialog */
635 /* here we have to use original parent size */
636 GetClientRect(hwndParentDlg, &rectParent);
637 GetClientRect(hwndChildDlg, &rectChild);
639 if (hwndStc32)
641 rectChild.right += child_width_fixup;
642 rectChild.bottom += child_height_fixup;
644 if (rectParent.right > rectChild.right)
646 rectParent.right += rectChild.right;
647 rectParent.right -= rectStc32.right - rectStc32.left;
649 else
651 rectParent.right = rectChild.right;
654 if (rectParent.bottom > rectChild.bottom)
656 rectParent.bottom += rectChild.bottom;
657 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
659 else
661 /* child dialog is higher, unconditionally set new dialog
662 * height to its size (help_fixup will be subtracted below)
664 rectParent.bottom = rectChild.bottom + help_fixup;
667 else
669 rectParent.bottom += rectChild.bottom;
672 /* finally use fixed parent size */
673 rectParent.bottom -= help_fixup;
675 /* save the size of the parent's client area */
676 rectChild.right = rectParent.right;
677 rectChild.bottom = rectParent.bottom;
679 /* set the size of the parent dialog */
680 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
681 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
682 SetWindowPos(hwndParentDlg, 0,
683 0, 0,
684 rectParent.right - rectParent.left,
685 rectParent.bottom - rectParent.top,
686 SWP_NOMOVE | SWP_NOZORDER);
688 /* set the size of the child dialog */
689 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
690 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
693 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
695 switch(uMsg) {
696 case WM_INITDIALOG:
697 return TRUE;
699 return FALSE;
702 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
704 LPCVOID template;
705 HRSRC hRes;
706 HANDLE hDlgTmpl = 0;
707 HWND hChildDlg = 0;
709 TRACE("\n");
712 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
713 * structure's hInstance parameter is not a HINSTANCE, but
714 * instead a pointer to a template resource to use.
716 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
718 HINSTANCE hinst;
719 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
721 hinst = 0;
722 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
724 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
725 return NULL;
728 else
730 hinst = fodInfos->ofnInfos->hInstance;
731 if(fodInfos->unicode)
733 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
734 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
736 else
738 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
739 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
741 if (!hRes)
743 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
744 return NULL;
746 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
747 !(template = LockResource( hDlgTmpl )))
749 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
750 return NULL;
753 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
754 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
755 (LPARAM)fodInfos->ofnInfos);
756 if(hChildDlg)
758 ShowWindow(hChildDlg,SW_SHOW);
759 return hChildDlg;
762 else if( IsHooked(fodInfos))
764 RECT rectHwnd;
765 struct {
766 DLGTEMPLATE tmplate;
767 WORD menu,class,title;
768 } temp;
769 GetClientRect(hwnd,&rectHwnd);
770 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
771 temp.tmplate.dwExtendedStyle = 0;
772 temp.tmplate.cdit = 0;
773 temp.tmplate.x = 0;
774 temp.tmplate.y = 0;
775 temp.tmplate.cx = 0;
776 temp.tmplate.cy = 0;
777 temp.menu = temp.class = temp.title = 0;
779 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
780 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
782 return hChildDlg;
784 return NULL;
787 /***********************************************************************
788 * SendCustomDlgNotificationMessage
790 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
793 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
795 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
797 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
799 if(!fodInfos) return 0;
801 if(fodInfos->DlgInfos.hwndCustomDlg)
803 HRESULT ret;
804 TRACE("CALL NOTIFY for %x\n", uCode);
805 if(fodInfos->unicode)
807 OFNOTIFYW ofnNotify;
808 ofnNotify.hdr.hwndFrom=hwndParentDlg;
809 ofnNotify.hdr.idFrom=0;
810 ofnNotify.hdr.code = uCode;
811 ofnNotify.lpOFN = fodInfos->ofnInfos;
812 ofnNotify.pszFile = NULL;
813 ret = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
815 else
817 OFNOTIFYA ofnNotify;
818 ofnNotify.hdr.hwndFrom=hwndParentDlg;
819 ofnNotify.hdr.idFrom=0;
820 ofnNotify.hdr.code = uCode;
821 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
822 ofnNotify.pszFile = NULL;
823 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
825 TRACE("RET NOTIFY\n");
826 return ret;
828 return TRUE;
831 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
833 UINT sizeUsed = 0, n, total;
834 LPWSTR lpstrFileList = NULL;
835 WCHAR lpstrCurrentDir[MAX_PATH];
836 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
838 TRACE("CDM_GETFILEPATH:\n");
840 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
841 return -1;
843 /* get path and filenames */
844 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
845 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
847 TRACE("path >%s< filespec >%s< %d files\n",
848 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
850 if( fodInfos->unicode )
852 LPWSTR bufW = buffer;
853 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
855 /* Prepend the current path */
856 n = strlenW(lpstrCurrentDir) + 1;
857 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
858 if(n<size)
860 /* 'n' includes trailing \0 */
861 bufW[n-1] = '\\';
862 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
864 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
866 else
868 LPSTR bufA = buffer;
869 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
870 NULL, 0, NULL, NULL);
871 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
872 NULL, 0, NULL, NULL);
874 /* Prepend the current path */
875 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
876 bufA, size, NULL, NULL);
878 if(n<size)
880 /* 'n' includes trailing \0 */
881 bufA[n-1] = '\\';
882 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
883 &bufA[n], size-n, NULL, NULL);
886 TRACE("returned -> %s\n",debugstr_an(bufA, total));
888 MemFree(lpstrFileList);
890 return total;
893 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
895 UINT sizeUsed = 0;
896 LPWSTR lpstrFileList = NULL;
897 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
899 TRACE("CDM_GETSPEC:\n");
901 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
902 if( fodInfos->unicode )
904 LPWSTR bufW = buffer;
905 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
907 else
909 LPSTR bufA = buffer;
910 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
911 NULL, 0, NULL, NULL);
912 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
913 bufA, size, NULL, NULL);
915 MemFree(lpstrFileList);
917 return sizeUsed;
920 /***********************************************************************
921 * FILEDLG95_HandleCustomDialogMessages
923 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
925 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
927 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
928 if(!fodInfos) return -1;
930 switch(uMsg)
932 case CDM_GETFILEPATH:
933 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
935 case CDM_GETFOLDERPATH:
936 TRACE("CDM_GETFOLDERPATH:\n");
937 if( fodInfos->unicode )
939 WCHAR lpstrPath[MAX_PATH], *bufW = (LPWSTR)lParam;
940 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
941 if (bufW)
942 lstrcpynW(bufW,lpstrPath,(int)wParam);
943 return strlenW(lpstrPath);
945 else
947 char lpstrPath[MAX_PATH], *bufA = (LPSTR)lParam;
948 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
949 if (bufA)
950 lstrcpynA(bufA,lpstrPath,(int)wParam);
951 return strlen(lpstrPath);
954 case CDM_GETSPEC:
955 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
957 case CDM_SETCONTROLTEXT:
958 TRACE("CDM_SETCONTROLTEXT:\n");
959 if ( lParam )
961 if( fodInfos->unicode )
962 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
963 else
964 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
966 return TRUE;
968 case CDM_HIDECONTROL:
969 case CDM_SETDEFEXT:
970 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
971 return -1;
973 return TRUE;
976 /***********************************************************************
977 * FileOpenDlgProc95
979 * File open dialog procedure
981 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
983 #if 0
984 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
985 #endif
987 switch(uMsg)
989 case WM_INITDIALOG:
991 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
993 /* Adds the FileOpenDlgInfos in the property list of the dialog
994 so it will be easily accessible through a GetPropA(...) */
995 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
997 fodInfos->DlgInfos.hwndCustomDlg =
998 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1000 FILEDLG95_InitControls(hwnd);
1002 if (fodInfos->DlgInfos.hwndCustomDlg)
1003 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1004 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1006 FILEDLG95_FillControls(hwnd, wParam, lParam);
1008 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1009 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1010 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1011 return 0;
1013 case WM_COMMAND:
1014 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1015 case WM_DRAWITEM:
1017 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1019 case IDC_LOOKIN:
1020 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1021 return TRUE;
1024 return FALSE;
1026 case WM_GETISHELLBROWSER:
1027 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1029 case WM_DESTROY:
1030 RemovePropA(hwnd, FileOpenDlgInfosStr);
1031 return FALSE;
1033 case WM_NOTIFY:
1035 LPNMHDR lpnmh = (LPNMHDR)lParam;
1036 UINT stringId = -1;
1038 /* set up the button tooltips strings */
1039 if(TTN_GETDISPINFOA == lpnmh->code )
1041 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1042 switch(lpnmh->idFrom )
1044 /* Up folder button */
1045 case FCIDM_TB_UPFOLDER:
1046 stringId = IDS_UPFOLDER;
1047 break;
1048 /* New folder button */
1049 case FCIDM_TB_NEWFOLDER:
1050 stringId = IDS_NEWFOLDER;
1051 break;
1052 /* List option button */
1053 case FCIDM_TB_SMALLICON:
1054 stringId = IDS_LISTVIEW;
1055 break;
1056 /* Details option button */
1057 case FCIDM_TB_REPORTVIEW:
1058 stringId = IDS_REPORTVIEW;
1059 break;
1060 /* Desktop button */
1061 case FCIDM_TB_DESKTOP:
1062 stringId = IDS_TODESKTOP;
1063 break;
1064 default:
1065 stringId = 0;
1067 lpdi->hinst = COMDLG32_hInstance;
1068 lpdi->lpszText = (LPSTR) stringId;
1070 return FALSE;
1072 default :
1073 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1074 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1075 return FALSE;
1079 /***********************************************************************
1080 * FILEDLG95_InitControls
1082 * WM_INITDIALOG message handler (before hook notification)
1084 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1086 int win2000plus = 0;
1087 int win98plus = 0;
1088 int handledPath = FALSE;
1089 OSVERSIONINFOA osVi;
1090 static const WCHAR szwSlash[] = { '\\', 0 };
1091 static const WCHAR szwStar[] = { '*',0 };
1093 TBBUTTON tbb[] =
1095 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1096 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1097 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1098 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1099 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1100 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1101 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1102 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1103 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1105 TBADDBITMAP tba[2];
1106 RECT rectTB;
1107 RECT rectlook;
1108 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1110 tba[0].hInst = HINST_COMMCTRL;
1111 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1112 tba[1].hInst = COMDLG32_hInstance;
1113 tba[1].nID = 800;
1115 TRACE("%p\n", fodInfos);
1117 /* Get windows version emulating */
1118 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1119 GetVersionExA(&osVi);
1120 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1121 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1122 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1123 win2000plus = (osVi.dwMajorVersion > 4);
1124 if (win2000plus) win98plus = TRUE;
1126 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1128 /* Get the hwnd of the controls */
1129 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1130 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1131 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1133 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1134 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1136 /* construct the toolbar */
1137 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1138 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1140 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1141 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1142 rectTB.left = rectlook.right;
1143 rectTB.top = rectlook.top-1;
1145 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1146 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1147 rectTB.left, rectTB.top,
1148 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1149 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1151 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1153 /* FIXME: use TB_LOADIMAGES when implemented */
1154 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1155 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1156 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1158 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1159 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1161 /* Set the window text with the text specified in the OPENFILENAME structure */
1162 if(fodInfos->title)
1164 SetWindowTextW(hwnd,fodInfos->title);
1166 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1168 WCHAR buf[16];
1169 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1170 SetWindowTextW(hwnd, buf);
1173 /* Initialise the file name edit control */
1174 handledPath = FALSE;
1175 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1177 if(fodInfos->filename)
1179 /* 1. If win2000 or higher and filename contains a path, use it
1180 in preference over the lpstrInitialDir */
1181 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1182 WCHAR tmpBuf[MAX_PATH];
1183 WCHAR *nameBit;
1184 DWORD result;
1186 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1187 if (result) {
1189 /* nameBit is always shorter than the original filename */
1190 strcpyW(fodInfos->filename,nameBit);
1192 *nameBit = 0x00;
1193 if (fodInfos->initdir == NULL)
1194 MemFree(fodInfos->initdir);
1195 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1196 strcpyW(fodInfos->initdir, tmpBuf);
1197 handledPath = TRUE;
1198 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1199 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1201 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1203 } else {
1204 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1208 /* 2. (All platforms) If initdir is not null, then use it */
1209 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1210 (*fodInfos->initdir!=0x00))
1212 /* Work out the proper path as supplied one might be relative */
1213 /* (Here because supplying '.' as dir browses to My Computer) */
1214 if (handledPath==FALSE) {
1215 WCHAR tmpBuf[MAX_PATH];
1216 WCHAR tmpBuf2[MAX_PATH];
1217 WCHAR *nameBit;
1218 DWORD result;
1220 strcpyW(tmpBuf, fodInfos->initdir);
1221 if( PathFileExistsW(tmpBuf) ) {
1222 /* initdir does not have to be a directory. If a file is
1223 * specified, the dir part is taken */
1224 if( PathIsDirectoryW(tmpBuf)) {
1225 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1226 strcatW(tmpBuf, szwSlash);
1228 strcatW(tmpBuf, szwStar);
1230 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1231 if (result) {
1232 *nameBit = 0x00;
1233 if (fodInfos->initdir)
1234 MemFree(fodInfos->initdir);
1235 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1236 strcpyW(fodInfos->initdir, tmpBuf2);
1237 handledPath = TRUE;
1238 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1241 else if (fodInfos->initdir)
1243 MemFree(fodInfos->initdir);
1244 fodInfos->initdir = NULL;
1245 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1250 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1251 (*fodInfos->initdir==0x00)))
1253 /* 3. All except w2k+: if filename contains a path use it */
1254 if (!win2000plus && fodInfos->filename &&
1255 *fodInfos->filename &&
1256 strpbrkW(fodInfos->filename, szwSlash)) {
1257 WCHAR tmpBuf[MAX_PATH];
1258 WCHAR *nameBit;
1259 DWORD result;
1261 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1262 tmpBuf, &nameBit);
1263 if (result) {
1264 int len;
1266 /* nameBit is always shorter than the original filename */
1267 strcpyW(fodInfos->filename, nameBit);
1268 *nameBit = 0x00;
1270 len = strlenW(tmpBuf);
1271 if(fodInfos->initdir)
1272 MemFree(fodInfos->initdir);
1273 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1274 strcpyW(fodInfos->initdir, tmpBuf);
1276 handledPath = TRUE;
1277 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1278 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1280 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1283 /* 4. win98+ and win2000+ if any files of specified filter types in
1284 current directory, use it */
1285 if ( win98plus && handledPath == FALSE &&
1286 fodInfos->filter && *fodInfos->filter) {
1288 BOOL searchMore = TRUE;
1289 LPCWSTR lpstrPos = fodInfos->filter;
1290 WIN32_FIND_DATAW FindFileData;
1291 HANDLE hFind;
1293 while (searchMore)
1295 /* filter is a list... title\0ext\0......\0\0 */
1297 /* Skip the title */
1298 if(! *lpstrPos) break; /* end */
1299 lpstrPos += strlenW(lpstrPos) + 1;
1301 /* See if any files exist in the current dir with this extension */
1302 if(! *lpstrPos) break; /* end */
1304 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1306 if (hFind == INVALID_HANDLE_VALUE) {
1307 /* None found - continue search */
1308 lpstrPos += strlenW(lpstrPos) + 1;
1310 } else {
1311 searchMore = FALSE;
1313 if(fodInfos->initdir)
1314 MemFree(fodInfos->initdir);
1315 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1316 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1318 handledPath = TRUE;
1319 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1320 debugstr_w(lpstrPos));
1321 break;
1326 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1328 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1329 if (handledPath == FALSE && (win2000plus || win98plus)) {
1330 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1332 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1334 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1336 /* last fallback */
1337 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1338 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1339 } else {
1340 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1342 } else {
1343 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1345 handledPath = TRUE;
1346 } else if (handledPath==FALSE) {
1347 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1348 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1349 handledPath = TRUE;
1350 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1353 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1354 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1356 /* Must the open as read only check box be checked ?*/
1357 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1359 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1362 /* Must the open as read only check box be hidden? */
1363 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1365 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1366 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1369 /* Must the help button be hidden? */
1370 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1372 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1373 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1376 /* Resize the height, if open as read only checkbox ad help button
1377 are hidden and we are not using a custom template nor a customDialog
1379 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1380 (!(fodInfos->ofnInfos->Flags &
1381 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1382 (!fodInfos->DlgInfos.hwndCustomDlg ))
1384 RECT rectDlg, rectHelp, rectCancel;
1385 GetWindowRect(hwnd, &rectDlg);
1386 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1387 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1388 /* subtract the height of the help button plus the space between
1389 the help button and the cancel button to the height of the dialog */
1390 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1391 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1392 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1394 /* change Open to Save */
1395 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1397 WCHAR buf[16];
1398 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1399 SetDlgItemTextW(hwnd, IDOK, buf);
1400 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1401 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1403 return 0;
1406 /***********************************************************************
1407 * FILEDLG95_FillControls
1409 * WM_INITDIALOG message handler (after hook notification)
1411 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1413 LPITEMIDLIST pidlItemId = NULL;
1415 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1417 TRACE("dir=%s file=%s\n",
1418 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1420 /* Get the initial directory pidl */
1422 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1424 WCHAR path[MAX_PATH];
1426 GetCurrentDirectoryW(MAX_PATH,path);
1427 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1430 /* Initialise shell objects */
1431 FILEDLG95_SHELL_Init(hwnd);
1433 /* Initialize the Look In combo box */
1434 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1436 /* Initialize the filter combo box */
1437 FILEDLG95_FILETYPE_Init(hwnd);
1439 /* Browse to the initial directory */
1440 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1442 /* Free pidlItem memory */
1443 COMDLG32_SHFree(pidlItemId);
1445 return TRUE;
1447 /***********************************************************************
1448 * FILEDLG95_Clean
1450 * Regroups all the cleaning functions of the filedlg
1452 void FILEDLG95_Clean(HWND hwnd)
1454 FILEDLG95_FILETYPE_Clean(hwnd);
1455 FILEDLG95_LOOKIN_Clean(hwnd);
1456 FILEDLG95_SHELL_Clean(hwnd);
1458 /***********************************************************************
1459 * FILEDLG95_OnWMCommand
1461 * WM_COMMAND message handler
1463 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1465 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1466 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1467 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1469 switch(wID)
1471 /* OK button */
1472 case IDOK:
1473 FILEDLG95_OnOpen(hwnd);
1474 break;
1475 /* Cancel button */
1476 case IDCANCEL:
1477 FILEDLG95_Clean(hwnd);
1478 EndDialog(hwnd, FALSE);
1479 break;
1480 /* Filetype combo box */
1481 case IDC_FILETYPE:
1482 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1483 break;
1484 /* LookIn combo box */
1485 case IDC_LOOKIN:
1486 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1487 break;
1489 /* --- toolbar --- */
1490 /* Up folder button */
1491 case FCIDM_TB_UPFOLDER:
1492 FILEDLG95_SHELL_UpFolder(hwnd);
1493 break;
1494 /* New folder button */
1495 case FCIDM_TB_NEWFOLDER:
1496 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1497 break;
1498 /* List option button */
1499 case FCIDM_TB_SMALLICON:
1500 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1501 break;
1502 /* Details option button */
1503 case FCIDM_TB_REPORTVIEW:
1504 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1505 break;
1506 /* Details option button */
1507 case FCIDM_TB_DESKTOP:
1508 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1509 break;
1511 case IDC_FILENAME:
1512 break;
1515 /* Do not use the listview selection anymore */
1516 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1517 return 0;
1520 /***********************************************************************
1521 * FILEDLG95_OnWMGetIShellBrowser
1523 * WM_GETISHELLBROWSER message handler
1525 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1528 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1530 TRACE("\n");
1532 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1534 return TRUE;
1538 /***********************************************************************
1539 * FILEDLG95_SendFileOK
1541 * Sends the CDN_FILEOK notification if required
1543 * RETURNS
1544 * TRUE if the dialog should close
1545 * FALSE if the dialog should not be closed
1547 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1549 /* ask the hook if we can close */
1550 if(IsHooked(fodInfos))
1552 TRACE("---\n");
1553 /* First send CDN_FILEOK as MSDN doc says */
1554 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1555 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1557 TRACE("canceled\n");
1558 return FALSE;
1561 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1562 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1563 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1564 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1566 TRACE("canceled\n");
1567 return FALSE;
1570 return TRUE;
1573 /***********************************************************************
1574 * FILEDLG95_OnOpenMultipleFiles
1576 * Handles the opening of multiple files.
1578 * FIXME
1579 * check destination buffer size
1581 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1583 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1584 UINT nCount, nSizePath;
1585 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1587 TRACE("\n");
1589 if(fodInfos->unicode)
1591 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1592 ofn->lpstrFile[0] = '\0';
1594 else
1596 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1597 ofn->lpstrFile[0] = '\0';
1600 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1602 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1603 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1604 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1606 LPWSTR lpstrTemp = lpstrFileList;
1608 for ( nCount = 0; nCount < nFileCount; nCount++ )
1610 LPITEMIDLIST pidl;
1612 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1613 if (!pidl)
1615 WCHAR lpstrNotFound[100];
1616 WCHAR lpstrMsg[100];
1617 WCHAR tmp[400];
1618 static const WCHAR nl[] = {'\n',0};
1620 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1621 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1623 strcpyW(tmp, lpstrTemp);
1624 strcatW(tmp, nl);
1625 strcatW(tmp, lpstrNotFound);
1626 strcatW(tmp, nl);
1627 strcatW(tmp, lpstrMsg);
1629 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1630 return FALSE;
1633 /* move to the next file in the list of files */
1634 lpstrTemp += strlenW(lpstrTemp) + 1;
1635 COMDLG32_SHFree(pidl);
1639 nSizePath = strlenW(lpstrPathSpec) + 1;
1640 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1642 /* For "oldstyle" dialog the components have to
1643 be separated by blanks (not '\0'!) and short
1644 filenames have to be used! */
1645 FIXME("Components have to be separated by blanks\n");
1647 if(fodInfos->unicode)
1649 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1650 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1651 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1653 else
1655 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1657 if (ofn->lpstrFile != NULL)
1659 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1660 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1661 if (ofn->nMaxFile > nSizePath)
1663 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1664 ofn->lpstrFile + nSizePath,
1665 ofn->nMaxFile - nSizePath, NULL, NULL);
1670 fodInfos->ofnInfos->nFileOffset = nSizePath;
1671 fodInfos->ofnInfos->nFileExtension = 0;
1673 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1674 return FALSE;
1676 /* clean and exit */
1677 FILEDLG95_Clean(hwnd);
1678 return EndDialog(hwnd,TRUE);
1681 /***********************************************************************
1682 * FILEDLG95_OnOpen
1684 * Ok button WM_COMMAND message handler
1686 * If the function succeeds, the return value is nonzero.
1688 #define ONOPEN_BROWSE 1
1689 #define ONOPEN_OPEN 2
1690 #define ONOPEN_SEARCH 3
1691 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1693 WCHAR strMsgTitle[MAX_PATH];
1694 WCHAR strMsgText [MAX_PATH];
1695 if (idCaption)
1696 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1697 else
1698 strMsgTitle[0] = '\0';
1699 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1700 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1703 BOOL FILEDLG95_OnOpen(HWND hwnd)
1705 LPWSTR lpstrFileList;
1706 UINT nFileCount = 0;
1707 UINT sizeUsed = 0;
1708 BOOL ret = TRUE;
1709 WCHAR lpstrPathAndFile[MAX_PATH];
1710 WCHAR lpstrTemp[MAX_PATH];
1711 LPSHELLFOLDER lpsf = NULL;
1712 int nOpenAction;
1713 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1715 TRACE("hwnd=%p\n", hwnd);
1717 /* get the files from the edit control */
1718 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1720 /* try if the user selected a folder in the shellview */
1721 if(nFileCount == 0)
1723 BrowseSelectedFolder(hwnd);
1724 return FALSE;
1727 if(nFileCount > 1)
1729 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1730 goto ret;
1733 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1736 Step 1: Build a complete path name from the current folder and
1737 the filename or path in the edit box.
1738 Special cases:
1739 - the path in the edit box is a root path
1740 (with or without drive letter)
1741 - the edit box contains ".." (or a path with ".." in it)
1744 /* Get the current directory name */
1745 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1747 /* we are in a special folder, default to desktop */
1748 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1750 /* last fallback */
1751 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1754 PathAddBackslashW(lpstrPathAndFile);
1756 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1758 /* if the user specifyed a fully qualified path use it */
1759 if(PathIsRelativeW(lpstrFileList))
1761 strcatW(lpstrPathAndFile, lpstrFileList);
1763 else
1765 /* does the path have a drive letter? */
1766 if (PathGetDriveNumberW(lpstrFileList) == -1)
1767 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1768 else
1769 strcpyW(lpstrPathAndFile, lpstrFileList);
1772 /* resolve "." and ".." */
1773 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1774 strcpyW(lpstrPathAndFile, lpstrTemp);
1775 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1777 MemFree(lpstrFileList);
1780 Step 2: here we have a cleaned up path
1782 We have to parse the path step by step to see if we have to browse
1783 to a folder if the path points to a directory or the last
1784 valid element is a directory.
1786 valid variables:
1787 lpstrPathAndFile: cleaned up path
1790 nOpenAction = ONOPEN_BROWSE;
1792 /* don't apply any checks with OFN_NOVALIDATE */
1794 LPWSTR lpszTemp, lpszTemp1;
1795 LPITEMIDLIST pidl = NULL;
1796 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1798 /* check for invalid chars */
1799 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1801 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1802 ret = FALSE;
1803 goto ret;
1806 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1808 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1809 while (lpszTemp1)
1811 LPSHELLFOLDER lpsfChild;
1812 WCHAR lpwstrTemp[MAX_PATH];
1813 DWORD dwEaten, dwAttributes;
1814 LPWSTR p;
1816 strcpyW(lpwstrTemp, lpszTemp);
1817 p = PathFindNextComponentW(lpwstrTemp);
1819 if (!p) break; /* end of path */
1821 *p = 0;
1822 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1824 if(*lpszTemp==0)
1826 static const WCHAR wszWild[] = { '*', '?', 0 };
1827 /* if the last element is a wildcard do a search */
1828 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1830 nOpenAction = ONOPEN_SEARCH;
1831 break;
1834 lpszTemp1 = lpszTemp;
1836 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1838 /* append a backslash to drive letters */
1839 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1840 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1841 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1843 PathAddBackslashW(lpwstrTemp);
1846 dwAttributes = SFGAO_FOLDER;
1847 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1849 /* the path component is valid, we have a pidl of the next path component */
1850 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1851 if(dwAttributes & SFGAO_FOLDER)
1853 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1855 ERR("bind to failed\n"); /* should not fail */
1856 break;
1858 IShellFolder_Release(lpsf);
1859 lpsf = lpsfChild;
1860 lpsfChild = NULL;
1862 else
1864 TRACE("value\n");
1866 /* end dialog, return value */
1867 nOpenAction = ONOPEN_OPEN;
1868 break;
1870 COMDLG32_SHFree(pidl);
1871 pidl = NULL;
1873 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1875 if(*lpszTemp) /* points to trailing null for last path element */
1877 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1879 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1880 break;
1883 else
1885 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1886 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1888 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1889 break;
1892 /* change to the current folder */
1893 nOpenAction = ONOPEN_OPEN;
1894 break;
1896 else
1898 nOpenAction = ONOPEN_OPEN;
1899 break;
1902 if(pidl) COMDLG32_SHFree(pidl);
1906 Step 3: here we have a cleaned up and validated path
1908 valid variables:
1909 lpsf: ShellFolder bound to the rightmost valid path component
1910 lpstrPathAndFile: cleaned up path
1911 nOpenAction: action to do
1913 TRACE("end validate sf=%p\n", lpsf);
1915 switch(nOpenAction)
1917 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1918 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1920 int iPos;
1921 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1922 DWORD len;
1924 /* replace the current filter */
1925 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1926 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1927 len = strlenW(lpszTemp)+1;
1928 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1929 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1931 /* set the filter cb to the extension when possible */
1932 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1933 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1935 /* fall through */
1936 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1937 TRACE("ONOPEN_BROWSE\n");
1939 IPersistFolder2 * ppf2;
1940 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1942 LPITEMIDLIST pidlCurrent;
1943 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1944 IPersistFolder2_Release(ppf2);
1945 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1947 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1949 else if( nOpenAction == ONOPEN_SEARCH )
1951 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1953 COMDLG32_SHFree(pidlCurrent);
1956 ret = FALSE;
1957 break;
1958 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1959 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1961 WCHAR *ext = NULL;
1963 /* update READONLY check box flag */
1964 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1965 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1966 else
1967 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1969 /* Attach the file extension with file name*/
1970 ext = PathFindExtensionW(lpstrPathAndFile);
1971 if (! *ext)
1973 /* if no extension is specified with file name, then */
1974 /* attach the extension from file filter or default one */
1976 WCHAR *filterExt = NULL;
1977 LPWSTR lpstrFilter = NULL;
1978 static const WCHAR szwDot[] = {'.',0};
1979 int PathLength = strlenW(lpstrPathAndFile);
1981 /* Attach the dot*/
1982 strcatW(lpstrPathAndFile, szwDot);
1984 /*Get the file extension from file type filter*/
1985 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1986 fodInfos->ofnInfos->nFilterIndex-1);
1988 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
1989 filterExt = PathFindExtensionW(lpstrFilter);
1991 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
1992 strcatW(lpstrPathAndFile, filterExt + 1);
1993 else if ( fodInfos->defext ) /* attach the default file extension*/
1994 strcatW(lpstrPathAndFile, fodInfos->defext);
1996 /* In Open dialog: if file does not exist try without extension */
1997 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
1998 lpstrPathAndFile[PathLength] = '\0';
2001 if (fodInfos->defext) /* add default extension */
2003 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2004 if (*ext)
2005 ext++;
2006 if (!lstrcmpiW(fodInfos->defext, ext))
2007 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2008 else
2009 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2012 /* In Save dialog: check if the file already exists */
2013 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2014 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2015 && PathFileExistsW(lpstrPathAndFile))
2017 WCHAR lpstrOverwrite[100];
2018 int answer;
2020 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2021 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2022 MB_YESNO | MB_ICONEXCLAMATION);
2023 if (answer == IDNO)
2025 ret = FALSE;
2026 goto ret;
2030 /* Check that the size of the file does not exceed buffer size.
2031 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2032 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2033 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2035 LPWSTR lpszTemp;
2037 /* fill destination buffer */
2038 if (fodInfos->ofnInfos->lpstrFile)
2040 if(fodInfos->unicode)
2042 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2044 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2045 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2046 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2048 else
2050 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2052 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2053 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2054 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2055 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2059 /* set filename offset */
2060 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2061 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2063 /* set extension offset */
2064 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2065 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2067 /* set the lpstrFileTitle */
2068 if(fodInfos->ofnInfos->lpstrFileTitle)
2070 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2071 if(fodInfos->unicode)
2073 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2074 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2076 else
2078 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2079 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2080 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2084 /* copy currently selected filter to lpstrCustomFilter */
2085 if (fodInfos->ofnInfos->lpstrCustomFilter)
2087 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2088 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2089 NULL, 0, NULL, NULL);
2090 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2092 LPSTR s = ofn->lpstrCustomFilter;
2093 s += strlen(ofn->lpstrCustomFilter)+1;
2094 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2095 s, len, NULL, NULL);
2100 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2101 goto ret;
2103 TRACE("close\n");
2104 FILEDLG95_Clean(hwnd);
2105 ret = EndDialog(hwnd, TRUE);
2107 else
2109 WORD size;
2111 size = strlenW(lpstrPathAndFile) + 1;
2112 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2113 size += 1;
2114 /* return needed size in first two bytes of lpstrFile */
2115 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2116 FILEDLG95_Clean(hwnd);
2117 ret = EndDialog(hwnd, FALSE);
2118 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2120 goto ret;
2122 break;
2125 ret:
2126 if(lpsf) IShellFolder_Release(lpsf);
2127 return ret;
2130 /***********************************************************************
2131 * FILEDLG95_SHELL_Init
2133 * Initialisation of the shell objects
2135 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2137 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2139 TRACE("\n");
2142 * Initialisation of the FileOpenDialogInfos structure
2145 /* Shell */
2147 /*ShellInfos */
2148 fodInfos->ShellInfos.hwndOwner = hwnd;
2150 /* Disable multi-select if flag not set */
2151 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2153 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2155 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2156 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2158 /* Construct the IShellBrowser interface */
2159 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2161 return NOERROR;
2164 /***********************************************************************
2165 * FILEDLG95_SHELL_ExecuteCommand
2167 * Change the folder option and refresh the view
2168 * If the function succeeds, the return value is nonzero.
2170 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2172 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2174 IContextMenu * pcm;
2175 TRACE("(%p,%p)\n", hwnd, lpVerb);
2177 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2178 SVGIO_BACKGROUND,
2179 &IID_IContextMenu,
2180 (LPVOID*)&pcm)))
2182 CMINVOKECOMMANDINFO ci;
2183 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2184 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2185 ci.lpVerb = lpVerb;
2186 ci.hwnd = hwnd;
2188 IContextMenu_InvokeCommand(pcm, &ci);
2189 IContextMenu_Release(pcm);
2192 return FALSE;
2195 /***********************************************************************
2196 * FILEDLG95_SHELL_UpFolder
2198 * Browse to the specified object
2199 * If the function succeeds, the return value is nonzero.
2201 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2203 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2205 TRACE("\n");
2207 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2208 NULL,
2209 SBSP_PARENT)))
2211 return TRUE;
2213 return FALSE;
2216 /***********************************************************************
2217 * FILEDLG95_SHELL_BrowseToDesktop
2219 * Browse to the Desktop
2220 * If the function succeeds, the return value is nonzero.
2222 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2224 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2225 LPITEMIDLIST pidl;
2226 HRESULT hres;
2228 TRACE("\n");
2230 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2231 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2232 COMDLG32_SHFree(pidl);
2233 return SUCCEEDED(hres);
2235 /***********************************************************************
2236 * FILEDLG95_SHELL_Clean
2238 * Cleans the memory used by shell objects
2240 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2242 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2244 TRACE("\n");
2246 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2248 /* clean Shell interfaces */
2249 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2250 IShellView_Release(fodInfos->Shell.FOIShellView);
2251 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2252 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2253 if (fodInfos->Shell.FOIDataObject)
2254 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2257 /***********************************************************************
2258 * FILEDLG95_FILETYPE_Init
2260 * Initialisation of the file type combo box
2262 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2264 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2265 int nFilters = 0; /* number of filters */
2266 int nFilterIndexCB;
2268 TRACE("\n");
2270 if(fodInfos->customfilter)
2272 /* customfilter has one entry... title\0ext\0
2273 * Set first entry of combo box item with customfilter
2275 LPWSTR lpstrExt;
2276 LPCWSTR lpstrPos = fodInfos->customfilter;
2278 /* Get the title */
2279 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2281 /* Copy the extensions */
2282 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2283 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2284 strcpyW(lpstrExt,lpstrPos);
2286 /* Add the item at the end of the combo */
2287 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2288 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2289 nFilters++;
2291 if(fodInfos->filter)
2293 LPCWSTR lpstrPos = fodInfos->filter;
2295 for(;;)
2297 /* filter is a list... title\0ext\0......\0\0
2298 * Set the combo item text to the title and the item data
2299 * to the ext
2301 LPCWSTR lpstrDisplay;
2302 LPWSTR lpstrExt;
2304 /* Get the title */
2305 if(! *lpstrPos) break; /* end */
2306 lpstrDisplay = lpstrPos;
2307 lpstrPos += strlenW(lpstrPos) + 1;
2309 /* Copy the extensions */
2310 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2311 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2312 strcpyW(lpstrExt,lpstrPos);
2313 lpstrPos += strlenW(lpstrPos) + 1;
2315 /* Add the item at the end of the combo */
2316 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2317 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2318 nFilters++;
2323 * Set the current filter to the one specified
2324 * in the initialisation structure
2326 if (fodInfos->filter || fodInfos->customfilter)
2328 LPWSTR lpstrFilter;
2330 /* Check to make sure our index isn't out of bounds. */
2331 if ( fodInfos->ofnInfos->nFilterIndex >
2332 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2333 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2335 /* set default filter index */
2336 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2337 fodInfos->ofnInfos->nFilterIndex = 1;
2339 /* calculate index of Combo Box item */
2340 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2341 if (fodInfos->customfilter == NULL)
2342 nFilterIndexCB--;
2344 /* Set the current index selection. */
2345 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2347 /* Get the corresponding text string from the combo box. */
2348 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2349 nFilterIndexCB);
2351 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2352 lpstrFilter = NULL;
2354 if(lpstrFilter)
2356 DWORD len;
2357 CharLowerW(lpstrFilter); /* lowercase */
2358 len = strlenW(lpstrFilter)+1;
2359 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2360 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2362 } else
2363 fodInfos->ofnInfos->nFilterIndex = 0;
2365 return NOERROR;
2368 /***********************************************************************
2369 * FILEDLG95_FILETYPE_OnCommand
2371 * WM_COMMAND of the file type combo box
2372 * If the function succeeds, the return value is nonzero.
2374 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2376 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2378 switch(wNotifyCode)
2380 case CBN_SELENDOK:
2382 LPWSTR lpstrFilter;
2384 /* Get the current item of the filetype combo box */
2385 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2387 /* set the current filter index */
2388 fodInfos->ofnInfos->nFilterIndex = iItem +
2389 (fodInfos->customfilter == NULL ? 1 : 0);
2391 /* Set the current filter with the current selection */
2392 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2393 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2395 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2396 iItem);
2397 if((int)lpstrFilter != CB_ERR)
2399 DWORD len;
2400 CharLowerW(lpstrFilter); /* lowercase */
2401 len = strlenW(lpstrFilter)+1;
2402 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2403 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2404 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2407 /* Refresh the actual view to display the included items*/
2408 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2411 return FALSE;
2413 /***********************************************************************
2414 * FILEDLG95_FILETYPE_SearchExt
2416 * searches for an extension in the filetype box
2418 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2420 int i, iCount = CBGetCount(hwnd);
2422 TRACE("%s\n", debugstr_w(lpstrExt));
2424 if(iCount != CB_ERR)
2426 for(i=0;i<iCount;i++)
2428 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2429 return i;
2432 return -1;
2435 /***********************************************************************
2436 * FILEDLG95_FILETYPE_Clean
2438 * Clean the memory used by the filetype combo box
2440 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2442 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2443 int iPos;
2444 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2446 TRACE("\n");
2448 /* Delete each string of the combo and their associated data */
2449 if(iCount != CB_ERR)
2451 for(iPos = iCount-1;iPos>=0;iPos--)
2453 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2454 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2457 /* Current filter */
2458 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2459 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2463 /***********************************************************************
2464 * FILEDLG95_LOOKIN_Init
2466 * Initialisation of the look in combo box
2468 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2470 IShellFolder *psfRoot, *psfDrives;
2471 IEnumIDList *lpeRoot, *lpeDrives;
2472 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2474 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2476 TRACE("\n");
2478 liInfos->iMaxIndentation = 0;
2480 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2482 /* set item height for both text field and listbox */
2483 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2484 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2486 /* Turn on the extended UI for the combo box like Windows does */
2487 CBSetExtendedUI(hwndCombo, TRUE);
2489 /* Initialise data of Desktop folder */
2490 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2491 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2492 COMDLG32_SHFree(pidlTmp);
2494 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2496 SHGetDesktopFolder(&psfRoot);
2498 if (psfRoot)
2500 /* enumerate the contents of the desktop */
2501 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2503 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2505 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2507 /* special handling for CSIDL_DRIVES */
2508 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2510 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2512 /* enumerate the drives */
2513 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2515 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2517 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2518 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2519 COMDLG32_SHFree(pidlAbsTmp);
2520 COMDLG32_SHFree(pidlTmp1);
2522 IEnumIDList_Release(lpeDrives);
2524 IShellFolder_Release(psfDrives);
2527 COMDLG32_SHFree(pidlTmp);
2529 IEnumIDList_Release(lpeRoot);
2531 IShellFolder_Release(psfRoot);
2534 COMDLG32_SHFree(pidlDrives);
2535 return NOERROR;
2538 /***********************************************************************
2539 * FILEDLG95_LOOKIN_DrawItem
2541 * WM_DRAWITEM message handler
2543 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2545 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2546 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2547 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2548 RECT rectText;
2549 RECT rectIcon;
2550 SHFILEINFOA sfi;
2551 HIMAGELIST ilItemImage;
2552 int iIndentation;
2553 TEXTMETRICA tm;
2554 LPSFOLDER tmpFolder;
2557 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2559 TRACE("\n");
2561 if(pDIStruct->itemID == -1)
2562 return 0;
2564 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2565 pDIStruct->itemID)))
2566 return 0;
2569 if(pDIStruct->itemID == liInfos->uSelectedItem)
2571 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2573 &sfi,
2574 sizeof (SHFILEINFOA),
2575 SHGFI_PIDL | SHGFI_SMALLICON |
2576 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2577 SHGFI_DISPLAYNAME );
2579 else
2581 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2583 &sfi,
2584 sizeof (SHFILEINFOA),
2585 SHGFI_PIDL | SHGFI_SMALLICON |
2586 SHGFI_SYSICONINDEX |
2587 SHGFI_DISPLAYNAME);
2590 /* Is this item selected ? */
2591 if(pDIStruct->itemState & ODS_SELECTED)
2593 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2594 SetBkColor(pDIStruct->hDC,crHighLight);
2595 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2597 else
2599 SetTextColor(pDIStruct->hDC,crText);
2600 SetBkColor(pDIStruct->hDC,crWin);
2601 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2604 /* Do not indent item if drawing in the edit of the combo */
2605 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2607 iIndentation = 0;
2608 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2610 &sfi,
2611 sizeof (SHFILEINFOA),
2612 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2613 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2616 else
2618 iIndentation = tmpFolder->m_iIndent;
2620 /* Draw text and icon */
2622 /* Initialise the icon display area */
2623 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2624 rectIcon.top = pDIStruct->rcItem.top;
2625 rectIcon.right = rectIcon.left + ICONWIDTH;
2626 rectIcon.bottom = pDIStruct->rcItem.bottom;
2628 /* Initialise the text display area */
2629 GetTextMetricsA(pDIStruct->hDC, &tm);
2630 rectText.left = rectIcon.right;
2631 rectText.top =
2632 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2633 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2634 rectText.bottom =
2635 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2637 /* Draw the icon from the image list */
2638 ImageList_Draw(ilItemImage,
2639 sfi.iIcon,
2640 pDIStruct->hDC,
2641 rectIcon.left,
2642 rectIcon.top,
2643 ILD_TRANSPARENT );
2645 /* Draw the associated text */
2646 if(sfi.szDisplayName)
2647 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2650 return NOERROR;
2653 /***********************************************************************
2654 * FILEDLG95_LOOKIN_OnCommand
2656 * LookIn combo box WM_COMMAND message handler
2657 * If the function succeeds, the return value is nonzero.
2659 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2661 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2663 TRACE("%p\n", fodInfos);
2665 switch(wNotifyCode)
2667 case CBN_SELENDOK:
2669 LPSFOLDER tmpFolder;
2670 int iItem;
2672 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2674 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2675 iItem)))
2676 return FALSE;
2679 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2680 tmpFolder->pidlItem,
2681 SBSP_ABSOLUTE)))
2683 return TRUE;
2685 break;
2689 return FALSE;
2692 /***********************************************************************
2693 * FILEDLG95_LOOKIN_AddItem
2695 * Adds an absolute pidl item to the lookin combo box
2696 * returns the index of the inserted item
2698 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2700 LPITEMIDLIST pidlNext;
2701 SHFILEINFOA sfi;
2702 SFOLDER *tmpFolder;
2703 LookInInfos *liInfos;
2705 TRACE("%08x\n", iInsertId);
2707 if(!pidl)
2708 return -1;
2710 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2711 return -1;
2713 tmpFolder = MemAlloc(sizeof(SFOLDER));
2714 tmpFolder->m_iIndent = 0;
2716 /* Calculate the indentation of the item in the lookin*/
2717 pidlNext = pidl;
2718 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2720 tmpFolder->m_iIndent++;
2723 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2725 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2726 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2728 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2729 SHGetFileInfoA((LPSTR)pidl,
2731 &sfi,
2732 sizeof(sfi),
2733 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2734 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2736 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2738 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2740 int iItemID;
2742 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2744 /* Add the item at the end of the list */
2745 if(iInsertId < 0)
2747 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2749 /* Insert the item at the iInsertId position*/
2750 else
2752 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2755 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2756 return iItemID;
2759 COMDLG32_SHFree( tmpFolder->pidlItem );
2760 MemFree( tmpFolder );
2761 return -1;
2765 /***********************************************************************
2766 * FILEDLG95_LOOKIN_InsertItemAfterParent
2768 * Insert an item below its parent
2770 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2773 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2774 int iParentPos;
2776 TRACE("\n");
2778 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2780 if(iParentPos < 0)
2782 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2785 /* Free pidlParent memory */
2786 COMDLG32_SHFree((LPVOID)pidlParent);
2788 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2791 /***********************************************************************
2792 * FILEDLG95_LOOKIN_SelectItem
2794 * Adds an absolute pidl item to the lookin combo box
2795 * returns the index of the inserted item
2797 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2799 int iItemPos;
2800 LookInInfos *liInfos;
2802 TRACE("\n");
2804 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2806 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2808 if(iItemPos < 0)
2810 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2811 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2814 else
2816 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2817 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2819 int iRemovedItem;
2821 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2822 break;
2823 if(iRemovedItem < iItemPos)
2824 iItemPos--;
2828 CBSetCurSel(hwnd,iItemPos);
2829 liInfos->uSelectedItem = iItemPos;
2831 return 0;
2835 /***********************************************************************
2836 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2838 * Remove the item with an expansion level over iExpansionLevel
2840 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2842 int iItemPos;
2844 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2846 TRACE("\n");
2848 if(liInfos->iMaxIndentation <= 2)
2849 return -1;
2851 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2853 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2854 COMDLG32_SHFree(tmpFolder->pidlItem);
2855 MemFree(tmpFolder);
2856 CBDeleteString(hwnd,iItemPos);
2857 liInfos->iMaxIndentation--;
2859 return iItemPos;
2862 return -1;
2865 /***********************************************************************
2866 * FILEDLG95_LOOKIN_SearchItem
2868 * Search for pidl in the lookin combo box
2869 * returns the index of the found item
2871 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2873 int i = 0;
2874 int iCount = CBGetCount(hwnd);
2876 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2878 if (iCount != CB_ERR)
2880 for(;i<iCount;i++)
2882 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2884 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2885 return i;
2886 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2887 return i;
2891 return -1;
2894 /***********************************************************************
2895 * FILEDLG95_LOOKIN_Clean
2897 * Clean the memory used by the lookin combo box
2899 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2901 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2902 int iPos;
2903 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2905 TRACE("\n");
2907 /* Delete each string of the combo and their associated data */
2908 if (iCount != CB_ERR)
2910 for(iPos = iCount-1;iPos>=0;iPos--)
2912 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2913 COMDLG32_SHFree(tmpFolder->pidlItem);
2914 MemFree(tmpFolder);
2915 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2919 /* LookInInfos structure */
2920 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2923 /***********************************************************************
2924 * FILEDLG95_FILENAME_FillFromSelection
2926 * fills the edit box from the cached DataObject
2928 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2930 FileOpenDlgInfos *fodInfos;
2931 LPITEMIDLIST pidl;
2932 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2933 char lpstrTemp[MAX_PATH];
2934 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2936 TRACE("\n");
2937 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2939 /* Count how many files we have */
2940 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2942 /* calculate the string length, count files */
2943 if (nFileSelected >= 1)
2945 nLength += 3; /* first and last quotes, trailing \0 */
2946 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2948 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2950 if (pidl)
2952 /* get the total length of the selected file names */
2953 lpstrTemp[0] = '\0';
2954 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2956 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2958 nLength += strlen( lpstrTemp ) + 3;
2959 nFiles++;
2961 COMDLG32_SHFree( pidl );
2966 /* allocate the buffer */
2967 if (nFiles <= 1) nLength = MAX_PATH;
2968 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2969 lpstrAllFile[0] = '\0';
2971 /* Generate the string for the edit control */
2972 if(nFiles >= 1)
2974 lpstrCurrFile = lpstrAllFile;
2975 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2977 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2979 if (pidl)
2981 /* get the file name */
2982 lpstrTemp[0] = '\0';
2983 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2985 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2987 if ( nFiles > 1)
2989 *lpstrCurrFile++ = '\"';
2990 strcpy( lpstrCurrFile, lpstrTemp );
2991 lpstrCurrFile += strlen( lpstrTemp );
2992 strcpy( lpstrCurrFile, "\" " );
2993 lpstrCurrFile += 2;
2995 else
2997 strcpy( lpstrAllFile, lpstrTemp );
3000 COMDLG32_SHFree( (LPVOID) pidl );
3003 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3005 /* Select the file name like Windows does */
3006 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3008 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3012 /* copied from shell32 to avoid linking to it */
3013 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3015 switch (src->uType)
3017 case STRRET_WSTR:
3018 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3019 COMDLG32_SHFree(src->u.pOleStr);
3020 break;
3022 case STRRET_CSTR:
3023 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3024 break;
3026 case STRRET_OFFSET:
3027 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3028 break;
3030 default:
3031 FIXME("unknown type!\n");
3032 if (len)
3034 *(LPSTR)dest = '\0';
3036 return(FALSE);
3038 return S_OK;
3041 /***********************************************************************
3042 * FILEDLG95_FILENAME_GetFileNames
3044 * Copies the filenames to a delimited string list.
3045 * The delimiter is specified by the parameter 'separator',
3046 * usually either a space or a nul
3048 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3050 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3051 UINT nStrCharCount = 0; /* index in src buffer */
3052 UINT nFileIndex = 0; /* index in dest buffer */
3053 UINT nFileCount = 0; /* number of files */
3054 UINT nStrLen = 0; /* length of string in edit control */
3055 LPWSTR lpstrEdit; /* buffer for string from edit control */
3057 TRACE("\n");
3059 /* get the filenames from the edit control */
3060 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3061 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3062 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3064 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3066 /* we might get single filename without any '"',
3067 * so we need nStrLen + terminating \0 + end-of-list \0 */
3068 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3069 *sizeUsed = 0;
3071 /* build delimited file list from filenames */
3072 while ( nStrCharCount <= nStrLen )
3074 if ( lpstrEdit[nStrCharCount]=='"' )
3076 nStrCharCount++;
3077 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3079 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3080 (*sizeUsed)++;
3081 nStrCharCount++;
3083 (*lpstrFileList)[nFileIndex++] = separator;
3084 (*sizeUsed)++;
3085 nFileCount++;
3087 nStrCharCount++;
3090 /* single, unquoted string */
3091 if ((nStrLen > 0) && (*sizeUsed == 0) )
3093 strcpyW(*lpstrFileList, lpstrEdit);
3094 nFileIndex = strlenW(lpstrEdit) + 1;
3095 (*sizeUsed) = nFileIndex;
3096 nFileCount = 1;
3099 /* trailing \0 */
3100 (*lpstrFileList)[nFileIndex] = '\0';
3101 (*sizeUsed)++;
3103 MemFree(lpstrEdit);
3104 return nFileCount;
3107 #define SETDefFormatEtc(fe,cf,med) \
3109 (fe).cfFormat = cf;\
3110 (fe).dwAspect = DVASPECT_CONTENT; \
3111 (fe).ptd =NULL;\
3112 (fe).tymed = med;\
3113 (fe).lindex = -1;\
3117 * DATAOBJECT Helper functions
3120 /***********************************************************************
3121 * COMCTL32_ReleaseStgMedium
3123 * like ReleaseStgMedium from ole32
3125 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3127 if(medium.pUnkForRelease)
3129 IUnknown_Release(medium.pUnkForRelease);
3131 else
3133 GlobalUnlock(medium.u.hGlobal);
3134 GlobalFree(medium.u.hGlobal);
3138 /***********************************************************************
3139 * GetPidlFromDataObject
3141 * Return pidl(s) by number from the cached DataObject
3143 * nPidlIndex=0 gets the fully qualified root path
3145 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3148 STGMEDIUM medium;
3149 FORMATETC formatetc;
3150 LPITEMIDLIST pidl = NULL;
3152 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3154 /* Set the FORMATETC structure*/
3155 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3157 /* Get the pidls from IDataObject */
3158 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3160 LPIDA cida = GlobalLock(medium.u.hGlobal);
3161 if(nPidlIndex <= cida->cidl)
3163 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3165 COMCTL32_ReleaseStgMedium(medium);
3167 return pidl;
3170 /***********************************************************************
3171 * GetNumSelected
3173 * Return the number of selected items in the DataObject.
3176 UINT GetNumSelected( IDataObject *doSelected )
3178 UINT retVal = 0;
3179 STGMEDIUM medium;
3180 FORMATETC formatetc;
3182 TRACE("sv=%p\n", doSelected);
3184 if (!doSelected) return 0;
3186 /* Set the FORMATETC structure*/
3187 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3189 /* Get the pidls from IDataObject */
3190 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3192 LPIDA cida = GlobalLock(medium.u.hGlobal);
3193 retVal = cida->cidl;
3194 COMCTL32_ReleaseStgMedium(medium);
3195 return retVal;
3197 return 0;
3201 * TOOLS
3204 /***********************************************************************
3205 * GetName
3207 * Get the pidl's display name (relative to folder) and
3208 * put it in lpstrFileName.
3210 * Return NOERROR on success,
3211 * E_FAIL otherwise
3214 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3216 STRRET str;
3217 HRESULT hRes;
3219 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3221 if(!lpsf)
3223 SHGetDesktopFolder(&lpsf);
3224 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3225 IShellFolder_Release(lpsf);
3226 return hRes;
3229 /* Get the display name of the pidl relative to the folder */
3230 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3232 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3234 return E_FAIL;
3237 /***********************************************************************
3238 * GetShellFolderFromPidl
3240 * pidlRel is the item pidl relative
3241 * Return the IShellFolder of the absolute pidl
3243 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3245 IShellFolder *psf = NULL,*psfParent;
3247 TRACE("%p\n", pidlAbs);
3249 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3251 psf = psfParent;
3252 if(pidlAbs && pidlAbs->mkid.cb)
3254 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3256 IShellFolder_Release(psfParent);
3257 return psf;
3260 /* return the desktop */
3261 return psfParent;
3263 return NULL;
3266 /***********************************************************************
3267 * GetParentPidl
3269 * Return the LPITEMIDLIST to the parent of the pidl in the list
3271 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3273 LPITEMIDLIST pidlParent;
3275 TRACE("%p\n", pidl);
3277 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3278 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3280 return pidlParent;
3283 /***********************************************************************
3284 * GetPidlFromName
3286 * returns the pidl of the file name relative to folder
3287 * NULL if an error occurred
3289 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3291 LPITEMIDLIST pidl = NULL;
3292 ULONG ulEaten;
3294 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3296 if(!lpcstrFileName) return NULL;
3297 if(!*lpcstrFileName) return NULL;
3299 if(!lpsf)
3301 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3302 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3303 IShellFolder_Release(lpsf);
3306 else
3308 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3310 return pidl;
3315 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3317 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3318 HRESULT ret;
3320 TRACE("%p, %p\n", psf, pidl);
3322 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3324 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3325 /* see documentation shell 4.1*/
3326 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3329 /***********************************************************************
3330 * BrowseSelectedFolder
3332 static BOOL BrowseSelectedFolder(HWND hwnd)
3334 BOOL bBrowseSelFolder = FALSE;
3335 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3337 TRACE("\n");
3339 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3341 LPITEMIDLIST pidlSelection;
3343 /* get the file selected */
3344 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3345 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3347 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3348 pidlSelection, SBSP_RELATIVE ) ) )
3350 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3351 ' ','n','o','t',' ','e','x','i','s','t',0};
3352 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3355 bBrowseSelFolder = TRUE;
3357 COMDLG32_SHFree( pidlSelection );
3360 return bBrowseSelFolder;
3364 * Memory allocation methods */
3365 static void *MemAlloc(UINT size)
3367 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3370 static void MemFree(void *mem)
3372 HeapFree(GetProcessHeap(),0,mem);
3376 * Old-style (win3.1) dialogs */
3378 /***********************************************************************
3379 * FD32_GetTemplate [internal]
3381 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3382 * by a 32 bits application
3385 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3387 LPOPENFILENAMEW ofnW = lfs->ofnW;
3388 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3389 HANDLE hDlgTmpl;
3391 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3393 if (!(lfs->template = LockResource( ofnW->hInstance )))
3395 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3396 return FALSE;
3399 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3401 HRSRC hResInfo;
3402 if (priv->ofnA)
3403 hResInfo = FindResourceA(priv->ofnA->hInstance,
3404 priv->ofnA->lpTemplateName,
3405 (LPSTR)RT_DIALOG);
3406 else
3407 hResInfo = FindResourceW(ofnW->hInstance,
3408 ofnW->lpTemplateName,
3409 (LPWSTR)RT_DIALOG);
3410 if (!hResInfo)
3412 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3413 return FALSE;
3415 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3416 hResInfo)) ||
3417 !(lfs->template = LockResource(hDlgTmpl)))
3419 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3420 return FALSE;
3422 } else { /* get it from internal Wine resource */
3423 HRSRC hResInfo;
3424 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3425 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3427 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3428 return FALSE;
3430 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3431 !(lfs->template = LockResource( hDlgTmpl )))
3433 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3434 return FALSE;
3437 return TRUE;
3441 /************************************************************************
3442 * FD32_Init [internal]
3443 * called from the common 16/32 code to initialize 32 bit data
3445 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3447 BOOL IsUnicode = (BOOL) data;
3448 PFD32_PRIVATE priv;
3450 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3451 lfs->private1632 = priv;
3452 if (NULL == lfs->private1632) return FALSE;
3453 if (IsUnicode)
3455 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3456 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3457 if (lfs->ofnW->lpfnHook)
3458 lfs->hook = TRUE;
3460 else
3462 priv->ofnA = (LPOPENFILENAMEA) lParam;
3463 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3464 if (priv->ofnA->lpfnHook)
3465 lfs->hook = TRUE;
3466 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3467 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3470 if (! FD32_GetTemplate(lfs)) return FALSE;
3472 return TRUE;
3475 /***********************************************************************
3476 * FD32_CallWindowProc [internal]
3478 * called from the common 16/32 code to call the appropriate hook
3480 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3481 LPARAM lParam)
3483 BOOL ret;
3484 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3486 if (priv->ofnA)
3488 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3489 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3490 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3491 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3492 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3493 return ret;
3496 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3497 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3498 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3499 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3500 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3501 return ret;
3504 /***********************************************************************
3505 * FD32_UpdateResult [internal]
3506 * update the real client structures if any
3508 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3510 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3511 LPOPENFILENAMEW ofnW = lfs->ofnW;
3513 if (priv->ofnA)
3515 if (ofnW->nMaxFile &&
3516 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3517 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3518 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3519 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3520 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3524 /***********************************************************************
3525 * FD32_UpdateFileTitle [internal]
3526 * update the real client structures if any
3528 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3530 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3531 LPOPENFILENAMEW ofnW = lfs->ofnW;
3533 if (priv->ofnA)
3535 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3536 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3537 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3542 /***********************************************************************
3543 * FD32_SendLbGetCurSel [internal]
3544 * retrieve selected listbox item
3546 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3548 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3552 /************************************************************************
3553 * FD32_Destroy [internal]
3554 * called from the common 16/32 code to cleanup 32 bit data
3556 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3558 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3560 /* if ofnW has been allocated, have to free everything in it */
3561 if (NULL != priv && NULL != priv->ofnA)
3563 FD31_FreeOfnW(lfs->ofnW);
3564 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3568 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3570 callbacks->Init = FD32_Init;
3571 callbacks->CWP = FD32_CallWindowProc;
3572 callbacks->UpdateResult = FD32_UpdateResult;
3573 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3574 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3575 callbacks->Destroy = FD32_Destroy;
3578 /***********************************************************************
3579 * FD32_WMMeasureItem [internal]
3581 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3583 LPMEASUREITEMSTRUCT lpmeasure;
3585 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3586 lpmeasure->itemHeight = FD31_GetFldrHeight();
3587 return TRUE;
3591 /***********************************************************************
3592 * FileOpenDlgProc [internal]
3593 * Used for open and save, in fact.
3595 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3596 WPARAM wParam, LPARAM lParam)
3598 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3600 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3601 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3603 INT_PTR lRet;
3604 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3605 if (lRet)
3606 return lRet; /* else continue message processing */
3608 switch (wMsg)
3610 case WM_INITDIALOG:
3611 return FD31_WMInitDialog(hWnd, wParam, lParam);
3613 case WM_MEASUREITEM:
3614 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3616 case WM_DRAWITEM:
3617 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3619 case WM_COMMAND:
3620 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3621 #if 0
3622 case WM_CTLCOLOR:
3623 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3624 switch (HIWORD(lParam))
3626 case CTLCOLOR_BTN:
3627 SetTextColor((HDC16)wParam, 0x00000000);
3628 return hGRAYBrush;
3629 case CTLCOLOR_STATIC:
3630 SetTextColor((HDC16)wParam, 0x00000000);
3631 return hGRAYBrush;
3633 break;
3634 #endif
3636 return FALSE;
3640 /***********************************************************************
3641 * GetFileName31A [internal]
3643 * Creates a win31 style dialog box for the user to select a file to open/save.
3645 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3646 UINT dlgType /* type dialogue : open/save */
3649 HINSTANCE hInst;
3650 BOOL bRet = FALSE;
3651 PFD31_DATA lfs;
3652 FD31_CALLBACKS callbacks;
3654 if (!lpofn || !FD31_Init()) return FALSE;
3656 TRACE("ofn flags %08lx\n", lpofn->Flags);
3657 FD32_SetupCallbacks(&callbacks);
3658 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3659 if (lfs)
3661 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3662 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3663 FD32_FileOpenDlgProc, (LPARAM)lfs);
3664 FD31_DestroyPrivate(lfs);
3667 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3668 return bRet;
3671 /***********************************************************************
3672 * GetFileName31W [internal]
3674 * Creates a win31 style dialog box for the user to select a file to open/save
3676 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3677 UINT dlgType /* type dialogue : open/save */
3680 HINSTANCE hInst;
3681 BOOL bRet = FALSE;
3682 PFD31_DATA lfs;
3683 FD31_CALLBACKS callbacks;
3685 if (!lpofn || !FD31_Init()) return FALSE;
3687 FD32_SetupCallbacks(&callbacks);
3688 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3689 if (lfs)
3691 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3692 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3693 FD32_FileOpenDlgProc, (LPARAM)lfs);
3694 FD31_DestroyPrivate(lfs);
3697 TRACE("file %s, file offset %d, ext offset %d\n",
3698 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3699 return bRet;
3702 /* ------------------ APIs ---------------------- */
3704 /***********************************************************************
3705 * GetOpenFileNameA (COMDLG32.@)
3707 * Creates a dialog box for the user to select a file to open.
3709 * RETURNS
3710 * TRUE on success: user enters a valid file
3711 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3714 BOOL WINAPI GetOpenFileNameA(
3715 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3717 BOOL win16look = FALSE;
3719 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3720 if (ofn->Flags & OFN_FILEMUSTEXIST)
3721 ofn->Flags |= OFN_PATHMUSTEXIST;
3723 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3724 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3726 if (win16look)
3727 return GetFileName31A(ofn, OPEN_DIALOG);
3728 else
3729 return GetFileDialog95A(ofn, OPEN_DIALOG);
3732 /***********************************************************************
3733 * GetOpenFileNameW (COMDLG32.@)
3735 * Creates a dialog box for the user to select a file to open.
3737 * RETURNS
3738 * TRUE on success: user enters a valid file
3739 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3742 BOOL WINAPI GetOpenFileNameW(
3743 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3745 BOOL win16look = FALSE;
3747 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3748 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3750 if (win16look)
3751 return GetFileName31W(ofn, OPEN_DIALOG);
3752 else
3753 return GetFileDialog95W(ofn, OPEN_DIALOG);
3757 /***********************************************************************
3758 * GetSaveFileNameA (COMDLG32.@)
3760 * Creates a dialog box for the user to select a file to save.
3762 * RETURNS
3763 * TRUE on success: user enters a valid file
3764 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3767 BOOL WINAPI GetSaveFileNameA(
3768 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3770 BOOL win16look = FALSE;
3772 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3773 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3775 if (win16look)
3776 return GetFileName31A(ofn, SAVE_DIALOG);
3777 else
3778 return GetFileDialog95A(ofn, SAVE_DIALOG);
3781 /***********************************************************************
3782 * GetSaveFileNameW (COMDLG32.@)
3784 * Creates a dialog box for the user to select a file to save.
3786 * RETURNS
3787 * TRUE on success: user enters a valid file
3788 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3791 BOOL WINAPI GetSaveFileNameW(
3792 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3794 BOOL win16look = FALSE;
3796 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3797 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3799 if (win16look)
3800 return GetFileName31W(ofn, SAVE_DIALOG);
3801 else
3802 return GetFileDialog95W(ofn, SAVE_DIALOG);