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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)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 if (fodInfos->unicode)
289 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
291 fodInfos->ofnInfos->hwndOwner,
295 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
296 (LPDLGTEMPLATEA) template,
297 fodInfos->ofnInfos->hwndOwner,
303 /* Unable to create the dialog */
310 /***********************************************************************
313 * Call GetFileName95 with this structure and clean the memory.
315 * IN : The OPENFILENAMEA initialisation structure passed to
316 * GetOpenFileNameA win api function (see filedlg.c)
318 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
321 FileOpenDlgInfos fodInfos;
322 LPSTR lpstrSavDir = NULL;
324 LPWSTR defext = NULL;
325 LPWSTR filter = NULL;
326 LPWSTR customfilter = NULL;
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
351 fodInfos.initdir = NULL;
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
359 fodInfos.filename = NULL;
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
417 ret = GetFileName95(&fodInfos);
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
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 if (fodInfos->unicode)
775 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
776 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
777 (LPARAM)fodInfos->ofnInfos);
779 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
780 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
781 (LPARAM)fodInfos->ofnInfos);
784 ShowWindow(hChildDlg,SW_SHOW);
788 else if( IsHooked(fodInfos))
793 WORD menu,class,title;
795 GetClientRect(hwnd,&rectHwnd);
796 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
797 temp.tmplate.dwExtendedStyle = 0;
798 temp.tmplate.cdit = 0;
803 temp.menu = temp.class = temp.title = 0;
805 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
806 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
813 /***********************************************************************
814 * SendCustomDlgNotificationMessage
816 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
819 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
821 LRESULT hook_result = 0;
823 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
825 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
827 if(!fodInfos) return 0;
829 if(fodInfos->DlgInfos.hwndCustomDlg)
831 TRACE("CALL NOTIFY for %x\n", uCode);
832 if(fodInfos->unicode)
835 ofnNotify.hdr.hwndFrom=hwndParentDlg;
836 ofnNotify.hdr.idFrom=0;
837 ofnNotify.hdr.code = uCode;
838 ofnNotify.lpOFN = fodInfos->ofnInfos;
839 ofnNotify.pszFile = NULL;
840 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
845 ofnNotify.hdr.hwndFrom=hwndParentDlg;
846 ofnNotify.hdr.idFrom=0;
847 ofnNotify.hdr.code = uCode;
848 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
849 ofnNotify.pszFile = NULL;
850 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
852 TRACE("RET NOTIFY\n");
854 TRACE("Retval: 0x%08lx\n", hook_result);
858 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
860 UINT sizeUsed = 0, n, total;
861 LPWSTR lpstrFileList = NULL;
862 WCHAR lpstrCurrentDir[MAX_PATH];
863 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
865 TRACE("CDM_GETFILEPATH:\n");
867 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
870 /* get path and filenames */
871 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
872 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
874 TRACE("path >%s< filespec >%s< %d files\n",
875 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
877 if( fodInfos->unicode )
879 LPWSTR bufW = buffer;
880 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
882 /* Prepend the current path */
883 n = strlenW(lpstrCurrentDir) + 1;
884 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
887 /* 'n' includes trailing \0 */
889 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
891 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
896 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
897 NULL, 0, NULL, NULL);
898 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
899 NULL, 0, NULL, NULL);
901 /* Prepend the current path */
902 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
903 bufA, size, NULL, NULL);
907 /* 'n' includes trailing \0 */
909 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
910 &bufA[n], size-n, NULL, NULL);
913 TRACE("returned -> %s\n",debugstr_an(bufA, total));
915 MemFree(lpstrFileList);
920 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
923 LPWSTR lpstrFileList = NULL;
924 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
926 TRACE("CDM_GETSPEC:\n");
928 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
929 if( fodInfos->unicode )
931 LPWSTR bufW = buffer;
932 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
937 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
938 NULL, 0, NULL, NULL);
939 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
940 bufA, size, NULL, NULL);
942 MemFree(lpstrFileList);
947 /***********************************************************************
948 * FILEDLG95_HandleCustomDialogMessages
950 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
952 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
954 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
955 WCHAR lpstrPath[MAX_PATH];
958 if(!fodInfos) return FALSE;
962 case CDM_GETFILEPATH:
963 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
966 case CDM_GETFOLDERPATH:
967 TRACE("CDM_GETFOLDERPATH:\n");
968 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
971 if (fodInfos->unicode)
972 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
974 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
975 (LPSTR)lParam, (int)wParam, NULL, NULL);
977 retval = strlenW(lpstrPath);
981 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
984 case CDM_SETCONTROLTEXT:
985 TRACE("CDM_SETCONTROLTEXT:\n");
988 if( fodInfos->unicode )
989 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
991 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
996 case CDM_HIDECONTROL:
997 /* MSDN states that it should fail for not OFN_EXPLORER case */
998 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1000 HWND control = GetDlgItem( hwnd, wParam );
1001 if (control) ShowWindow( control, SW_HIDE );
1004 else retval = FALSE;
1008 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1009 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1012 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1016 /***********************************************************************
1019 * File open dialog procedure
1021 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1024 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1031 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1033 /* Adds the FileOpenDlgInfos in the property list of the dialog
1034 so it will be easily accessible through a GetPropA(...) */
1035 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1037 fodInfos->DlgInfos.hwndCustomDlg =
1038 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1040 FILEDLG95_InitControls(hwnd);
1042 if (fodInfos->DlgInfos.hwndCustomDlg)
1045 UINT flags = SWP_NOACTIVATE;
1047 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1048 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1050 /* resize the custom dialog to the parent size */
1051 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1052 GetClientRect(hwnd, &rc);
1055 /* our own fake template is zero sized and doesn't have
1056 * children, so there is no need to resize it.
1057 * Picasa depends on it.
1059 flags |= SWP_NOSIZE;
1062 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1063 0, 0, rc.right, rc.bottom, flags);
1066 FILEDLG95_FillControls(hwnd, wParam, lParam);
1068 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1069 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1070 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1074 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1077 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1080 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1086 case WM_GETISHELLBROWSER:
1087 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1090 RemovePropA(hwnd, FileOpenDlgInfosStr);
1095 LPNMHDR lpnmh = (LPNMHDR)lParam;
1098 /* set up the button tooltips strings */
1099 if(TTN_GETDISPINFOA == lpnmh->code )
1101 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1102 switch(lpnmh->idFrom )
1104 /* Up folder button */
1105 case FCIDM_TB_UPFOLDER:
1106 stringId = IDS_UPFOLDER;
1108 /* New folder button */
1109 case FCIDM_TB_NEWFOLDER:
1110 stringId = IDS_NEWFOLDER;
1112 /* List option button */
1113 case FCIDM_TB_SMALLICON:
1114 stringId = IDS_LISTVIEW;
1116 /* Details option button */
1117 case FCIDM_TB_REPORTVIEW:
1118 stringId = IDS_REPORTVIEW;
1120 /* Desktop button */
1121 case FCIDM_TB_DESKTOP:
1122 stringId = IDS_TODESKTOP;
1127 lpdi->hinst = COMDLG32_hInstance;
1128 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1133 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1134 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1139 /***********************************************************************
1140 * FILEDLG95_InitControls
1142 * WM_INITDIALOG message handler (before hook notification)
1144 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1146 int win2000plus = 0;
1148 int handledPath = FALSE;
1149 OSVERSIONINFOA osVi;
1150 static const WCHAR szwSlash[] = { '\\', 0 };
1151 static const WCHAR szwStar[] = { '*',0 };
1155 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1156 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1157 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1158 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1159 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1160 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1161 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1162 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1163 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1168 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1170 tba[0].hInst = HINST_COMMCTRL;
1171 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1172 tba[1].hInst = COMDLG32_hInstance;
1175 TRACE("%p\n", fodInfos);
1177 /* Get windows version emulating */
1178 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1179 GetVersionExA(&osVi);
1180 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1181 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1182 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1183 win2000plus = (osVi.dwMajorVersion > 4);
1184 if (win2000plus) win98plus = TRUE;
1186 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1188 /* Get the hwnd of the controls */
1189 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1190 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1191 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1193 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1194 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1196 /* construct the toolbar */
1197 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1198 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1200 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1201 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1202 rectTB.left = rectlook.right;
1203 rectTB.top = rectlook.top-1;
1205 if (fodInfos->unicode)
1206 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1207 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1208 rectTB.left, rectTB.top,
1209 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1210 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1212 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1213 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1214 rectTB.left, rectTB.top,
1215 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1216 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1218 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1220 /* FIXME: use TB_LOADIMAGES when implemented */
1221 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1222 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1223 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1225 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1226 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1228 /* Set the window text with the text specified in the OPENFILENAME structure */
1231 SetWindowTextW(hwnd,fodInfos->title);
1233 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1236 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1237 SetWindowTextW(hwnd, buf);
1240 /* Initialise the file name edit control */
1241 handledPath = FALSE;
1242 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1244 if(fodInfos->filename)
1246 /* 1. If win2000 or higher and filename contains a path, use it
1247 in preference over the lpstrInitialDir */
1248 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1249 WCHAR tmpBuf[MAX_PATH];
1253 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1256 /* nameBit is always shorter than the original filename */
1257 strcpyW(fodInfos->filename,nameBit);
1260 if (fodInfos->initdir == NULL)
1261 MemFree(fodInfos->initdir);
1262 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1263 strcpyW(fodInfos->initdir, tmpBuf);
1265 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1266 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1268 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1271 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1275 /* 2. (All platforms) If initdir is not null, then use it */
1276 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1277 (*fodInfos->initdir!=0x00))
1279 /* Work out the proper path as supplied one might be relative */
1280 /* (Here because supplying '.' as dir browses to My Computer) */
1281 if (handledPath==FALSE) {
1282 WCHAR tmpBuf[MAX_PATH];
1283 WCHAR tmpBuf2[MAX_PATH];
1287 strcpyW(tmpBuf, fodInfos->initdir);
1288 if( PathFileExistsW(tmpBuf) ) {
1289 /* initdir does not have to be a directory. If a file is
1290 * specified, the dir part is taken */
1291 if( PathIsDirectoryW(tmpBuf)) {
1292 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1293 strcatW(tmpBuf, szwSlash);
1295 strcatW(tmpBuf, szwStar);
1297 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1300 MemFree(fodInfos->initdir);
1301 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1302 strcpyW(fodInfos->initdir, tmpBuf2);
1304 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1307 else if (fodInfos->initdir)
1309 MemFree(fodInfos->initdir);
1310 fodInfos->initdir = NULL;
1311 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1316 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1317 (*fodInfos->initdir==0x00)))
1319 /* 3. All except w2k+: if filename contains a path use it */
1320 if (!win2000plus && fodInfos->filename &&
1321 *fodInfos->filename &&
1322 strpbrkW(fodInfos->filename, szwSlash)) {
1323 WCHAR tmpBuf[MAX_PATH];
1327 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1332 /* nameBit is always shorter than the original filename */
1333 strcpyW(fodInfos->filename, nameBit);
1336 len = strlenW(tmpBuf);
1337 MemFree(fodInfos->initdir);
1338 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1339 strcpyW(fodInfos->initdir, tmpBuf);
1342 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1343 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1345 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1348 /* 4. win98+ and win2000+ if any files of specified filter types in
1349 current directory, use it */
1350 if ( win98plus && handledPath == FALSE &&
1351 fodInfos->filter && *fodInfos->filter) {
1353 BOOL searchMore = TRUE;
1354 LPCWSTR lpstrPos = fodInfos->filter;
1355 WIN32_FIND_DATAW FindFileData;
1360 /* filter is a list... title\0ext\0......\0\0 */
1362 /* Skip the title */
1363 if(! *lpstrPos) break; /* end */
1364 lpstrPos += strlenW(lpstrPos) + 1;
1366 /* See if any files exist in the current dir with this extension */
1367 if(! *lpstrPos) break; /* end */
1369 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1371 if (hFind == INVALID_HANDLE_VALUE) {
1372 /* None found - continue search */
1373 lpstrPos += strlenW(lpstrPos) + 1;
1378 MemFree(fodInfos->initdir);
1379 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1380 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1383 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1384 debugstr_w(lpstrPos));
1390 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1392 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1393 if (handledPath == FALSE && (win2000plus || win98plus)) {
1394 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1396 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1398 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1401 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1402 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1404 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1407 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1410 } else if (handledPath==FALSE) {
1411 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1412 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1414 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1417 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1418 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1420 /* Must the open as read only check box be checked ?*/
1421 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1423 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1426 /* Must the open as read only check box be hidden? */
1427 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1429 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1430 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1433 /* Must the help button be hidden? */
1434 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1436 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1437 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1440 /* Resize the height, if open as read only checkbox ad help button
1441 are hidden and we are not using a custom template nor a customDialog
1443 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1444 (!(fodInfos->ofnInfos->Flags &
1445 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1446 (!fodInfos->DlgInfos.hwndCustomDlg ))
1448 RECT rectDlg, rectHelp, rectCancel;
1449 GetWindowRect(hwnd, &rectDlg);
1450 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1451 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1452 /* subtract the height of the help button plus the space between
1453 the help button and the cancel button to the height of the dialog */
1454 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1455 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1456 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1458 /* change Open to Save */
1459 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1462 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1463 SetDlgItemTextW(hwnd, IDOK, buf);
1464 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1465 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1470 /***********************************************************************
1471 * FILEDLG95_FillControls
1473 * WM_INITDIALOG message handler (after hook notification)
1475 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1477 LPITEMIDLIST pidlItemId = NULL;
1479 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1481 TRACE("dir=%s file=%s\n",
1482 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1484 /* Get the initial directory pidl */
1486 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1488 WCHAR path[MAX_PATH];
1490 GetCurrentDirectoryW(MAX_PATH,path);
1491 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1494 /* Initialise shell objects */
1495 FILEDLG95_SHELL_Init(hwnd);
1497 /* Initialize the Look In combo box */
1498 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1500 /* Initialize the filter combo box */
1501 FILEDLG95_FILETYPE_Init(hwnd);
1503 /* Browse to the initial directory */
1504 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1506 /* Free pidlItem memory */
1507 COMDLG32_SHFree(pidlItemId);
1511 /***********************************************************************
1514 * Regroups all the cleaning functions of the filedlg
1516 void FILEDLG95_Clean(HWND hwnd)
1518 FILEDLG95_FILETYPE_Clean(hwnd);
1519 FILEDLG95_LOOKIN_Clean(hwnd);
1520 FILEDLG95_SHELL_Clean(hwnd);
1522 /***********************************************************************
1523 * FILEDLG95_OnWMCommand
1525 * WM_COMMAND message handler
1527 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1529 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1530 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1531 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1537 FILEDLG95_OnOpen(hwnd);
1541 FILEDLG95_Clean(hwnd);
1542 EndDialog(hwnd, FALSE);
1544 /* Filetype combo box */
1546 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1548 /* LookIn combo box */
1550 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1553 /* --- toolbar --- */
1554 /* Up folder button */
1555 case FCIDM_TB_UPFOLDER:
1556 FILEDLG95_SHELL_UpFolder(hwnd);
1558 /* New folder button */
1559 case FCIDM_TB_NEWFOLDER:
1560 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1562 /* List option button */
1563 case FCIDM_TB_SMALLICON:
1564 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1566 /* Details option button */
1567 case FCIDM_TB_REPORTVIEW:
1568 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1570 /* Details option button */
1571 case FCIDM_TB_DESKTOP:
1572 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1579 /* Do not use the listview selection anymore */
1580 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1584 /***********************************************************************
1585 * FILEDLG95_OnWMGetIShellBrowser
1587 * WM_GETISHELLBROWSER message handler
1589 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1592 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1596 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1602 /***********************************************************************
1603 * FILEDLG95_SendFileOK
1605 * Sends the CDN_FILEOK notification if required
1608 * TRUE if the dialog should close
1609 * FALSE if the dialog should not be closed
1611 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1613 /* ask the hook if we can close */
1614 if(IsHooked(fodInfos))
1619 /* First send CDN_FILEOK as MSDN doc says */
1620 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1621 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1623 TRACE("canceled\n");
1624 return (retval == 0);
1627 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1628 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1629 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1630 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1632 TRACE("canceled\n");
1633 return (retval == 0);
1639 /***********************************************************************
1640 * FILEDLG95_OnOpenMultipleFiles
1642 * Handles the opening of multiple files.
1645 * check destination buffer size
1647 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1649 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1650 UINT nCount, nSizePath;
1651 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1655 if(fodInfos->unicode)
1657 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1658 ofn->lpstrFile[0] = '\0';
1662 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1663 ofn->lpstrFile[0] = '\0';
1666 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1668 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1669 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1670 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1672 LPWSTR lpstrTemp = lpstrFileList;
1674 for ( nCount = 0; nCount < nFileCount; nCount++ )
1678 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1681 WCHAR lpstrNotFound[100];
1682 WCHAR lpstrMsg[100];
1684 static const WCHAR nl[] = {'\n',0};
1686 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1687 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1689 strcpyW(tmp, lpstrTemp);
1691 strcatW(tmp, lpstrNotFound);
1693 strcatW(tmp, lpstrMsg);
1695 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1699 /* move to the next file in the list of files */
1700 lpstrTemp += strlenW(lpstrTemp) + 1;
1701 COMDLG32_SHFree(pidl);
1705 nSizePath = strlenW(lpstrPathSpec) + 1;
1706 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1708 /* For "oldstyle" dialog the components have to
1709 be separated by blanks (not '\0'!) and short
1710 filenames have to be used! */
1711 FIXME("Components have to be separated by blanks\n");
1713 if(fodInfos->unicode)
1715 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1716 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1717 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1721 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1723 if (ofn->lpstrFile != NULL)
1725 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1726 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1727 if (ofn->nMaxFile > nSizePath)
1729 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1730 ofn->lpstrFile + nSizePath,
1731 ofn->nMaxFile - nSizePath, NULL, NULL);
1736 fodInfos->ofnInfos->nFileOffset = nSizePath;
1737 fodInfos->ofnInfos->nFileExtension = 0;
1739 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1742 /* clean and exit */
1743 FILEDLG95_Clean(hwnd);
1744 return EndDialog(hwnd,TRUE);
1747 /***********************************************************************
1750 * Ok button WM_COMMAND message handler
1752 * If the function succeeds, the return value is nonzero.
1754 #define ONOPEN_BROWSE 1
1755 #define ONOPEN_OPEN 2
1756 #define ONOPEN_SEARCH 3
1757 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1759 WCHAR strMsgTitle[MAX_PATH];
1760 WCHAR strMsgText [MAX_PATH];
1762 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1764 strMsgTitle[0] = '\0';
1765 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1766 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1769 BOOL FILEDLG95_OnOpen(HWND hwnd)
1771 LPWSTR lpstrFileList;
1772 UINT nFileCount = 0;
1775 WCHAR lpstrPathAndFile[MAX_PATH];
1776 WCHAR lpstrTemp[MAX_PATH];
1777 LPSHELLFOLDER lpsf = NULL;
1779 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1781 TRACE("hwnd=%p\n", hwnd);
1783 /* get the files from the edit control */
1784 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1786 /* try if the user selected a folder in the shellview */
1789 BrowseSelectedFolder(hwnd);
1795 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1799 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1802 Step 1: Build a complete path name from the current folder and
1803 the filename or path in the edit box.
1805 - the path in the edit box is a root path
1806 (with or without drive letter)
1807 - the edit box contains ".." (or a path with ".." in it)
1810 /* Get the current directory name */
1811 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1814 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1816 PathAddBackslashW(lpstrPathAndFile);
1818 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1820 /* if the user specifyed a fully qualified path use it */
1821 if(PathIsRelativeW(lpstrFileList))
1823 strcatW(lpstrPathAndFile, lpstrFileList);
1827 /* does the path have a drive letter? */
1828 if (PathGetDriveNumberW(lpstrFileList) == -1)
1829 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1831 strcpyW(lpstrPathAndFile, lpstrFileList);
1834 /* resolve "." and ".." */
1835 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1836 strcpyW(lpstrPathAndFile, lpstrTemp);
1837 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1839 MemFree(lpstrFileList);
1842 Step 2: here we have a cleaned up path
1844 We have to parse the path step by step to see if we have to browse
1845 to a folder if the path points to a directory or the last
1846 valid element is a directory.
1849 lpstrPathAndFile: cleaned up path
1853 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1854 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1855 nOpenAction = ONOPEN_OPEN;
1857 nOpenAction = ONOPEN_BROWSE;
1859 /* don't apply any checks with OFN_NOVALIDATE */
1861 LPWSTR lpszTemp, lpszTemp1;
1862 LPITEMIDLIST pidl = NULL;
1863 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1865 /* check for invalid chars */
1866 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1868 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1873 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1875 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1878 LPSHELLFOLDER lpsfChild;
1879 WCHAR lpwstrTemp[MAX_PATH];
1880 DWORD dwEaten, dwAttributes;
1883 strcpyW(lpwstrTemp, lpszTemp);
1884 p = PathFindNextComponentW(lpwstrTemp);
1886 if (!p) break; /* end of path */
1889 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1891 /* There are no wildcards when OFN_NOVALIDATE is set */
1892 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1894 static const WCHAR wszWild[] = { '*', '?', 0 };
1895 /* if the last element is a wildcard do a search */
1896 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1898 nOpenAction = ONOPEN_SEARCH;
1902 lpszTemp1 = lpszTemp;
1904 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1906 /* append a backslash to drive letters */
1907 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1908 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1909 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1911 PathAddBackslashW(lpwstrTemp);
1914 dwAttributes = SFGAO_FOLDER;
1915 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1917 /* the path component is valid, we have a pidl of the next path component */
1918 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1919 if(dwAttributes & SFGAO_FOLDER)
1921 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1923 ERR("bind to failed\n"); /* should not fail */
1926 IShellFolder_Release(lpsf);
1934 /* end dialog, return value */
1935 nOpenAction = ONOPEN_OPEN;
1938 COMDLG32_SHFree(pidl);
1941 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1943 if(*lpszTemp) /* points to trailing null for last path element */
1945 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1947 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1953 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1954 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1956 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1960 /* change to the current folder */
1961 nOpenAction = ONOPEN_OPEN;
1966 nOpenAction = ONOPEN_OPEN;
1970 if(pidl) COMDLG32_SHFree(pidl);
1974 Step 3: here we have a cleaned up and validated path
1977 lpsf: ShellFolder bound to the rightmost valid path component
1978 lpstrPathAndFile: cleaned up path
1979 nOpenAction: action to do
1981 TRACE("end validate sf=%p\n", lpsf);
1985 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1986 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1989 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1992 /* replace the current filter */
1993 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1994 len = strlenW(lpszTemp)+1;
1995 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1996 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1998 /* set the filter cb to the extension when possible */
1999 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2000 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2003 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2004 TRACE("ONOPEN_BROWSE\n");
2006 IPersistFolder2 * ppf2;
2007 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2009 LPITEMIDLIST pidlCurrent;
2010 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2011 IPersistFolder2_Release(ppf2);
2012 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2014 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
2016 else if( nOpenAction == ONOPEN_SEARCH )
2018 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2020 COMDLG32_SHFree(pidlCurrent);
2025 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2026 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2030 /* update READONLY check box flag */
2031 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2032 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2034 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2036 /* Attach the file extension with file name*/
2037 ext = PathFindExtensionW(lpstrPathAndFile);
2040 /* if no extension is specified with file name, then */
2041 /* attach the extension from file filter or default one */
2043 WCHAR *filterExt = NULL;
2044 LPWSTR lpstrFilter = NULL;
2045 static const WCHAR szwDot[] = {'.',0};
2046 int PathLength = strlenW(lpstrPathAndFile);
2049 strcatW(lpstrPathAndFile, szwDot);
2051 /*Get the file extension from file type filter*/
2052 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2053 fodInfos->ofnInfos->nFilterIndex-1);
2055 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2056 filterExt = PathFindExtensionW(lpstrFilter);
2058 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2059 strcatW(lpstrPathAndFile, filterExt + 1);
2060 else if ( fodInfos->defext ) /* attach the default file extension*/
2061 strcatW(lpstrPathAndFile, fodInfos->defext);
2063 /* In Open dialog: if file does not exist try without extension */
2064 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2065 lpstrPathAndFile[PathLength] = '\0';
2068 if (fodInfos->defext) /* add default extension */
2070 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2073 if (!lstrcmpiW(fodInfos->defext, ext))
2074 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2076 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2079 /* In Save dialog: check if the file already exists */
2080 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2081 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2082 && PathFileExistsW(lpstrPathAndFile))
2084 WCHAR lpstrOverwrite[100];
2087 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2088 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2089 MB_YESNO | MB_ICONEXCLAMATION);
2097 /* Check that the size of the file does not exceed buffer size.
2098 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2099 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2100 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2104 /* fill destination buffer */
2105 if (fodInfos->ofnInfos->lpstrFile)
2107 if(fodInfos->unicode)
2109 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2111 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2112 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2113 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2117 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2119 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2120 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2121 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2122 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2126 /* set filename offset */
2127 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2128 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2130 /* set extension offset */
2131 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2132 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2134 /* set the lpstrFileTitle */
2135 if(fodInfos->ofnInfos->lpstrFileTitle)
2137 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2138 if(fodInfos->unicode)
2140 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2141 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2145 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2146 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2147 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2151 /* copy currently selected filter to lpstrCustomFilter */
2152 if (fodInfos->ofnInfos->lpstrCustomFilter)
2154 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2155 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2156 NULL, 0, NULL, NULL);
2157 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2159 LPSTR s = ofn->lpstrCustomFilter;
2160 s += strlen(ofn->lpstrCustomFilter)+1;
2161 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2162 s, len, NULL, NULL);
2167 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2171 FILEDLG95_Clean(hwnd);
2172 ret = EndDialog(hwnd, TRUE);
2178 size = strlenW(lpstrPathAndFile) + 1;
2179 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2181 /* return needed size in first two bytes of lpstrFile */
2182 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2183 FILEDLG95_Clean(hwnd);
2184 ret = EndDialog(hwnd, FALSE);
2185 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2193 if(lpsf) IShellFolder_Release(lpsf);
2197 /***********************************************************************
2198 * FILEDLG95_SHELL_Init
2200 * Initialisation of the shell objects
2202 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2204 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2209 * Initialisation of the FileOpenDialogInfos structure
2215 fodInfos->ShellInfos.hwndOwner = hwnd;
2217 /* Disable multi-select if flag not set */
2218 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2220 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2222 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2223 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2225 /* Construct the IShellBrowser interface */
2226 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2231 /***********************************************************************
2232 * FILEDLG95_SHELL_ExecuteCommand
2234 * Change the folder option and refresh the view
2235 * If the function succeeds, the return value is nonzero.
2237 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2239 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2242 TRACE("(%p,%p)\n", hwnd, lpVerb);
2244 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2249 CMINVOKECOMMANDINFO ci;
2250 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2251 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2255 IContextMenu_InvokeCommand(pcm, &ci);
2256 IContextMenu_Release(pcm);
2262 /***********************************************************************
2263 * FILEDLG95_SHELL_UpFolder
2265 * Browse to the specified object
2266 * If the function succeeds, the return value is nonzero.
2268 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2270 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2274 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2278 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2284 /***********************************************************************
2285 * FILEDLG95_SHELL_BrowseToDesktop
2287 * Browse to the Desktop
2288 * If the function succeeds, the return value is nonzero.
2290 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2292 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2298 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2299 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2300 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2301 COMDLG32_SHFree(pidl);
2302 return SUCCEEDED(hres);
2304 /***********************************************************************
2305 * FILEDLG95_SHELL_Clean
2307 * Cleans the memory used by shell objects
2309 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2311 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2315 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2317 /* clean Shell interfaces */
2318 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2319 IShellView_Release(fodInfos->Shell.FOIShellView);
2320 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2321 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2322 if (fodInfos->Shell.FOIDataObject)
2323 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2326 /***********************************************************************
2327 * FILEDLG95_FILETYPE_Init
2329 * Initialisation of the file type combo box
2331 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2333 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2334 int nFilters = 0; /* number of filters */
2339 if(fodInfos->customfilter)
2341 /* customfilter has one entry... title\0ext\0
2342 * Set first entry of combo box item with customfilter
2345 LPCWSTR lpstrPos = fodInfos->customfilter;
2348 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2350 /* Copy the extensions */
2351 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2352 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2353 strcpyW(lpstrExt,lpstrPos);
2355 /* Add the item at the end of the combo */
2356 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2357 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2360 if(fodInfos->filter)
2362 LPCWSTR lpstrPos = fodInfos->filter;
2366 /* filter is a list... title\0ext\0......\0\0
2367 * Set the combo item text to the title and the item data
2370 LPCWSTR lpstrDisplay;
2374 if(! *lpstrPos) break; /* end */
2375 lpstrDisplay = lpstrPos;
2376 lpstrPos += strlenW(lpstrPos) + 1;
2378 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2382 /* Copy the extensions */
2383 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2384 strcpyW(lpstrExt,lpstrPos);
2385 lpstrPos += strlenW(lpstrPos) + 1;
2387 /* Add the item at the end of the combo */
2388 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2390 /* malformed filters are added anyway... */
2391 if (!*lpstrExt) break;
2396 * Set the current filter to the one specified
2397 * in the initialisation structure
2399 if (fodInfos->filter || fodInfos->customfilter)
2403 /* Check to make sure our index isn't out of bounds. */
2404 if ( fodInfos->ofnInfos->nFilterIndex >
2405 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2406 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2408 /* set default filter index */
2409 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2410 fodInfos->ofnInfos->nFilterIndex = 1;
2412 /* calculate index of Combo Box item */
2413 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2414 if (fodInfos->customfilter == NULL)
2417 /* Set the current index selection. */
2418 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2420 /* Get the corresponding text string from the combo box. */
2421 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2424 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2430 CharLowerW(lpstrFilter); /* lowercase */
2431 len = strlenW(lpstrFilter)+1;
2432 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2433 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2436 fodInfos->ofnInfos->nFilterIndex = 0;
2440 /***********************************************************************
2441 * FILEDLG95_FILETYPE_OnCommand
2443 * WM_COMMAND of the file type combo box
2444 * If the function succeeds, the return value is nonzero.
2446 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2448 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2456 /* Get the current item of the filetype combo box */
2457 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2459 /* set the current filter index */
2460 fodInfos->ofnInfos->nFilterIndex = iItem +
2461 (fodInfos->customfilter == NULL ? 1 : 0);
2463 /* Set the current filter with the current selection */
2464 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2466 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2468 if((INT_PTR)lpstrFilter != CB_ERR)
2471 CharLowerW(lpstrFilter); /* lowercase */
2472 len = strlenW(lpstrFilter)+1;
2473 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2474 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2475 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2478 /* Refresh the actual view to display the included items*/
2479 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2484 /***********************************************************************
2485 * FILEDLG95_FILETYPE_SearchExt
2487 * searches for an extension in the filetype box
2489 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2491 int i, iCount = CBGetCount(hwnd);
2493 TRACE("%s\n", debugstr_w(lpstrExt));
2495 if(iCount != CB_ERR)
2497 for(i=0;i<iCount;i++)
2499 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2506 /***********************************************************************
2507 * FILEDLG95_FILETYPE_Clean
2509 * Clean the memory used by the filetype combo box
2511 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2513 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2515 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2519 /* Delete each string of the combo and their associated data */
2520 if(iCount != CB_ERR)
2522 for(iPos = iCount-1;iPos>=0;iPos--)
2524 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2525 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2528 /* Current filter */
2529 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2533 /***********************************************************************
2534 * FILEDLG95_LOOKIN_Init
2536 * Initialisation of the look in combo box
2539 /* Small helper function, to determine if the unixfs shell extension is rooted
2540 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2542 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2544 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2545 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2546 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2547 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2548 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2549 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2550 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2552 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2559 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2561 IShellFolder *psfRoot, *psfDrives;
2562 IEnumIDList *lpeRoot, *lpeDrives;
2563 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2565 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2569 liInfos->iMaxIndentation = 0;
2571 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2573 /* set item height for both text field and listbox */
2574 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2575 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2577 /* Turn on the extended UI for the combo box like Windows does */
2578 CBSetExtendedUI(hwndCombo, TRUE);
2580 /* Initialise data of Desktop folder */
2581 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2582 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2583 COMDLG32_SHFree(pidlTmp);
2585 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2587 SHGetDesktopFolder(&psfRoot);
2591 /* enumerate the contents of the desktop */
2592 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2594 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2596 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2598 /* If the unixfs extension is rooted, we don't expand the drives by default */
2599 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2601 /* special handling for CSIDL_DRIVES */
2602 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2604 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2606 /* enumerate the drives */
2607 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2609 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2611 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2612 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2613 COMDLG32_SHFree(pidlAbsTmp);
2614 COMDLG32_SHFree(pidlTmp1);
2616 IEnumIDList_Release(lpeDrives);
2618 IShellFolder_Release(psfDrives);
2623 COMDLG32_SHFree(pidlTmp);
2625 IEnumIDList_Release(lpeRoot);
2627 IShellFolder_Release(psfRoot);
2630 COMDLG32_SHFree(pidlDrives);
2633 /***********************************************************************
2634 * FILEDLG95_LOOKIN_DrawItem
2636 * WM_DRAWITEM message handler
2638 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2640 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2641 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2642 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2646 HIMAGELIST ilItemImage;
2649 LPSFOLDER tmpFolder;
2652 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2656 if(pDIStruct->itemID == -1)
2659 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2660 pDIStruct->itemID)))
2664 if(pDIStruct->itemID == liInfos->uSelectedItem)
2666 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2669 sizeof (SHFILEINFOA),
2670 SHGFI_PIDL | SHGFI_SMALLICON |
2671 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2672 SHGFI_DISPLAYNAME );
2676 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2679 sizeof (SHFILEINFOA),
2680 SHGFI_PIDL | SHGFI_SMALLICON |
2681 SHGFI_SYSICONINDEX |
2685 /* Is this item selected ? */
2686 if(pDIStruct->itemState & ODS_SELECTED)
2688 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2689 SetBkColor(pDIStruct->hDC,crHighLight);
2690 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2694 SetTextColor(pDIStruct->hDC,crText);
2695 SetBkColor(pDIStruct->hDC,crWin);
2696 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2699 /* Do not indent item if drawing in the edit of the combo */
2700 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2703 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2706 sizeof (SHFILEINFOA),
2707 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2708 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2713 iIndentation = tmpFolder->m_iIndent;
2715 /* Draw text and icon */
2717 /* Initialise the icon display area */
2718 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2719 rectIcon.top = pDIStruct->rcItem.top;
2720 rectIcon.right = rectIcon.left + ICONWIDTH;
2721 rectIcon.bottom = pDIStruct->rcItem.bottom;
2723 /* Initialise the text display area */
2724 GetTextMetricsA(pDIStruct->hDC, &tm);
2725 rectText.left = rectIcon.right;
2727 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2728 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2730 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2732 /* Draw the icon from the image list */
2733 ImageList_Draw(ilItemImage,
2740 /* Draw the associated text */
2741 if(sfi.szDisplayName)
2742 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2748 /***********************************************************************
2749 * FILEDLG95_LOOKIN_OnCommand
2751 * LookIn combo box WM_COMMAND message handler
2752 * If the function succeeds, the return value is nonzero.
2754 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2756 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2758 TRACE("%p\n", fodInfos);
2764 LPSFOLDER tmpFolder;
2767 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2769 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2774 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2775 tmpFolder->pidlItem,
2778 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2788 /***********************************************************************
2789 * FILEDLG95_LOOKIN_AddItem
2791 * Adds an absolute pidl item to the lookin combo box
2792 * returns the index of the inserted item
2794 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2796 LPITEMIDLIST pidlNext;
2799 LookInInfos *liInfos;
2801 TRACE("%08x\n", iInsertId);
2806 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2809 tmpFolder = MemAlloc(sizeof(SFOLDER));
2810 tmpFolder->m_iIndent = 0;
2812 /* Calculate the indentation of the item in the lookin*/
2814 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2816 tmpFolder->m_iIndent++;
2819 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2821 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2822 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2824 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2825 SHGetFileInfoA((LPSTR)pidl,
2829 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2830 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2832 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2834 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2838 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2840 /* Add the item at the end of the list */
2843 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2845 /* Insert the item at the iInsertId position*/
2848 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2851 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2855 COMDLG32_SHFree( tmpFolder->pidlItem );
2856 MemFree( tmpFolder );
2861 /***********************************************************************
2862 * FILEDLG95_LOOKIN_InsertItemAfterParent
2864 * Insert an item below its parent
2866 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2869 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2874 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2878 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2881 /* Free pidlParent memory */
2882 COMDLG32_SHFree((LPVOID)pidlParent);
2884 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2887 /***********************************************************************
2888 * FILEDLG95_LOOKIN_SelectItem
2890 * Adds an absolute pidl item to the lookin combo box
2891 * returns the index of the inserted item
2893 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2896 LookInInfos *liInfos;
2900 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2902 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2906 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2907 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2912 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2913 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2917 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2919 if(iRemovedItem < iItemPos)
2924 CBSetCurSel(hwnd,iItemPos);
2925 liInfos->uSelectedItem = iItemPos;
2931 /***********************************************************************
2932 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2934 * Remove the item with an expansion level over iExpansionLevel
2936 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2940 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2944 if(liInfos->iMaxIndentation <= 2)
2947 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2949 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2950 COMDLG32_SHFree(tmpFolder->pidlItem);
2952 CBDeleteString(hwnd,iItemPos);
2953 liInfos->iMaxIndentation--;
2961 /***********************************************************************
2962 * FILEDLG95_LOOKIN_SearchItem
2964 * Search for pidl in the lookin combo box
2965 * returns the index of the found item
2967 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2970 int iCount = CBGetCount(hwnd);
2972 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2974 if (iCount != CB_ERR)
2978 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2980 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2982 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2990 /***********************************************************************
2991 * FILEDLG95_LOOKIN_Clean
2993 * Clean the memory used by the lookin combo box
2995 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2997 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2999 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3003 /* Delete each string of the combo and their associated data */
3004 if (iCount != CB_ERR)
3006 for(iPos = iCount-1;iPos>=0;iPos--)
3008 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3009 COMDLG32_SHFree(tmpFolder->pidlItem);
3011 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3015 /* LookInInfos structure */
3016 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3019 /***********************************************************************
3020 * FILEDLG95_FILENAME_FillFromSelection
3022 * fills the edit box from the cached DataObject
3024 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3026 FileOpenDlgInfos *fodInfos;
3028 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3029 char lpstrTemp[MAX_PATH];
3030 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
3033 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3035 /* Count how many files we have */
3036 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3038 /* calculate the string length, count files */
3039 if (nFileSelected >= 1)
3041 nLength += 3; /* first and last quotes, trailing \0 */
3042 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3044 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3048 /* get the total length of the selected file names */
3049 lpstrTemp[0] = '\0';
3050 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3052 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3054 nLength += strlen( lpstrTemp ) + 3;
3057 COMDLG32_SHFree( pidl );
3062 /* allocate the buffer */
3063 if (nFiles <= 1) nLength = MAX_PATH;
3064 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
3065 lpstrAllFile[0] = '\0';
3067 /* Generate the string for the edit control */
3070 lpstrCurrFile = lpstrAllFile;
3071 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3073 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3077 /* get the file name */
3078 lpstrTemp[0] = '\0';
3079 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3081 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3085 *lpstrCurrFile++ = '\"';
3086 strcpy( lpstrCurrFile, lpstrTemp );
3087 lpstrCurrFile += strlen( lpstrTemp );
3088 strcpy( lpstrCurrFile, "\" " );
3093 strcpy( lpstrAllFile, lpstrTemp );
3096 COMDLG32_SHFree( (LPVOID) pidl );
3099 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3101 /* Select the file name like Windows does */
3102 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3104 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3108 /* copied from shell32 to avoid linking to it
3109 * FIXME: why? shell32 is already linked
3111 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3116 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3117 COMDLG32_SHFree(src->u.pOleStr);
3121 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3125 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3129 FIXME("unknown type!\n");
3132 *(LPSTR)dest = '\0';
3139 /***********************************************************************
3140 * FILEDLG95_FILENAME_GetFileNames
3142 * Copies the filenames to a delimited string list.
3143 * The delimiter is specified by the parameter 'separator',
3144 * usually either a space or a nul
3146 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3148 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3149 UINT nStrCharCount = 0; /* index in src buffer */
3150 UINT nFileIndex = 0; /* index in dest buffer */
3151 UINT nFileCount = 0; /* number of files */
3152 UINT nStrLen = 0; /* length of string in edit control */
3153 LPWSTR lpstrEdit; /* buffer for string from edit control */
3157 /* get the filenames from the edit control */
3158 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3159 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3160 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3162 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3164 /* we might get single filename without any '"',
3165 * so we need nStrLen + terminating \0 + end-of-list \0 */
3166 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3169 /* build delimited file list from filenames */
3170 while ( nStrCharCount <= nStrLen )
3172 if ( lpstrEdit[nStrCharCount]=='"' )
3175 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3177 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3181 (*lpstrFileList)[nFileIndex++] = separator;
3188 /* single, unquoted string */
3189 if ((nStrLen > 0) && (*sizeUsed == 0) )
3191 strcpyW(*lpstrFileList, lpstrEdit);
3192 nFileIndex = strlenW(lpstrEdit) + 1;
3193 (*sizeUsed) = nFileIndex;
3198 (*lpstrFileList)[nFileIndex] = '\0';
3205 #define SETDefFormatEtc(fe,cf,med) \
3207 (fe).cfFormat = cf;\
3208 (fe).dwAspect = DVASPECT_CONTENT; \
3215 * DATAOBJECT Helper functions
3218 /***********************************************************************
3219 * COMCTL32_ReleaseStgMedium
3221 * like ReleaseStgMedium from ole32
3223 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3225 if(medium.pUnkForRelease)
3227 IUnknown_Release(medium.pUnkForRelease);
3231 GlobalUnlock(medium.u.hGlobal);
3232 GlobalFree(medium.u.hGlobal);
3236 /***********************************************************************
3237 * GetPidlFromDataObject
3239 * Return pidl(s) by number from the cached DataObject
3241 * nPidlIndex=0 gets the fully qualified root path
3243 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3247 FORMATETC formatetc;
3248 LPITEMIDLIST pidl = NULL;
3250 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3255 /* Set the FORMATETC structure*/
3256 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3258 /* Get the pidls from IDataObject */
3259 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3261 LPIDA cida = GlobalLock(medium.u.hGlobal);
3262 if(nPidlIndex <= cida->cidl)
3264 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3266 COMCTL32_ReleaseStgMedium(medium);
3271 /***********************************************************************
3274 * Return the number of selected items in the DataObject.
3277 UINT GetNumSelected( IDataObject *doSelected )
3281 FORMATETC formatetc;
3283 TRACE("sv=%p\n", doSelected);
3285 if (!doSelected) return 0;
3287 /* Set the FORMATETC structure*/
3288 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3290 /* Get the pidls from IDataObject */
3291 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3293 LPIDA cida = GlobalLock(medium.u.hGlobal);
3294 retVal = cida->cidl;
3295 COMCTL32_ReleaseStgMedium(medium);
3305 /***********************************************************************
3308 * Get the pidl's display name (relative to folder) and
3309 * put it in lpstrFileName.
3311 * Return NOERROR on success,
3315 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3320 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3324 SHGetDesktopFolder(&lpsf);
3325 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3326 IShellFolder_Release(lpsf);
3330 /* Get the display name of the pidl relative to the folder */
3331 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3333 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3338 /***********************************************************************
3339 * GetShellFolderFromPidl
3341 * pidlRel is the item pidl relative
3342 * Return the IShellFolder of the absolute pidl
3344 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3346 IShellFolder *psf = NULL,*psfParent;
3348 TRACE("%p\n", pidlAbs);
3350 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3353 if(pidlAbs && pidlAbs->mkid.cb)
3355 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3357 IShellFolder_Release(psfParent);
3361 /* return the desktop */
3367 /***********************************************************************
3370 * Return the LPITEMIDLIST to the parent of the pidl in the list
3372 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3374 LPITEMIDLIST pidlParent;
3376 TRACE("%p\n", pidl);
3378 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3379 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3384 /***********************************************************************
3387 * returns the pidl of the file name relative to folder
3388 * NULL if an error occurred
3390 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3392 LPITEMIDLIST pidl = NULL;
3395 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3397 if(!lpcstrFileName) return NULL;
3398 if(!*lpcstrFileName) return NULL;
3402 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3403 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3404 IShellFolder_Release(lpsf);
3409 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3416 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3418 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3421 TRACE("%p, %p\n", psf, pidl);
3423 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3425 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3426 /* see documentation shell 4.1*/
3427 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3430 /***********************************************************************
3431 * BrowseSelectedFolder
3433 static BOOL BrowseSelectedFolder(HWND hwnd)
3435 BOOL bBrowseSelFolder = FALSE;
3436 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3440 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3442 LPITEMIDLIST pidlSelection;
3444 /* get the file selected */
3445 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3446 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3448 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3449 pidlSelection, SBSP_RELATIVE ) ) )
3451 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3452 ' ','n','o','t',' ','e','x','i','s','t',0};
3453 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3455 bBrowseSelFolder = TRUE;
3456 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3458 COMDLG32_SHFree( pidlSelection );
3461 return bBrowseSelFolder;
3465 * Memory allocation methods */
3466 static void *MemAlloc(UINT size)
3468 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3471 static void MemFree(void *mem)
3473 HeapFree(GetProcessHeap(),0,mem);
3477 * Old-style (win3.1) dialogs */
3479 /***********************************************************************
3480 * FD32_GetTemplate [internal]
3482 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3483 * by a 32 bits application
3486 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3488 LPOPENFILENAMEW ofnW = lfs->ofnW;
3489 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3492 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3494 if (!(lfs->template = LockResource( ofnW->hInstance )))
3496 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3500 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3504 hResInfo = FindResourceA(priv->ofnA->hInstance,
3505 priv->ofnA->lpTemplateName,
3508 hResInfo = FindResourceW(ofnW->hInstance,
3509 ofnW->lpTemplateName,
3513 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3516 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3518 !(lfs->template = LockResource(hDlgTmpl)))
3520 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3523 } else { /* get it from internal Wine resource */
3525 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3526 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3528 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3531 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3532 !(lfs->template = LockResource( hDlgTmpl )))
3534 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3542 /************************************************************************
3543 * FD32_Init [internal]
3544 * called from the common 16/32 code to initialize 32 bit data
3546 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3548 BOOL IsUnicode = (BOOL) data;
3551 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3552 lfs->private1632 = priv;
3553 if (NULL == lfs->private1632) return FALSE;
3556 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3557 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3558 if (lfs->ofnW->lpfnHook)
3563 priv->ofnA = (LPOPENFILENAMEA) lParam;
3564 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3565 if (priv->ofnA->lpfnHook)
3567 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3568 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3571 if (! FD32_GetTemplate(lfs)) return FALSE;
3576 /***********************************************************************
3577 * FD32_CallWindowProc [internal]
3579 * called from the common 16/32 code to call the appropriate hook
3581 static BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3585 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3589 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3590 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3591 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3592 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3593 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3597 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3598 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3599 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3600 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3601 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3605 /***********************************************************************
3606 * FD32_UpdateResult [internal]
3607 * update the real client structures if any
3609 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3611 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3612 LPOPENFILENAMEW ofnW = lfs->ofnW;
3616 if (ofnW->nMaxFile &&
3617 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3618 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3619 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3620 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3621 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3625 /***********************************************************************
3626 * FD32_UpdateFileTitle [internal]
3627 * update the real client structures if any
3629 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3631 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3632 LPOPENFILENAMEW ofnW = lfs->ofnW;
3636 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3637 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3638 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3643 /***********************************************************************
3644 * FD32_SendLbGetCurSel [internal]
3645 * retrieve selected listbox item
3647 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3649 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3653 /************************************************************************
3654 * FD32_Destroy [internal]
3655 * called from the common 16/32 code to cleanup 32 bit data
3657 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3659 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3661 /* if ofnW has been allocated, have to free everything in it */
3662 if (NULL != priv && NULL != priv->ofnA)
3664 FD31_FreeOfnW(lfs->ofnW);
3665 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3669 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3671 callbacks->Init = FD32_Init;
3672 callbacks->CWP = FD32_CallWindowProc;
3673 callbacks->UpdateResult = FD32_UpdateResult;
3674 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3675 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3676 callbacks->Destroy = FD32_Destroy;
3679 /***********************************************************************
3680 * FD32_WMMeasureItem [internal]
3682 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3684 LPMEASUREITEMSTRUCT lpmeasure;
3686 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3687 lpmeasure->itemHeight = FD31_GetFldrHeight();
3692 /***********************************************************************
3693 * FileOpenDlgProc [internal]
3694 * Used for open and save, in fact.
3696 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3697 WPARAM wParam, LPARAM lParam)
3699 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3701 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3702 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3705 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3707 return lRet; /* else continue message processing */
3712 return FD31_WMInitDialog(hWnd, wParam, lParam);
3714 case WM_MEASUREITEM:
3715 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3718 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3721 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3724 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3725 switch (HIWORD(lParam))
3728 SetTextColor((HDC16)wParam, 0x00000000);
3730 case CTLCOLOR_STATIC:
3731 SetTextColor((HDC16)wParam, 0x00000000);
3741 /***********************************************************************
3742 * GetFileName31A [internal]
3744 * Creates a win31 style dialog box for the user to select a file to open/save.
3746 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3747 UINT dlgType /* type dialogue : open/save */
3753 FD31_CALLBACKS callbacks;
3755 if (!lpofn || !FD31_Init()) return FALSE;
3757 TRACE("ofn flags %08lx\n", lpofn->Flags);
3758 FD32_SetupCallbacks(&callbacks);
3759 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3762 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3763 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3764 FD32_FileOpenDlgProc, (LPARAM)lfs);
3765 FD31_DestroyPrivate(lfs);
3768 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3772 /***********************************************************************
3773 * GetFileName31W [internal]
3775 * Creates a win31 style dialog box for the user to select a file to open/save
3777 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3778 UINT dlgType /* type dialogue : open/save */
3784 FD31_CALLBACKS callbacks;
3786 if (!lpofn || !FD31_Init()) return FALSE;
3788 FD32_SetupCallbacks(&callbacks);
3789 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3792 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3793 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3794 FD32_FileOpenDlgProc, (LPARAM)lfs);
3795 FD31_DestroyPrivate(lfs);
3798 TRACE("file %s, file offset %d, ext offset %d\n",
3799 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3803 /* ------------------ APIs ---------------------- */
3805 /***********************************************************************
3806 * GetOpenFileNameA (COMDLG32.@)
3808 * Creates a dialog box for the user to select a file to open.
3811 * TRUE on success: user enters a valid file
3812 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3815 BOOL WINAPI GetOpenFileNameA(
3816 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3818 BOOL win16look = FALSE;
3820 TRACE("flags %08lx\n", ofn->Flags);
3822 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3823 if (ofn->Flags & OFN_FILEMUSTEXIST)
3824 ofn->Flags |= OFN_PATHMUSTEXIST;
3826 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3827 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3830 return GetFileName31A(ofn, OPEN_DIALOG);
3832 return GetFileDialog95A(ofn, OPEN_DIALOG);
3835 /***********************************************************************
3836 * GetOpenFileNameW (COMDLG32.@)
3838 * Creates a dialog box for the user to select a file to open.
3841 * TRUE on success: user enters a valid file
3842 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3845 BOOL WINAPI GetOpenFileNameW(
3846 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3848 BOOL win16look = FALSE;
3850 TRACE("flags %08lx\n", ofn->Flags);
3852 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3853 if (ofn->Flags & OFN_FILEMUSTEXIST)
3854 ofn->Flags |= OFN_PATHMUSTEXIST;
3856 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3857 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3860 return GetFileName31W(ofn, OPEN_DIALOG);
3862 return GetFileDialog95W(ofn, OPEN_DIALOG);
3866 /***********************************************************************
3867 * GetSaveFileNameA (COMDLG32.@)
3869 * Creates a dialog box for the user to select a file to save.
3872 * TRUE on success: user enters a valid file
3873 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3876 BOOL WINAPI GetSaveFileNameA(
3877 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3879 BOOL win16look = FALSE;
3881 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3882 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3885 return GetFileName31A(ofn, SAVE_DIALOG);
3887 return GetFileDialog95A(ofn, SAVE_DIALOG);
3890 /***********************************************************************
3891 * GetSaveFileNameW (COMDLG32.@)
3893 * Creates a dialog box for the user to select a file to save.
3896 * TRUE on success: user enters a valid file
3897 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3900 BOOL WINAPI GetSaveFileNameW(
3901 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3903 BOOL win16look = FALSE;
3905 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3906 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3909 return GetFileName31W(ofn, SAVE_DIALOG);
3911 return GetFileDialog95W(ofn, SAVE_DIALOG);