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"
74 #include "filedlg31.h"
75 #include "wine/debug.h"
80 #include "filedlgbrowser.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
123 #define XTEXTOFFSET 3
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBAddStringW(hwnd,str) \
145 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
147 #define CBInsertString(hwnd,str,pos) \
148 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
150 #define CBDeleteString(hwnd,pos) \
151 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
153 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
154 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
156 #define CBGetItemDataPtr(hwnd,iItemId) \
157 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
159 #define CBGetLBText(hwnd,iItemId,str) \
160 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
162 #define CBGetCurSel(hwnd) \
163 SendMessageA(hwnd,CB_GETCURSEL,0,0);
165 #define CBSetCurSel(hwnd,pos) \
166 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
168 #define CBGetCount(hwnd) \
169 SendMessageA(hwnd,CB_GETCOUNT,0,0);
170 #define CBShowDropDown(hwnd,show) \
171 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
172 #define CBSetItemHeight(hwnd,index,height) \
173 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
175 #define CBSetExtendedUI(hwnd,flag) \
176 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
178 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
179 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
181 /***********************************************************************
185 /* Internal functions used by the dialog */
186 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
188 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
189 BOOL FILEDLG95_OnOpen(HWND hwnd);
190 static LRESULT FILEDLG95_InitControls(HWND hwnd);
191 static void FILEDLG95_Clean(HWND hwnd);
193 /* Functions used by the shell navigation */
194 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
197 static void FILEDLG95_SHELL_Clean(HWND hwnd);
198 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
200 /* Functions used by the EDIT box */
201 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
203 /* Functions used by the filetype combo box */
204 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
205 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
206 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
207 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
209 /* Functions used by the Look In combo box */
210 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
211 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
212 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
213 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
214 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
215 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
216 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
217 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
218 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
220 /* Miscellaneous tool functions */
221 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
222 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
223 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
224 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
230 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
232 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
233 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
234 static BOOL BrowseSelectedFolder(HWND hwnd);
236 /***********************************************************************
239 * Creates an Open common dialog box that lets the user select
240 * the drive, directory, and the name of a file or set of files to open.
242 * IN : The FileOpenDlgInfos structure associated with the dialog
243 * OUT : TRUE on success
244 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
246 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
255 /* test for missing functionality */
256 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
258 FIXME("Flags 0x%08lx not yet implemented\n",
259 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
262 /* Create the dialog from a template */
264 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
266 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
269 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
270 !(template = LockResource( hDlgTmpl )))
272 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
276 /* old style hook messages */
277 if (IsHooked(fodInfos))
279 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
280 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
281 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
282 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
285 /* Some shell namespace extensions depend on COM being initialized. */
286 hr = OleInitialize(NULL);
288 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
289 (LPDLGTEMPLATEA) template,
290 fodInfos->ofnInfos->hwndOwner,
296 /* Unable to create the dialog */
303 /***********************************************************************
306 * Call GetFileName95 with this structure and clean the memory.
308 * IN : The OPENFILENAMEA initialisation structure passed to
309 * GetOpenFileNameA win api function (see filedlg.c)
311 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
314 FileOpenDlgInfos fodInfos;
315 LPSTR lpstrSavDir = NULL;
317 LPWSTR defext = NULL;
318 LPWSTR filter = NULL;
319 LPWSTR customfilter = NULL;
321 /* Initialize FileOpenDlgInfos structure */
322 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
324 /* Pass in the original ofn */
325 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
327 /* save current directory */
328 if (ofn->Flags & OFN_NOCHANGEDIR)
330 lpstrSavDir = MemAlloc(MAX_PATH);
331 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
334 fodInfos.unicode = FALSE;
336 /* convert all the input strings to unicode */
337 if(ofn->lpstrInitialDir)
339 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
340 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
344 fodInfos.initdir = NULL;
348 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
349 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
352 fodInfos.filename = NULL;
356 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
357 defext = MemAlloc((len+1)*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
360 fodInfos.defext = defext;
364 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
365 title = MemAlloc((len+1)*sizeof(WCHAR));
366 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
368 fodInfos.title = title;
370 if (ofn->lpstrFilter)
375 /* filter is a list... title\0ext\0......\0\0 */
376 s = ofn->lpstrFilter;
377 while (*s) s = s+strlen(s)+1;
379 n = s - ofn->lpstrFilter;
380 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
381 filter = MemAlloc(len*sizeof(WCHAR));
382 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
384 fodInfos.filter = filter;
386 /* convert lpstrCustomFilter */
387 if (ofn->lpstrCustomFilter)
392 /* customfilter contains a pair of strings... title\0ext\0 */
393 s = ofn->lpstrCustomFilter;
394 if (*s) s = s+strlen(s)+1;
395 if (*s) s = s+strlen(s)+1;
396 n = s - ofn->lpstrCustomFilter;
397 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
398 customfilter = MemAlloc(len*sizeof(WCHAR));
399 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
401 fodInfos.customfilter = customfilter;
403 /* Initialize the dialog property */
404 fodInfos.DlgInfos.dwDlgProp = 0;
405 fodInfos.DlgInfos.hwndCustomDlg = NULL;
410 ret = GetFileName95(&fodInfos);
413 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
414 ret = GetFileName95(&fodInfos);
422 SetCurrentDirectoryA(lpstrSavDir);
423 MemFree(lpstrSavDir);
433 MemFree(customfilter);
435 MemFree(fodInfos.initdir);
437 if(fodInfos.filename)
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
445 /***********************************************************************
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize FileOpenDlgInfos structure */
459 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
461 /* Pass in the original ofn */
462 fodInfos.ofnInfos = ofn;
464 fodInfos.title = ofn->lpstrTitle;
465 fodInfos.defext = ofn->lpstrDefExt;
466 fodInfos.filter = ofn->lpstrFilter;
467 fodInfos.customfilter = ofn->lpstrCustomFilter;
469 /* convert string arguments, save others */
472 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
473 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
476 fodInfos.filename = NULL;
478 if(ofn->lpstrInitialDir)
480 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
481 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
482 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
483 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
486 fodInfos.initdir = NULL;
488 /* save current directory */
489 if (ofn->Flags & OFN_NOCHANGEDIR)
491 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
492 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
495 fodInfos.unicode = TRUE;
500 ret = GetFileName95(&fodInfos);
503 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
504 ret = GetFileName95(&fodInfos);
512 SetCurrentDirectoryW(lpstrSavDir);
513 MemFree(lpstrSavDir);
516 /* restore saved IN arguments and convert OUT arguments back */
517 MemFree(fodInfos.filename);
518 MemFree(fodInfos.initdir);
522 /******************************************************************************
523 * COMDLG32_GetDisplayNameOf [internal]
525 * Helper function to get the display name for a pidl.
527 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
528 LPSHELLFOLDER psfDesktop;
531 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
534 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
535 IShellFolder_Release(psfDesktop);
539 IShellFolder_Release(psfDesktop);
540 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
543 /***********************************************************************
544 * ArrangeCtrlPositions [internal]
546 * NOTE: Do not change anything here without a lot of testing.
548 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
550 HWND hwndChild, hwndStc32;
551 RECT rectParent, rectChild, rectStc32;
552 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
554 /* Take into account if open as read only checkbox and help button
559 RECT rectHelp, rectCancel;
560 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
561 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
562 /* subtract the height of the help button plus the space between
563 * the help button and the cancel button to the height of the dialog
565 help_fixup = rectHelp.bottom - rectCancel.bottom;
569 There are two possibilities to add components to the default file dialog box.
571 By default, all the new components are added below the standard dialog box (the else case).
573 However, if there is a static text component with the stc32 id, a special case happens.
574 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
575 in the window and the cx and cy indicate how to size the window.
576 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
577 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
581 GetClientRect(hwndParentDlg, &rectParent);
583 /* when arranging controls we have to use fixed parent size */
584 rectParent.bottom -= help_fixup;
586 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
589 GetWindowRect(hwndStc32, &rectStc32);
590 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
592 /* set the size of the stc32 control according to the size of
593 * client area of the parent dialog
595 SetWindowPos(hwndStc32, 0,
597 rectParent.right, rectParent.bottom,
598 SWP_NOMOVE | SWP_NOZORDER);
601 SetRectEmpty(&rectStc32);
603 /* this part moves controls of the child dialog */
604 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
607 if (hwndChild != hwndStc32)
609 GetWindowRect(hwndChild, &rectChild);
610 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
612 /* move only if stc32 exist */
613 if (hwndStc32 && rectChild.left > rectStc32.right)
615 LONG old_left = rectChild.left;
617 /* move to the right of visible controls of the parent dialog */
618 rectChild.left += rectParent.right;
619 rectChild.left -= rectStc32.right;
621 child_width_fixup = rectChild.left - old_left;
623 /* move even if stc32 doesn't exist */
624 if (rectChild.top >= rectStc32.bottom)
626 LONG old_top = rectChild.top;
628 /* move below visible controls of the parent dialog */
629 rectChild.top += rectParent.bottom;
630 rectChild.top -= rectStc32.bottom - rectStc32.top;
632 child_height_fixup = rectChild.top - old_top;
635 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
636 0, 0, SWP_NOSIZE | SWP_NOZORDER);
638 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
641 /* this part moves controls of the parent dialog */
642 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
645 if (hwndChild != hwndChildDlg)
647 GetWindowRect(hwndChild, &rectChild);
648 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
650 /* left,top of stc32 marks the position of controls
651 * from the parent dialog
653 rectChild.left += rectStc32.left;
654 rectChild.top += rectStc32.top;
656 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
657 0, 0, SWP_NOSIZE | SWP_NOZORDER);
659 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
662 /* calculate the size of the resulting dialog */
664 /* here we have to use original parent size */
665 GetClientRect(hwndParentDlg, &rectParent);
666 GetClientRect(hwndChildDlg, &rectChild);
670 rectChild.right += child_width_fixup;
671 rectChild.bottom += child_height_fixup;
673 if (rectParent.right > rectChild.right)
675 rectParent.right += rectChild.right;
676 rectParent.right -= rectStc32.right - rectStc32.left;
680 rectParent.right = rectChild.right;
683 if (rectParent.bottom > rectChild.bottom)
685 rectParent.bottom += rectChild.bottom;
686 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
690 /* child dialog is higher, unconditionally set new dialog
691 * height to its size (help_fixup will be subtracted below)
693 rectParent.bottom = rectChild.bottom + help_fixup;
698 rectParent.bottom += rectChild.bottom;
701 /* finally use fixed parent size */
702 rectParent.bottom -= help_fixup;
704 /* set the size of the parent dialog */
705 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
706 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
707 SetWindowPos(hwndParentDlg, 0,
709 rectParent.right - rectParent.left,
710 rectParent.bottom - rectParent.top,
711 SWP_NOMOVE | SWP_NOZORDER);
714 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
723 static 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)
742 hinst = COMDLG32_hInstance;
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(hinst, 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 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
816 LRESULT hook_result = 0;
818 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
820 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
822 if(!fodInfos) return 0;
824 if(fodInfos->DlgInfos.hwndCustomDlg)
826 TRACE("CALL NOTIFY for %x\n", uCode);
827 if(fodInfos->unicode)
830 ofnNotify.hdr.hwndFrom=hwndParentDlg;
831 ofnNotify.hdr.idFrom=0;
832 ofnNotify.hdr.code = uCode;
833 ofnNotify.lpOFN = fodInfos->ofnInfos;
834 ofnNotify.pszFile = NULL;
835 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
840 ofnNotify.hdr.hwndFrom=hwndParentDlg;
841 ofnNotify.hdr.idFrom=0;
842 ofnNotify.hdr.code = uCode;
843 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
844 ofnNotify.pszFile = NULL;
845 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
847 TRACE("RET NOTIFY\n");
849 TRACE("Retval: 0x%08lx\n", hook_result);
853 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
855 UINT sizeUsed = 0, n, total;
856 LPWSTR lpstrFileList = NULL;
857 WCHAR lpstrCurrentDir[MAX_PATH];
858 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
860 TRACE("CDM_GETFILEPATH:\n");
862 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
865 /* get path and filenames */
866 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
867 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
869 TRACE("path >%s< filespec >%s< %d files\n",
870 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
872 if( fodInfos->unicode )
874 LPWSTR bufW = buffer;
875 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
877 /* Prepend the current path */
878 n = strlenW(lpstrCurrentDir) + 1;
879 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
882 /* 'n' includes trailing \0 */
884 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
886 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
891 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
892 NULL, 0, NULL, NULL);
893 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
894 NULL, 0, NULL, NULL);
896 /* Prepend the current path */
897 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
898 bufA, size, NULL, NULL);
902 /* 'n' includes trailing \0 */
904 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
905 &bufA[n], size-n, NULL, NULL);
908 TRACE("returned -> %s\n",debugstr_an(bufA, total));
910 MemFree(lpstrFileList);
915 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
918 LPWSTR lpstrFileList = NULL;
919 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
921 TRACE("CDM_GETSPEC:\n");
923 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
924 if( fodInfos->unicode )
926 LPWSTR bufW = buffer;
927 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
932 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
933 NULL, 0, NULL, NULL);
934 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
935 bufA, size, NULL, NULL);
937 MemFree(lpstrFileList);
942 /***********************************************************************
943 * FILEDLG95_HandleCustomDialogMessages
945 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
947 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
949 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
950 WCHAR lpstrPath[MAX_PATH];
953 if(!fodInfos) return FALSE;
957 case CDM_GETFILEPATH:
958 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
961 case CDM_GETFOLDERPATH:
962 TRACE("CDM_GETFOLDERPATH:\n");
963 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
966 if (fodInfos->unicode)
967 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
969 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
970 (LPSTR)lParam, (int)wParam, NULL, NULL);
972 retval = strlenW(lpstrPath);
976 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
979 case CDM_SETCONTROLTEXT:
980 TRACE("CDM_SETCONTROLTEXT:\n");
983 if( fodInfos->unicode )
984 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
986 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
991 case CDM_HIDECONTROL:
993 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
1000 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1004 /***********************************************************************
1007 * File open dialog procedure
1009 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1012 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1019 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1021 /* Adds the FileOpenDlgInfos in the property list of the dialog
1022 so it will be easily accessible through a GetPropA(...) */
1023 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1025 fodInfos->DlgInfos.hwndCustomDlg =
1026 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1028 FILEDLG95_InitControls(hwnd);
1030 if (fodInfos->DlgInfos.hwndCustomDlg)
1033 UINT flags = SWP_NOACTIVATE;
1035 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1036 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1038 /* resize the custom dialog to the parent size */
1039 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1040 GetClientRect(hwnd, &rc);
1043 /* our own fake template is zero sized and doesn't have
1044 * children, so there is no need to resize it.
1045 * Picasa depends on it.
1047 flags |= SWP_NOSIZE;
1050 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1051 0, 0, rc.right, rc.bottom, flags);
1054 FILEDLG95_FillControls(hwnd, wParam, lParam);
1056 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1057 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1058 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1062 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1065 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1068 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1074 case WM_GETISHELLBROWSER:
1075 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1078 RemovePropA(hwnd, FileOpenDlgInfosStr);
1083 LPNMHDR lpnmh = (LPNMHDR)lParam;
1086 /* set up the button tooltips strings */
1087 if(TTN_GETDISPINFOA == lpnmh->code )
1089 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1090 switch(lpnmh->idFrom )
1092 /* Up folder button */
1093 case FCIDM_TB_UPFOLDER:
1094 stringId = IDS_UPFOLDER;
1096 /* New folder button */
1097 case FCIDM_TB_NEWFOLDER:
1098 stringId = IDS_NEWFOLDER;
1100 /* List option button */
1101 case FCIDM_TB_SMALLICON:
1102 stringId = IDS_LISTVIEW;
1104 /* Details option button */
1105 case FCIDM_TB_REPORTVIEW:
1106 stringId = IDS_REPORTVIEW;
1108 /* Desktop button */
1109 case FCIDM_TB_DESKTOP:
1110 stringId = IDS_TODESKTOP;
1115 lpdi->hinst = COMDLG32_hInstance;
1116 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1121 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1122 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1127 /***********************************************************************
1128 * FILEDLG95_InitControls
1130 * WM_INITDIALOG message handler (before hook notification)
1132 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1134 int win2000plus = 0;
1136 int handledPath = FALSE;
1137 OSVERSIONINFOA osVi;
1138 static const WCHAR szwSlash[] = { '\\', 0 };
1139 static const WCHAR szwStar[] = { '*',0 };
1143 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1144 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1145 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1146 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1147 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1148 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1149 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1150 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1151 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1156 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1158 tba[0].hInst = HINST_COMMCTRL;
1159 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1160 tba[1].hInst = COMDLG32_hInstance;
1163 TRACE("%p\n", fodInfos);
1165 /* Get windows version emulating */
1166 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1167 GetVersionExA(&osVi);
1168 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1169 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1170 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1171 win2000plus = (osVi.dwMajorVersion > 4);
1172 if (win2000plus) win98plus = TRUE;
1174 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1176 /* Get the hwnd of the controls */
1177 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1178 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1179 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1181 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1182 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1184 /* construct the toolbar */
1185 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1186 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1188 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1189 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1190 rectTB.left = rectlook.right;
1191 rectTB.top = rectlook.top-1;
1193 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1194 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1195 rectTB.left, rectTB.top,
1196 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1197 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1199 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1201 /* FIXME: use TB_LOADIMAGES when implemented */
1202 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1203 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1204 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1206 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1207 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1209 /* Set the window text with the text specified in the OPENFILENAME structure */
1212 SetWindowTextW(hwnd,fodInfos->title);
1214 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1217 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1218 SetWindowTextW(hwnd, buf);
1221 /* Initialise the file name edit control */
1222 handledPath = FALSE;
1223 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1225 if(fodInfos->filename)
1227 /* 1. If win2000 or higher and filename contains a path, use it
1228 in preference over the lpstrInitialDir */
1229 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1230 WCHAR tmpBuf[MAX_PATH];
1234 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1237 /* nameBit is always shorter than the original filename */
1238 strcpyW(fodInfos->filename,nameBit);
1241 if (fodInfos->initdir == NULL)
1242 MemFree(fodInfos->initdir);
1243 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1244 strcpyW(fodInfos->initdir, tmpBuf);
1246 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1247 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1249 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1252 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1256 /* 2. (All platforms) If initdir is not null, then use it */
1257 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1258 (*fodInfos->initdir!=0x00))
1260 /* Work out the proper path as supplied one might be relative */
1261 /* (Here because supplying '.' as dir browses to My Computer) */
1262 if (handledPath==FALSE) {
1263 WCHAR tmpBuf[MAX_PATH];
1264 WCHAR tmpBuf2[MAX_PATH];
1268 strcpyW(tmpBuf, fodInfos->initdir);
1269 if( PathFileExistsW(tmpBuf) ) {
1270 /* initdir does not have to be a directory. If a file is
1271 * specified, the dir part is taken */
1272 if( PathIsDirectoryW(tmpBuf)) {
1273 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1274 strcatW(tmpBuf, szwSlash);
1276 strcatW(tmpBuf, szwStar);
1278 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1281 if (fodInfos->initdir)
1282 MemFree(fodInfos->initdir);
1283 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1284 strcpyW(fodInfos->initdir, tmpBuf2);
1286 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1289 else if (fodInfos->initdir)
1291 MemFree(fodInfos->initdir);
1292 fodInfos->initdir = NULL;
1293 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1298 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1299 (*fodInfos->initdir==0x00)))
1301 /* 3. All except w2k+: if filename contains a path use it */
1302 if (!win2000plus && fodInfos->filename &&
1303 *fodInfos->filename &&
1304 strpbrkW(fodInfos->filename, szwSlash)) {
1305 WCHAR tmpBuf[MAX_PATH];
1309 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1314 /* nameBit is always shorter than the original filename */
1315 strcpyW(fodInfos->filename, nameBit);
1318 len = strlenW(tmpBuf);
1319 if(fodInfos->initdir)
1320 MemFree(fodInfos->initdir);
1321 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1322 strcpyW(fodInfos->initdir, tmpBuf);
1325 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1326 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1328 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1331 /* 4. win98+ and win2000+ if any files of specified filter types in
1332 current directory, use it */
1333 if ( win98plus && handledPath == FALSE &&
1334 fodInfos->filter && *fodInfos->filter) {
1336 BOOL searchMore = TRUE;
1337 LPCWSTR lpstrPos = fodInfos->filter;
1338 WIN32_FIND_DATAW FindFileData;
1343 /* filter is a list... title\0ext\0......\0\0 */
1345 /* Skip the title */
1346 if(! *lpstrPos) break; /* end */
1347 lpstrPos += strlenW(lpstrPos) + 1;
1349 /* See if any files exist in the current dir with this extension */
1350 if(! *lpstrPos) break; /* end */
1352 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1354 if (hFind == INVALID_HANDLE_VALUE) {
1355 /* None found - continue search */
1356 lpstrPos += strlenW(lpstrPos) + 1;
1361 if(fodInfos->initdir)
1362 MemFree(fodInfos->initdir);
1363 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1364 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1367 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1368 debugstr_w(lpstrPos));
1374 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1376 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1377 if (handledPath == FALSE && (win2000plus || win98plus)) {
1378 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1380 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1382 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1385 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1386 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1388 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1391 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1394 } else if (handledPath==FALSE) {
1395 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1396 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1398 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1401 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1402 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1404 /* Must the open as read only check box be checked ?*/
1405 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1407 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1410 /* Must the open as read only check box be hidden? */
1411 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1413 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1414 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1417 /* Must the help button be hidden? */
1418 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1420 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1421 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1424 /* Resize the height, if open as read only checkbox ad help button
1425 are hidden and we are not using a custom template nor a customDialog
1427 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1428 (!(fodInfos->ofnInfos->Flags &
1429 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1430 (!fodInfos->DlgInfos.hwndCustomDlg ))
1432 RECT rectDlg, rectHelp, rectCancel;
1433 GetWindowRect(hwnd, &rectDlg);
1434 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1435 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1436 /* subtract the height of the help button plus the space between
1437 the help button and the cancel button to the height of the dialog */
1438 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1439 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1440 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1442 /* change Open to Save */
1443 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1446 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1447 SetDlgItemTextW(hwnd, IDOK, buf);
1448 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1449 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1454 /***********************************************************************
1455 * FILEDLG95_FillControls
1457 * WM_INITDIALOG message handler (after hook notification)
1459 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1461 LPITEMIDLIST pidlItemId = NULL;
1463 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1465 TRACE("dir=%s file=%s\n",
1466 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1468 /* Get the initial directory pidl */
1470 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1472 WCHAR path[MAX_PATH];
1474 GetCurrentDirectoryW(MAX_PATH,path);
1475 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1478 /* Initialise shell objects */
1479 FILEDLG95_SHELL_Init(hwnd);
1481 /* Initialize the Look In combo box */
1482 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1484 /* Initialize the filter combo box */
1485 FILEDLG95_FILETYPE_Init(hwnd);
1487 /* Browse to the initial directory */
1488 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1490 /* Free pidlItem memory */
1491 COMDLG32_SHFree(pidlItemId);
1495 /***********************************************************************
1498 * Regroups all the cleaning functions of the filedlg
1500 void FILEDLG95_Clean(HWND hwnd)
1502 FILEDLG95_FILETYPE_Clean(hwnd);
1503 FILEDLG95_LOOKIN_Clean(hwnd);
1504 FILEDLG95_SHELL_Clean(hwnd);
1506 /***********************************************************************
1507 * FILEDLG95_OnWMCommand
1509 * WM_COMMAND message handler
1511 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1513 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1514 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1515 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1521 FILEDLG95_OnOpen(hwnd);
1525 FILEDLG95_Clean(hwnd);
1526 EndDialog(hwnd, FALSE);
1528 /* Filetype combo box */
1530 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1532 /* LookIn combo box */
1534 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1537 /* --- toolbar --- */
1538 /* Up folder button */
1539 case FCIDM_TB_UPFOLDER:
1540 FILEDLG95_SHELL_UpFolder(hwnd);
1542 /* New folder button */
1543 case FCIDM_TB_NEWFOLDER:
1544 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1546 /* List option button */
1547 case FCIDM_TB_SMALLICON:
1548 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1550 /* Details option button */
1551 case FCIDM_TB_REPORTVIEW:
1552 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1554 /* Details option button */
1555 case FCIDM_TB_DESKTOP:
1556 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1563 /* Do not use the listview selection anymore */
1564 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1568 /***********************************************************************
1569 * FILEDLG95_OnWMGetIShellBrowser
1571 * WM_GETISHELLBROWSER message handler
1573 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1576 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1580 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1586 /***********************************************************************
1587 * FILEDLG95_SendFileOK
1589 * Sends the CDN_FILEOK notification if required
1592 * TRUE if the dialog should close
1593 * FALSE if the dialog should not be closed
1595 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1597 /* ask the hook if we can close */
1598 if(IsHooked(fodInfos))
1603 /* First send CDN_FILEOK as MSDN doc says */
1604 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1605 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1607 TRACE("canceled\n");
1608 return (retval == 0);
1611 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1612 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1613 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1614 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1616 TRACE("canceled\n");
1617 return (retval == 0);
1623 /***********************************************************************
1624 * FILEDLG95_OnOpenMultipleFiles
1626 * Handles the opening of multiple files.
1629 * check destination buffer size
1631 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1633 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1634 UINT nCount, nSizePath;
1635 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1639 if(fodInfos->unicode)
1641 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1642 ofn->lpstrFile[0] = '\0';
1646 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1647 ofn->lpstrFile[0] = '\0';
1650 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1652 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1653 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1654 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1656 LPWSTR lpstrTemp = lpstrFileList;
1658 for ( nCount = 0; nCount < nFileCount; nCount++ )
1662 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1665 WCHAR lpstrNotFound[100];
1666 WCHAR lpstrMsg[100];
1668 static const WCHAR nl[] = {'\n',0};
1670 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1671 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1673 strcpyW(tmp, lpstrTemp);
1675 strcatW(tmp, lpstrNotFound);
1677 strcatW(tmp, lpstrMsg);
1679 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1683 /* move to the next file in the list of files */
1684 lpstrTemp += strlenW(lpstrTemp) + 1;
1685 COMDLG32_SHFree(pidl);
1689 nSizePath = strlenW(lpstrPathSpec) + 1;
1690 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1692 /* For "oldstyle" dialog the components have to
1693 be separated by blanks (not '\0'!) and short
1694 filenames have to be used! */
1695 FIXME("Components have to be separated by blanks\n");
1697 if(fodInfos->unicode)
1699 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1700 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1701 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1705 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1707 if (ofn->lpstrFile != NULL)
1709 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1710 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1711 if (ofn->nMaxFile > nSizePath)
1713 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1714 ofn->lpstrFile + nSizePath,
1715 ofn->nMaxFile - nSizePath, NULL, NULL);
1720 fodInfos->ofnInfos->nFileOffset = nSizePath;
1721 fodInfos->ofnInfos->nFileExtension = 0;
1723 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1726 /* clean and exit */
1727 FILEDLG95_Clean(hwnd);
1728 return EndDialog(hwnd,TRUE);
1731 /***********************************************************************
1734 * Ok button WM_COMMAND message handler
1736 * If the function succeeds, the return value is nonzero.
1738 #define ONOPEN_BROWSE 1
1739 #define ONOPEN_OPEN 2
1740 #define ONOPEN_SEARCH 3
1741 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1743 WCHAR strMsgTitle[MAX_PATH];
1744 WCHAR strMsgText [MAX_PATH];
1746 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1748 strMsgTitle[0] = '\0';
1749 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1750 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1753 BOOL FILEDLG95_OnOpen(HWND hwnd)
1755 LPWSTR lpstrFileList;
1756 UINT nFileCount = 0;
1759 WCHAR lpstrPathAndFile[MAX_PATH];
1760 WCHAR lpstrTemp[MAX_PATH];
1761 LPSHELLFOLDER lpsf = NULL;
1763 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1765 TRACE("hwnd=%p\n", hwnd);
1767 /* get the files from the edit control */
1768 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1770 /* try if the user selected a folder in the shellview */
1773 BrowseSelectedFolder(hwnd);
1779 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1783 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1786 Step 1: Build a complete path name from the current folder and
1787 the filename or path in the edit box.
1789 - the path in the edit box is a root path
1790 (with or without drive letter)
1791 - the edit box contains ".." (or a path with ".." in it)
1794 /* Get the current directory name */
1795 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1798 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1800 PathAddBackslashW(lpstrPathAndFile);
1802 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1804 /* if the user specifyed a fully qualified path use it */
1805 if(PathIsRelativeW(lpstrFileList))
1807 strcatW(lpstrPathAndFile, lpstrFileList);
1811 /* does the path have a drive letter? */
1812 if (PathGetDriveNumberW(lpstrFileList) == -1)
1813 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1815 strcpyW(lpstrPathAndFile, lpstrFileList);
1818 /* resolve "." and ".." */
1819 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1820 strcpyW(lpstrPathAndFile, lpstrTemp);
1821 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1823 MemFree(lpstrFileList);
1826 Step 2: here we have a cleaned up path
1828 We have to parse the path step by step to see if we have to browse
1829 to a folder if the path points to a directory or the last
1830 valid element is a directory.
1833 lpstrPathAndFile: cleaned up path
1837 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1838 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1839 nOpenAction = ONOPEN_OPEN;
1841 nOpenAction = ONOPEN_BROWSE;
1843 /* don't apply any checks with OFN_NOVALIDATE */
1845 LPWSTR lpszTemp, lpszTemp1;
1846 LPITEMIDLIST pidl = NULL;
1847 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1849 /* check for invalid chars */
1850 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1852 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1857 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1859 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1862 LPSHELLFOLDER lpsfChild;
1863 WCHAR lpwstrTemp[MAX_PATH];
1864 DWORD dwEaten, dwAttributes;
1867 strcpyW(lpwstrTemp, lpszTemp);
1868 p = PathFindNextComponentW(lpwstrTemp);
1870 if (!p) break; /* end of path */
1873 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1875 /* There are no wildcards when OFN_NOVALIDATE is set */
1876 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1878 static const WCHAR wszWild[] = { '*', '?', 0 };
1879 /* if the last element is a wildcard do a search */
1880 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1882 nOpenAction = ONOPEN_SEARCH;
1886 lpszTemp1 = lpszTemp;
1888 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1890 /* append a backslash to drive letters */
1891 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1892 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1893 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1895 PathAddBackslashW(lpwstrTemp);
1898 dwAttributes = SFGAO_FOLDER;
1899 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1901 /* the path component is valid, we have a pidl of the next path component */
1902 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1903 if(dwAttributes & SFGAO_FOLDER)
1905 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1907 ERR("bind to failed\n"); /* should not fail */
1910 IShellFolder_Release(lpsf);
1918 /* end dialog, return value */
1919 nOpenAction = ONOPEN_OPEN;
1922 COMDLG32_SHFree(pidl);
1925 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1927 if(*lpszTemp) /* points to trailing null for last path element */
1929 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1931 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1937 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1938 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1940 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1944 /* change to the current folder */
1945 nOpenAction = ONOPEN_OPEN;
1950 nOpenAction = ONOPEN_OPEN;
1954 if(pidl) COMDLG32_SHFree(pidl);
1958 Step 3: here we have a cleaned up and validated path
1961 lpsf: ShellFolder bound to the rightmost valid path component
1962 lpstrPathAndFile: cleaned up path
1963 nOpenAction: action to do
1965 TRACE("end validate sf=%p\n", lpsf);
1969 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1970 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1973 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1976 /* replace the current filter */
1977 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1978 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1979 len = strlenW(lpszTemp)+1;
1980 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1981 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1983 /* set the filter cb to the extension when possible */
1984 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1985 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1988 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1989 TRACE("ONOPEN_BROWSE\n");
1991 IPersistFolder2 * ppf2;
1992 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1994 LPITEMIDLIST pidlCurrent;
1995 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1996 IPersistFolder2_Release(ppf2);
1997 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1999 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
2001 else if( nOpenAction == ONOPEN_SEARCH )
2003 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2005 COMDLG32_SHFree(pidlCurrent);
2010 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2011 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2015 /* update READONLY check box flag */
2016 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2017 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2019 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2021 /* Attach the file extension with file name*/
2022 ext = PathFindExtensionW(lpstrPathAndFile);
2025 /* if no extension is specified with file name, then */
2026 /* attach the extension from file filter or default one */
2028 WCHAR *filterExt = NULL;
2029 LPWSTR lpstrFilter = NULL;
2030 static const WCHAR szwDot[] = {'.',0};
2031 int PathLength = strlenW(lpstrPathAndFile);
2034 strcatW(lpstrPathAndFile, szwDot);
2036 /*Get the file extension from file type filter*/
2037 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2038 fodInfos->ofnInfos->nFilterIndex-1);
2040 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2041 filterExt = PathFindExtensionW(lpstrFilter);
2043 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2044 strcatW(lpstrPathAndFile, filterExt + 1);
2045 else if ( fodInfos->defext ) /* attach the default file extension*/
2046 strcatW(lpstrPathAndFile, fodInfos->defext);
2048 /* In Open dialog: if file does not exist try without extension */
2049 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2050 lpstrPathAndFile[PathLength] = '\0';
2053 if (fodInfos->defext) /* add default extension */
2055 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2058 if (!lstrcmpiW(fodInfos->defext, ext))
2059 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2061 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2064 /* In Save dialog: check if the file already exists */
2065 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2066 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2067 && PathFileExistsW(lpstrPathAndFile))
2069 WCHAR lpstrOverwrite[100];
2072 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2073 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2074 MB_YESNO | MB_ICONEXCLAMATION);
2082 /* Check that the size of the file does not exceed buffer size.
2083 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2084 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2085 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2089 /* fill destination buffer */
2090 if (fodInfos->ofnInfos->lpstrFile)
2092 if(fodInfos->unicode)
2094 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2096 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2097 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2098 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2102 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2104 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2105 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2106 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2107 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2111 /* set filename offset */
2112 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2113 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2115 /* set extension offset */
2116 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2117 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2119 /* set the lpstrFileTitle */
2120 if(fodInfos->ofnInfos->lpstrFileTitle)
2122 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2123 if(fodInfos->unicode)
2125 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2126 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2130 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2131 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2132 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2136 /* copy currently selected filter to lpstrCustomFilter */
2137 if (fodInfos->ofnInfos->lpstrCustomFilter)
2139 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2140 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2141 NULL, 0, NULL, NULL);
2142 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2144 LPSTR s = ofn->lpstrCustomFilter;
2145 s += strlen(ofn->lpstrCustomFilter)+1;
2146 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2147 s, len, NULL, NULL);
2152 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2156 FILEDLG95_Clean(hwnd);
2157 ret = EndDialog(hwnd, TRUE);
2163 size = strlenW(lpstrPathAndFile) + 1;
2164 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2166 /* return needed size in first two bytes of lpstrFile */
2167 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2168 FILEDLG95_Clean(hwnd);
2169 ret = EndDialog(hwnd, FALSE);
2170 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2178 if(lpsf) IShellFolder_Release(lpsf);
2182 /***********************************************************************
2183 * FILEDLG95_SHELL_Init
2185 * Initialisation of the shell objects
2187 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2189 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2194 * Initialisation of the FileOpenDialogInfos structure
2200 fodInfos->ShellInfos.hwndOwner = hwnd;
2202 /* Disable multi-select if flag not set */
2203 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2205 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2207 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2208 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2210 /* Construct the IShellBrowser interface */
2211 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2216 /***********************************************************************
2217 * FILEDLG95_SHELL_ExecuteCommand
2219 * Change the folder option and refresh the view
2220 * If the function succeeds, the return value is nonzero.
2222 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2224 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2227 TRACE("(%p,%p)\n", hwnd, lpVerb);
2229 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2234 CMINVOKECOMMANDINFO ci;
2235 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2236 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2240 IContextMenu_InvokeCommand(pcm, &ci);
2241 IContextMenu_Release(pcm);
2247 /***********************************************************************
2248 * FILEDLG95_SHELL_UpFolder
2250 * Browse to the specified object
2251 * If the function succeeds, the return value is nonzero.
2253 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2255 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2259 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2263 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2269 /***********************************************************************
2270 * FILEDLG95_SHELL_BrowseToDesktop
2272 * Browse to the Desktop
2273 * If the function succeeds, the return value is nonzero.
2275 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2277 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2283 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2284 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2285 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2286 COMDLG32_SHFree(pidl);
2287 return SUCCEEDED(hres);
2289 /***********************************************************************
2290 * FILEDLG95_SHELL_Clean
2292 * Cleans the memory used by shell objects
2294 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2296 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2300 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2302 /* clean Shell interfaces */
2303 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2304 IShellView_Release(fodInfos->Shell.FOIShellView);
2305 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2306 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2307 if (fodInfos->Shell.FOIDataObject)
2308 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2311 /***********************************************************************
2312 * FILEDLG95_FILETYPE_Init
2314 * Initialisation of the file type combo box
2316 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2318 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2319 int nFilters = 0; /* number of filters */
2324 if(fodInfos->customfilter)
2326 /* customfilter has one entry... title\0ext\0
2327 * Set first entry of combo box item with customfilter
2330 LPCWSTR lpstrPos = fodInfos->customfilter;
2333 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2335 /* Copy the extensions */
2336 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2337 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2338 strcpyW(lpstrExt,lpstrPos);
2340 /* Add the item at the end of the combo */
2341 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2342 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2345 if(fodInfos->filter)
2347 LPCWSTR lpstrPos = fodInfos->filter;
2351 /* filter is a list... title\0ext\0......\0\0
2352 * Set the combo item text to the title and the item data
2355 LPCWSTR lpstrDisplay;
2359 if(! *lpstrPos) break; /* end */
2360 lpstrDisplay = lpstrPos;
2361 lpstrPos += strlenW(lpstrPos) + 1;
2363 /* Copy the extensions */
2364 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2365 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2366 strcpyW(lpstrExt,lpstrPos);
2367 lpstrPos += strlenW(lpstrPos) + 1;
2369 /* Add the item at the end of the combo */
2370 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2371 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2377 * Set the current filter to the one specified
2378 * in the initialisation structure
2380 if (fodInfos->filter || fodInfos->customfilter)
2384 /* Check to make sure our index isn't out of bounds. */
2385 if ( fodInfos->ofnInfos->nFilterIndex >
2386 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2387 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2389 /* set default filter index */
2390 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2391 fodInfos->ofnInfos->nFilterIndex = 1;
2393 /* calculate index of Combo Box item */
2394 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2395 if (fodInfos->customfilter == NULL)
2398 /* Set the current index selection. */
2399 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2401 /* Get the corresponding text string from the combo box. */
2402 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2405 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2411 CharLowerW(lpstrFilter); /* lowercase */
2412 len = strlenW(lpstrFilter)+1;
2413 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2414 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2417 fodInfos->ofnInfos->nFilterIndex = 0;
2421 /***********************************************************************
2422 * FILEDLG95_FILETYPE_OnCommand
2424 * WM_COMMAND of the file type combo box
2425 * If the function succeeds, the return value is nonzero.
2427 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2429 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2437 /* Get the current item of the filetype combo box */
2438 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2440 /* set the current filter index */
2441 fodInfos->ofnInfos->nFilterIndex = iItem +
2442 (fodInfos->customfilter == NULL ? 1 : 0);
2444 /* Set the current filter with the current selection */
2445 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2446 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2448 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2450 if((INT_PTR)lpstrFilter != CB_ERR)
2453 CharLowerW(lpstrFilter); /* lowercase */
2454 len = strlenW(lpstrFilter)+1;
2455 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2456 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2457 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2460 /* Refresh the actual view to display the included items*/
2461 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2466 /***********************************************************************
2467 * FILEDLG95_FILETYPE_SearchExt
2469 * searches for an extension in the filetype box
2471 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2473 int i, iCount = CBGetCount(hwnd);
2475 TRACE("%s\n", debugstr_w(lpstrExt));
2477 if(iCount != CB_ERR)
2479 for(i=0;i<iCount;i++)
2481 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2488 /***********************************************************************
2489 * FILEDLG95_FILETYPE_Clean
2491 * Clean the memory used by the filetype combo box
2493 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2495 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2497 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2501 /* Delete each string of the combo and their associated data */
2502 if(iCount != CB_ERR)
2504 for(iPos = iCount-1;iPos>=0;iPos--)
2506 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2507 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2510 /* Current filter */
2511 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2512 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2516 /***********************************************************************
2517 * FILEDLG95_LOOKIN_Init
2519 * Initialisation of the look in combo box
2522 /* Small helper function, to determine if the unixfs shell extension is rooted
2523 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2525 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2527 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2528 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2529 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2530 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2531 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2532 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2533 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2535 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2542 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2544 IShellFolder *psfRoot, *psfDrives;
2545 IEnumIDList *lpeRoot, *lpeDrives;
2546 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2548 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2552 liInfos->iMaxIndentation = 0;
2554 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2556 /* set item height for both text field and listbox */
2557 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2558 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2560 /* Turn on the extended UI for the combo box like Windows does */
2561 CBSetExtendedUI(hwndCombo, TRUE);
2563 /* Initialise data of Desktop folder */
2564 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2565 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2566 COMDLG32_SHFree(pidlTmp);
2568 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2570 SHGetDesktopFolder(&psfRoot);
2574 /* enumerate the contents of the desktop */
2575 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2577 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2579 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2581 /* If the unixfs extension is rooted, we don't expand the drives by default */
2582 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2584 /* special handling for CSIDL_DRIVES */
2585 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2587 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2589 /* enumerate the drives */
2590 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2592 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2594 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2595 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2596 COMDLG32_SHFree(pidlAbsTmp);
2597 COMDLG32_SHFree(pidlTmp1);
2599 IEnumIDList_Release(lpeDrives);
2601 IShellFolder_Release(psfDrives);
2606 COMDLG32_SHFree(pidlTmp);
2608 IEnumIDList_Release(lpeRoot);
2610 IShellFolder_Release(psfRoot);
2613 COMDLG32_SHFree(pidlDrives);
2616 /***********************************************************************
2617 * FILEDLG95_LOOKIN_DrawItem
2619 * WM_DRAWITEM message handler
2621 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2623 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2624 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2625 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2629 HIMAGELIST ilItemImage;
2632 LPSFOLDER tmpFolder;
2635 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2639 if(pDIStruct->itemID == -1)
2642 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2643 pDIStruct->itemID)))
2647 if(pDIStruct->itemID == liInfos->uSelectedItem)
2649 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2652 sizeof (SHFILEINFOA),
2653 SHGFI_PIDL | SHGFI_SMALLICON |
2654 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2655 SHGFI_DISPLAYNAME );
2659 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2662 sizeof (SHFILEINFOA),
2663 SHGFI_PIDL | SHGFI_SMALLICON |
2664 SHGFI_SYSICONINDEX |
2668 /* Is this item selected ? */
2669 if(pDIStruct->itemState & ODS_SELECTED)
2671 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2672 SetBkColor(pDIStruct->hDC,crHighLight);
2673 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2677 SetTextColor(pDIStruct->hDC,crText);
2678 SetBkColor(pDIStruct->hDC,crWin);
2679 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2682 /* Do not indent item if drawing in the edit of the combo */
2683 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2686 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2689 sizeof (SHFILEINFOA),
2690 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2691 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2696 iIndentation = tmpFolder->m_iIndent;
2698 /* Draw text and icon */
2700 /* Initialise the icon display area */
2701 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2702 rectIcon.top = pDIStruct->rcItem.top;
2703 rectIcon.right = rectIcon.left + ICONWIDTH;
2704 rectIcon.bottom = pDIStruct->rcItem.bottom;
2706 /* Initialise the text display area */
2707 GetTextMetricsA(pDIStruct->hDC, &tm);
2708 rectText.left = rectIcon.right;
2710 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2711 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2713 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2715 /* Draw the icon from the image list */
2716 ImageList_Draw(ilItemImage,
2723 /* Draw the associated text */
2724 if(sfi.szDisplayName)
2725 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2731 /***********************************************************************
2732 * FILEDLG95_LOOKIN_OnCommand
2734 * LookIn combo box WM_COMMAND message handler
2735 * If the function succeeds, the return value is nonzero.
2737 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2739 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2741 TRACE("%p\n", fodInfos);
2747 LPSFOLDER tmpFolder;
2750 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2752 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2757 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2758 tmpFolder->pidlItem,
2761 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2771 /***********************************************************************
2772 * FILEDLG95_LOOKIN_AddItem
2774 * Adds an absolute pidl item to the lookin combo box
2775 * returns the index of the inserted item
2777 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2779 LPITEMIDLIST pidlNext;
2782 LookInInfos *liInfos;
2784 TRACE("%08x\n", iInsertId);
2789 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2792 tmpFolder = MemAlloc(sizeof(SFOLDER));
2793 tmpFolder->m_iIndent = 0;
2795 /* Calculate the indentation of the item in the lookin*/
2797 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2799 tmpFolder->m_iIndent++;
2802 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2804 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2805 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2807 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2808 SHGetFileInfoA((LPSTR)pidl,
2812 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2813 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2815 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2817 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2821 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2823 /* Add the item at the end of the list */
2826 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2828 /* Insert the item at the iInsertId position*/
2831 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2834 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2838 COMDLG32_SHFree( tmpFolder->pidlItem );
2839 MemFree( tmpFolder );
2844 /***********************************************************************
2845 * FILEDLG95_LOOKIN_InsertItemAfterParent
2847 * Insert an item below its parent
2849 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2852 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2857 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2861 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2864 /* Free pidlParent memory */
2865 COMDLG32_SHFree((LPVOID)pidlParent);
2867 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2870 /***********************************************************************
2871 * FILEDLG95_LOOKIN_SelectItem
2873 * Adds an absolute pidl item to the lookin combo box
2874 * returns the index of the inserted item
2876 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2879 LookInInfos *liInfos;
2883 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2885 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2889 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2890 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2895 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2896 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2900 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2902 if(iRemovedItem < iItemPos)
2907 CBSetCurSel(hwnd,iItemPos);
2908 liInfos->uSelectedItem = iItemPos;
2914 /***********************************************************************
2915 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2917 * Remove the item with an expansion level over iExpansionLevel
2919 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2923 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2927 if(liInfos->iMaxIndentation <= 2)
2930 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2932 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2933 COMDLG32_SHFree(tmpFolder->pidlItem);
2935 CBDeleteString(hwnd,iItemPos);
2936 liInfos->iMaxIndentation--;
2944 /***********************************************************************
2945 * FILEDLG95_LOOKIN_SearchItem
2947 * Search for pidl in the lookin combo box
2948 * returns the index of the found item
2950 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2953 int iCount = CBGetCount(hwnd);
2955 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2957 if (iCount != CB_ERR)
2961 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2963 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2965 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2973 /***********************************************************************
2974 * FILEDLG95_LOOKIN_Clean
2976 * Clean the memory used by the lookin combo box
2978 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2980 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2982 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2986 /* Delete each string of the combo and their associated data */
2987 if (iCount != CB_ERR)
2989 for(iPos = iCount-1;iPos>=0;iPos--)
2991 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2992 COMDLG32_SHFree(tmpFolder->pidlItem);
2994 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2998 /* LookInInfos structure */
2999 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3002 /***********************************************************************
3003 * FILEDLG95_FILENAME_FillFromSelection
3005 * fills the edit box from the cached DataObject
3007 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3009 FileOpenDlgInfos *fodInfos;
3011 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3012 char lpstrTemp[MAX_PATH];
3013 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3016 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3018 /* Count how many files we have */
3019 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3021 /* calculate the string length, count files */
3022 if (nFileSelected >= 1)
3024 nLength += 3; /* first and last quotes, trailing \0 */
3025 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3027 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3031 /* get the total length of the selected file names */
3032 lpstrTemp[0] = '\0';
3033 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3035 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3037 nLength += strlen( lpstrTemp ) + 3;
3040 COMDLG32_SHFree( pidl );
3045 /* allocate the buffer */
3046 if (nFiles <= 1) nLength = MAX_PATH;
3047 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3048 lpstrAllFile[0] = '\0';
3050 /* Generate the string for the edit control */
3053 lpstrCurrFile = lpstrAllFile;
3054 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3056 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3060 /* get the file name */
3061 lpstrTemp[0] = '\0';
3062 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3064 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3068 *lpstrCurrFile++ = '\"';
3069 strcpy( lpstrCurrFile, lpstrTemp );
3070 lpstrCurrFile += strlen( lpstrTemp );
3071 strcpy( lpstrCurrFile, "\" " );
3076 strcpy( lpstrAllFile, lpstrTemp );
3079 COMDLG32_SHFree( (LPVOID) pidl );
3082 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3084 /* Select the file name like Windows does */
3085 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3087 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3091 /* copied from shell32 to avoid linking to it
3092 * FIXME: why? shell32 is already linked
3094 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3099 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3100 COMDLG32_SHFree(src->u.pOleStr);
3104 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3108 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3112 FIXME("unknown type!\n");
3115 *(LPSTR)dest = '\0';
3122 /***********************************************************************
3123 * FILEDLG95_FILENAME_GetFileNames
3125 * Copies the filenames to a delimited string list.
3126 * The delimiter is specified by the parameter 'separator',
3127 * usually either a space or a nul
3129 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3131 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3132 UINT nStrCharCount = 0; /* index in src buffer */
3133 UINT nFileIndex = 0; /* index in dest buffer */
3134 UINT nFileCount = 0; /* number of files */
3135 UINT nStrLen = 0; /* length of string in edit control */
3136 LPWSTR lpstrEdit; /* buffer for string from edit control */
3140 /* get the filenames from the edit control */
3141 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3142 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3143 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3145 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3147 /* we might get single filename without any '"',
3148 * so we need nStrLen + terminating \0 + end-of-list \0 */
3149 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3152 /* build delimited file list from filenames */
3153 while ( nStrCharCount <= nStrLen )
3155 if ( lpstrEdit[nStrCharCount]=='"' )
3158 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3160 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3164 (*lpstrFileList)[nFileIndex++] = separator;
3171 /* single, unquoted string */
3172 if ((nStrLen > 0) && (*sizeUsed == 0) )
3174 strcpyW(*lpstrFileList, lpstrEdit);
3175 nFileIndex = strlenW(lpstrEdit) + 1;
3176 (*sizeUsed) = nFileIndex;
3181 (*lpstrFileList)[nFileIndex] = '\0';
3188 #define SETDefFormatEtc(fe,cf,med) \
3190 (fe).cfFormat = cf;\
3191 (fe).dwAspect = DVASPECT_CONTENT; \
3198 * DATAOBJECT Helper functions
3201 /***********************************************************************
3202 * COMCTL32_ReleaseStgMedium
3204 * like ReleaseStgMedium from ole32
3206 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3208 if(medium.pUnkForRelease)
3210 IUnknown_Release(medium.pUnkForRelease);
3214 GlobalUnlock(medium.u.hGlobal);
3215 GlobalFree(medium.u.hGlobal);
3219 /***********************************************************************
3220 * GetPidlFromDataObject
3222 * Return pidl(s) by number from the cached DataObject
3224 * nPidlIndex=0 gets the fully qualified root path
3226 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3230 FORMATETC formatetc;
3231 LPITEMIDLIST pidl = NULL;
3233 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3238 /* Set the FORMATETC structure*/
3239 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3241 /* Get the pidls from IDataObject */
3242 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3244 LPIDA cida = GlobalLock(medium.u.hGlobal);
3245 if(nPidlIndex <= cida->cidl)
3247 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3249 COMCTL32_ReleaseStgMedium(medium);
3254 /***********************************************************************
3257 * Return the number of selected items in the DataObject.
3260 UINT GetNumSelected( IDataObject *doSelected )
3264 FORMATETC formatetc;
3266 TRACE("sv=%p\n", doSelected);
3268 if (!doSelected) return 0;
3270 /* Set the FORMATETC structure*/
3271 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3273 /* Get the pidls from IDataObject */
3274 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3276 LPIDA cida = GlobalLock(medium.u.hGlobal);
3277 retVal = cida->cidl;
3278 COMCTL32_ReleaseStgMedium(medium);
3288 /***********************************************************************
3291 * Get the pidl's display name (relative to folder) and
3292 * put it in lpstrFileName.
3294 * Return NOERROR on success,
3298 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3303 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3307 SHGetDesktopFolder(&lpsf);
3308 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3309 IShellFolder_Release(lpsf);
3313 /* Get the display name of the pidl relative to the folder */
3314 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3316 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3321 /***********************************************************************
3322 * GetShellFolderFromPidl
3324 * pidlRel is the item pidl relative
3325 * Return the IShellFolder of the absolute pidl
3327 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3329 IShellFolder *psf = NULL,*psfParent;
3331 TRACE("%p\n", pidlAbs);
3333 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3336 if(pidlAbs && pidlAbs->mkid.cb)
3338 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3340 IShellFolder_Release(psfParent);
3344 /* return the desktop */
3350 /***********************************************************************
3353 * Return the LPITEMIDLIST to the parent of the pidl in the list
3355 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3357 LPITEMIDLIST pidlParent;
3359 TRACE("%p\n", pidl);
3361 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3362 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3367 /***********************************************************************
3370 * returns the pidl of the file name relative to folder
3371 * NULL if an error occurred
3373 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3375 LPITEMIDLIST pidl = NULL;
3378 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3380 if(!lpcstrFileName) return NULL;
3381 if(!*lpcstrFileName) return NULL;
3385 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3386 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3387 IShellFolder_Release(lpsf);
3392 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3399 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3401 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3404 TRACE("%p, %p\n", psf, pidl);
3406 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3408 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3409 /* see documentation shell 4.1*/
3410 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3413 /***********************************************************************
3414 * BrowseSelectedFolder
3416 static BOOL BrowseSelectedFolder(HWND hwnd)
3418 BOOL bBrowseSelFolder = FALSE;
3419 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3423 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3425 LPITEMIDLIST pidlSelection;
3427 /* get the file selected */
3428 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3429 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3431 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3432 pidlSelection, SBSP_RELATIVE ) ) )
3434 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3435 ' ','n','o','t',' ','e','x','i','s','t',0};
3436 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3438 bBrowseSelFolder = TRUE;
3439 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3441 COMDLG32_SHFree( pidlSelection );
3444 return bBrowseSelFolder;
3448 * Memory allocation methods */
3449 static void *MemAlloc(UINT size)
3451 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3454 static void MemFree(void *mem)
3456 HeapFree(GetProcessHeap(),0,mem);
3460 * Old-style (win3.1) dialogs */
3462 /***********************************************************************
3463 * FD32_GetTemplate [internal]
3465 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3466 * by a 32 bits application
3469 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3471 LPOPENFILENAMEW ofnW = lfs->ofnW;
3472 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3475 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3477 if (!(lfs->template = LockResource( ofnW->hInstance )))
3479 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3483 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3487 hResInfo = FindResourceA(priv->ofnA->hInstance,
3488 priv->ofnA->lpTemplateName,
3491 hResInfo = FindResourceW(ofnW->hInstance,
3492 ofnW->lpTemplateName,
3496 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3499 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3501 !(lfs->template = LockResource(hDlgTmpl)))
3503 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3506 } else { /* get it from internal Wine resource */
3508 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3509 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3511 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3514 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3515 !(lfs->template = LockResource( hDlgTmpl )))
3517 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3525 /************************************************************************
3526 * FD32_Init [internal]
3527 * called from the common 16/32 code to initialize 32 bit data
3529 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3531 BOOL IsUnicode = (BOOL) data;
3534 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3535 lfs->private1632 = priv;
3536 if (NULL == lfs->private1632) return FALSE;
3539 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3540 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3541 if (lfs->ofnW->lpfnHook)
3546 priv->ofnA = (LPOPENFILENAMEA) lParam;
3547 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3548 if (priv->ofnA->lpfnHook)
3550 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3551 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3554 if (! FD32_GetTemplate(lfs)) return FALSE;
3559 /***********************************************************************
3560 * FD32_CallWindowProc [internal]
3562 * called from the common 16/32 code to call the appropriate hook
3564 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3568 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3572 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3573 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3574 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3575 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3576 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3580 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3581 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3582 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3583 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3584 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3588 /***********************************************************************
3589 * FD32_UpdateResult [internal]
3590 * update the real client structures if any
3592 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3594 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3595 LPOPENFILENAMEW ofnW = lfs->ofnW;
3599 if (ofnW->nMaxFile &&
3600 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3601 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3602 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3603 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3604 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3608 /***********************************************************************
3609 * FD32_UpdateFileTitle [internal]
3610 * update the real client structures if any
3612 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3614 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3615 LPOPENFILENAMEW ofnW = lfs->ofnW;
3619 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3620 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3621 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3626 /***********************************************************************
3627 * FD32_SendLbGetCurSel [internal]
3628 * retrieve selected listbox item
3630 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3632 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3636 /************************************************************************
3637 * FD32_Destroy [internal]
3638 * called from the common 16/32 code to cleanup 32 bit data
3640 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3642 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3644 /* if ofnW has been allocated, have to free everything in it */
3645 if (NULL != priv && NULL != priv->ofnA)
3647 FD31_FreeOfnW(lfs->ofnW);
3648 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3652 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3654 callbacks->Init = FD32_Init;
3655 callbacks->CWP = FD32_CallWindowProc;
3656 callbacks->UpdateResult = FD32_UpdateResult;
3657 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3658 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3659 callbacks->Destroy = FD32_Destroy;
3662 /***********************************************************************
3663 * FD32_WMMeasureItem [internal]
3665 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3667 LPMEASUREITEMSTRUCT lpmeasure;
3669 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3670 lpmeasure->itemHeight = FD31_GetFldrHeight();
3675 /***********************************************************************
3676 * FileOpenDlgProc [internal]
3677 * Used for open and save, in fact.
3679 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3680 WPARAM wParam, LPARAM lParam)
3682 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3684 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3685 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3688 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3690 return lRet; /* else continue message processing */
3695 return FD31_WMInitDialog(hWnd, wParam, lParam);
3697 case WM_MEASUREITEM:
3698 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3701 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3704 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3707 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3708 switch (HIWORD(lParam))
3711 SetTextColor((HDC16)wParam, 0x00000000);
3713 case CTLCOLOR_STATIC:
3714 SetTextColor((HDC16)wParam, 0x00000000);
3724 /***********************************************************************
3725 * GetFileName31A [internal]
3727 * Creates a win31 style dialog box for the user to select a file to open/save.
3729 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3730 UINT dlgType /* type dialogue : open/save */
3736 FD31_CALLBACKS callbacks;
3738 if (!lpofn || !FD31_Init()) return FALSE;
3740 TRACE("ofn flags %08lx\n", lpofn->Flags);
3741 FD32_SetupCallbacks(&callbacks);
3742 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3745 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3746 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3747 FD32_FileOpenDlgProc, (LPARAM)lfs);
3748 FD31_DestroyPrivate(lfs);
3751 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3755 /***********************************************************************
3756 * GetFileName31W [internal]
3758 * Creates a win31 style dialog box for the user to select a file to open/save
3760 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3761 UINT dlgType /* type dialogue : open/save */
3767 FD31_CALLBACKS callbacks;
3769 if (!lpofn || !FD31_Init()) return FALSE;
3771 FD32_SetupCallbacks(&callbacks);
3772 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3775 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3776 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3777 FD32_FileOpenDlgProc, (LPARAM)lfs);
3778 FD31_DestroyPrivate(lfs);
3781 TRACE("file %s, file offset %d, ext offset %d\n",
3782 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3786 /* ------------------ APIs ---------------------- */
3788 /***********************************************************************
3789 * GetOpenFileNameA (COMDLG32.@)
3791 * Creates a dialog box for the user to select a file to open.
3794 * TRUE on success: user enters a valid file
3795 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3798 BOOL WINAPI GetOpenFileNameA(
3799 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3801 BOOL win16look = FALSE;
3803 TRACE("flags %08lx\n", ofn->Flags);
3805 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3806 if (ofn->Flags & OFN_FILEMUSTEXIST)
3807 ofn->Flags |= OFN_PATHMUSTEXIST;
3809 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3810 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3813 return GetFileName31A(ofn, OPEN_DIALOG);
3815 return GetFileDialog95A(ofn, OPEN_DIALOG);
3818 /***********************************************************************
3819 * GetOpenFileNameW (COMDLG32.@)
3821 * Creates a dialog box for the user to select a file to open.
3824 * TRUE on success: user enters a valid file
3825 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3828 BOOL WINAPI GetOpenFileNameW(
3829 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3831 BOOL win16look = FALSE;
3833 TRACE("flags %08lx\n", ofn->Flags);
3835 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3836 if (ofn->Flags & OFN_FILEMUSTEXIST)
3837 ofn->Flags |= OFN_PATHMUSTEXIST;
3839 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3840 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3843 return GetFileName31W(ofn, OPEN_DIALOG);
3845 return GetFileDialog95W(ofn, OPEN_DIALOG);
3849 /***********************************************************************
3850 * GetSaveFileNameA (COMDLG32.@)
3852 * Creates a dialog box for the user to select a file to save.
3855 * TRUE on success: user enters a valid file
3856 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3859 BOOL WINAPI GetSaveFileNameA(
3860 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3862 BOOL win16look = FALSE;
3864 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3865 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3868 return GetFileName31A(ofn, SAVE_DIALOG);
3870 return GetFileDialog95A(ofn, SAVE_DIALOG);
3873 /***********************************************************************
3874 * GetSaveFileNameW (COMDLG32.@)
3876 * Creates a dialog box for the user to select a file to save.
3879 * TRUE on success: user enters a valid file
3880 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3883 BOOL WINAPI GetSaveFileNameW(
3884 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3886 BOOL win16look = FALSE;
3888 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3889 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3892 return GetFileName31W(ofn, SAVE_DIALOG);
3894 return GetFileDialog95W(ofn, SAVE_DIALOG);