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 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
473 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
474 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
475 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
478 fodInfos.initdir = NULL;
480 /* save current directory */
481 if (ofn->Flags & OFN_NOCHANGEDIR)
483 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
484 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
487 fodInfos.unicode = TRUE;
492 ret = GetFileName95(&fodInfos);
495 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
496 ret = GetFileName95(&fodInfos);
504 SetCurrentDirectoryW(lpstrSavDir);
505 MemFree(lpstrSavDir);
508 /* restore saved IN arguments and convert OUT arguments back */
509 MemFree(fodInfos.filename);
510 MemFree(fodInfos.initdir);
514 /******************************************************************************
515 * COMDLG32_GetDisplayNameOf [internal]
517 * Helper function to get the display name for a pidl.
519 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
520 LPSHELLFOLDER psfDesktop;
523 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
526 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
527 IShellFolder_Release(psfDesktop);
531 IShellFolder_Release(psfDesktop);
532 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
535 /***********************************************************************
536 * ArrangeCtrlPositions [internal]
538 * NOTE: Do not change anything here without a lot of testing.
540 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
542 HWND hwndChild, hwndStc32;
543 RECT rectParent, rectChild, rectStc32;
544 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
546 /* Take into account if open as read only checkbox and help button
551 RECT rectHelp, rectCancel;
552 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
553 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
554 /* subtract the height of the help button plus the space between
555 * the help button and the cancel button to the height of the dialog
557 help_fixup = rectHelp.bottom - rectCancel.bottom;
561 There are two possibilities to add components to the default file dialog box.
563 By default, all the new components are added below the standard dialog box (the else case).
565 However, if there is a static text component with the stc32 id, a special case happens.
566 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
567 in the window and the cx and cy indicate how to size the window.
568 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
569 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
573 GetClientRect(hwndParentDlg, &rectParent);
575 /* when arranging controls we have to use fixed parent size */
576 rectParent.bottom -= help_fixup;
578 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
581 GetWindowRect(hwndStc32, &rectStc32);
582 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
584 /* set the size of the stc32 control according to the size of
585 * client area of the parent dialog
587 SetWindowPos(hwndStc32, 0,
589 rectParent.right, rectParent.bottom,
590 SWP_NOMOVE | SWP_NOZORDER);
593 SetRectEmpty(&rectStc32);
595 /* this part moves controls of the child dialog */
596 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
599 if (hwndChild != hwndStc32)
601 GetWindowRect(hwndChild, &rectChild);
602 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
604 /* move only if stc32 exist */
605 if (hwndStc32 && rectChild.left > rectStc32.right)
607 LONG old_left = rectChild.left;
609 /* move to the right of visible controls of the parent dialog */
610 rectChild.left += rectParent.right;
611 rectChild.left -= rectStc32.right;
613 child_width_fixup = rectChild.left - old_left;
615 /* move even if stc32 doesn't exist */
616 if (rectChild.top >= rectStc32.bottom)
618 LONG old_top = rectChild.top;
620 /* move below visible controls of the parent dialog */
621 rectChild.top += rectParent.bottom;
622 rectChild.top -= rectStc32.bottom - rectStc32.top;
624 child_height_fixup = rectChild.top - old_top;
627 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
628 0, 0, SWP_NOSIZE | SWP_NOZORDER);
630 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
633 /* this part moves controls of the parent dialog */
634 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
637 if (hwndChild != hwndChildDlg)
639 GetWindowRect(hwndChild, &rectChild);
640 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
642 /* left,top of stc32 marks the position of controls
643 * from the parent dialog
645 rectChild.left += rectStc32.left;
646 rectChild.top += rectStc32.top;
648 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
649 0, 0, SWP_NOSIZE | SWP_NOZORDER);
651 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
654 /* calculate the size of the resulting dialog */
656 /* here we have to use original parent size */
657 GetClientRect(hwndParentDlg, &rectParent);
658 GetClientRect(hwndChildDlg, &rectChild);
662 rectChild.right += child_width_fixup;
663 rectChild.bottom += child_height_fixup;
665 if (rectParent.right > rectChild.right)
667 rectParent.right += rectChild.right;
668 rectParent.right -= rectStc32.right - rectStc32.left;
672 rectParent.right = rectChild.right;
675 if (rectParent.bottom > rectChild.bottom)
677 rectParent.bottom += rectChild.bottom;
678 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
682 /* child dialog is higher, unconditionally set new dialog
683 * height to its size (help_fixup will be subtracted below)
685 rectParent.bottom = rectChild.bottom + help_fixup;
690 rectParent.bottom += rectChild.bottom;
693 /* finally use fixed parent size */
694 rectParent.bottom -= help_fixup;
696 /* save the size of the parent's client area */
697 rectChild.right = rectParent.right;
698 rectChild.bottom = rectParent.bottom;
700 /* set the size of the parent dialog */
701 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
702 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
703 SetWindowPos(hwndParentDlg, 0,
705 rectParent.right - rectParent.left,
706 rectParent.bottom - rectParent.top,
707 SWP_NOMOVE | SWP_NOZORDER);
709 /* set the size of the child dialog */
710 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
711 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
714 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
723 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
774 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
775 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
776 (LPARAM)fodInfos->ofnInfos);
779 ShowWindow(hChildDlg,SW_SHOW);
783 else if( IsHooked(fodInfos))
788 WORD menu,class,title;
790 GetClientRect(hwnd,&rectHwnd);
791 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
792 temp.tmplate.dwExtendedStyle = 0;
793 temp.tmplate.cdit = 0;
798 temp.menu = temp.class = temp.title = 0;
800 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
801 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
808 /***********************************************************************
809 * SendCustomDlgNotificationMessage
811 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
814 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
816 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
818 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
820 if(!fodInfos) return 0;
822 if(fodInfos->DlgInfos.hwndCustomDlg)
825 TRACE("CALL NOTIFY for %x\n", uCode);
826 if(fodInfos->unicode)
829 ofnNotify.hdr.hwndFrom=hwndParentDlg;
830 ofnNotify.hdr.idFrom=0;
831 ofnNotify.hdr.code = uCode;
832 ofnNotify.lpOFN = fodInfos->ofnInfos;
833 ofnNotify.pszFile = NULL;
834 ret = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
839 ofnNotify.hdr.hwndFrom=hwndParentDlg;
840 ofnNotify.hdr.idFrom=0;
841 ofnNotify.hdr.code = uCode;
842 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
843 ofnNotify.pszFile = NULL;
844 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
846 TRACE("RET NOTIFY\n");
852 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
854 UINT sizeUsed = 0, n, total;
855 LPWSTR lpstrFileList = NULL;
856 WCHAR lpstrCurrentDir[MAX_PATH];
857 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
859 TRACE("CDM_GETFILEPATH:\n");
861 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
864 /* get path and filenames */
865 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
866 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
868 TRACE("path >%s< filespec >%s< %d files\n",
869 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
871 if( fodInfos->unicode )
873 LPWSTR bufW = buffer;
874 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
876 /* Prepend the current path */
877 n = strlenW(lpstrCurrentDir) + 1;
878 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
881 /* 'n' includes trailing \0 */
883 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
885 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
890 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
891 NULL, 0, NULL, NULL);
892 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
893 NULL, 0, NULL, NULL);
895 /* Prepend the current path */
896 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
897 bufA, size, NULL, NULL);
901 /* 'n' includes trailing \0 */
903 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
904 &bufA[n], size-n, NULL, NULL);
907 TRACE("returned -> %s\n",debugstr_an(bufA, total));
909 MemFree(lpstrFileList);
914 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
917 LPWSTR lpstrFileList = NULL;
918 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
920 TRACE("CDM_GETSPEC:\n");
922 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
923 if( fodInfos->unicode )
925 LPWSTR bufW = buffer;
926 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
931 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
932 NULL, 0, NULL, NULL);
933 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
934 bufA, size, NULL, NULL);
936 MemFree(lpstrFileList);
941 /***********************************************************************
942 * FILEDLG95_HandleCustomDialogMessages
944 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
946 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
948 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
949 WCHAR lpstrPath[MAX_PATH];
952 if(!fodInfos) return FALSE;
956 case CDM_GETFILEPATH:
957 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
960 case CDM_GETFOLDERPATH:
961 TRACE("CDM_GETFOLDERPATH:\n");
962 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
965 if (fodInfos->unicode)
966 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
968 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
969 (LPSTR)lParam, (int)wParam, NULL, NULL);
971 retval = strlenW(lpstrPath);
975 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
978 case CDM_SETCONTROLTEXT:
979 TRACE("CDM_SETCONTROLTEXT:\n");
982 if( fodInfos->unicode )
983 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
985 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
990 case CDM_HIDECONTROL:
992 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
999 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1003 /***********************************************************************
1006 * File open dialog procedure
1008 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1011 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1018 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1020 /* Adds the FileOpenDlgInfos in the property list of the dialog
1021 so it will be easily accessible through a GetPropA(...) */
1022 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1024 fodInfos->DlgInfos.hwndCustomDlg =
1025 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1027 FILEDLG95_InitControls(hwnd);
1029 if (fodInfos->DlgInfos.hwndCustomDlg)
1030 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1031 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1033 FILEDLG95_FillControls(hwnd, wParam, lParam);
1035 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1036 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1037 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1041 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1044 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1047 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1053 case WM_GETISHELLBROWSER:
1054 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1057 RemovePropA(hwnd, FileOpenDlgInfosStr);
1062 LPNMHDR lpnmh = (LPNMHDR)lParam;
1065 /* set up the button tooltips strings */
1066 if(TTN_GETDISPINFOA == lpnmh->code )
1068 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1069 switch(lpnmh->idFrom )
1071 /* Up folder button */
1072 case FCIDM_TB_UPFOLDER:
1073 stringId = IDS_UPFOLDER;
1075 /* New folder button */
1076 case FCIDM_TB_NEWFOLDER:
1077 stringId = IDS_NEWFOLDER;
1079 /* List option button */
1080 case FCIDM_TB_SMALLICON:
1081 stringId = IDS_LISTVIEW;
1083 /* Details option button */
1084 case FCIDM_TB_REPORTVIEW:
1085 stringId = IDS_REPORTVIEW;
1087 /* Desktop button */
1088 case FCIDM_TB_DESKTOP:
1089 stringId = IDS_TODESKTOP;
1094 lpdi->hinst = COMDLG32_hInstance;
1095 lpdi->lpszText = (LPSTR) stringId;
1100 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1101 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1106 /***********************************************************************
1107 * FILEDLG95_InitControls
1109 * WM_INITDIALOG message handler (before hook notification)
1111 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1113 int win2000plus = 0;
1115 int handledPath = FALSE;
1116 OSVERSIONINFOA osVi;
1117 static const WCHAR szwSlash[] = { '\\', 0 };
1118 static const WCHAR szwStar[] = { '*',0 };
1122 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1123 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1124 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1125 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1126 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1127 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1128 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1129 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1130 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1135 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1137 tba[0].hInst = HINST_COMMCTRL;
1138 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1139 tba[1].hInst = COMDLG32_hInstance;
1142 TRACE("%p\n", fodInfos);
1144 /* Get windows version emulating */
1145 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1146 GetVersionExA(&osVi);
1147 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1148 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1149 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1150 win2000plus = (osVi.dwMajorVersion > 4);
1151 if (win2000plus) win98plus = TRUE;
1153 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1155 /* Get the hwnd of the controls */
1156 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1157 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1158 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1160 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1161 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1163 /* construct the toolbar */
1164 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1165 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1167 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1168 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1169 rectTB.left = rectlook.right;
1170 rectTB.top = rectlook.top-1;
1172 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1173 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1174 rectTB.left, rectTB.top,
1175 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1176 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1178 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1180 /* FIXME: use TB_LOADIMAGES when implemented */
1181 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1182 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1183 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1185 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1186 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1188 /* Set the window text with the text specified in the OPENFILENAME structure */
1191 SetWindowTextW(hwnd,fodInfos->title);
1193 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1196 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1197 SetWindowTextW(hwnd, buf);
1200 /* Initialise the file name edit control */
1201 handledPath = FALSE;
1202 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1204 if(fodInfos->filename)
1206 /* 1. If win2000 or higher and filename contains a path, use it
1207 in preference over the lpstrInitialDir */
1208 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1209 WCHAR tmpBuf[MAX_PATH];
1213 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1216 /* nameBit is always shorter than the original filename */
1217 strcpyW(fodInfos->filename,nameBit);
1220 if (fodInfos->initdir == NULL)
1221 MemFree(fodInfos->initdir);
1222 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1223 strcpyW(fodInfos->initdir, tmpBuf);
1225 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1226 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1228 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1231 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1235 /* 2. (All platforms) If initdir is not null, then use it */
1236 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1237 (*fodInfos->initdir!=0x00))
1239 /* Work out the proper path as supplied one might be relative */
1240 /* (Here because supplying '.' as dir browses to My Computer) */
1241 if (handledPath==FALSE) {
1242 WCHAR tmpBuf[MAX_PATH];
1243 WCHAR tmpBuf2[MAX_PATH];
1247 strcpyW(tmpBuf, fodInfos->initdir);
1248 if( PathFileExistsW(tmpBuf) ) {
1249 /* initdir does not have to be a directory. If a file is
1250 * specified, the dir part is taken */
1251 if( PathIsDirectoryW(tmpBuf)) {
1252 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1253 strcatW(tmpBuf, szwSlash);
1255 strcatW(tmpBuf, szwStar);
1257 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1260 if (fodInfos->initdir)
1261 MemFree(fodInfos->initdir);
1262 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1263 strcpyW(fodInfos->initdir, tmpBuf2);
1265 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1268 else if (fodInfos->initdir)
1270 MemFree(fodInfos->initdir);
1271 fodInfos->initdir = NULL;
1272 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1277 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1278 (*fodInfos->initdir==0x00)))
1280 /* 3. All except w2k+: if filename contains a path use it */
1281 if (!win2000plus && fodInfos->filename &&
1282 *fodInfos->filename &&
1283 strpbrkW(fodInfos->filename, szwSlash)) {
1284 WCHAR tmpBuf[MAX_PATH];
1288 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1293 /* nameBit is always shorter than the original filename */
1294 strcpyW(fodInfos->filename, nameBit);
1297 len = strlenW(tmpBuf);
1298 if(fodInfos->initdir)
1299 MemFree(fodInfos->initdir);
1300 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1301 strcpyW(fodInfos->initdir, tmpBuf);
1304 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1305 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1307 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1310 /* 4. win98+ and win2000+ if any files of specified filter types in
1311 current directory, use it */
1312 if ( win98plus && handledPath == FALSE &&
1313 fodInfos->filter && *fodInfos->filter) {
1315 BOOL searchMore = TRUE;
1316 LPCWSTR lpstrPos = fodInfos->filter;
1317 WIN32_FIND_DATAW FindFileData;
1322 /* filter is a list... title\0ext\0......\0\0 */
1324 /* Skip the title */
1325 if(! *lpstrPos) break; /* end */
1326 lpstrPos += strlenW(lpstrPos) + 1;
1328 /* See if any files exist in the current dir with this extension */
1329 if(! *lpstrPos) break; /* end */
1331 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1333 if (hFind == INVALID_HANDLE_VALUE) {
1334 /* None found - continue search */
1335 lpstrPos += strlenW(lpstrPos) + 1;
1340 if(fodInfos->initdir)
1341 MemFree(fodInfos->initdir);
1342 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1343 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1346 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1347 debugstr_w(lpstrPos));
1353 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1355 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1356 if (handledPath == FALSE && (win2000plus || win98plus)) {
1357 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1359 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1361 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1364 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1365 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1367 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1370 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1373 } else if (handledPath==FALSE) {
1374 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1375 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1377 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1380 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1381 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1383 /* Must the open as read only check box be checked ?*/
1384 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1386 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1389 /* Must the open as read only check box be hidden? */
1390 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1392 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1393 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1396 /* Must the help button be hidden? */
1397 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1399 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1400 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1403 /* Resize the height, if open as read only checkbox ad help button
1404 are hidden and we are not using a custom template nor a customDialog
1406 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1407 (!(fodInfos->ofnInfos->Flags &
1408 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1409 (!fodInfos->DlgInfos.hwndCustomDlg ))
1411 RECT rectDlg, rectHelp, rectCancel;
1412 GetWindowRect(hwnd, &rectDlg);
1413 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1414 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1415 /* subtract the height of the help button plus the space between
1416 the help button and the cancel button to the height of the dialog */
1417 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1418 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1419 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1421 /* change Open to Save */
1422 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1425 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1426 SetDlgItemTextW(hwnd, IDOK, buf);
1427 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1428 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1433 /***********************************************************************
1434 * FILEDLG95_FillControls
1436 * WM_INITDIALOG message handler (after hook notification)
1438 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1440 LPITEMIDLIST pidlItemId = NULL;
1442 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1444 TRACE("dir=%s file=%s\n",
1445 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1447 /* Get the initial directory pidl */
1449 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1451 WCHAR path[MAX_PATH];
1453 GetCurrentDirectoryW(MAX_PATH,path);
1454 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1457 /* Initialise shell objects */
1458 FILEDLG95_SHELL_Init(hwnd);
1460 /* Initialize the Look In combo box */
1461 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1463 /* Initialize the filter combo box */
1464 FILEDLG95_FILETYPE_Init(hwnd);
1466 /* Browse to the initial directory */
1467 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1469 /* Free pidlItem memory */
1470 COMDLG32_SHFree(pidlItemId);
1474 /***********************************************************************
1477 * Regroups all the cleaning functions of the filedlg
1479 void FILEDLG95_Clean(HWND hwnd)
1481 FILEDLG95_FILETYPE_Clean(hwnd);
1482 FILEDLG95_LOOKIN_Clean(hwnd);
1483 FILEDLG95_SHELL_Clean(hwnd);
1485 /***********************************************************************
1486 * FILEDLG95_OnWMCommand
1488 * WM_COMMAND message handler
1490 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1492 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1493 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1494 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1500 FILEDLG95_OnOpen(hwnd);
1504 FILEDLG95_Clean(hwnd);
1505 EndDialog(hwnd, FALSE);
1507 /* Filetype combo box */
1509 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1511 /* LookIn combo box */
1513 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1516 /* --- toolbar --- */
1517 /* Up folder button */
1518 case FCIDM_TB_UPFOLDER:
1519 FILEDLG95_SHELL_UpFolder(hwnd);
1521 /* New folder button */
1522 case FCIDM_TB_NEWFOLDER:
1523 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1525 /* List option button */
1526 case FCIDM_TB_SMALLICON:
1527 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1529 /* Details option button */
1530 case FCIDM_TB_REPORTVIEW:
1531 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1533 /* Details option button */
1534 case FCIDM_TB_DESKTOP:
1535 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1542 /* Do not use the listview selection anymore */
1543 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1547 /***********************************************************************
1548 * FILEDLG95_OnWMGetIShellBrowser
1550 * WM_GETISHELLBROWSER message handler
1552 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1555 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1559 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1565 /***********************************************************************
1566 * FILEDLG95_SendFileOK
1568 * Sends the CDN_FILEOK notification if required
1571 * TRUE if the dialog should close
1572 * FALSE if the dialog should not be closed
1574 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1576 /* ask the hook if we can close */
1577 if(IsHooked(fodInfos))
1580 /* First send CDN_FILEOK as MSDN doc says */
1581 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1582 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1584 TRACE("canceled\n");
1588 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1589 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1590 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1591 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1593 TRACE("canceled\n");
1600 /***********************************************************************
1601 * FILEDLG95_OnOpenMultipleFiles
1603 * Handles the opening of multiple files.
1606 * check destination buffer size
1608 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1610 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1611 UINT nCount, nSizePath;
1612 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1616 if(fodInfos->unicode)
1618 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1619 ofn->lpstrFile[0] = '\0';
1623 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1624 ofn->lpstrFile[0] = '\0';
1627 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1629 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1630 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1631 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1633 LPWSTR lpstrTemp = lpstrFileList;
1635 for ( nCount = 0; nCount < nFileCount; nCount++ )
1639 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1642 WCHAR lpstrNotFound[100];
1643 WCHAR lpstrMsg[100];
1645 static const WCHAR nl[] = {'\n',0};
1647 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1648 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1650 strcpyW(tmp, lpstrTemp);
1652 strcatW(tmp, lpstrNotFound);
1654 strcatW(tmp, lpstrMsg);
1656 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1660 /* move to the next file in the list of files */
1661 lpstrTemp += strlenW(lpstrTemp) + 1;
1662 COMDLG32_SHFree(pidl);
1666 nSizePath = strlenW(lpstrPathSpec) + 1;
1667 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1669 /* For "oldstyle" dialog the components have to
1670 be separated by blanks (not '\0'!) and short
1671 filenames have to be used! */
1672 FIXME("Components have to be separated by blanks\n");
1674 if(fodInfos->unicode)
1676 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1677 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1678 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1682 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1684 if (ofn->lpstrFile != NULL)
1686 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1687 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1688 if (ofn->nMaxFile > nSizePath)
1690 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1691 ofn->lpstrFile + nSizePath,
1692 ofn->nMaxFile - nSizePath, NULL, NULL);
1697 fodInfos->ofnInfos->nFileOffset = nSizePath;
1698 fodInfos->ofnInfos->nFileExtension = 0;
1700 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1703 /* clean and exit */
1704 FILEDLG95_Clean(hwnd);
1705 return EndDialog(hwnd,TRUE);
1708 /***********************************************************************
1711 * Ok button WM_COMMAND message handler
1713 * If the function succeeds, the return value is nonzero.
1715 #define ONOPEN_OPEN 1
1716 #define ONOPEN_SEARCH 2
1717 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1719 WCHAR strMsgTitle[MAX_PATH];
1720 WCHAR strMsgText [MAX_PATH];
1722 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1724 strMsgTitle[0] = '\0';
1725 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1726 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1729 BOOL FILEDLG95_OnOpen(HWND hwnd)
1731 LPWSTR lpstrFileList;
1732 UINT nFileCount = 0;
1735 WCHAR lpstrPathAndFile[MAX_PATH];
1736 WCHAR lpstrTemp[MAX_PATH];
1737 LPSHELLFOLDER lpsf = NULL;
1739 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1741 TRACE("hwnd=%p\n", hwnd);
1743 if(BrowseSelectedFolder(hwnd))
1746 /* get the files from the edit control */
1747 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1749 /* try if the user selected a folder in the shellview */
1755 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1759 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1762 Step 1: Build a complete path name from the current folder and
1763 the filename or path in the edit box.
1765 - the path in the edit box is a root path
1766 (with or without drive letter)
1767 - the edit box contains ".." (or a path with ".." in it)
1770 /* Get the current directory name */
1771 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1774 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1776 PathAddBackslashW(lpstrPathAndFile);
1778 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1780 /* if the user specifyed a fully qualified path use it */
1781 if(PathIsRelativeW(lpstrFileList))
1783 strcatW(lpstrPathAndFile, lpstrFileList);
1787 /* does the path have a drive letter? */
1788 if (PathGetDriveNumberW(lpstrFileList) == -1)
1789 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1791 strcpyW(lpstrPathAndFile, lpstrFileList);
1794 /* resolve "." and ".." */
1795 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1796 strcpyW(lpstrPathAndFile, lpstrTemp);
1797 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1799 MemFree(lpstrFileList);
1802 Step 2: here we have a cleaned up path
1804 We have to parse the path step by step to see if we have to browse
1805 to a folder if the path points to a directory or the last
1806 valid element is a directory.
1809 lpstrPathAndFile: cleaned up path
1812 nOpenAction = ONOPEN_OPEN;
1814 /* don't apply any checks with OFN_NOVALIDATE */
1816 LPWSTR lpszTemp, lpszTemp1;
1817 LPITEMIDLIST pidl = NULL;
1818 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1820 /* check for invalid chars */
1821 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1823 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1828 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1830 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1833 LPSHELLFOLDER lpsfChild;
1834 WCHAR lpwstrTemp[MAX_PATH];
1835 DWORD dwEaten, dwAttributes;
1838 strcpyW(lpwstrTemp, lpszTemp);
1839 p = PathFindNextComponentW(lpwstrTemp);
1841 if (!p) break; /* end of path */
1844 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1848 static const WCHAR wszWild[] = { '*', '?', 0 };
1849 /* if the last element is a wildcard do a search */
1850 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1852 nOpenAction = ONOPEN_SEARCH;
1856 lpszTemp1 = lpszTemp;
1858 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1860 /* append a backslash to drive letters */
1861 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1862 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1863 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1865 PathAddBackslashW(lpwstrTemp);
1868 dwAttributes = SFGAO_FOLDER;
1869 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1871 /* the path component is valid, we have a pidl of the next path component */
1872 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1873 if(dwAttributes & SFGAO_FOLDER)
1875 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1877 ERR("bind to failed\n"); /* should not fail */
1880 IShellFolder_Release(lpsf);
1888 /* end dialog, return value */
1889 nOpenAction = ONOPEN_OPEN;
1892 COMDLG32_SHFree(pidl);
1895 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1897 if(*lpszTemp) /* points to trailing null for last path element */
1899 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1901 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1907 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1908 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1910 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1914 /* change to the current folder */
1915 nOpenAction = ONOPEN_OPEN;
1920 nOpenAction = ONOPEN_OPEN;
1924 if(pidl) COMDLG32_SHFree(pidl);
1928 Step 3: here we have a cleaned up and validated path
1931 lpsf: ShellFolder bound to the rightmost valid path component
1932 lpstrPathAndFile: cleaned up path
1933 nOpenAction: action to do
1935 TRACE("end validate sf=%p\n", lpsf);
1939 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1940 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1943 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1945 IPersistFolder2 * ppf2;
1947 /* replace the current filter */
1948 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1949 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1950 len = strlenW(lpszTemp)+1;
1951 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1952 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1954 /* set the filter cb to the extension when possible */
1955 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1956 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1958 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1960 LPITEMIDLIST pidlCurrent;
1961 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1962 IPersistFolder2_Release(ppf2);
1963 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1965 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1969 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1971 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1972 COMDLG32_SHFree(pidlCurrent);
1977 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1978 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1982 /* update READONLY check box flag */
1983 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1984 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1986 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1988 /* Attach the file extension with file name*/
1990 if(!PathIsDirectoryW(lpstrPathAndFile))
1992 if((ext = PathFindExtensionW(lpstrPathAndFile)) == NULL)
1994 /* if no extension is specified with file name, then */
1995 /* attach the extension from file filter or default one */
1997 WCHAR *filterExt = NULL;
1998 LPWSTR lpstrFilter = NULL;
1999 static const WCHAR szwDot[] = {'.',0};
2000 int PathLength = strlenW(lpstrPathAndFile);
2003 strcatW(lpstrPathAndFile, szwDot);
2005 /*Get the file extension from file type filter*/
2006 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2007 fodInfos->ofnInfos->nFilterIndex-1);
2009 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2010 filterExt = PathFindExtensionW(lpstrFilter);
2012 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2013 strcatW(lpstrPathAndFile, filterExt + 1);
2014 else if ( fodInfos->defext ) /* attach the default file extension*/
2015 strcatW(lpstrPathAndFile, fodInfos->defext);
2017 /* In Open dialog: if file does not exist try without extension */
2018 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2019 lpstrPathAndFile[PathLength] = '\0';
2022 if (fodInfos->defext) /* add default extension */
2024 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2027 if (!lstrcmpiW(fodInfos->defext, ext))
2028 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2030 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2034 /* In Save dialog: check if the file already exists */
2035 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2036 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2037 && PathFileExistsW(lpstrPathAndFile))
2039 WCHAR lpstrOverwrite[100];
2042 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2043 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2044 MB_YESNO | MB_ICONEXCLAMATION);
2052 /* Check that the size of the file does not exceed buffer size.
2053 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2054 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2055 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2059 /* fill destination buffer */
2060 if (fodInfos->ofnInfos->lpstrFile)
2062 if(fodInfos->unicode)
2064 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2066 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2067 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2068 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2072 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2074 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2075 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2076 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2077 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2081 /* set filename offset */
2082 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2083 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2085 /* set extension offset */
2086 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2087 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2089 /* set the lpstrFileTitle */
2090 if(fodInfos->ofnInfos->lpstrFileTitle)
2092 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2093 if(fodInfos->unicode)
2095 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2096 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2100 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2101 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2102 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2106 /* copy currently selected filter to lpstrCustomFilter */
2107 if (fodInfos->ofnInfos->lpstrCustomFilter)
2109 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2110 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2111 NULL, 0, NULL, NULL);
2112 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2114 LPSTR s = ofn->lpstrCustomFilter;
2115 s += strlen(ofn->lpstrCustomFilter)+1;
2116 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2117 s, len, NULL, NULL);
2122 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2126 FILEDLG95_Clean(hwnd);
2127 ret = EndDialog(hwnd, TRUE);
2133 size = strlenW(lpstrPathAndFile) + 1;
2134 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2136 /* return needed size in first two bytes of lpstrFile */
2137 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2138 FILEDLG95_Clean(hwnd);
2139 ret = EndDialog(hwnd, FALSE);
2140 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2148 if(lpsf) IShellFolder_Release(lpsf);
2152 /***********************************************************************
2153 * FILEDLG95_SHELL_Init
2155 * Initialisation of the shell objects
2157 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2159 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2164 * Initialisation of the FileOpenDialogInfos structure
2170 fodInfos->ShellInfos.hwndOwner = hwnd;
2172 /* Disable multi-select if flag not set */
2173 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2175 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2177 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2178 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2180 /* Construct the IShellBrowser interface */
2181 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2186 /***********************************************************************
2187 * FILEDLG95_SHELL_ExecuteCommand
2189 * Change the folder option and refresh the view
2190 * If the function succeeds, the return value is nonzero.
2192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2194 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2197 TRACE("(%p,%p)\n", hwnd, lpVerb);
2199 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2204 CMINVOKECOMMANDINFO ci;
2205 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2206 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2210 IContextMenu_InvokeCommand(pcm, &ci);
2211 IContextMenu_Release(pcm);
2217 /***********************************************************************
2218 * FILEDLG95_SHELL_UpFolder
2220 * Browse to the specified object
2221 * If the function succeeds, the return value is nonzero.
2223 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2225 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2229 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2233 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2239 /***********************************************************************
2240 * FILEDLG95_SHELL_BrowseToDesktop
2242 * Browse to the Desktop
2243 * If the function succeeds, the return value is nonzero.
2245 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2247 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2253 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2254 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2255 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2256 COMDLG32_SHFree(pidl);
2257 return SUCCEEDED(hres);
2259 /***********************************************************************
2260 * FILEDLG95_SHELL_Clean
2262 * Cleans the memory used by shell objects
2264 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2266 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2270 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2272 /* clean Shell interfaces */
2273 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2274 IShellView_Release(fodInfos->Shell.FOIShellView);
2275 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2276 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2277 if (fodInfos->Shell.FOIDataObject)
2278 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2281 /***********************************************************************
2282 * FILEDLG95_FILETYPE_Init
2284 * Initialisation of the file type combo box
2286 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2288 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2289 int nFilters = 0; /* number of filters */
2294 if(fodInfos->customfilter)
2296 /* customfilter has one entry... title\0ext\0
2297 * Set first entry of combo box item with customfilter
2300 LPCWSTR lpstrPos = fodInfos->customfilter;
2303 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2305 /* Copy the extensions */
2306 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2307 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2308 strcpyW(lpstrExt,lpstrPos);
2310 /* Add the item at the end of the combo */
2311 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2312 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2315 if(fodInfos->filter)
2317 LPCWSTR lpstrPos = fodInfos->filter;
2321 /* filter is a list... title\0ext\0......\0\0
2322 * Set the combo item text to the title and the item data
2325 LPCWSTR lpstrDisplay;
2329 if(! *lpstrPos) break; /* end */
2330 lpstrDisplay = lpstrPos;
2331 lpstrPos += strlenW(lpstrPos) + 1;
2333 /* Copy the extensions */
2334 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2335 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2336 strcpyW(lpstrExt,lpstrPos);
2337 lpstrPos += strlenW(lpstrPos) + 1;
2339 /* Add the item at the end of the combo */
2340 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2341 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2347 * Set the current filter to the one specified
2348 * in the initialisation structure
2350 if (fodInfos->filter || fodInfos->customfilter)
2354 /* Check to make sure our index isn't out of bounds. */
2355 if ( fodInfos->ofnInfos->nFilterIndex >
2356 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2357 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2359 /* set default filter index */
2360 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2361 fodInfos->ofnInfos->nFilterIndex = 1;
2363 /* calculate index of Combo Box item */
2364 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2365 if (fodInfos->customfilter == NULL)
2368 /* Set the current index selection. */
2369 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2371 /* Get the corresponding text string from the combo box. */
2372 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2375 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2381 CharLowerW(lpstrFilter); /* lowercase */
2382 len = strlenW(lpstrFilter)+1;
2383 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2384 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2387 fodInfos->ofnInfos->nFilterIndex = 0;
2392 /***********************************************************************
2393 * FILEDLG95_FILETYPE_OnCommand
2395 * WM_COMMAND of the file type combo box
2396 * If the function succeeds, the return value is nonzero.
2398 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2400 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2408 /* Get the current item of the filetype combo box */
2409 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2411 /* set the current filter index */
2412 fodInfos->ofnInfos->nFilterIndex = iItem +
2413 (fodInfos->customfilter == NULL ? 1 : 0);
2415 /* Set the current filter with the current selection */
2416 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2417 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2419 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2421 if((int)lpstrFilter != CB_ERR)
2424 CharLowerW(lpstrFilter); /* lowercase */
2425 len = strlenW(lpstrFilter)+1;
2426 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2427 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2428 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2431 /* Refresh the actual view to display the included items*/
2432 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2437 /***********************************************************************
2438 * FILEDLG95_FILETYPE_SearchExt
2440 * searches for an extension in the filetype box
2442 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2444 int i, iCount = CBGetCount(hwnd);
2446 TRACE("%s\n", debugstr_w(lpstrExt));
2448 if(iCount != CB_ERR)
2450 for(i=0;i<iCount;i++)
2452 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2459 /***********************************************************************
2460 * FILEDLG95_FILETYPE_Clean
2462 * Clean the memory used by the filetype combo box
2464 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2466 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2468 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2472 /* Delete each string of the combo and their associated data */
2473 if(iCount != CB_ERR)
2475 for(iPos = iCount-1;iPos>=0;iPos--)
2477 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2478 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2481 /* Current filter */
2482 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2483 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2487 /***********************************************************************
2488 * FILEDLG95_LOOKIN_Init
2490 * Initialisation of the look in combo box
2492 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2494 IShellFolder *psfRoot, *psfDrives;
2495 IEnumIDList *lpeRoot, *lpeDrives;
2496 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2498 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2502 liInfos->iMaxIndentation = 0;
2504 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2506 /* set item height for both text field and listbox */
2507 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2508 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2510 /* Turn on the extended UI for the combo box like Windows does */
2511 CBSetExtendedUI(hwndCombo, TRUE);
2513 /* Initialise data of Desktop folder */
2514 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2515 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2516 COMDLG32_SHFree(pidlTmp);
2518 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2520 SHGetDesktopFolder(&psfRoot);
2524 /* enumerate the contents of the desktop */
2525 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2527 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2529 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2531 /* special handling for CSIDL_DRIVES */
2532 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2534 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2536 /* enumerate the drives */
2537 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2539 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2541 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2542 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2543 COMDLG32_SHFree(pidlAbsTmp);
2544 COMDLG32_SHFree(pidlTmp1);
2546 IEnumIDList_Release(lpeDrives);
2548 IShellFolder_Release(psfDrives);
2551 COMDLG32_SHFree(pidlTmp);
2553 IEnumIDList_Release(lpeRoot);
2555 IShellFolder_Release(psfRoot);
2558 COMDLG32_SHFree(pidlDrives);
2562 /***********************************************************************
2563 * FILEDLG95_LOOKIN_DrawItem
2565 * WM_DRAWITEM message handler
2567 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2569 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2570 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2571 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2575 HIMAGELIST ilItemImage;
2578 LPSFOLDER tmpFolder;
2581 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2585 if(pDIStruct->itemID == -1)
2588 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2589 pDIStruct->itemID)))
2593 if(pDIStruct->itemID == liInfos->uSelectedItem)
2595 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2598 sizeof (SHFILEINFOA),
2599 SHGFI_PIDL | SHGFI_SMALLICON |
2600 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2601 SHGFI_DISPLAYNAME );
2605 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2608 sizeof (SHFILEINFOA),
2609 SHGFI_PIDL | SHGFI_SMALLICON |
2610 SHGFI_SYSICONINDEX |
2614 /* Is this item selected ? */
2615 if(pDIStruct->itemState & ODS_SELECTED)
2617 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2618 SetBkColor(pDIStruct->hDC,crHighLight);
2619 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2623 SetTextColor(pDIStruct->hDC,crText);
2624 SetBkColor(pDIStruct->hDC,crWin);
2625 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2628 /* Do not indent item if drawing in the edit of the combo */
2629 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2632 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2635 sizeof (SHFILEINFOA),
2636 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2637 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2642 iIndentation = tmpFolder->m_iIndent;
2644 /* Draw text and icon */
2646 /* Initialise the icon display area */
2647 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2648 rectIcon.top = pDIStruct->rcItem.top;
2649 rectIcon.right = rectIcon.left + ICONWIDTH;
2650 rectIcon.bottom = pDIStruct->rcItem.bottom;
2652 /* Initialise the text display area */
2653 GetTextMetricsA(pDIStruct->hDC, &tm);
2654 rectText.left = rectIcon.right;
2656 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2657 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2659 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2661 /* Draw the icon from the image list */
2662 ImageList_Draw(ilItemImage,
2669 /* Draw the associated text */
2670 if(sfi.szDisplayName)
2671 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2677 /***********************************************************************
2678 * FILEDLG95_LOOKIN_OnCommand
2680 * LookIn combo box WM_COMMAND message handler
2681 * If the function succeeds, the return value is nonzero.
2683 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2685 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2687 TRACE("%p\n", fodInfos);
2693 LPSFOLDER tmpFolder;
2696 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2698 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2703 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2704 tmpFolder->pidlItem,
2707 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2717 /***********************************************************************
2718 * FILEDLG95_LOOKIN_AddItem
2720 * Adds an absolute pidl item to the lookin combo box
2721 * returns the index of the inserted item
2723 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2725 LPITEMIDLIST pidlNext;
2728 LookInInfos *liInfos;
2730 TRACE("%08x\n", iInsertId);
2735 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2738 tmpFolder = MemAlloc(sizeof(SFOLDER));
2739 tmpFolder->m_iIndent = 0;
2741 /* Calculate the indentation of the item in the lookin*/
2743 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2745 tmpFolder->m_iIndent++;
2748 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2750 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2751 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2753 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2754 SHGetFileInfoA((LPSTR)pidl,
2758 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2759 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2761 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2763 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2767 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2769 /* Add the item at the end of the list */
2772 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2774 /* Insert the item at the iInsertId position*/
2777 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2780 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2784 COMDLG32_SHFree( tmpFolder->pidlItem );
2785 MemFree( tmpFolder );
2790 /***********************************************************************
2791 * FILEDLG95_LOOKIN_InsertItemAfterParent
2793 * Insert an item below its parent
2795 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2798 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2803 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2807 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2810 /* Free pidlParent memory */
2811 COMDLG32_SHFree((LPVOID)pidlParent);
2813 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2816 /***********************************************************************
2817 * FILEDLG95_LOOKIN_SelectItem
2819 * Adds an absolute pidl item to the lookin combo box
2820 * returns the index of the inserted item
2822 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2825 LookInInfos *liInfos;
2829 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2831 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2835 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2836 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2841 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2842 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2846 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2848 if(iRemovedItem < iItemPos)
2853 CBSetCurSel(hwnd,iItemPos);
2854 liInfos->uSelectedItem = iItemPos;
2860 /***********************************************************************
2861 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2863 * Remove the item with an expansion level over iExpansionLevel
2865 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2869 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2873 if(liInfos->iMaxIndentation <= 2)
2876 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2878 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2879 COMDLG32_SHFree(tmpFolder->pidlItem);
2881 CBDeleteString(hwnd,iItemPos);
2882 liInfos->iMaxIndentation--;
2890 /***********************************************************************
2891 * FILEDLG95_LOOKIN_SearchItem
2893 * Search for pidl in the lookin combo box
2894 * returns the index of the found item
2896 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2899 int iCount = CBGetCount(hwnd);
2901 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2903 if (iCount != CB_ERR)
2907 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2909 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2911 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2919 /***********************************************************************
2920 * FILEDLG95_LOOKIN_Clean
2922 * Clean the memory used by the lookin combo box
2924 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2926 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2928 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2932 /* Delete each string of the combo and their associated data */
2933 if (iCount != CB_ERR)
2935 for(iPos = iCount-1;iPos>=0;iPos--)
2937 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2938 COMDLG32_SHFree(tmpFolder->pidlItem);
2940 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2944 /* LookInInfos structure */
2945 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2948 /***********************************************************************
2949 * FILEDLG95_FILENAME_FillFromSelection
2951 * fills the edit box from the cached DataObject
2953 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2955 FileOpenDlgInfos *fodInfos;
2957 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2958 char lpstrTemp[MAX_PATH];
2959 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2962 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2964 /* Count how many files we have */
2965 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2967 /* calculate the string length, count files */
2968 if (nFileSelected >= 1)
2970 nLength += 3; /* first and last quotes, trailing \0 */
2971 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2973 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2977 /* get the total length of the selected file names */
2978 lpstrTemp[0] = '\0';
2979 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2981 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2983 nLength += strlen( lpstrTemp ) + 3;
2986 COMDLG32_SHFree( pidl );
2991 /* allocate the buffer */
2992 if (nFiles <= 1) nLength = MAX_PATH;
2993 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2994 lpstrAllFile[0] = '\0';
2996 /* Generate the string for the edit control */
2999 lpstrCurrFile = lpstrAllFile;
3000 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3002 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3006 /* get the file name */
3007 lpstrTemp[0] = '\0';
3008 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3010 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3014 *lpstrCurrFile++ = '\"';
3015 strcpy( lpstrCurrFile, lpstrTemp );
3016 lpstrCurrFile += strlen( lpstrTemp );
3017 strcpy( lpstrCurrFile, "\" " );
3022 strcpy( lpstrAllFile, lpstrTemp );
3025 COMDLG32_SHFree( (LPVOID) pidl );
3028 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3030 /* Select the file name like Windows does */
3031 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3033 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3037 /* copied from shell32 to avoid linking to it */
3038 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3043 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3044 COMDLG32_SHFree(src->u.pOleStr);
3048 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3052 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3056 FIXME("unknown type!\n");
3059 *(LPSTR)dest = '\0';
3066 /***********************************************************************
3067 * FILEDLG95_FILENAME_GetFileNames
3069 * Copies the filenames to a delimited string list.
3070 * The delimiter is specified by the parameter 'separator',
3071 * usually either a space or a nul
3073 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3075 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3076 UINT nStrCharCount = 0; /* index in src buffer */
3077 UINT nFileIndex = 0; /* index in dest buffer */
3078 UINT nFileCount = 0; /* number of files */
3079 UINT nStrLen = 0; /* length of string in edit control */
3080 LPWSTR lpstrEdit; /* buffer for string from edit control */
3084 /* get the filenames from the edit control */
3085 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3086 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3087 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3089 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3091 /* we might get single filename without any '"',
3092 * so we need nStrLen + terminating \0 + end-of-list \0 */
3093 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3096 /* build delimited file list from filenames */
3097 while ( nStrCharCount <= nStrLen )
3099 if ( lpstrEdit[nStrCharCount]=='"' )
3102 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3104 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3108 (*lpstrFileList)[nFileIndex++] = separator;
3115 /* single, unquoted string */
3116 if ((nStrLen > 0) && (*sizeUsed == 0) )
3118 strcpyW(*lpstrFileList, lpstrEdit);
3119 nFileIndex = strlenW(lpstrEdit) + 1;
3120 (*sizeUsed) = nFileIndex;
3125 (*lpstrFileList)[nFileIndex] = '\0';
3132 #define SETDefFormatEtc(fe,cf,med) \
3134 (fe).cfFormat = cf;\
3135 (fe).dwAspect = DVASPECT_CONTENT; \
3142 * DATAOBJECT Helper functions
3145 /***********************************************************************
3146 * COMCTL32_ReleaseStgMedium
3148 * like ReleaseStgMedium from ole32
3150 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3152 if(medium.pUnkForRelease)
3154 IUnknown_Release(medium.pUnkForRelease);
3158 GlobalUnlock(medium.u.hGlobal);
3159 GlobalFree(medium.u.hGlobal);
3163 /***********************************************************************
3164 * GetPidlFromDataObject
3166 * Return pidl(s) by number from the cached DataObject
3168 * nPidlIndex=0 gets the fully qualified root path
3170 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3174 FORMATETC formatetc;
3175 LPITEMIDLIST pidl = NULL;
3177 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3179 /* Set the FORMATETC structure*/
3180 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3182 /* Get the pidls from IDataObject */
3183 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3185 LPIDA cida = GlobalLock(medium.u.hGlobal);
3186 if(nPidlIndex <= cida->cidl)
3188 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3190 COMCTL32_ReleaseStgMedium(medium);
3195 /***********************************************************************
3198 * Return the number of selected items in the DataObject.
3201 UINT GetNumSelected( IDataObject *doSelected )
3205 FORMATETC formatetc;
3207 TRACE("sv=%p\n", doSelected);
3209 if (!doSelected) return 0;
3211 /* Set the FORMATETC structure*/
3212 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3214 /* Get the pidls from IDataObject */
3215 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3217 LPIDA cida = GlobalLock(medium.u.hGlobal);
3218 retVal = cida->cidl;
3219 COMCTL32_ReleaseStgMedium(medium);
3229 /***********************************************************************
3232 * Get the pidl's display name (relative to folder) and
3233 * put it in lpstrFileName.
3235 * Return NOERROR on success,
3239 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3244 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3248 SHGetDesktopFolder(&lpsf);
3249 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3250 IShellFolder_Release(lpsf);
3254 /* Get the display name of the pidl relative to the folder */
3255 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3257 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3262 /***********************************************************************
3263 * GetShellFolderFromPidl
3265 * pidlRel is the item pidl relative
3266 * Return the IShellFolder of the absolute pidl
3268 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3270 IShellFolder *psf = NULL,*psfParent;
3272 TRACE("%p\n", pidlAbs);
3274 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3277 if(pidlAbs && pidlAbs->mkid.cb)
3279 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3281 IShellFolder_Release(psfParent);
3285 /* return the desktop */
3291 /***********************************************************************
3294 * Return the LPITEMIDLIST to the parent of the pidl in the list
3296 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3298 LPITEMIDLIST pidlParent;
3300 TRACE("%p\n", pidl);
3302 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3303 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3308 /***********************************************************************
3311 * returns the pidl of the file name relative to folder
3312 * NULL if an error occurred
3314 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3316 LPITEMIDLIST pidl = NULL;
3319 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3321 if(!lpcstrFileName) return NULL;
3322 if(!*lpcstrFileName) return NULL;
3326 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3327 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3328 IShellFolder_Release(lpsf);
3333 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3340 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3342 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3345 TRACE("%p, %p\n", psf, pidl);
3347 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3349 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3350 /* see documentation shell 4.1*/
3351 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3354 /***********************************************************************
3355 * BrowseSelectedFolder
3357 static BOOL BrowseSelectedFolder(HWND hwnd)
3359 BOOL bBrowseSelFolder = FALSE;
3360 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3364 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3366 LPITEMIDLIST pidlSelection;
3368 /* get the file selected */
3369 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3370 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3372 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3373 pidlSelection, SBSP_RELATIVE ) ) )
3375 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3376 ' ','n','o','t',' ','e','x','i','s','t',0};
3377 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3379 bBrowseSelFolder = TRUE;
3380 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3382 COMDLG32_SHFree( pidlSelection );
3385 return bBrowseSelFolder;
3389 * Memory allocation methods */
3390 static void *MemAlloc(UINT size)
3392 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3395 static void MemFree(void *mem)
3397 HeapFree(GetProcessHeap(),0,mem);
3401 * Old-style (win3.1) dialogs */
3403 /***********************************************************************
3404 * FD32_GetTemplate [internal]
3406 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3407 * by a 32 bits application
3410 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3412 LPOPENFILENAMEW ofnW = lfs->ofnW;
3413 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3416 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3418 if (!(lfs->template = LockResource( ofnW->hInstance )))
3420 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3424 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3428 hResInfo = FindResourceA(priv->ofnA->hInstance,
3429 priv->ofnA->lpTemplateName,
3432 hResInfo = FindResourceW(ofnW->hInstance,
3433 ofnW->lpTemplateName,
3437 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3440 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3442 !(lfs->template = LockResource(hDlgTmpl)))
3444 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3447 } else { /* get it from internal Wine resource */
3449 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3450 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3452 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3455 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3456 !(lfs->template = LockResource( hDlgTmpl )))
3458 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3466 /************************************************************************
3467 * FD32_Init [internal]
3468 * called from the common 16/32 code to initialize 32 bit data
3470 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3472 BOOL IsUnicode = (BOOL) data;
3475 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3476 lfs->private1632 = priv;
3477 if (NULL == lfs->private1632) return FALSE;
3480 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3481 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3482 if (lfs->ofnW->lpfnHook)
3487 priv->ofnA = (LPOPENFILENAMEA) lParam;
3488 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3489 if (priv->ofnA->lpfnHook)
3491 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3492 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3495 if (! FD32_GetTemplate(lfs)) return FALSE;
3500 /***********************************************************************
3501 * FD32_CallWindowProc [internal]
3503 * called from the common 16/32 code to call the appropriate hook
3505 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3509 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3513 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3514 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3515 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3516 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3517 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3521 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3522 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3523 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3524 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3525 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3529 /***********************************************************************
3530 * FD32_UpdateResult [internal]
3531 * update the real client structures if any
3533 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3535 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3536 LPOPENFILENAMEW ofnW = lfs->ofnW;
3540 if (ofnW->nMaxFile &&
3541 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3542 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3543 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3544 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3545 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3549 /***********************************************************************
3550 * FD32_UpdateFileTitle [internal]
3551 * update the real client structures if any
3553 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3555 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3556 LPOPENFILENAMEW ofnW = lfs->ofnW;
3560 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3561 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3562 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3567 /***********************************************************************
3568 * FD32_SendLbGetCurSel [internal]
3569 * retrieve selected listbox item
3571 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3573 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3577 /************************************************************************
3578 * FD32_Destroy [internal]
3579 * called from the common 16/32 code to cleanup 32 bit data
3581 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3583 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3585 /* if ofnW has been allocated, have to free everything in it */
3586 if (NULL != priv && NULL != priv->ofnA)
3588 FD31_FreeOfnW(lfs->ofnW);
3589 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3593 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3595 callbacks->Init = FD32_Init;
3596 callbacks->CWP = FD32_CallWindowProc;
3597 callbacks->UpdateResult = FD32_UpdateResult;
3598 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3599 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3600 callbacks->Destroy = FD32_Destroy;
3603 /***********************************************************************
3604 * FD32_WMMeasureItem [internal]
3606 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3608 LPMEASUREITEMSTRUCT lpmeasure;
3610 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3611 lpmeasure->itemHeight = FD31_GetFldrHeight();
3616 /***********************************************************************
3617 * FileOpenDlgProc [internal]
3618 * Used for open and save, in fact.
3620 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3621 WPARAM wParam, LPARAM lParam)
3623 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3625 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3626 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3629 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3631 return lRet; /* else continue message processing */
3636 return FD31_WMInitDialog(hWnd, wParam, lParam);
3638 case WM_MEASUREITEM:
3639 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3642 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3645 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3648 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3649 switch (HIWORD(lParam))
3652 SetTextColor((HDC16)wParam, 0x00000000);
3654 case CTLCOLOR_STATIC:
3655 SetTextColor((HDC16)wParam, 0x00000000);
3665 /***********************************************************************
3666 * GetFileName31A [internal]
3668 * Creates a win31 style dialog box for the user to select a file to open/save.
3670 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3671 UINT dlgType /* type dialogue : open/save */
3677 FD31_CALLBACKS callbacks;
3679 if (!lpofn || !FD31_Init()) return FALSE;
3681 TRACE("ofn flags %08lx\n", lpofn->Flags);
3682 FD32_SetupCallbacks(&callbacks);
3683 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3686 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3687 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3688 FD32_FileOpenDlgProc, (LPARAM)lfs);
3689 FD31_DestroyPrivate(lfs);
3692 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3696 /***********************************************************************
3697 * GetFileName31W [internal]
3699 * Creates a win31 style dialog box for the user to select a file to open/save
3701 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3702 UINT dlgType /* type dialogue : open/save */
3708 FD31_CALLBACKS callbacks;
3710 if (!lpofn || !FD31_Init()) return FALSE;
3712 FD32_SetupCallbacks(&callbacks);
3713 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3716 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3717 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3718 FD32_FileOpenDlgProc, (LPARAM)lfs);
3719 FD31_DestroyPrivate(lfs);
3722 TRACE("file %s, file offset %d, ext offset %d\n",
3723 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3727 /* ------------------ APIs ---------------------- */
3729 /***********************************************************************
3730 * GetOpenFileNameA (COMDLG32.@)
3732 * Creates a dialog box for the user to select a file to open.
3735 * TRUE on success: user enters a valid file
3736 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3739 BOOL WINAPI GetOpenFileNameA(
3740 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3742 BOOL win16look = FALSE;
3744 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3745 if (ofn->Flags & OFN_FILEMUSTEXIST)
3746 ofn->Flags |= OFN_PATHMUSTEXIST;
3748 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3749 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3752 return GetFileName31A(ofn, OPEN_DIALOG);
3754 return GetFileDialog95A(ofn, OPEN_DIALOG);
3757 /***********************************************************************
3758 * GetOpenFileNameW (COMDLG32.@)
3760 * Creates a dialog box for the user to select a file to open.
3763 * TRUE on success: user enters a valid file
3764 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3767 BOOL WINAPI GetOpenFileNameW(
3768 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3770 BOOL win16look = FALSE;
3772 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3773 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3776 return GetFileName31W(ofn, OPEN_DIALOG);
3778 return GetFileDialog95W(ofn, OPEN_DIALOG);
3782 /***********************************************************************
3783 * GetSaveFileNameA (COMDLG32.@)
3785 * Creates a dialog box for the user to select a file to save.
3788 * TRUE on success: user enters a valid file
3789 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3792 BOOL WINAPI GetSaveFileNameA(
3793 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3795 BOOL win16look = FALSE;
3797 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3798 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3801 return GetFileName31A(ofn, SAVE_DIALOG);
3803 return GetFileDialog95A(ofn, SAVE_DIALOG);
3806 /***********************************************************************
3807 * GetSaveFileNameW (COMDLG32.@)
3809 * Creates a dialog box for the user to select a file to save.
3812 * TRUE on success: user enters a valid file
3813 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3816 BOOL WINAPI GetSaveFileNameW(
3817 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3819 BOOL win16look = FALSE;
3821 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3822 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3825 return GetFileName31W(ofn, SAVE_DIALOG);
3827 return GetFileDialog95W(ofn, SAVE_DIALOG);