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)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/unicode.h"
73 #include "filedlg31.h"
74 #include "wine/debug.h"
79 #include "filedlgbrowser.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 */
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
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 */
122 #define XTEXTOFFSET 3
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
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 /***********************************************************************
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 /***********************************************************************
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)
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);
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
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,
288 /* Unable to create the dialog */
295 /***********************************************************************
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)
306 FileOpenDlgInfos fodInfos;
307 LPSTR lpstrSavDir = 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);
336 fodInfos.initdir = NULL;
340 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
344 fodInfos.filename = NULL;
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;
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)
367 /* filter is a list... title\0ext\0......\0\0 */
368 s = ofn->lpstrFilter;
369 while (*s) s = s+strlen(s)+1;
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)
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;
402 ret = GetFileName95(&fodInfos);
405 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
406 ret = GetFileName95(&fodInfos);
414 SetCurrentDirectoryA(lpstrSavDir);
415 MemFree(lpstrSavDir);
425 MemFree(customfilter);
427 MemFree(fodInfos.initdir);
429 if(fodInfos.filename)
430 MemFree(fodInfos.filename);
432 TRACE("selected file: %s\n",ofn->lpstrFile);
437 /***********************************************************************
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)
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 */
464 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 DWORD len = strlenW(ofn->lpstrInitialDir);
473 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
474 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
477 fodInfos.initdir = NULL;
479 /* save current directory */
480 if (ofn->Flags & OFN_NOCHANGEDIR)
482 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
483 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
486 fodInfos.unicode = TRUE;
491 ret = GetFileName95(&fodInfos);
494 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
495 ret = GetFileName95(&fodInfos);
503 SetCurrentDirectoryW(lpstrSavDir);
504 MemFree(lpstrSavDir);
507 /* restore saved IN arguments and convert OUT arguments back */
508 MemFree(fodInfos.filename);
509 MemFree(fodInfos.initdir);
513 /***********************************************************************
514 * ArrangeCtrlPositions [internal]
516 * NOTE: Do not change anything here without a lot of testing.
518 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
520 HWND hwndChild, hwndStc32;
521 RECT rectParent, rectChild, rectStc32;
522 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
524 /* Take into account if open as read only checkbox and help button
529 RECT rectHelp, rectCancel;
530 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
531 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
532 /* subtract the height of the help button plus the space between
533 * the help button and the cancel button to the height of the dialog
535 help_fixup = rectHelp.bottom - rectCancel.bottom;
539 There are two possibilities to add components to the default file dialog box.
541 By default, all the new components are added below the standard dialog box (the else case).
543 However, if there is a static text component with the stc32 id, a special case happens.
544 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
545 in the window and the cx and cy indicate how to size the window.
546 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
547 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
551 GetClientRect(hwndParentDlg, &rectParent);
553 /* when arranging controls we have to use fixed parent size */
554 rectParent.bottom -= help_fixup;
556 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
559 GetWindowRect(hwndStc32, &rectStc32);
560 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
562 /* set the size of the stc32 control according to the size of
563 * client area of the parent dialog
565 SetWindowPos(hwndStc32, 0,
567 rectParent.right, rectParent.bottom,
568 SWP_NOMOVE | SWP_NOZORDER);
571 SetRectEmpty(&rectStc32);
573 /* this part moves controls of the child dialog */
574 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
577 if (hwndChild != hwndStc32)
579 GetWindowRect(hwndChild, &rectChild);
580 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
582 /* move only if stc32 exist */
583 if (hwndStc32 && rectChild.left > rectStc32.right)
585 LONG old_left = rectChild.left;
587 /* move to the right of visible controls of the parent dialog */
588 rectChild.left += rectParent.right;
589 rectChild.left -= rectStc32.right;
591 child_width_fixup = rectChild.left - old_left;
593 /* move even if stc32 doesn't exist */
594 if (rectChild.top >= rectStc32.bottom)
596 LONG old_top = rectChild.top;
598 /* move below visible controls of the parent dialog */
599 rectChild.top += rectParent.bottom;
600 rectChild.top -= rectStc32.bottom - rectStc32.top;
602 child_height_fixup = rectChild.top - old_top;
605 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
606 0, 0, SWP_NOSIZE | SWP_NOZORDER);
608 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
611 /* this part moves controls of the parent dialog */
612 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
615 if (hwndChild != hwndChildDlg)
617 GetWindowRect(hwndChild, &rectChild);
618 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
620 /* left,top of stc32 marks the position of controls
621 * from the parent dialog
623 rectChild.left += rectStc32.left;
624 rectChild.top += rectStc32.top;
626 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
627 0, 0, SWP_NOSIZE | SWP_NOZORDER);
629 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
632 /* calculate the size of the resulting dialog */
634 /* here we have to use original parent size */
635 GetClientRect(hwndParentDlg, &rectParent);
636 GetClientRect(hwndChildDlg, &rectChild);
640 rectChild.right += child_width_fixup;
641 rectChild.bottom += child_height_fixup;
643 if (rectParent.right > rectChild.right)
645 rectParent.right += rectChild.right;
646 rectParent.right -= rectStc32.right - rectStc32.left;
650 rectParent.right = rectChild.right;
653 if (rectParent.bottom > rectChild.bottom)
655 rectParent.bottom += rectChild.bottom;
656 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
660 /* child dialog is higher, unconditionally set new dialog
661 * height to its size (help_fixup will be subtracted below)
663 rectParent.bottom = rectChild.bottom + help_fixup;
668 rectParent.bottom += rectChild.bottom;
671 /* finally use fixed parent size */
672 rectParent.bottom -= help_fixup;
674 /* save the size of the parent's client area */
675 rectChild.right = rectParent.right;
676 rectChild.bottom = rectParent.bottom;
678 /* set the size of the parent dialog */
679 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
680 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
681 SetWindowPos(hwndParentDlg, 0,
683 rectParent.right - rectParent.left,
684 rectParent.bottom - rectParent.top,
685 SWP_NOMOVE | SWP_NOZORDER);
687 /* set the size of the child dialog */
688 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
689 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
692 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
701 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
711 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
712 * structure's hInstance parameter is not a HINSTANCE, but
713 * instead a pointer to a template resource to use.
715 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
718 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
721 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
723 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
729 hinst = fodInfos->ofnInfos->hInstance;
730 if(fodInfos->unicode)
732 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
733 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
737 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
738 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
742 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
745 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
746 !(template = LockResource( hDlgTmpl )))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
752 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
753 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
754 (LPARAM)fodInfos->ofnInfos);
757 ShowWindow(hChildDlg,SW_SHOW);
761 else if( IsHooked(fodInfos))
766 WORD menu,class,title;
768 GetClientRect(hwnd,&rectHwnd);
769 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
770 temp.tmplate.dwExtendedStyle = 0;
771 temp.tmplate.cdit = 0;
776 temp.menu = temp.class = temp.title = 0;
778 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
779 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
786 /***********************************************************************
787 * SendCustomDlgNotificationMessage
789 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
792 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
794 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
796 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
798 if(!fodInfos) return 0;
800 if(fodInfos->DlgInfos.hwndCustomDlg)
803 TRACE("CALL NOTIFY for %x\n", uCode);
804 if(fodInfos->unicode)
807 ofnNotify.hdr.hwndFrom=hwndParentDlg;
808 ofnNotify.hdr.idFrom=0;
809 ofnNotify.hdr.code = uCode;
810 ofnNotify.lpOFN = fodInfos->ofnInfos;
811 ofnNotify.pszFile = NULL;
812 ret = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
817 ofnNotify.hdr.hwndFrom=hwndParentDlg;
818 ofnNotify.hdr.idFrom=0;
819 ofnNotify.hdr.code = uCode;
820 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
821 ofnNotify.pszFile = NULL;
822 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
824 TRACE("RET NOTIFY\n");
830 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
832 UINT sizeUsed = 0, n, total;
833 LPWSTR lpstrFileList = NULL;
834 WCHAR lpstrCurrentDir[MAX_PATH];
835 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
837 TRACE("CDM_GETFILEPATH:\n");
839 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
842 /* get path and filenames */
843 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
844 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
846 TRACE("path >%s< filespec >%s< %d files\n",
847 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
849 if( fodInfos->unicode )
851 LPWSTR bufW = buffer;
852 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
854 /* Prepend the current path */
855 n = strlenW(lpstrCurrentDir) + 1;
856 strncpyW( bufW, lpstrCurrentDir, size );
859 /* 'n' includes trailing \0 */
861 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
863 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
868 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
869 NULL, 0, NULL, NULL);
870 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
871 NULL, 0, NULL, NULL);
873 /* Prepend the current path */
874 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
875 bufA, size, NULL, NULL);
879 /* 'n' includes trailing \0 */
881 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
882 &bufA[n], size-n, NULL, NULL);
885 TRACE("returned -> %s\n",debugstr_an(bufA, total));
887 MemFree(lpstrFileList);
892 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
895 LPWSTR lpstrFileList = NULL;
896 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
898 TRACE("CDM_GETSPEC:\n");
900 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
901 if( fodInfos->unicode )
903 LPWSTR bufW = buffer;
904 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
909 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
910 NULL, 0, NULL, NULL);
911 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
912 bufA, size, NULL, NULL);
914 MemFree(lpstrFileList);
919 /***********************************************************************
920 * FILEDLG95_HandleCustomDialogMessages
922 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
924 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
926 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
927 if(!fodInfos) return -1;
931 case CDM_GETFILEPATH:
932 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
934 case CDM_GETFOLDERPATH:
935 TRACE("CDM_GETFOLDERPATH:\n");
936 if( fodInfos->unicode )
938 WCHAR lpstrPath[MAX_PATH], *bufW = (LPWSTR)lParam;
939 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
941 lstrcpynW(bufW,lpstrPath,(int)wParam);
942 return strlenW(lpstrPath);
946 char lpstrPath[MAX_PATH], *bufA = (LPSTR)lParam;
947 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
949 lstrcpynA(bufA,lpstrPath,(int)wParam);
950 return strlen(lpstrPath);
954 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
956 case CDM_SETCONTROLTEXT:
957 TRACE("CDM_SETCONTROLTEXT:\n");
960 if( fodInfos->unicode )
961 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
963 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
967 case CDM_HIDECONTROL:
969 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
975 /***********************************************************************
978 * File open dialog procedure
980 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
983 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
990 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
992 /* Adds the FileOpenDlgInfos in the property list of the dialog
993 so it will be easily accessible through a GetPropA(...) */
994 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
996 fodInfos->DlgInfos.hwndCustomDlg =
997 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
999 FILEDLG95_InitControls(hwnd);
1001 if (fodInfos->DlgInfos.hwndCustomDlg)
1002 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1003 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1005 FILEDLG95_FillControls(hwnd, wParam, lParam);
1007 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1008 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1009 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1013 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1016 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1019 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1025 case WM_GETISHELLBROWSER:
1026 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1029 RemovePropA(hwnd, FileOpenDlgInfosStr);
1034 LPNMHDR lpnmh = (LPNMHDR)lParam;
1037 /* set up the button tooltips strings */
1038 if(TTN_GETDISPINFOA == lpnmh->code )
1040 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1041 switch(lpnmh->idFrom )
1043 /* Up folder button */
1044 case FCIDM_TB_UPFOLDER:
1045 stringId = IDS_UPFOLDER;
1047 /* New folder button */
1048 case FCIDM_TB_NEWFOLDER:
1049 stringId = IDS_NEWFOLDER;
1051 /* List option button */
1052 case FCIDM_TB_SMALLICON:
1053 stringId = IDS_LISTVIEW;
1055 /* Details option button */
1056 case FCIDM_TB_REPORTVIEW:
1057 stringId = IDS_REPORTVIEW;
1059 /* Desktop button */
1060 case FCIDM_TB_DESKTOP:
1061 stringId = IDS_TODESKTOP;
1066 lpdi->hinst = COMDLG32_hInstance;
1067 lpdi->lpszText = (LPSTR) stringId;
1072 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1073 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1078 /***********************************************************************
1079 * FILEDLG95_InitControls
1081 * WM_INITDIALOG message handler (before hook notification)
1083 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1085 int win2000plus = 0;
1087 int handledPath = FALSE;
1088 OSVERSIONINFOA osVi;
1089 static const WCHAR szwSlash[] = { '\\', 0 };
1090 static const WCHAR szwStar[] = { '*',0 };
1094 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1095 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1096 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1097 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1098 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1099 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1100 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1101 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1102 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1107 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1109 tba[0].hInst = HINST_COMMCTRL;
1110 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1111 tba[1].hInst = COMDLG32_hInstance;
1114 TRACE("%p\n", fodInfos);
1116 /* Get windows version emulating */
1117 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1118 GetVersionExA(&osVi);
1119 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1120 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1121 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1122 win2000plus = (osVi.dwMajorVersion > 4);
1123 if (win2000plus) win98plus = TRUE;
1125 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1127 /* Get the hwnd of the controls */
1128 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1129 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1130 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1132 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1133 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1135 /* construct the toolbar */
1136 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1137 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1139 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1140 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1141 rectTB.left = rectlook.right;
1142 rectTB.top = rectlook.top-1;
1144 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1145 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1146 rectTB.left, rectTB.top,
1147 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1148 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1150 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1152 /* FIXME: use TB_LOADIMAGES when implemented */
1153 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1154 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1155 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1157 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1158 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1160 /* Set the window text with the text specified in the OPENFILENAME structure */
1163 SetWindowTextW(hwnd,fodInfos->title);
1165 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1168 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1169 SetWindowTextW(hwnd, buf);
1172 /* Initialise the file name edit control */
1173 handledPath = FALSE;
1174 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1176 if(fodInfos->filename)
1178 /* 1. If win2000 or higher and filename contains a path, use it
1179 in preference over the lpstrInitialDir */
1180 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1181 WCHAR tmpBuf[MAX_PATH];
1185 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1188 /* nameBit is always shorter than the original filename */
1189 strcpyW(fodInfos->filename,nameBit);
1192 if (fodInfos->initdir == NULL)
1193 MemFree(fodInfos->initdir);
1194 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1195 strcpyW(fodInfos->initdir, tmpBuf);
1197 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1198 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1200 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1203 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1207 /* 2. (All platforms) If initdir is not null, then use it */
1208 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1209 (*fodInfos->initdir!=0x00))
1211 /* Work out the proper path as supplied one might be relative */
1212 /* (Here because supplying '.' as dir browses to My Computer) */
1213 if (handledPath==FALSE) {
1214 WCHAR tmpBuf[MAX_PATH];
1215 WCHAR tmpBuf2[MAX_PATH];
1219 strcpyW(tmpBuf, fodInfos->initdir);
1220 if( PathFileExistsW(tmpBuf) ) {
1221 /* initdir does not have to be a directory. If a file is
1222 * specified, the dir part is taken */
1223 if( PathIsDirectoryW(tmpBuf)) {
1224 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1225 strcatW(tmpBuf, szwSlash);
1227 strcatW(tmpBuf, szwStar);
1229 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1232 if (fodInfos->initdir)
1233 MemFree(fodInfos->initdir);
1234 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1235 strcpyW(fodInfos->initdir, tmpBuf2);
1237 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1240 else if (fodInfos->initdir)
1242 MemFree(fodInfos->initdir);
1243 fodInfos->initdir = NULL;
1244 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1249 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1250 (*fodInfos->initdir==0x00)))
1252 /* 3. All except w2k+: if filename contains a path use it */
1253 if (!win2000plus && fodInfos->filename &&
1254 *fodInfos->filename &&
1255 strpbrkW(fodInfos->filename, szwSlash)) {
1256 WCHAR tmpBuf[MAX_PATH];
1260 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1265 /* nameBit is always shorter than the original filename */
1266 strcpyW(fodInfos->filename, nameBit);
1269 len = strlenW(tmpBuf);
1270 if(fodInfos->initdir)
1271 MemFree(fodInfos->initdir);
1272 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1273 strcpyW(fodInfos->initdir, tmpBuf);
1276 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1277 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1279 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1282 /* 4. win98+ and win2000+ if any files of specified filter types in
1283 current directory, use it */
1284 if ( win98plus && handledPath == FALSE &&
1285 fodInfos->filter && *fodInfos->filter) {
1287 BOOL searchMore = TRUE;
1288 LPCWSTR lpstrPos = fodInfos->filter;
1289 WIN32_FIND_DATAW FindFileData;
1294 /* filter is a list... title\0ext\0......\0\0 */
1296 /* Skip the title */
1297 if(! *lpstrPos) break; /* end */
1298 lpstrPos += strlenW(lpstrPos) + 1;
1300 /* See if any files exist in the current dir with this extension */
1301 if(! *lpstrPos) break; /* end */
1303 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1305 if (hFind == INVALID_HANDLE_VALUE) {
1306 /* None found - continue search */
1307 lpstrPos += strlenW(lpstrPos) + 1;
1312 if(fodInfos->initdir)
1313 MemFree(fodInfos->initdir);
1314 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1315 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1318 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1319 debugstr_w(lpstrPos));
1325 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1327 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1328 if (handledPath == FALSE && (win2000plus || win98plus)) {
1329 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1331 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1333 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1336 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1337 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1339 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1342 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1345 } else if (handledPath==FALSE) {
1346 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1347 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1349 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1352 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1353 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1355 /* Must the open as read only check box be checked ?*/
1356 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1358 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1361 /* Must the open as read only check box be hidden? */
1362 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1364 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1365 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1368 /* Must the help button be hidden? */
1369 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1371 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1372 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1375 /* Resize the height, if open as read only checkbox ad help button
1376 are hidden and we are not using a custom template nor a customDialog
1378 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1379 (!(fodInfos->ofnInfos->Flags &
1380 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1381 (!fodInfos->DlgInfos.hwndCustomDlg ))
1383 RECT rectDlg, rectHelp, rectCancel;
1384 GetWindowRect(hwnd, &rectDlg);
1385 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1386 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1387 /* subtract the height of the help button plus the space between
1388 the help button and the cancel button to the height of the dialog */
1389 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1390 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1391 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1393 /* change Open to Save */
1394 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1397 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1398 SetDlgItemTextW(hwnd, IDOK, buf);
1399 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1400 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1405 /***********************************************************************
1406 * FILEDLG95_FillControls
1408 * WM_INITDIALOG message handler (after hook notification)
1410 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1412 LPITEMIDLIST pidlItemId = NULL;
1414 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1416 TRACE("dir=%s file=%s\n",
1417 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1419 /* Get the initial directory pidl */
1421 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1423 WCHAR path[MAX_PATH];
1425 GetCurrentDirectoryW(MAX_PATH,path);
1426 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1429 /* Initialise shell objects */
1430 FILEDLG95_SHELL_Init(hwnd);
1432 /* Initialize the Look In combo box */
1433 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1435 /* Initialize the filter combo box */
1436 FILEDLG95_FILETYPE_Init(hwnd);
1438 /* Browse to the initial directory */
1439 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1441 /* Free pidlItem memory */
1442 COMDLG32_SHFree(pidlItemId);
1446 /***********************************************************************
1449 * Regroups all the cleaning functions of the filedlg
1451 void FILEDLG95_Clean(HWND hwnd)
1453 FILEDLG95_FILETYPE_Clean(hwnd);
1454 FILEDLG95_LOOKIN_Clean(hwnd);
1455 FILEDLG95_SHELL_Clean(hwnd);
1457 /***********************************************************************
1458 * FILEDLG95_OnWMCommand
1460 * WM_COMMAND message handler
1462 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1464 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1465 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1466 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1472 FILEDLG95_OnOpen(hwnd);
1476 FILEDLG95_Clean(hwnd);
1477 EndDialog(hwnd, FALSE);
1479 /* Filetype combo box */
1481 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1483 /* LookIn combo box */
1485 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1488 /* --- toolbar --- */
1489 /* Up folder button */
1490 case FCIDM_TB_UPFOLDER:
1491 FILEDLG95_SHELL_UpFolder(hwnd);
1493 /* New folder button */
1494 case FCIDM_TB_NEWFOLDER:
1495 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1497 /* List option button */
1498 case FCIDM_TB_SMALLICON:
1499 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1501 /* Details option button */
1502 case FCIDM_TB_REPORTVIEW:
1503 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1505 /* Details option button */
1506 case FCIDM_TB_DESKTOP:
1507 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1514 /* Do not use the listview selection anymore */
1515 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1519 /***********************************************************************
1520 * FILEDLG95_OnWMGetIShellBrowser
1522 * WM_GETISHELLBROWSER message handler
1524 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1527 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1531 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1537 /***********************************************************************
1538 * FILEDLG95_SendFileOK
1540 * Sends the CDN_FILEOK notification if required
1543 * TRUE if the dialog should close
1544 * FALSE if the dialog should not be closed
1546 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1548 /* ask the hook if we can close */
1549 if(IsHooked(fodInfos))
1552 /* First send CDN_FILEOK as MSDN doc says */
1553 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1554 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1556 TRACE("canceled\n");
1560 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1561 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1562 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1563 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1565 TRACE("canceled\n");
1572 /***********************************************************************
1573 * FILEDLG95_OnOpenMultipleFiles
1575 * Handles the opening of multiple files.
1578 * check destination buffer size
1580 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1582 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1583 UINT nCount, nSizePath;
1584 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1588 if(fodInfos->unicode)
1590 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1591 ofn->lpstrFile[0] = '\0';
1595 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1596 ofn->lpstrFile[0] = '\0';
1599 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1601 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1602 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1603 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1605 LPWSTR lpstrTemp = lpstrFileList;
1607 for ( nCount = 0; nCount < nFileCount; nCount++ )
1611 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1614 WCHAR lpstrNotFound[100];
1615 WCHAR lpstrMsg[100];
1617 static const WCHAR nl[] = {'\n',0};
1619 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1620 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1622 strcpyW(tmp, lpstrTemp);
1624 strcatW(tmp, lpstrNotFound);
1626 strcatW(tmp, lpstrMsg);
1628 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1632 /* move to the next file in the list of files */
1633 lpstrTemp += strlenW(lpstrTemp) + 1;
1634 COMDLG32_SHFree(pidl);
1638 nSizePath = strlenW(lpstrPathSpec) + 1;
1639 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1641 /* For "oldstyle" dialog the components have to
1642 be separated by blanks (not '\0'!) and short
1643 filenames have to be used! */
1644 FIXME("Components have to be separated by blanks\n");
1646 if(fodInfos->unicode)
1648 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1649 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1650 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1654 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1656 if (ofn->lpstrFile != NULL)
1658 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1659 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1660 if (ofn->nMaxFile > nSizePath)
1662 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1663 ofn->lpstrFile + nSizePath,
1664 ofn->nMaxFile - nSizePath, NULL, NULL);
1669 fodInfos->ofnInfos->nFileOffset = nSizePath;
1670 fodInfos->ofnInfos->nFileExtension = 0;
1672 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1675 /* clean and exit */
1676 FILEDLG95_Clean(hwnd);
1677 return EndDialog(hwnd,TRUE);
1680 /***********************************************************************
1683 * Ok button WM_COMMAND message handler
1685 * If the function succeeds, the return value is nonzero.
1687 #define ONOPEN_BROWSE 1
1688 #define ONOPEN_OPEN 2
1689 #define ONOPEN_SEARCH 3
1690 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1692 WCHAR strMsgTitle[MAX_PATH];
1693 WCHAR strMsgText [MAX_PATH];
1695 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1697 strMsgTitle[0] = '\0';
1698 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1699 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1702 BOOL FILEDLG95_OnOpen(HWND hwnd)
1704 LPWSTR lpstrFileList;
1705 UINT nFileCount = 0;
1708 WCHAR lpstrPathAndFile[MAX_PATH];
1709 WCHAR lpstrTemp[MAX_PATH];
1710 LPSHELLFOLDER lpsf = NULL;
1712 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1714 TRACE("hwnd=%p\n", hwnd);
1716 /* get the files from the edit control */
1717 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1719 /* try if the user selected a folder in the shellview */
1722 BrowseSelectedFolder(hwnd);
1728 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1732 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1735 Step 1: Build a complete path name from the current folder and
1736 the filename or path in the edit box.
1738 - the path in the edit box is a root path
1739 (with or without drive letter)
1740 - the edit box contains ".." (or a path with ".." in it)
1743 /* Get the current directory name */
1744 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1746 /* we are in a special folder, default to desktop */
1747 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1750 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1753 PathAddBackslashW(lpstrPathAndFile);
1755 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1757 /* if the user specifyed a fully qualified path use it */
1758 if(PathIsRelativeW(lpstrFileList))
1760 strcatW(lpstrPathAndFile, lpstrFileList);
1764 /* does the path have a drive letter? */
1765 if (PathGetDriveNumberW(lpstrFileList) == -1)
1766 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1768 strcpyW(lpstrPathAndFile, lpstrFileList);
1771 /* resolve "." and ".." */
1772 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1773 strcpyW(lpstrPathAndFile, lpstrTemp);
1774 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1776 MemFree(lpstrFileList);
1779 Step 2: here we have a cleaned up path
1781 We have to parse the path step by step to see if we have to browse
1782 to a folder if the path points to a directory or the last
1783 valid element is a directory.
1786 lpstrPathAndFile: cleaned up path
1789 nOpenAction = ONOPEN_BROWSE;
1791 /* don't apply any checks with OFN_NOVALIDATE */
1793 LPWSTR lpszTemp, lpszTemp1;
1794 LPITEMIDLIST pidl = NULL;
1795 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1797 /* check for invalid chars */
1798 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1800 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1805 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1807 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1810 LPSHELLFOLDER lpsfChild;
1811 WCHAR lpwstrTemp[MAX_PATH];
1812 DWORD dwEaten, dwAttributes;
1815 strcpyW(lpwstrTemp, lpszTemp);
1816 p = PathFindNextComponentW(lpwstrTemp);
1818 if (!p) break; /* end of path */
1821 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1825 static const WCHAR wszWild[] = { '*', '?', 0 };
1826 /* if the last element is a wildcard do a search */
1827 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1829 nOpenAction = ONOPEN_SEARCH;
1833 lpszTemp1 = lpszTemp;
1835 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1837 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1839 dwAttributes = SFGAO_FOLDER;
1840 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1842 /* the path component is valid, we have a pidl of the next path component */
1843 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1844 if(dwAttributes & SFGAO_FOLDER)
1846 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1848 ERR("bind to failed\n"); /* should not fail */
1851 IShellFolder_Release(lpsf);
1859 /* end dialog, return value */
1860 nOpenAction = ONOPEN_OPEN;
1863 COMDLG32_SHFree(pidl);
1866 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1868 if(*lpszTemp) /* points to trailing null for last path element */
1870 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1872 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1878 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1879 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1881 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1885 /* change to the current folder */
1886 nOpenAction = ONOPEN_OPEN;
1891 nOpenAction = ONOPEN_OPEN;
1895 if(pidl) COMDLG32_SHFree(pidl);
1899 Step 3: here we have a cleaned up and validated path
1902 lpsf: ShellFolder bound to the rightmost valid path component
1903 lpstrPathAndFile: cleaned up path
1904 nOpenAction: action to do
1906 TRACE("end validate sf=%p\n", lpsf);
1910 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1911 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1914 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1917 /* replace the current filter */
1918 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1919 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1920 len = strlenW(lpszTemp)+1;
1921 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1922 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1924 /* set the filter cb to the extension when possible */
1925 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1926 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1929 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1930 TRACE("ONOPEN_BROWSE\n");
1932 IPersistFolder2 * ppf2;
1933 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1935 LPITEMIDLIST pidlCurrent;
1936 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1937 IPersistFolder2_Release(ppf2);
1938 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1940 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1942 else if( nOpenAction == ONOPEN_SEARCH )
1944 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1946 COMDLG32_SHFree(pidlCurrent);
1951 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1952 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1956 /* update READONLY check box flag */
1957 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1958 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1960 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1962 /* Attach the file extension with file name*/
1963 ext = PathFindExtensionW(lpstrPathAndFile);
1966 /* if no extension is specified with file name, then */
1967 /* attach the extension from file filter or default one */
1969 WCHAR *filterExt = NULL;
1970 LPWSTR lpstrFilter = NULL;
1971 static const WCHAR szwDot[] = {'.',0};
1972 int PathLength = strlenW(lpstrPathAndFile);
1975 strcatW(lpstrPathAndFile, szwDot);
1977 /*Get the file extension from file type filter*/
1978 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1979 fodInfos->ofnInfos->nFilterIndex-1);
1981 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
1982 filterExt = PathFindExtensionW(lpstrFilter);
1984 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
1985 strcatW(lpstrPathAndFile, filterExt + 1);
1986 else if ( fodInfos->defext ) /* attach the default file extension*/
1987 strcatW(lpstrPathAndFile, fodInfos->defext);
1989 /* In Open dialog: if file does not exist try without extension */
1990 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
1991 lpstrPathAndFile[PathLength] = '\0';
1994 if (fodInfos->defext) /* add default extension */
1996 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1999 if (!lstrcmpiW(fodInfos->defext, ext))
2000 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2002 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2005 /* In Save dialog: check if the file already exists */
2006 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2007 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2008 && PathFileExistsW(lpstrPathAndFile))
2010 WCHAR lpstrOverwrite[100];
2013 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2014 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2015 MB_YESNO | MB_ICONEXCLAMATION);
2023 /* Check that the size of the file does not exceed buffer size.
2024 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2025 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2026 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2030 /* fill destination buffer */
2031 if (fodInfos->ofnInfos->lpstrFile)
2033 if(fodInfos->unicode)
2035 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2037 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2038 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2039 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2043 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2045 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2046 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2047 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2048 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2052 /* set filename offset */
2053 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2054 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2056 /* set extension offset */
2057 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2058 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2060 /* set the lpstrFileTitle */
2061 if(fodInfos->ofnInfos->lpstrFileTitle)
2063 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2064 if(fodInfos->unicode)
2066 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2067 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2071 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2072 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2073 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2077 /* copy currently selected filter to lpstrCustomFilter */
2078 if (fodInfos->ofnInfos->lpstrCustomFilter)
2080 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2081 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2082 NULL, 0, NULL, NULL);
2083 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2085 LPSTR s = ofn->lpstrCustomFilter;
2086 s += strlen(ofn->lpstrCustomFilter)+1;
2087 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2088 s, len, NULL, NULL);
2093 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2097 FILEDLG95_Clean(hwnd);
2098 ret = EndDialog(hwnd, TRUE);
2104 size = strlenW(lpstrPathAndFile) + 1;
2105 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2107 /* return needed size in first two bytes of lpstrFile */
2108 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2109 FILEDLG95_Clean(hwnd);
2110 ret = EndDialog(hwnd, FALSE);
2111 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2119 if(lpsf) IShellFolder_Release(lpsf);
2123 /***********************************************************************
2124 * FILEDLG95_SHELL_Init
2126 * Initialisation of the shell objects
2128 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2130 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2135 * Initialisation of the FileOpenDialogInfos structure
2141 fodInfos->ShellInfos.hwndOwner = hwnd;
2143 /* Disable multi-select if flag not set */
2144 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2146 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2148 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2149 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2151 /* Construct the IShellBrowser interface */
2152 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2157 /***********************************************************************
2158 * FILEDLG95_SHELL_ExecuteCommand
2160 * Change the folder option and refresh the view
2161 * If the function succeeds, the return value is nonzero.
2163 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2165 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2168 TRACE("(%p,%p)\n", hwnd, lpVerb);
2170 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2175 CMINVOKECOMMANDINFO ci;
2176 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2177 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2181 IContextMenu_InvokeCommand(pcm, &ci);
2182 IContextMenu_Release(pcm);
2188 /***********************************************************************
2189 * FILEDLG95_SHELL_UpFolder
2191 * Browse to the specified object
2192 * If the function succeeds, the return value is nonzero.
2194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2196 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2200 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2209 /***********************************************************************
2210 * FILEDLG95_SHELL_BrowseToDesktop
2212 * Browse to the Desktop
2213 * If the function succeeds, the return value is nonzero.
2215 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2217 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2223 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2224 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2225 COMDLG32_SHFree(pidl);
2226 return SUCCEEDED(hres);
2228 /***********************************************************************
2229 * FILEDLG95_SHELL_Clean
2231 * Cleans the memory used by shell objects
2233 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2235 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2239 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2241 /* clean Shell interfaces */
2242 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2243 IShellView_Release(fodInfos->Shell.FOIShellView);
2244 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2245 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2246 if (fodInfos->Shell.FOIDataObject)
2247 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2250 /***********************************************************************
2251 * FILEDLG95_FILETYPE_Init
2253 * Initialisation of the file type combo box
2255 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2257 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2258 int nFilters = 0; /* number of filters */
2263 if(fodInfos->customfilter)
2265 /* customfilter has one entry... title\0ext\0
2266 * Set first entry of combo box item with customfilter
2269 LPCWSTR lpstrPos = fodInfos->customfilter;
2272 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2274 /* Copy the extensions */
2275 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2276 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2277 strcpyW(lpstrExt,lpstrPos);
2279 /* Add the item at the end of the combo */
2280 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2281 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2284 if(fodInfos->filter)
2286 LPCWSTR lpstrPos = fodInfos->filter;
2290 /* filter is a list... title\0ext\0......\0\0
2291 * Set the combo item text to the title and the item data
2294 LPCWSTR lpstrDisplay;
2298 if(! *lpstrPos) break; /* end */
2299 lpstrDisplay = lpstrPos;
2300 lpstrPos += strlenW(lpstrPos) + 1;
2302 /* Copy the extensions */
2303 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2304 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2305 strcpyW(lpstrExt,lpstrPos);
2306 lpstrPos += strlenW(lpstrPos) + 1;
2308 /* Add the item at the end of the combo */
2309 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2310 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2316 * Set the current filter to the one specified
2317 * in the initialisation structure
2319 if (fodInfos->filter || fodInfos->customfilter)
2323 /* Check to make sure our index isn't out of bounds. */
2324 if ( fodInfos->ofnInfos->nFilterIndex >
2325 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2326 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2328 /* set default filter index */
2329 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2330 fodInfos->ofnInfos->nFilterIndex = 1;
2332 /* calculate index of Combo Box item */
2333 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2334 if (fodInfos->customfilter == NULL)
2337 /* Set the current index selection. */
2338 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2340 /* Get the corresponding text string from the combo box. */
2341 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2344 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2350 CharLowerW(lpstrFilter); /* lowercase */
2351 len = strlenW(lpstrFilter)+1;
2352 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2353 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2356 fodInfos->ofnInfos->nFilterIndex = 0;
2361 /***********************************************************************
2362 * FILEDLG95_FILETYPE_OnCommand
2364 * WM_COMMAND of the file type combo box
2365 * If the function succeeds, the return value is nonzero.
2367 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2369 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2377 /* Get the current item of the filetype combo box */
2378 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2380 /* set the current filter index */
2381 fodInfos->ofnInfos->nFilterIndex = iItem +
2382 (fodInfos->customfilter == NULL ? 1 : 0);
2384 /* Set the current filter with the current selection */
2385 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2386 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2388 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2390 if((int)lpstrFilter != CB_ERR)
2393 CharLowerW(lpstrFilter); /* lowercase */
2394 len = strlenW(lpstrFilter)+1;
2395 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2396 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2397 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2400 /* Refresh the actual view to display the included items*/
2401 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2406 /***********************************************************************
2407 * FILEDLG95_FILETYPE_SearchExt
2409 * searches for an extension in the filetype box
2411 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2413 int i, iCount = CBGetCount(hwnd);
2415 TRACE("%s\n", debugstr_w(lpstrExt));
2417 if(iCount != CB_ERR)
2419 for(i=0;i<iCount;i++)
2421 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2428 /***********************************************************************
2429 * FILEDLG95_FILETYPE_Clean
2431 * Clean the memory used by the filetype combo box
2433 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2435 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2437 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2441 /* Delete each string of the combo and their associated data */
2442 if(iCount != CB_ERR)
2444 for(iPos = iCount-1;iPos>=0;iPos--)
2446 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2447 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2450 /* Current filter */
2451 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2452 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2456 /***********************************************************************
2457 * FILEDLG95_LOOKIN_Init
2459 * Initialisation of the look in combo box
2461 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2463 IShellFolder *psfRoot, *psfDrives;
2464 IEnumIDList *lpeRoot, *lpeDrives;
2465 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2467 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2471 liInfos->iMaxIndentation = 0;
2473 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2475 /* set item height for both text field and listbox */
2476 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2477 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2479 /* Turn on the extended UI for the combo box like Windows does */
2480 CBSetExtendedUI(hwndCombo, TRUE);
2482 /* Initialise data of Desktop folder */
2483 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2484 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2485 COMDLG32_SHFree(pidlTmp);
2487 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2489 SHGetDesktopFolder(&psfRoot);
2493 /* enumerate the contents of the desktop */
2494 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2496 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2498 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2500 /* special handling for CSIDL_DRIVES */
2501 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2503 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2505 /* enumerate the drives */
2506 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2508 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2510 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2511 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2512 COMDLG32_SHFree(pidlAbsTmp);
2513 COMDLG32_SHFree(pidlTmp1);
2515 IEnumIDList_Release(lpeDrives);
2517 IShellFolder_Release(psfDrives);
2520 COMDLG32_SHFree(pidlTmp);
2522 IEnumIDList_Release(lpeRoot);
2524 IShellFolder_Release(psfRoot);
2527 COMDLG32_SHFree(pidlDrives);
2531 /***********************************************************************
2532 * FILEDLG95_LOOKIN_DrawItem
2534 * WM_DRAWITEM message handler
2536 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2538 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2539 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2540 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2544 HIMAGELIST ilItemImage;
2547 LPSFOLDER tmpFolder;
2550 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2554 if(pDIStruct->itemID == -1)
2557 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2558 pDIStruct->itemID)))
2562 if(pDIStruct->itemID == liInfos->uSelectedItem)
2564 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2567 sizeof (SHFILEINFOA),
2568 SHGFI_PIDL | SHGFI_SMALLICON |
2569 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2570 SHGFI_DISPLAYNAME );
2574 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2577 sizeof (SHFILEINFOA),
2578 SHGFI_PIDL | SHGFI_SMALLICON |
2579 SHGFI_SYSICONINDEX |
2583 /* Is this item selected ? */
2584 if(pDIStruct->itemState & ODS_SELECTED)
2586 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2587 SetBkColor(pDIStruct->hDC,crHighLight);
2588 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2592 SetTextColor(pDIStruct->hDC,crText);
2593 SetBkColor(pDIStruct->hDC,crWin);
2594 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2597 /* Do not indent item if drawing in the edit of the combo */
2598 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2601 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2604 sizeof (SHFILEINFOA),
2605 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2606 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2611 iIndentation = tmpFolder->m_iIndent;
2613 /* Draw text and icon */
2615 /* Initialise the icon display area */
2616 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2617 rectIcon.top = pDIStruct->rcItem.top;
2618 rectIcon.right = rectIcon.left + ICONWIDTH;
2619 rectIcon.bottom = pDIStruct->rcItem.bottom;
2621 /* Initialise the text display area */
2622 GetTextMetricsA(pDIStruct->hDC, &tm);
2623 rectText.left = rectIcon.right;
2625 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2626 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2628 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2630 /* Draw the icon from the image list */
2631 ImageList_Draw(ilItemImage,
2638 /* Draw the associated text */
2639 if(sfi.szDisplayName)
2640 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2646 /***********************************************************************
2647 * FILEDLG95_LOOKIN_OnCommand
2649 * LookIn combo box WM_COMMAND message handler
2650 * If the function succeeds, the return value is nonzero.
2652 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2654 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2656 TRACE("%p\n", fodInfos);
2662 LPSFOLDER tmpFolder;
2665 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2667 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2672 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2673 tmpFolder->pidlItem,
2685 /***********************************************************************
2686 * FILEDLG95_LOOKIN_AddItem
2688 * Adds an absolute pidl item to the lookin combo box
2689 * returns the index of the inserted item
2691 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2693 LPITEMIDLIST pidlNext;
2696 LookInInfos *liInfos;
2698 TRACE("%08x\n", iInsertId);
2703 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2706 tmpFolder = MemAlloc(sizeof(SFOLDER));
2707 tmpFolder->m_iIndent = 0;
2709 /* Calculate the indentation of the item in the lookin*/
2711 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2713 tmpFolder->m_iIndent++;
2716 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2718 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2719 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2721 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2722 SHGetFileInfoA((LPSTR)pidl,
2726 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2727 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2729 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2731 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2735 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2737 /* Add the item at the end of the list */
2740 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2742 /* Insert the item at the iInsertId position*/
2745 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2748 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2752 COMDLG32_SHFree( tmpFolder->pidlItem );
2753 MemFree( tmpFolder );
2758 /***********************************************************************
2759 * FILEDLG95_LOOKIN_InsertItemAfterParent
2761 * Insert an item below its parent
2763 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2766 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2771 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2775 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2778 /* Free pidlParent memory */
2779 COMDLG32_SHFree((LPVOID)pidlParent);
2781 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2784 /***********************************************************************
2785 * FILEDLG95_LOOKIN_SelectItem
2787 * Adds an absolute pidl item to the lookin combo box
2788 * returns the index of the inserted item
2790 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2793 LookInInfos *liInfos;
2797 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2799 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2803 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2804 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2809 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2810 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2814 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2816 if(iRemovedItem < iItemPos)
2821 CBSetCurSel(hwnd,iItemPos);
2822 liInfos->uSelectedItem = iItemPos;
2828 /***********************************************************************
2829 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2831 * Remove the item with an expansion level over iExpansionLevel
2833 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2837 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2841 if(liInfos->iMaxIndentation <= 2)
2844 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2846 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2847 COMDLG32_SHFree(tmpFolder->pidlItem);
2849 CBDeleteString(hwnd,iItemPos);
2850 liInfos->iMaxIndentation--;
2858 /***********************************************************************
2859 * FILEDLG95_LOOKIN_SearchItem
2861 * Search for pidl in the lookin combo box
2862 * returns the index of the found item
2864 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2867 int iCount = CBGetCount(hwnd);
2869 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2871 if (iCount != CB_ERR)
2875 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2877 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2879 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2887 /***********************************************************************
2888 * FILEDLG95_LOOKIN_Clean
2890 * Clean the memory used by the lookin combo box
2892 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2894 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2896 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2900 /* Delete each string of the combo and their associated data */
2901 if (iCount != CB_ERR)
2903 for(iPos = iCount-1;iPos>=0;iPos--)
2905 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2906 COMDLG32_SHFree(tmpFolder->pidlItem);
2908 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2912 /* LookInInfos structure */
2913 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2916 /***********************************************************************
2917 * FILEDLG95_FILENAME_FillFromSelection
2919 * fills the edit box from the cached DataObject
2921 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2923 FileOpenDlgInfos *fodInfos;
2925 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2926 char lpstrTemp[MAX_PATH];
2927 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2930 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2932 /* Count how many files we have */
2933 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2935 /* calculate the string length, count files */
2936 if (nFileSelected >= 1)
2938 nLength += 3; /* first and last quotes, trailing \0 */
2939 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2941 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2945 /* get the total length of the selected file names */
2946 lpstrTemp[0] = '\0';
2947 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2949 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2951 nLength += strlen( lpstrTemp ) + 3;
2954 COMDLG32_SHFree( pidl );
2959 /* allocate the buffer */
2960 if (nFiles <= 1) nLength = MAX_PATH;
2961 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2962 lpstrAllFile[0] = '\0';
2964 /* Generate the string for the edit control */
2967 lpstrCurrFile = lpstrAllFile;
2968 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2970 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2974 /* get the file name */
2975 lpstrTemp[0] = '\0';
2976 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2978 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2982 *lpstrCurrFile++ = '\"';
2983 strcpy( lpstrCurrFile, lpstrTemp );
2984 lpstrCurrFile += strlen( lpstrTemp );
2985 strcpy( lpstrCurrFile, "\" " );
2990 strcpy( lpstrAllFile, lpstrTemp );
2993 COMDLG32_SHFree( (LPVOID) pidl );
2996 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2998 /* Select the file name like Windows does */
2999 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3001 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3005 /* copied from shell32 to avoid linking to it */
3006 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3011 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3012 COMDLG32_SHFree(src->u.pOleStr);
3016 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3020 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3024 FIXME("unknown type!\n");
3027 *(LPSTR)dest = '\0';
3034 /***********************************************************************
3035 * FILEDLG95_FILENAME_GetFileNames
3037 * Copies the filenames to a delimited string list.
3038 * The delimiter is specified by the parameter 'separator',
3039 * usually either a space or a nul
3041 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3043 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3044 UINT nStrCharCount = 0; /* index in src buffer */
3045 UINT nFileIndex = 0; /* index in dest buffer */
3046 UINT nFileCount = 0; /* number of files */
3047 UINT nStrLen = 0; /* length of string in edit control */
3048 LPWSTR lpstrEdit; /* buffer for string from edit control */
3052 /* get the filenames from the edit control */
3053 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3054 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3055 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3057 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3059 /* we might get single filename without any '"',
3060 * so we need nStrLen + terminating \0 + end-of-list \0 */
3061 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3064 /* build delimited file list from filenames */
3065 while ( nStrCharCount <= nStrLen )
3067 if ( lpstrEdit[nStrCharCount]=='"' )
3070 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3072 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3076 (*lpstrFileList)[nFileIndex++] = separator;
3083 /* single, unquoted string */
3084 if ((nStrLen > 0) && (*sizeUsed == 0) )
3086 strcpyW(*lpstrFileList, lpstrEdit);
3087 nFileIndex = strlenW(lpstrEdit) + 1;
3088 (*sizeUsed) = nFileIndex;
3093 (*lpstrFileList)[nFileIndex] = '\0';
3100 #define SETDefFormatEtc(fe,cf,med) \
3102 (fe).cfFormat = cf;\
3103 (fe).dwAspect = DVASPECT_CONTENT; \
3110 * DATAOBJECT Helper functions
3113 /***********************************************************************
3114 * COMCTL32_ReleaseStgMedium
3116 * like ReleaseStgMedium from ole32
3118 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3120 if(medium.pUnkForRelease)
3122 IUnknown_Release(medium.pUnkForRelease);
3126 GlobalUnlock(medium.u.hGlobal);
3127 GlobalFree(medium.u.hGlobal);
3131 /***********************************************************************
3132 * GetPidlFromDataObject
3134 * Return pidl(s) by number from the cached DataObject
3136 * nPidlIndex=0 gets the fully qualified root path
3138 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3142 FORMATETC formatetc;
3143 LPITEMIDLIST pidl = NULL;
3145 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3147 /* Set the FORMATETC structure*/
3148 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3150 /* Get the pidls from IDataObject */
3151 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3153 LPIDA cida = GlobalLock(medium.u.hGlobal);
3154 if(nPidlIndex <= cida->cidl)
3156 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3158 COMCTL32_ReleaseStgMedium(medium);
3163 /***********************************************************************
3166 * Return the number of selected items in the DataObject.
3169 UINT GetNumSelected( IDataObject *doSelected )
3173 FORMATETC formatetc;
3175 TRACE("sv=%p\n", doSelected);
3177 if (!doSelected) return 0;
3179 /* Set the FORMATETC structure*/
3180 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3182 /* Get the pidls from IDataObject */
3183 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3185 LPIDA cida = GlobalLock(medium.u.hGlobal);
3186 retVal = cida->cidl;
3187 COMCTL32_ReleaseStgMedium(medium);
3197 /***********************************************************************
3200 * Get the pidl's display name (relative to folder) and
3201 * put it in lpstrFileName.
3203 * Return NOERROR on success,
3207 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3212 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3216 SHGetDesktopFolder(&lpsf);
3217 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3218 IShellFolder_Release(lpsf);
3222 /* Get the display name of the pidl relative to the folder */
3223 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3225 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3230 /***********************************************************************
3231 * GetShellFolderFromPidl
3233 * pidlRel is the item pidl relative
3234 * Return the IShellFolder of the absolute pidl
3236 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3238 IShellFolder *psf = NULL,*psfParent;
3240 TRACE("%p\n", pidlAbs);
3242 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3245 if(pidlAbs && pidlAbs->mkid.cb)
3247 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3249 IShellFolder_Release(psfParent);
3253 /* return the desktop */
3259 /***********************************************************************
3262 * Return the LPITEMIDLIST to the parent of the pidl in the list
3264 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3266 LPITEMIDLIST pidlParent;
3268 TRACE("%p\n", pidl);
3270 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3271 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3276 /***********************************************************************
3279 * returns the pidl of the file name relative to folder
3280 * NULL if an error occurred
3282 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3284 LPITEMIDLIST pidl = NULL;
3287 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3289 if(!lpcstrFileName) return NULL;
3290 if(!*lpcstrFileName) return NULL;
3294 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3295 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3296 IShellFolder_Release(lpsf);
3301 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3308 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3310 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3313 TRACE("%p, %p\n", psf, pidl);
3315 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3317 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3318 /* see documentation shell 4.1*/
3319 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3322 /***********************************************************************
3323 * BrowseSelectedFolder
3325 static BOOL BrowseSelectedFolder(HWND hwnd)
3327 BOOL bBrowseSelFolder = FALSE;
3328 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3332 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3334 LPITEMIDLIST pidlSelection;
3336 /* get the file selected */
3337 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3338 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3340 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3341 pidlSelection, SBSP_RELATIVE ) ) )
3343 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3344 ' ','n','o','t',' ','e','x','i','s','t',0};
3345 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3348 bBrowseSelFolder = TRUE;
3350 COMDLG32_SHFree( pidlSelection );
3353 return bBrowseSelFolder;
3357 * Memory allocation methods */
3358 static void *MemAlloc(UINT size)
3360 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3363 static void MemFree(void *mem)
3365 HeapFree(GetProcessHeap(),0,mem);
3369 * Old-style (win3.1) dialogs */
3371 /***********************************************************************
3372 * FD32_GetTemplate [internal]
3374 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3375 * by a 32 bits application
3378 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3380 LPOPENFILENAMEW ofnW = lfs->ofnW;
3381 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3384 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3386 if (!(lfs->template = LockResource( ofnW->hInstance )))
3388 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3392 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3396 hResInfo = FindResourceA(priv->ofnA->hInstance,
3397 priv->ofnA->lpTemplateName,
3400 hResInfo = FindResourceW(ofnW->hInstance,
3401 ofnW->lpTemplateName,
3405 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3408 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3410 !(lfs->template = LockResource(hDlgTmpl)))
3412 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3415 } else { /* get it from internal Wine resource */
3417 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3418 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3420 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3423 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3424 !(lfs->template = LockResource( hDlgTmpl )))
3426 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3434 /************************************************************************
3435 * FD32_Init [internal]
3436 * called from the common 16/32 code to initialize 32 bit data
3438 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3440 BOOL IsUnicode = (BOOL) data;
3443 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3444 lfs->private1632 = priv;
3445 if (NULL == lfs->private1632) return FALSE;
3448 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3449 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3450 if (lfs->ofnW->lpfnHook)
3455 priv->ofnA = (LPOPENFILENAMEA) lParam;
3456 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3457 if (priv->ofnA->lpfnHook)
3459 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3460 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3463 if (! FD32_GetTemplate(lfs)) return FALSE;
3468 /***********************************************************************
3469 * FD32_CallWindowProc [internal]
3471 * called from the common 16/32 code to call the appropriate hook
3473 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3477 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3481 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3482 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3483 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3484 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3485 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3489 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3490 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3491 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3492 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3493 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3497 /***********************************************************************
3498 * FD32_UpdateResult [internal]
3499 * update the real client structures if any
3501 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3503 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3504 LPOPENFILENAMEW ofnW = lfs->ofnW;
3508 if (ofnW->nMaxFile &&
3509 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3510 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3511 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3512 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3513 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3517 /***********************************************************************
3518 * FD32_UpdateFileTitle [internal]
3519 * update the real client structures if any
3521 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3523 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3524 LPOPENFILENAMEW ofnW = lfs->ofnW;
3528 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3529 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3530 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3535 /***********************************************************************
3536 * FD32_SendLbGetCurSel [internal]
3537 * retrieve selected listbox item
3539 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3541 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3545 /************************************************************************
3546 * FD32_Destroy [internal]
3547 * called from the common 16/32 code to cleanup 32 bit data
3549 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3551 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3553 /* if ofnW has been allocated, have to free everything in it */
3554 if (NULL != priv && NULL != priv->ofnA)
3556 FD31_FreeOfnW(lfs->ofnW);
3557 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3561 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3563 callbacks->Init = FD32_Init;
3564 callbacks->CWP = FD32_CallWindowProc;
3565 callbacks->UpdateResult = FD32_UpdateResult;
3566 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3567 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3568 callbacks->Destroy = FD32_Destroy;
3571 /***********************************************************************
3572 * FD32_WMMeasureItem [internal]
3574 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3576 LPMEASUREITEMSTRUCT lpmeasure;
3578 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3579 lpmeasure->itemHeight = FD31_GetFldrHeight();
3584 /***********************************************************************
3585 * FileOpenDlgProc [internal]
3586 * Used for open and save, in fact.
3588 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3589 WPARAM wParam, LPARAM lParam)
3591 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3593 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3594 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3597 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3599 return lRet; /* else continue message processing */
3604 return FD31_WMInitDialog(hWnd, wParam, lParam);
3606 case WM_MEASUREITEM:
3607 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3610 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3613 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3616 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3617 switch (HIWORD(lParam))
3620 SetTextColor((HDC16)wParam, 0x00000000);
3622 case CTLCOLOR_STATIC:
3623 SetTextColor((HDC16)wParam, 0x00000000);
3633 /***********************************************************************
3634 * GetFileName31A [internal]
3636 * Creates a win31 style dialog box for the user to select a file to open/save.
3638 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3639 UINT dlgType /* type dialogue : open/save */
3645 FD31_CALLBACKS callbacks;
3647 if (!lpofn || !FD31_Init()) return FALSE;
3649 TRACE("ofn flags %08lx\n", lpofn->Flags);
3650 FD32_SetupCallbacks(&callbacks);
3651 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3654 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3655 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3656 FD32_FileOpenDlgProc, (LPARAM)lfs);
3657 FD31_DestroyPrivate(lfs);
3660 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3664 /***********************************************************************
3665 * GetFileName31W [internal]
3667 * Creates a win31 style dialog box for the user to select a file to open/save
3669 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3670 UINT dlgType /* type dialogue : open/save */
3676 FD31_CALLBACKS callbacks;
3678 if (!lpofn || !FD31_Init()) return FALSE;
3680 FD32_SetupCallbacks(&callbacks);
3681 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3684 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3685 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3686 FD32_FileOpenDlgProc, (LPARAM)lfs);
3687 FD31_DestroyPrivate(lfs);
3690 TRACE("file %s, file offset %d, ext offset %d\n",
3691 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3695 /* ------------------ APIs ---------------------- */
3697 /***********************************************************************
3698 * GetOpenFileNameA (COMDLG32.@)
3700 * Creates a dialog box for the user to select a file to open.
3703 * TRUE on success: user enters a valid file
3704 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3707 BOOL WINAPI GetOpenFileNameA(
3708 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3710 BOOL win16look = FALSE;
3712 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3713 if (ofn->Flags & OFN_FILEMUSTEXIST)
3714 ofn->Flags |= OFN_PATHMUSTEXIST;
3716 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3717 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3720 return GetFileName31A(ofn, OPEN_DIALOG);
3722 return GetFileDialog95A(ofn, OPEN_DIALOG);
3725 /***********************************************************************
3726 * GetOpenFileNameW (COMDLG32.@)
3728 * Creates a dialog box for the user to select a file to open.
3731 * TRUE on success: user enters a valid file
3732 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3735 BOOL WINAPI GetOpenFileNameW(
3736 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3738 BOOL win16look = FALSE;
3740 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3741 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3744 return GetFileName31W(ofn, OPEN_DIALOG);
3746 return GetFileDialog95W(ofn, OPEN_DIALOG);
3750 /***********************************************************************
3751 * GetSaveFileNameA (COMDLG32.@)
3753 * Creates a dialog box for the user to select a file to save.
3756 * TRUE on success: user enters a valid file
3757 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3760 BOOL WINAPI GetSaveFileNameA(
3761 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3763 BOOL win16look = FALSE;
3765 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3766 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3769 return GetFileName31A(ofn, SAVE_DIALOG);
3771 return GetFileDialog95A(ofn, SAVE_DIALOG);
3774 /***********************************************************************
3775 * GetSaveFileNameW (COMDLG32.@)
3777 * Creates a dialog box for the user to select a file to save.
3780 * TRUE on success: user enters a valid file
3781 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3784 BOOL WINAPI GetSaveFileNameW(
3785 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3787 BOOL win16look = FALSE;
3789 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3790 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3793 return GetFileName31W(ofn, SAVE_DIALOG);
3795 return GetFileDialog95W(ofn, SAVE_DIALOG);