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_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "wine/port.h"
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
71 #include "filedlg31.h"
75 #include "filedlgbrowser.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
108 typedef struct tagFD32_PRIVATE
110 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
111 } FD32_PRIVATE, *PFD32_PRIVATE;
114 /***********************************************************************
115 * Defines and global variables
118 /* Draw item constant */
120 #define XTEXTOFFSET 3
125 /* SearchItem methods */
126 #define SEARCH_PIDL 1
128 #define ITEM_NOTFOUND -1
130 /* Undefined windows message sent by CreateViewObject*/
131 #define WM_GETISHELLBROWSER WM_USER+7
134 * Those macros exist in windowsx.h. However, you can't really use them since
135 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 /* Combo box macros */
139 #define CBAddString(hwnd,str) \
140 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
142 #define CBInsertString(hwnd,str,pos) \
143 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
145 #define CBDeleteString(hwnd,pos) \
146 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
148 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
149 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
151 #define CBGetItemDataPtr(hwnd,iItemId) \
152 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
154 #define CBGetLBText(hwnd,iItemId,str) \
155 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
157 #define CBGetCurSel(hwnd) \
158 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
160 #define CBSetCurSel(hwnd,pos) \
161 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
163 #define CBGetCount(hwnd) \
164 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
165 #define CBShowDropDown(hwnd,show) \
166 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
167 #define CBSetItemHeight(hwnd,index,height) \
168 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
170 #define CBSetExtendedUI(hwnd,flag) \
171 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
173 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
174 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
175 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
177 /***********************************************************************
181 /* Internal functions used by the dialog */
182 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186 static BOOL FILEDLG95_OnOpen(HWND hwnd);
187 static LRESULT FILEDLG95_InitControls(HWND hwnd);
188 static void FILEDLG95_Clean(HWND hwnd);
190 /* Functions used by the shell navigation */
191 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
200 /* Functions used by the filetype combo box */
201 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
202 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
204 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
206 /* Functions used by the Look In combo box */
207 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
208 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
209 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
210 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
211 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
212 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
213 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
214 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
215 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
217 /* Miscellaneous tool functions */
218 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
221 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
222 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
223 static UINT GetNumSelected( IDataObject *doSelected );
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size);
227 static void MemFree(void *mem);
229 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
253 /* test for missing functionality */
254 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 FIXME("Flags 0x%08x not yet implemented\n",
257 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
260 /* Create the dialog from a template */
262 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
267 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268 !(template = LockResource( hDlgTmpl )))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
274 /* msdn: explorer style dialogs permit sizing by default.
275 * The OFN_ENABLESIZING flag is only needed when a hook or
276 * custom tmeplate is provided */
277 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
278 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
279 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
281 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
283 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
284 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
285 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
288 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
291 /* old style hook messages */
292 if (IsHooked(fodInfos))
294 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
295 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
296 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
297 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
300 /* Some shell namespace extensions depend on COM being initialized. */
301 hr = OleInitialize(NULL);
303 if (fodInfos->unicode)
304 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
306 fodInfos->ofnInfos->hwndOwner,
310 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
312 fodInfos->ofnInfos->hwndOwner,
318 /* Unable to create the dialog */
325 /***********************************************************************
328 * Call GetFileName95 with this structure and clean the memory.
330 * IN : The OPENFILENAMEA initialisation structure passed to
331 * GetOpenFileNameA win api function (see filedlg.c)
333 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
336 FileOpenDlgInfos fodInfos;
337 LPSTR lpstrSavDir = NULL;
339 LPWSTR defext = NULL;
340 LPWSTR filter = NULL;
341 LPWSTR customfilter = NULL;
343 /* Initialize CommDlgExtendedError() */
344 COMDLG32_SetCommDlgExtendedError(0);
346 /* Initialize FileOpenDlgInfos structure */
347 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
349 /* Pass in the original ofn */
350 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
352 /* save current directory */
353 if (ofn->Flags & OFN_NOCHANGEDIR)
355 lpstrSavDir = MemAlloc(MAX_PATH);
356 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
359 fodInfos.unicode = FALSE;
361 /* convert all the input strings to unicode */
362 if(ofn->lpstrInitialDir)
364 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
365 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
366 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
369 fodInfos.initdir = NULL;
373 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
374 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
377 fodInfos.filename = NULL;
381 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
382 defext = MemAlloc((len+1)*sizeof(WCHAR));
383 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
385 fodInfos.defext = defext;
389 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
390 title = MemAlloc((len+1)*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
393 fodInfos.title = title;
395 if (ofn->lpstrFilter)
400 /* filter is a list... title\0ext\0......\0\0 */
401 s = ofn->lpstrFilter;
402 while (*s) s = s+strlen(s)+1;
404 n = s - ofn->lpstrFilter;
405 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
406 filter = MemAlloc(len*sizeof(WCHAR));
407 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
409 fodInfos.filter = filter;
411 /* convert lpstrCustomFilter */
412 if (ofn->lpstrCustomFilter)
417 /* customfilter contains a pair of strings... title\0ext\0 */
418 s = ofn->lpstrCustomFilter;
419 if (*s) s = s+strlen(s)+1;
420 if (*s) s = s+strlen(s)+1;
421 n = s - ofn->lpstrCustomFilter;
422 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
423 customfilter = MemAlloc(len*sizeof(WCHAR));
424 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
426 fodInfos.customfilter = customfilter;
428 /* Initialize the dialog property */
429 fodInfos.DlgInfos.dwDlgProp = 0;
430 fodInfos.DlgInfos.hwndCustomDlg = NULL;
435 ret = GetFileName95(&fodInfos);
438 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
439 ret = GetFileName95(&fodInfos);
447 SetCurrentDirectoryA(lpstrSavDir);
448 MemFree(lpstrSavDir);
454 MemFree(customfilter);
455 MemFree(fodInfos.initdir);
456 MemFree(fodInfos.filename);
458 TRACE("selected file: %s\n",ofn->lpstrFile);
463 /***********************************************************************
466 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
467 * Call GetFileName95 with this structure and clean the memory.
470 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
473 FileOpenDlgInfos fodInfos;
474 LPWSTR lpstrSavDir = NULL;
476 /* Initialize CommDlgExtendedError() */
477 COMDLG32_SetCommDlgExtendedError(0);
479 /* Initialize FileOpenDlgInfos structure */
480 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
482 /* Pass in the original ofn */
483 fodInfos.ofnInfos = ofn;
485 fodInfos.title = ofn->lpstrTitle;
486 fodInfos.defext = ofn->lpstrDefExt;
487 fodInfos.filter = ofn->lpstrFilter;
488 fodInfos.customfilter = ofn->lpstrCustomFilter;
490 /* convert string arguments, save others */
493 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
494 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
497 fodInfos.filename = NULL;
499 if(ofn->lpstrInitialDir)
501 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
502 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
503 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
504 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
507 fodInfos.initdir = NULL;
509 /* save current directory */
510 if (ofn->Flags & OFN_NOCHANGEDIR)
512 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
513 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
516 fodInfos.unicode = TRUE;
521 ret = GetFileName95(&fodInfos);
524 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
525 ret = GetFileName95(&fodInfos);
533 SetCurrentDirectoryW(lpstrSavDir);
534 MemFree(lpstrSavDir);
537 /* restore saved IN arguments and convert OUT arguments back */
538 MemFree(fodInfos.filename);
539 MemFree(fodInfos.initdir);
543 /******************************************************************************
544 * COMDLG32_GetDisplayNameOf [internal]
546 * Helper function to get the display name for a pidl.
548 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
549 LPSHELLFOLDER psfDesktop;
552 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
555 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
556 IShellFolder_Release(psfDesktop);
560 IShellFolder_Release(psfDesktop);
561 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
564 /***********************************************************************
565 * ArrangeCtrlPositions [internal]
567 * NOTE: Make sure to add testcases for any changes made here.
569 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
571 HWND hwndChild, hwndStc32;
572 RECT rectParent, rectChild, rectStc32;
576 /* Take into account if open as read only checkbox and help button
581 RECT rectHelp, rectCancel;
582 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
583 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
584 /* subtract the height of the help button plus the space between
585 * the help button and the cancel button to the height of the dialog
587 help_fixup = rectHelp.bottom - rectCancel.bottom;
591 There are two possibilities to add components to the default file dialog box.
593 By default, all the new components are added below the standard dialog box (the else case).
595 However, if there is a static text component with the stc32 id, a special case happens.
596 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
597 in the window and the cx and cy indicate how to size the window.
598 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
599 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
603 GetClientRect(hwndParentDlg, &rectParent);
605 /* when arranging controls we have to use fixed parent size */
606 rectParent.bottom -= help_fixup;
608 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
611 GetWindowRect(hwndStc32, &rectStc32);
612 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
614 /* set the size of the stc32 control according to the size of
615 * client area of the parent dialog
617 SetWindowPos(hwndStc32, 0,
619 rectParent.right, rectParent.bottom,
620 SWP_NOMOVE | SWP_NOZORDER);
623 SetRectEmpty(&rectStc32);
625 /* this part moves controls of the child dialog */
626 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
629 if (hwndChild != hwndStc32)
631 GetWindowRect(hwndChild, &rectChild);
632 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
634 /* move only if stc32 exist */
635 if (hwndStc32 && rectChild.left > rectStc32.right)
637 /* move to the right of visible controls of the parent dialog */
638 rectChild.left += rectParent.right;
639 rectChild.left -= rectStc32.right;
641 /* move even if stc32 doesn't exist */
642 if (rectChild.top >= rectStc32.bottom)
644 /* move below visible controls of the parent dialog */
645 rectChild.top += rectParent.bottom;
646 rectChild.top -= rectStc32.bottom - rectStc32.top;
649 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
650 0, 0, SWP_NOSIZE | SWP_NOZORDER);
652 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
655 /* this part moves controls of the parent dialog */
656 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
659 if (hwndChild != hwndChildDlg)
661 GetWindowRect(hwndChild, &rectChild);
662 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
664 /* left,top of stc32 marks the position of controls
665 * from the parent dialog
667 rectChild.left += rectStc32.left;
668 rectChild.top += rectStc32.top;
670 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
671 0, 0, SWP_NOSIZE | SWP_NOZORDER);
673 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
676 /* calculate the size of the resulting dialog */
678 /* here we have to use original parent size */
679 GetClientRect(hwndParentDlg, &rectParent);
680 GetClientRect(hwndChildDlg, &rectChild);
681 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
682 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
687 if (rectParent.right > rectStc32.right - rectStc32.left)
688 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
690 chgx = rectChild.right - rectParent.right;
692 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
693 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
695 /* Unconditionally set new dialog
696 * height to that of the child
698 chgy = rectChild.bottom - rectParent.bottom;
703 chgy = rectChild.bottom - help_fixup;
705 /* set the size of the parent dialog */
706 GetWindowRect(hwndParentDlg, &rectParent);
707 SetWindowPos(hwndParentDlg, 0,
709 rectParent.right - rectParent.left + chgx,
710 rectParent.bottom - rectParent.top + chgy,
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 else if( IsHooked(fodInfos))
789 WORD menu,class,title;
791 GetClientRect(hwnd,&rectHwnd);
792 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
793 temp.tmplate.dwExtendedStyle = 0;
794 temp.tmplate.cdit = 0;
799 temp.menu = temp.class = temp.title = 0;
801 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
802 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
809 /***********************************************************************
810 * SendCustomDlgNotificationMessage
812 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
815 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
817 LRESULT hook_result = 0;
818 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
820 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
822 if(!fodInfos) return 0;
824 if(fodInfos->DlgInfos.hwndCustomDlg)
826 TRACE("CALL NOTIFY for %x\n", uCode);
827 if(fodInfos->unicode)
830 ofnNotify.hdr.hwndFrom=hwndParentDlg;
831 ofnNotify.hdr.idFrom=0;
832 ofnNotify.hdr.code = uCode;
833 ofnNotify.lpOFN = fodInfos->ofnInfos;
834 ofnNotify.pszFile = NULL;
835 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
840 ofnNotify.hdr.hwndFrom=hwndParentDlg;
841 ofnNotify.hdr.idFrom=0;
842 ofnNotify.hdr.code = uCode;
843 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
844 ofnNotify.pszFile = NULL;
845 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
847 TRACE("RET NOTIFY\n");
849 TRACE("Retval: 0x%08lx\n", hook_result);
853 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
857 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
859 TRACE("CDM_GETFILEPATH:\n");
861 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
864 /* get path and filenames */
865 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
866 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
867 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
870 p = buffer + strlenW(buffer);
872 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
874 if (fodInfos->unicode)
876 total = strlenW( buffer) + 1;
877 if (result) lstrcpynW( result, buffer, size );
878 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
882 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
883 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
884 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
886 HeapFree( GetProcessHeap(), 0, buffer );
890 /***********************************************************************
891 * FILEDLG95_HandleCustomDialogMessages
893 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
895 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
897 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
898 WCHAR lpstrPath[MAX_PATH];
901 if(!fodInfos) return FALSE;
905 case CDM_GETFILEPATH:
906 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
909 case CDM_GETFOLDERPATH:
910 TRACE("CDM_GETFOLDERPATH:\n");
911 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
914 if (fodInfos->unicode)
915 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
917 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
918 (LPSTR)lParam, (int)wParam, NULL, NULL);
920 retval = lstrlenW(lpstrPath) + 1;
923 case CDM_GETFOLDERIDLIST:
924 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
925 if (retval <= wParam)
926 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
930 TRACE("CDM_GETSPEC:\n");
931 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
934 if (fodInfos->unicode)
935 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
937 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
941 case CDM_SETCONTROLTEXT:
942 TRACE("CDM_SETCONTROLTEXT:\n");
945 if( fodInfos->unicode )
946 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
948 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
953 case CDM_HIDECONTROL:
954 /* MSDN states that it should fail for not OFN_EXPLORER case */
955 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
957 HWND control = GetDlgItem( hwnd, wParam );
958 if (control) ShowWindow( control, SW_HIDE );
965 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
966 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
969 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
973 /***********************************************************************
974 * FILEDLG95_OnWMGetMMI
976 * WM_GETMINMAXINFO message handler for resizable dialogs
978 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
980 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
981 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
982 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
984 mmiptr->ptMinTrackSize = fodInfos->initial_size;
989 /***********************************************************************
992 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
994 * FIXME: this could be made more elaborate. Now use a simple scheme
995 * where the file view is enlarged and the controls are either moved
996 * vertically or horizontally to get out of the way. Only the "grip"
997 * is moved in both directions to stay in the corner.
999 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1005 FileOpenDlgInfos *fodInfos;
1007 if( wParam != SIZE_RESTORED) return FALSE;
1008 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1009 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1010 /* get the new dialog rectangle */
1011 GetWindowRect( hwnd, &rc);
1012 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1013 rc.right -rc.left, rc.bottom -rc.top);
1014 /* not initialized yet */
1015 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1016 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1017 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1019 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1020 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1021 fodInfos->sizedlg.cx = rc.right - rc.left;
1022 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1023 /* change the size of the view window */
1024 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1025 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1026 hdwp = BeginDeferWindowPos( 10);
1027 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1028 rcview.right - rcview.left + chgx,
1029 rcview.bottom - rcview.top + chgy,
1030 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1031 /* change position and sizes of the controls */
1032 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1034 int ctrlid = GetDlgCtrlID( ctrl);
1035 GetWindowRect( ctrl, &rc);
1036 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1037 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1039 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1041 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1043 else if( rc.top > rcview.bottom)
1045 /* if it was below the shell view
1049 /* file name box and file types combo change also width */
1052 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1053 rc.right - rc.left + chgx, rc.bottom - rc.top,
1054 SWP_NOACTIVATE | SWP_NOZORDER);
1056 /* then these buttons must move out of the way */
1060 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1062 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1065 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1067 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1070 else if( rc.left > rcview.right)
1072 /* if it was to the right of the shell view
1074 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1076 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1083 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1085 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1086 rc.right - rc.left + chgx, rc.bottom - rc.top,
1087 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1089 case IDC_TOOLBARSTATIC:
1091 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1093 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1096 /* not resized in windows. Since wine uses this invisible control
1097 * to size the browser view it needs to be resized */
1098 case IDC_SHELLSTATIC:
1099 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1100 rc.right - rc.left + chgx,
1101 rc.bottom - rc.top + chgy,
1102 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1107 if(fodInfos->DlgInfos.hwndCustomDlg &&
1108 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1110 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1111 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1113 GetWindowRect( ctrl, &rc);
1114 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1115 if( rc.top > rcview.bottom)
1117 /* if it was below the shell view
1119 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1120 rc.right - rc.left, rc.bottom - rc.top,
1121 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1123 else if( rc.left > rcview.right)
1125 /* if it was to the right of the shell view
1127 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1128 rc.right - rc.left, rc.bottom - rc.top,
1129 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1132 /* size the custom dialog at the end: some applications do some
1133 * control re-arranging at this point */
1134 GetClientRect(hwnd, &rc);
1135 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1136 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1138 EndDeferWindowPos( hdwp);
1139 /* should not be needed */
1140 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1144 /***********************************************************************
1147 * File open dialog procedure
1149 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1152 TRACE("%p 0x%04x\n", hwnd, uMsg);
1159 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1161 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1162 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1164 /* Adds the FileOpenDlgInfos in the property list of the dialog
1165 so it will be easily accessible through a GetPropA(...) */
1166 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1168 FILEDLG95_InitControls(hwnd);
1170 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1172 GetWindowRect( hwnd, &rc);
1173 fodInfos->DlgInfos.hwndGrip =
1174 CreateWindowExA( 0, "SCROLLBAR", NULL,
1175 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1176 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1177 rc.right - gripx, rc.bottom - gripy,
1178 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1181 fodInfos->DlgInfos.hwndCustomDlg =
1182 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1184 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1185 FILEDLG95_FillControls(hwnd, wParam, lParam);
1187 if( fodInfos->DlgInfos.hwndCustomDlg)
1188 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1190 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1191 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1192 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1195 /* if the app has changed the position of the invisible listbox,
1196 * change that of the listview (browser) as well */
1197 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1198 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1199 if( !EqualRect( &rc, &rcstc))
1201 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1202 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1203 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1204 SWP_NOACTIVATE | SWP_NOZORDER);
1207 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1209 GetWindowRect( hwnd, &rc);
1210 fodInfos->sizedlg.cx = rc.right - rc.left;
1211 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1212 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1213 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1214 GetClientRect( hwnd, &rc);
1215 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1216 rc.right - gripx, rc.bottom - gripy,
1217 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1218 /* resize the dialog to the previous invocation */
1219 if( MemDialogSize.cx && MemDialogSize.cy)
1220 SetWindowPos( hwnd, NULL,
1221 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1222 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1225 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1226 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1231 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1232 case WM_GETMINMAXINFO:
1233 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1235 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1238 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1241 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1247 case WM_GETISHELLBROWSER:
1248 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1252 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1253 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1254 MemDialogSize = fodInfos->sizedlg;
1255 RemovePropA(hwnd, FileOpenDlgInfosStr);
1260 LPNMHDR lpnmh = (LPNMHDR)lParam;
1263 /* set up the button tooltips strings */
1264 if(TTN_GETDISPINFOA == lpnmh->code )
1266 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1267 switch(lpnmh->idFrom )
1269 /* Up folder button */
1270 case FCIDM_TB_UPFOLDER:
1271 stringId = IDS_UPFOLDER;
1273 /* New folder button */
1274 case FCIDM_TB_NEWFOLDER:
1275 stringId = IDS_NEWFOLDER;
1277 /* List option button */
1278 case FCIDM_TB_SMALLICON:
1279 stringId = IDS_LISTVIEW;
1281 /* Details option button */
1282 case FCIDM_TB_REPORTVIEW:
1283 stringId = IDS_REPORTVIEW;
1285 /* Desktop button */
1286 case FCIDM_TB_DESKTOP:
1287 stringId = IDS_TODESKTOP;
1292 lpdi->hinst = COMDLG32_hInstance;
1293 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1298 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1299 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1304 /***********************************************************************
1305 * FILEDLG95_InitControls
1307 * WM_INITDIALOG message handler (before hook notification)
1309 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1311 int win2000plus = 0;
1313 int handledPath = FALSE;
1314 OSVERSIONINFOW osVi;
1315 static const WCHAR szwSlash[] = { '\\', 0 };
1316 static const WCHAR szwStar[] = { '*',0 };
1318 static const TBBUTTON tbb[] =
1320 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1321 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1322 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1323 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1324 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1325 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1326 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1327 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1328 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1330 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1335 HIMAGELIST toolbarImageList;
1336 SHFILEINFOA shFileInfo;
1337 ITEMIDLIST *desktopPidl;
1339 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1341 TRACE("%p\n", fodInfos);
1343 /* Get windows version emulating */
1344 osVi.dwOSVersionInfoSize = sizeof(osVi);
1345 GetVersionExW(&osVi);
1346 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1347 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1348 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1349 win2000plus = (osVi.dwMajorVersion > 4);
1350 if (win2000plus) win98plus = TRUE;
1352 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1354 /* Get the hwnd of the controls */
1355 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1356 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1357 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1359 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1360 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1362 /* construct the toolbar */
1363 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1364 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1366 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1367 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1368 rectTB.left = rectlook.right;
1369 rectTB.top = rectlook.top-1;
1371 if (fodInfos->unicode)
1372 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1373 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1374 rectTB.left, rectTB.top,
1375 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1376 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1378 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1379 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1380 rectTB.left, rectTB.top,
1381 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1382 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1384 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1386 /* FIXME: use TB_LOADIMAGES when implemented */
1387 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1388 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1389 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1391 /* Retrieve and add desktop icon to the toolbar */
1392 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1393 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1394 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1395 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1396 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1398 DestroyIcon(shFileInfo.hIcon);
1399 CoTaskMemFree(desktopPidl);
1401 /* Finish Toolbar Construction */
1402 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1403 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1405 /* Set the window text with the text specified in the OPENFILENAME structure */
1408 SetWindowTextW(hwnd,fodInfos->title);
1410 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1413 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1414 SetWindowTextW(hwnd, buf);
1417 /* Initialise the file name edit control */
1418 handledPath = FALSE;
1419 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1421 if(fodInfos->filename)
1423 /* 1. If win2000 or higher and filename contains a path, use it
1424 in preference over the lpstrInitialDir */
1425 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1426 WCHAR tmpBuf[MAX_PATH];
1430 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1433 /* nameBit is always shorter than the original filename */
1434 lstrcpyW(fodInfos->filename,nameBit);
1437 if (fodInfos->initdir == NULL)
1438 MemFree(fodInfos->initdir);
1439 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1440 lstrcpyW(fodInfos->initdir, tmpBuf);
1442 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1443 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1445 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1448 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1452 /* 2. (All platforms) If initdir is not null, then use it */
1453 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1454 (*fodInfos->initdir!=0x00))
1456 /* Work out the proper path as supplied one might be relative */
1457 /* (Here because supplying '.' as dir browses to My Computer) */
1458 if (handledPath==FALSE) {
1459 WCHAR tmpBuf[MAX_PATH];
1460 WCHAR tmpBuf2[MAX_PATH];
1464 lstrcpyW(tmpBuf, fodInfos->initdir);
1465 if( PathFileExistsW(tmpBuf) ) {
1466 /* initdir does not have to be a directory. If a file is
1467 * specified, the dir part is taken */
1468 if( PathIsDirectoryW(tmpBuf)) {
1469 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1470 lstrcatW(tmpBuf, szwSlash);
1472 lstrcatW(tmpBuf, szwStar);
1474 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1477 MemFree(fodInfos->initdir);
1478 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1479 lstrcpyW(fodInfos->initdir, tmpBuf2);
1481 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1484 else if (fodInfos->initdir)
1486 MemFree(fodInfos->initdir);
1487 fodInfos->initdir = NULL;
1488 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1493 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1494 (*fodInfos->initdir==0x00)))
1496 /* 3. All except w2k+: if filename contains a path use it */
1497 if (!win2000plus && fodInfos->filename &&
1498 *fodInfos->filename &&
1499 strpbrkW(fodInfos->filename, szwSlash)) {
1500 WCHAR tmpBuf[MAX_PATH];
1504 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1509 /* nameBit is always shorter than the original filename */
1510 lstrcpyW(fodInfos->filename, nameBit);
1513 len = lstrlenW(tmpBuf);
1514 MemFree(fodInfos->initdir);
1515 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1516 lstrcpyW(fodInfos->initdir, tmpBuf);
1519 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1520 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1522 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1525 /* 4. win98+ and win2000+ if any files of specified filter types in
1526 current directory, use it */
1527 if ( win98plus && handledPath == FALSE &&
1528 fodInfos->filter && *fodInfos->filter) {
1530 BOOL searchMore = TRUE;
1531 LPCWSTR lpstrPos = fodInfos->filter;
1532 WIN32_FIND_DATAW FindFileData;
1537 /* filter is a list... title\0ext\0......\0\0 */
1539 /* Skip the title */
1540 if(! *lpstrPos) break; /* end */
1541 lpstrPos += lstrlenW(lpstrPos) + 1;
1543 /* See if any files exist in the current dir with this extension */
1544 if(! *lpstrPos) break; /* end */
1546 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1548 if (hFind == INVALID_HANDLE_VALUE) {
1549 /* None found - continue search */
1550 lpstrPos += lstrlenW(lpstrPos) + 1;
1555 MemFree(fodInfos->initdir);
1556 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1557 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1560 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1561 debugstr_w(lpstrPos));
1567 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1569 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1570 if (handledPath == FALSE && (win2000plus || win98plus)) {
1571 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1573 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1575 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1578 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1579 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1581 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1584 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1587 } else if (handledPath==FALSE) {
1588 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1589 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1591 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1594 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1595 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1597 /* Must the open as read only check box be checked ?*/
1598 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1600 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1603 /* Must the open as read only check box be hidden? */
1604 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1606 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1607 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1610 /* Must the help button be hidden? */
1611 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1613 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1614 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1617 /* change Open to Save */
1618 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1621 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1622 SetDlgItemTextW(hwnd, IDOK, buf);
1623 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1624 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1627 /* Initialize the filter combo box */
1628 FILEDLG95_FILETYPE_Init(hwnd);
1633 /***********************************************************************
1634 * FILEDLG95_ResizeControls
1636 * WM_INITDIALOG message handler (after hook notification)
1638 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1640 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1642 if (fodInfos->DlgInfos.hwndCustomDlg)
1645 UINT flags = SWP_NOACTIVATE;
1647 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1648 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1650 /* resize the custom dialog to the parent size */
1651 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1652 GetClientRect(hwnd, &rc);
1655 /* our own fake template is zero sized and doesn't have children, so
1656 * there is no need to resize it. Picasa depends on it.
1658 flags |= SWP_NOSIZE;
1661 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1662 0, 0, rc.right, rc.bottom, flags);
1666 /* Resize the height, if open as read only checkbox ad help button are
1667 * hidden and we are not using a custom template nor a customDialog
1669 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1670 (!(fodInfos->ofnInfos->Flags &
1671 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1673 RECT rectDlg, rectHelp, rectCancel;
1674 GetWindowRect(hwnd, &rectDlg);
1675 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1676 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1677 /* subtract the height of the help button plus the space between the help
1678 * button and the cancel button to the height of the dialog
1680 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1681 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1682 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1688 /***********************************************************************
1689 * FILEDLG95_FillControls
1691 * WM_INITDIALOG message handler (after hook notification)
1693 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1695 LPITEMIDLIST pidlItemId = NULL;
1697 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1699 TRACE("dir=%s file=%s\n",
1700 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1702 /* Get the initial directory pidl */
1704 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1706 WCHAR path[MAX_PATH];
1708 GetCurrentDirectoryW(MAX_PATH,path);
1709 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1712 /* Initialise shell objects */
1713 FILEDLG95_SHELL_Init(hwnd);
1715 /* Initialize the Look In combo box */
1716 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1718 /* Browse to the initial directory */
1719 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1721 /* Free pidlItem memory */
1722 COMDLG32_SHFree(pidlItemId);
1726 /***********************************************************************
1729 * Regroups all the cleaning functions of the filedlg
1731 void FILEDLG95_Clean(HWND hwnd)
1733 FILEDLG95_FILETYPE_Clean(hwnd);
1734 FILEDLG95_LOOKIN_Clean(hwnd);
1735 FILEDLG95_SHELL_Clean(hwnd);
1737 /***********************************************************************
1738 * FILEDLG95_OnWMCommand
1740 * WM_COMMAND message handler
1742 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1744 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1745 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1746 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1752 FILEDLG95_OnOpen(hwnd);
1756 FILEDLG95_Clean(hwnd);
1757 EndDialog(hwnd, FALSE);
1759 /* Filetype combo box */
1761 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1763 /* LookIn combo box */
1765 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1768 /* --- toolbar --- */
1769 /* Up folder button */
1770 case FCIDM_TB_UPFOLDER:
1771 FILEDLG95_SHELL_UpFolder(hwnd);
1773 /* New folder button */
1774 case FCIDM_TB_NEWFOLDER:
1775 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1777 /* List option button */
1778 case FCIDM_TB_SMALLICON:
1779 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1781 /* Details option button */
1782 case FCIDM_TB_REPORTVIEW:
1783 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1785 /* Details option button */
1786 case FCIDM_TB_DESKTOP:
1787 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1794 /* Do not use the listview selection anymore */
1795 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1799 /***********************************************************************
1800 * FILEDLG95_OnWMGetIShellBrowser
1802 * WM_GETISHELLBROWSER message handler
1804 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1806 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1810 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1816 /***********************************************************************
1817 * FILEDLG95_SendFileOK
1819 * Sends the CDN_FILEOK notification if required
1822 * TRUE if the dialog should close
1823 * FALSE if the dialog should not be closed
1825 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1827 /* ask the hook if we can close */
1828 if(IsHooked(fodInfos))
1833 /* First send CDN_FILEOK as MSDN doc says */
1834 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1835 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1838 TRACE("canceled\n");
1842 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1843 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1844 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1847 TRACE("canceled\n");
1854 /***********************************************************************
1855 * FILEDLG95_OnOpenMultipleFiles
1857 * Handles the opening of multiple files.
1860 * check destination buffer size
1862 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1864 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1865 UINT nCount, nSizePath;
1866 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1870 if(fodInfos->unicode)
1872 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1873 ofn->lpstrFile[0] = '\0';
1877 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1878 ofn->lpstrFile[0] = '\0';
1881 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1883 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1884 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1885 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1887 LPWSTR lpstrTemp = lpstrFileList;
1889 for ( nCount = 0; nCount < nFileCount; nCount++ )
1893 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1896 WCHAR lpstrNotFound[100];
1897 WCHAR lpstrMsg[100];
1899 static const WCHAR nl[] = {'\n',0};
1901 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1902 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1904 lstrcpyW(tmp, lpstrTemp);
1906 lstrcatW(tmp, lpstrNotFound);
1908 lstrcatW(tmp, lpstrMsg);
1910 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1914 /* move to the next file in the list of files */
1915 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1916 COMDLG32_SHFree(pidl);
1920 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1921 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1923 /* For "oldstyle" dialog the components have to
1924 be separated by blanks (not '\0'!) and short
1925 filenames have to be used! */
1926 FIXME("Components have to be separated by blanks\n");
1928 if(fodInfos->unicode)
1930 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1931 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1932 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1936 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1938 if (ofn->lpstrFile != NULL)
1940 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1941 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1942 if (ofn->nMaxFile > nSizePath)
1944 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1945 ofn->lpstrFile + nSizePath,
1946 ofn->nMaxFile - nSizePath, NULL, NULL);
1951 fodInfos->ofnInfos->nFileOffset = nSizePath;
1952 fodInfos->ofnInfos->nFileExtension = 0;
1954 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1957 /* clean and exit */
1958 FILEDLG95_Clean(hwnd);
1959 return EndDialog(hwnd,TRUE);
1962 /***********************************************************************
1965 * Ok button WM_COMMAND message handler
1967 * If the function succeeds, the return value is nonzero.
1969 #define ONOPEN_BROWSE 1
1970 #define ONOPEN_OPEN 2
1971 #define ONOPEN_SEARCH 3
1972 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1974 WCHAR strMsgTitle[MAX_PATH];
1975 WCHAR strMsgText [MAX_PATH];
1977 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1979 strMsgTitle[0] = '\0';
1980 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1981 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1984 BOOL FILEDLG95_OnOpen(HWND hwnd)
1986 LPWSTR lpstrFileList;
1987 UINT nFileCount = 0;
1990 WCHAR lpstrPathAndFile[MAX_PATH];
1991 WCHAR lpstrTemp[MAX_PATH];
1992 LPSHELLFOLDER lpsf = NULL;
1994 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1996 TRACE("hwnd=%p\n", hwnd);
1998 /* get the files from the edit control */
1999 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2001 /* try if the user selected a folder in the shellview */
2004 BrowseSelectedFolder(hwnd);
2010 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2014 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2017 Step 1: Build a complete path name from the current folder and
2018 the filename or path in the edit box.
2020 - the path in the edit box is a root path
2021 (with or without drive letter)
2022 - the edit box contains ".." (or a path with ".." in it)
2025 /* Get the current directory name */
2026 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2029 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2031 PathAddBackslashW(lpstrPathAndFile);
2033 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2035 /* if the user specified a fully qualified path use it */
2036 if(PathIsRelativeW(lpstrFileList))
2038 lstrcatW(lpstrPathAndFile, lpstrFileList);
2042 /* does the path have a drive letter? */
2043 if (PathGetDriveNumberW(lpstrFileList) == -1)
2044 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2046 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2049 /* resolve "." and ".." */
2050 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2051 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2052 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2054 MemFree(lpstrFileList);
2057 Step 2: here we have a cleaned up path
2059 We have to parse the path step by step to see if we have to browse
2060 to a folder if the path points to a directory or the last
2061 valid element is a directory.
2064 lpstrPathAndFile: cleaned up path
2068 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2069 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2070 nOpenAction = ONOPEN_OPEN;
2072 nOpenAction = ONOPEN_BROWSE;
2074 /* don't apply any checks with OFN_NOVALIDATE */
2076 LPWSTR lpszTemp, lpszTemp1;
2077 LPITEMIDLIST pidl = NULL;
2078 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2080 /* check for invalid chars */
2081 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2083 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2088 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2090 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2093 LPSHELLFOLDER lpsfChild;
2094 WCHAR lpwstrTemp[MAX_PATH];
2095 DWORD dwEaten, dwAttributes;
2098 lstrcpyW(lpwstrTemp, lpszTemp);
2099 p = PathFindNextComponentW(lpwstrTemp);
2101 if (!p) break; /* end of path */
2104 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2106 /* There are no wildcards when OFN_NOVALIDATE is set */
2107 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2109 static const WCHAR wszWild[] = { '*', '?', 0 };
2110 /* if the last element is a wildcard do a search */
2111 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2113 nOpenAction = ONOPEN_SEARCH;
2117 lpszTemp1 = lpszTemp;
2119 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2121 /* append a backslash to drive letters */
2122 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2123 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2124 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2126 PathAddBackslashW(lpwstrTemp);
2129 dwAttributes = SFGAO_FOLDER;
2130 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2132 /* the path component is valid, we have a pidl of the next path component */
2133 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2134 if(dwAttributes & SFGAO_FOLDER)
2136 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2138 ERR("bind to failed\n"); /* should not fail */
2141 IShellFolder_Release(lpsf);
2149 /* end dialog, return value */
2150 nOpenAction = ONOPEN_OPEN;
2153 COMDLG32_SHFree(pidl);
2156 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2158 if(*lpszTemp || /* points to trailing null for last path element */
2159 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2161 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2163 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2169 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2170 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2172 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2176 /* change to the current folder */
2177 nOpenAction = ONOPEN_OPEN;
2182 nOpenAction = ONOPEN_OPEN;
2186 if(pidl) COMDLG32_SHFree(pidl);
2190 Step 3: here we have a cleaned up and validated path
2193 lpsf: ShellFolder bound to the rightmost valid path component
2194 lpstrPathAndFile: cleaned up path
2195 nOpenAction: action to do
2197 TRACE("end validate sf=%p\n", lpsf);
2201 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2202 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2205 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2208 /* replace the current filter */
2209 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2210 len = lstrlenW(lpszTemp)+1;
2211 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2212 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2214 /* set the filter cb to the extension when possible */
2215 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2216 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2219 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2220 TRACE("ONOPEN_BROWSE\n");
2222 IPersistFolder2 * ppf2;
2223 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2225 LPITEMIDLIST pidlCurrent;
2226 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2227 IPersistFolder2_Release(ppf2);
2228 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2230 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2231 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2233 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2236 else if( nOpenAction == ONOPEN_SEARCH )
2238 if (fodInfos->Shell.FOIShellView)
2239 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2241 COMDLG32_SHFree(pidlCurrent);
2242 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2247 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2248 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2252 /* update READONLY check box flag */
2253 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2254 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2256 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2258 /* Attach the file extension with file name*/
2259 ext = PathFindExtensionW(lpstrPathAndFile);
2262 /* if no extension is specified with file name, then */
2263 /* attach the extension from file filter or default one */
2265 WCHAR *filterExt = NULL;
2266 LPWSTR lpstrFilter = NULL;
2267 static const WCHAR szwDot[] = {'.',0};
2268 int PathLength = lstrlenW(lpstrPathAndFile);
2271 lstrcatW(lpstrPathAndFile, szwDot);
2273 /*Get the file extension from file type filter*/
2274 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2275 fodInfos->ofnInfos->nFilterIndex-1);
2277 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2278 filterExt = PathFindExtensionW(lpstrFilter);
2280 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2281 lstrcatW(lpstrPathAndFile, filterExt + 1);
2282 else if ( fodInfos->defext ) /* attach the default file extension*/
2283 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2285 /* In Open dialog: if file does not exist try without extension */
2286 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2287 lpstrPathAndFile[PathLength] = '\0';
2290 if (fodInfos->defext) /* add default extension */
2292 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2295 if (!lstrcmpiW(fodInfos->defext, ext))
2296 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2298 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2301 /* In Save dialog: check if the file already exists */
2302 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2303 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2304 && PathFileExistsW(lpstrPathAndFile))
2306 WCHAR lpstrOverwrite[100];
2309 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2310 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2311 MB_YESNO | MB_ICONEXCLAMATION);
2319 /* In Open dialog: check if it should be created if it doesn't exist */
2320 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2321 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2322 && !PathFileExistsW(lpstrPathAndFile))
2324 WCHAR lpstrCreate[100];
2327 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2328 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2329 MB_YESNO | MB_ICONEXCLAMATION);
2337 /* Check that the size of the file does not exceed buffer size.
2338 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2339 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2340 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2343 /* fill destination buffer */
2344 if (fodInfos->ofnInfos->lpstrFile)
2346 if(fodInfos->unicode)
2348 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2350 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2351 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2352 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2356 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2358 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2359 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2360 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2361 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2365 if(fodInfos->unicode)
2369 /* set filename offset */
2370 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2371 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2373 /* set extension offset */
2374 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2375 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2380 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2382 /* set filename offset */
2383 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2384 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2386 /* set extension offset */
2387 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2388 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2391 /* set the lpstrFileTitle */
2392 if(fodInfos->ofnInfos->lpstrFileTitle)
2394 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2395 if(fodInfos->unicode)
2397 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2398 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2402 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2403 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2404 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2408 /* copy currently selected filter to lpstrCustomFilter */
2409 if (fodInfos->ofnInfos->lpstrCustomFilter)
2411 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2412 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2413 NULL, 0, NULL, NULL);
2414 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2416 LPSTR s = ofn->lpstrCustomFilter;
2417 s += strlen(ofn->lpstrCustomFilter)+1;
2418 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2419 s, len, NULL, NULL);
2424 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2428 FILEDLG95_Clean(hwnd);
2429 ret = EndDialog(hwnd, TRUE);
2435 size = lstrlenW(lpstrPathAndFile) + 1;
2436 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2438 /* return needed size in first two bytes of lpstrFile */
2439 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2440 FILEDLG95_Clean(hwnd);
2441 ret = EndDialog(hwnd, FALSE);
2442 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2449 if(lpsf) IShellFolder_Release(lpsf);
2453 /***********************************************************************
2454 * FILEDLG95_SHELL_Init
2456 * Initialisation of the shell objects
2458 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2460 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2465 * Initialisation of the FileOpenDialogInfos structure
2471 fodInfos->ShellInfos.hwndOwner = hwnd;
2473 /* Disable multi-select if flag not set */
2474 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2476 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2478 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2479 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2481 /* Construct the IShellBrowser interface */
2482 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2487 /***********************************************************************
2488 * FILEDLG95_SHELL_ExecuteCommand
2490 * Change the folder option and refresh the view
2491 * If the function succeeds, the return value is nonzero.
2493 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2495 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2498 TRACE("(%p,%p)\n", hwnd, lpVerb);
2500 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2505 CMINVOKECOMMANDINFO ci;
2506 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2507 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2511 IContextMenu_InvokeCommand(pcm, &ci);
2512 IContextMenu_Release(pcm);
2518 /***********************************************************************
2519 * FILEDLG95_SHELL_UpFolder
2521 * Browse to the specified object
2522 * If the function succeeds, the return value is nonzero.
2524 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2526 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2530 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2534 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2535 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2541 /***********************************************************************
2542 * FILEDLG95_SHELL_BrowseToDesktop
2544 * Browse to the Desktop
2545 * If the function succeeds, the return value is nonzero.
2547 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2549 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2555 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2556 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2557 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2558 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2559 COMDLG32_SHFree(pidl);
2560 return SUCCEEDED(hres);
2562 /***********************************************************************
2563 * FILEDLG95_SHELL_Clean
2565 * Cleans the memory used by shell objects
2567 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2569 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2573 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2575 /* clean Shell interfaces */
2576 if (fodInfos->Shell.FOIShellView)
2578 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2579 IShellView_Release(fodInfos->Shell.FOIShellView);
2581 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2582 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2583 if (fodInfos->Shell.FOIDataObject)
2584 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2587 /***********************************************************************
2588 * FILEDLG95_FILETYPE_Init
2590 * Initialisation of the file type combo box
2592 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2594 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2595 int nFilters = 0; /* number of filters */
2600 if(fodInfos->customfilter)
2602 /* customfilter has one entry... title\0ext\0
2603 * Set first entry of combo box item with customfilter
2606 LPCWSTR lpstrPos = fodInfos->customfilter;
2609 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2611 /* Copy the extensions */
2612 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2613 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2614 lstrcpyW(lpstrExt,lpstrPos);
2616 /* Add the item at the end of the combo */
2617 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2618 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2621 if(fodInfos->filter)
2623 LPCWSTR lpstrPos = fodInfos->filter;
2627 /* filter is a list... title\0ext\0......\0\0
2628 * Set the combo item text to the title and the item data
2631 LPCWSTR lpstrDisplay;
2635 if(! *lpstrPos) break; /* end */
2636 lpstrDisplay = lpstrPos;
2637 lpstrPos += lstrlenW(lpstrPos) + 1;
2639 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2643 /* Copy the extensions */
2644 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2645 lstrcpyW(lpstrExt,lpstrPos);
2646 lpstrPos += lstrlenW(lpstrPos) + 1;
2648 /* Add the item at the end of the combo */
2649 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2651 /* malformed filters are added anyway... */
2652 if (!*lpstrExt) break;
2657 * Set the current filter to the one specified
2658 * in the initialisation structure
2660 if (fodInfos->filter || fodInfos->customfilter)
2664 /* Check to make sure our index isn't out of bounds. */
2665 if ( fodInfos->ofnInfos->nFilterIndex >
2666 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2667 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2669 /* set default filter index */
2670 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2671 fodInfos->ofnInfos->nFilterIndex = 1;
2673 /* calculate index of Combo Box item */
2674 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2675 if (fodInfos->customfilter == NULL)
2678 /* Set the current index selection. */
2679 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2681 /* Get the corresponding text string from the combo box. */
2682 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2685 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2691 CharLowerW(lpstrFilter); /* lowercase */
2692 len = lstrlenW(lpstrFilter)+1;
2693 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2694 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2697 fodInfos->ofnInfos->nFilterIndex = 0;
2701 /***********************************************************************
2702 * FILEDLG95_FILETYPE_OnCommand
2704 * WM_COMMAND of the file type combo box
2705 * If the function succeeds, the return value is nonzero.
2707 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2709 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2717 /* Get the current item of the filetype combo box */
2718 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2720 /* set the current filter index */
2721 fodInfos->ofnInfos->nFilterIndex = iItem +
2722 (fodInfos->customfilter == NULL ? 1 : 0);
2724 /* Set the current filter with the current selection */
2725 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2727 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2729 if((INT_PTR)lpstrFilter != CB_ERR)
2732 CharLowerW(lpstrFilter); /* lowercase */
2733 len = lstrlenW(lpstrFilter)+1;
2734 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2735 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2736 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2737 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2740 /* Refresh the actual view to display the included items*/
2741 if (fodInfos->Shell.FOIShellView)
2742 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2747 /***********************************************************************
2748 * FILEDLG95_FILETYPE_SearchExt
2750 * searches for an extension in the filetype box
2752 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2754 int i, iCount = CBGetCount(hwnd);
2756 TRACE("%s\n", debugstr_w(lpstrExt));
2758 if(iCount != CB_ERR)
2760 for(i=0;i<iCount;i++)
2762 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2769 /***********************************************************************
2770 * FILEDLG95_FILETYPE_Clean
2772 * Clean the memory used by the filetype combo box
2774 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2776 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2778 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2782 /* Delete each string of the combo and their associated data */
2783 if(iCount != CB_ERR)
2785 for(iPos = iCount-1;iPos>=0;iPos--)
2787 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2788 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2791 /* Current filter */
2792 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2796 /***********************************************************************
2797 * FILEDLG95_LOOKIN_Init
2799 * Initialisation of the look in combo box
2802 /* Small helper function, to determine if the unixfs shell extension is rooted
2803 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2805 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2807 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2808 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2809 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2810 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2811 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2812 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2813 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2815 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2822 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2824 IShellFolder *psfRoot, *psfDrives;
2825 IEnumIDList *lpeRoot, *lpeDrives;
2826 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2828 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2832 liInfos->iMaxIndentation = 0;
2834 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2836 /* set item height for both text field and listbox */
2837 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2838 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2840 /* Turn on the extended UI for the combo box like Windows does */
2841 CBSetExtendedUI(hwndCombo, TRUE);
2843 /* Initialise data of Desktop folder */
2844 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2845 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2846 COMDLG32_SHFree(pidlTmp);
2848 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2850 SHGetDesktopFolder(&psfRoot);
2854 /* enumerate the contents of the desktop */
2855 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2857 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2859 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2861 /* If the unixfs extension is rooted, we don't expand the drives by default */
2862 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2864 /* special handling for CSIDL_DRIVES */
2865 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2867 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2869 /* enumerate the drives */
2870 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2872 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2874 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2875 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2876 COMDLG32_SHFree(pidlAbsTmp);
2877 COMDLG32_SHFree(pidlTmp1);
2879 IEnumIDList_Release(lpeDrives);
2881 IShellFolder_Release(psfDrives);
2886 COMDLG32_SHFree(pidlTmp);
2888 IEnumIDList_Release(lpeRoot);
2890 IShellFolder_Release(psfRoot);
2893 COMDLG32_SHFree(pidlDrives);
2896 /***********************************************************************
2897 * FILEDLG95_LOOKIN_DrawItem
2899 * WM_DRAWITEM message handler
2901 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2903 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2904 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2905 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2909 HIMAGELIST ilItemImage;
2912 LPSFOLDER tmpFolder;
2913 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2917 if(pDIStruct->itemID == -1)
2920 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2921 pDIStruct->itemID)))
2925 if(pDIStruct->itemID == liInfos->uSelectedItem)
2927 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2931 SHGFI_PIDL | SHGFI_SMALLICON |
2932 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2933 SHGFI_DISPLAYNAME );
2937 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2941 SHGFI_PIDL | SHGFI_SMALLICON |
2942 SHGFI_SYSICONINDEX |
2946 /* Is this item selected ? */
2947 if(pDIStruct->itemState & ODS_SELECTED)
2949 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2950 SetBkColor(pDIStruct->hDC,crHighLight);
2951 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2955 SetTextColor(pDIStruct->hDC,crText);
2956 SetBkColor(pDIStruct->hDC,crWin);
2957 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2960 /* Do not indent item if drawing in the edit of the combo */
2961 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2964 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2968 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2969 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2974 iIndentation = tmpFolder->m_iIndent;
2976 /* Draw text and icon */
2978 /* Initialise the icon display area */
2979 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2980 rectIcon.top = pDIStruct->rcItem.top;
2981 rectIcon.right = rectIcon.left + ICONWIDTH;
2982 rectIcon.bottom = pDIStruct->rcItem.bottom;
2984 /* Initialise the text display area */
2985 GetTextMetricsW(pDIStruct->hDC, &tm);
2986 rectText.left = rectIcon.right;
2988 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2989 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2991 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2993 /* Draw the icon from the image list */
2994 ImageList_Draw(ilItemImage,
3001 /* Draw the associated text */
3002 if(sfi.szDisplayName)
3003 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3009 /***********************************************************************
3010 * FILEDLG95_LOOKIN_OnCommand
3012 * LookIn combo box WM_COMMAND message handler
3013 * If the function succeeds, the return value is nonzero.
3015 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3017 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3019 TRACE("%p\n", fodInfos);
3025 LPSFOLDER tmpFolder;
3028 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3030 if( iItem == CB_ERR) return FALSE;
3032 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3037 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3038 tmpFolder->pidlItem,
3041 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3042 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3052 /***********************************************************************
3053 * FILEDLG95_LOOKIN_AddItem
3055 * Adds an absolute pidl item to the lookin combo box
3056 * returns the index of the inserted item
3058 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3060 LPITEMIDLIST pidlNext;
3063 LookInInfos *liInfos;
3065 TRACE("%08x\n", iInsertId);
3070 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3073 tmpFolder = MemAlloc(sizeof(SFOLDER));
3074 tmpFolder->m_iIndent = 0;
3076 /* Calculate the indentation of the item in the lookin*/
3078 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3080 tmpFolder->m_iIndent++;
3083 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3085 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3086 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3088 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3089 SHGetFileInfoW((LPCWSTR)pidl,
3093 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3094 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3096 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3098 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3102 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3104 /* Add the item at the end of the list */
3107 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3109 /* Insert the item at the iInsertId position*/
3112 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3115 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3119 COMDLG32_SHFree( tmpFolder->pidlItem );
3120 MemFree( tmpFolder );
3125 /***********************************************************************
3126 * FILEDLG95_LOOKIN_InsertItemAfterParent
3128 * Insert an item below its parent
3130 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3133 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3138 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3142 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3145 /* Free pidlParent memory */
3146 COMDLG32_SHFree(pidlParent);
3148 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3151 /***********************************************************************
3152 * FILEDLG95_LOOKIN_SelectItem
3154 * Adds an absolute pidl item to the lookin combo box
3155 * returns the index of the inserted item
3157 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3160 LookInInfos *liInfos;
3164 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3166 liInfos = GetPropA(hwnd,LookInInfosStr);
3170 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3171 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3176 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3177 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3181 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3183 if(iRemovedItem < iItemPos)
3188 CBSetCurSel(hwnd,iItemPos);
3189 liInfos->uSelectedItem = iItemPos;
3195 /***********************************************************************
3196 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3198 * Remove the item with an expansion level over iExpansionLevel
3200 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3203 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3207 if(liInfos->iMaxIndentation <= 2)
3210 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3212 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3213 COMDLG32_SHFree(tmpFolder->pidlItem);
3215 CBDeleteString(hwnd,iItemPos);
3216 liInfos->iMaxIndentation--;
3224 /***********************************************************************
3225 * FILEDLG95_LOOKIN_SearchItem
3227 * Search for pidl in the lookin combo box
3228 * returns the index of the found item
3230 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3233 int iCount = CBGetCount(hwnd);
3235 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3237 if (iCount != CB_ERR)
3241 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3243 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3245 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3253 /***********************************************************************
3254 * FILEDLG95_LOOKIN_Clean
3256 * Clean the memory used by the lookin combo box
3258 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3260 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3262 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3266 /* Delete each string of the combo and their associated data */
3267 if (iCount != CB_ERR)
3269 for(iPos = iCount-1;iPos>=0;iPos--)
3271 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3272 COMDLG32_SHFree(tmpFolder->pidlItem);
3274 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3278 /* LookInInfos structure */
3279 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3282 /***********************************************************************
3283 * FILEDLG95_FILENAME_FillFromSelection
3285 * fills the edit box from the cached DataObject
3287 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3289 FileOpenDlgInfos *fodInfos;
3291 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3292 WCHAR lpstrTemp[MAX_PATH];
3293 LPWSTR lpstrAllFile, lpstrCurrFile;
3296 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3298 /* Count how many files we have */
3299 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3301 /* calculate the string length, count files */
3302 if (nFileSelected >= 1)
3304 nLength += 3; /* first and last quotes, trailing \0 */
3305 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3307 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3311 /* get the total length of the selected file names */
3312 lpstrTemp[0] = '\0';
3313 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3315 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3317 nLength += lstrlenW( lpstrTemp ) + 3;
3320 COMDLG32_SHFree( pidl );
3325 /* allocate the buffer */
3326 if (nFiles <= 1) nLength = MAX_PATH;
3327 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3329 /* Generate the string for the edit control */
3332 lpstrCurrFile = lpstrAllFile;
3333 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3335 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3339 /* get the file name */
3340 lpstrTemp[0] = '\0';
3341 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3343 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3347 *lpstrCurrFile++ = '\"';
3348 lstrcpyW( lpstrCurrFile, lpstrTemp );
3349 lpstrCurrFile += lstrlenW( lpstrTemp );
3350 *lpstrCurrFile++ = '\"';
3351 *lpstrCurrFile++ = ' ';
3356 lstrcpyW( lpstrAllFile, lpstrTemp );
3359 COMDLG32_SHFree( pidl );
3362 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3364 /* Select the file name like Windows does */
3365 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3367 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3371 /* copied from shell32 to avoid linking to it
3372 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3373 * is dependent on whether emulated OS is unicode or not.
3375 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3380 lstrcpynW(dest, src->u.pOleStr, len);
3381 COMDLG32_SHFree(src->u.pOleStr);
3385 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3390 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3395 FIXME("unknown type %x!\n", src->uType);
3396 if (len) *dest = '\0';
3402 /***********************************************************************
3403 * FILEDLG95_FILENAME_GetFileNames
3405 * Copies the filenames to a delimited string list.
3406 * The delimiter is specified by the parameter 'separator',
3407 * usually either a space or a nul
3409 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3411 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3412 UINT nStrCharCount = 0; /* index in src buffer */
3413 UINT nFileIndex = 0; /* index in dest buffer */
3414 UINT nFileCount = 0; /* number of files */
3415 UINT nStrLen = 0; /* length of string in edit control */
3416 LPWSTR lpstrEdit; /* buffer for string from edit control */
3420 /* get the filenames from the edit control */
3421 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3422 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3423 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3425 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3427 /* we might get single filename without any '"',
3428 * so we need nStrLen + terminating \0 + end-of-list \0 */
3429 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3432 /* build delimited file list from filenames */
3433 while ( nStrCharCount <= nStrLen )
3435 if ( lpstrEdit[nStrCharCount]=='"' )
3438 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3440 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3443 (*lpstrFileList)[nFileIndex++] = 0;
3449 /* single, unquoted string */
3450 if ((nStrLen > 0) && (nFileIndex == 0) )
3452 lstrcpyW(*lpstrFileList, lpstrEdit);
3453 nFileIndex = lstrlenW(lpstrEdit) + 1;
3458 (*lpstrFileList)[nFileIndex++] = '\0';
3460 *sizeUsed = nFileIndex;
3465 #define SETDefFormatEtc(fe,cf,med) \
3467 (fe).cfFormat = cf;\
3468 (fe).dwAspect = DVASPECT_CONTENT; \
3475 * DATAOBJECT Helper functions
3478 /***********************************************************************
3479 * COMCTL32_ReleaseStgMedium
3481 * like ReleaseStgMedium from ole32
3483 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3485 if(medium.pUnkForRelease)
3487 IUnknown_Release(medium.pUnkForRelease);
3491 GlobalUnlock(medium.u.hGlobal);
3492 GlobalFree(medium.u.hGlobal);
3496 /***********************************************************************
3497 * GetPidlFromDataObject
3499 * Return pidl(s) by number from the cached DataObject
3501 * nPidlIndex=0 gets the fully qualified root path
3503 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3507 FORMATETC formatetc;
3508 LPITEMIDLIST pidl = NULL;
3510 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3515 /* Set the FORMATETC structure*/
3516 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3518 /* Get the pidls from IDataObject */
3519 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3521 LPIDA cida = GlobalLock(medium.u.hGlobal);
3522 if(nPidlIndex <= cida->cidl)
3524 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3526 COMCTL32_ReleaseStgMedium(medium);
3531 /***********************************************************************
3534 * Return the number of selected items in the DataObject.
3537 static UINT GetNumSelected( IDataObject *doSelected )
3541 FORMATETC formatetc;
3543 TRACE("sv=%p\n", doSelected);
3545 if (!doSelected) return 0;
3547 /* Set the FORMATETC structure*/
3548 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3550 /* Get the pidls from IDataObject */
3551 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3553 LPIDA cida = GlobalLock(medium.u.hGlobal);
3554 retVal = cida->cidl;
3555 COMCTL32_ReleaseStgMedium(medium);
3565 /***********************************************************************
3568 * Get the pidl's display name (relative to folder) and
3569 * put it in lpstrFileName.
3571 * Return NOERROR on success,
3575 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3580 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3584 SHGetDesktopFolder(&lpsf);
3585 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3586 IShellFolder_Release(lpsf);
3590 /* Get the display name of the pidl relative to the folder */
3591 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3593 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3598 /***********************************************************************
3599 * GetShellFolderFromPidl
3601 * pidlRel is the item pidl relative
3602 * Return the IShellFolder of the absolute pidl
3604 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3606 IShellFolder *psf = NULL,*psfParent;
3608 TRACE("%p\n", pidlAbs);
3610 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3613 if(pidlAbs && pidlAbs->mkid.cb)
3615 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3617 IShellFolder_Release(psfParent);
3621 /* return the desktop */
3627 /***********************************************************************
3630 * Return the LPITEMIDLIST to the parent of the pidl in the list
3632 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3634 LPITEMIDLIST pidlParent;
3636 TRACE("%p\n", pidl);
3638 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3639 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3644 /***********************************************************************
3647 * returns the pidl of the file name relative to folder
3648 * NULL if an error occurred
3650 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3652 LPITEMIDLIST pidl = NULL;
3655 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3657 if(!lpcstrFileName) return NULL;
3658 if(!*lpcstrFileName) return NULL;
3662 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3663 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3664 IShellFolder_Release(lpsf);
3669 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3676 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3678 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3681 TRACE("%p, %p\n", psf, pidl);
3683 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3685 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3686 /* see documentation shell 4.1*/
3687 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3690 /***********************************************************************
3691 * BrowseSelectedFolder
3693 static BOOL BrowseSelectedFolder(HWND hwnd)
3695 BOOL bBrowseSelFolder = FALSE;
3696 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3700 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3702 LPITEMIDLIST pidlSelection;
3704 /* get the file selected */
3705 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3706 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3708 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3709 pidlSelection, SBSP_RELATIVE ) ) )
3711 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3712 ' ','n','o','t',' ','e','x','i','s','t',0};
3713 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3715 bBrowseSelFolder = TRUE;
3716 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3717 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3719 COMDLG32_SHFree( pidlSelection );
3722 return bBrowseSelFolder;
3726 * Memory allocation methods */
3727 static void *MemAlloc(UINT size)
3729 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3732 static void MemFree(void *mem)
3734 HeapFree(GetProcessHeap(),0,mem);
3738 * Old-style (win3.1) dialogs */
3740 /***********************************************************************
3741 * FD32_GetTemplate [internal]
3743 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3744 * by a 32 bits application
3747 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3749 LPOPENFILENAMEW ofnW = lfs->ofnW;
3750 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3753 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3755 if (!(lfs->template = LockResource( ofnW->hInstance )))
3757 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3761 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3765 hResInfo = FindResourceA(priv->ofnA->hInstance,
3766 priv->ofnA->lpTemplateName,
3769 hResInfo = FindResourceW(ofnW->hInstance,
3770 ofnW->lpTemplateName,
3774 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3777 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3779 !(lfs->template = LockResource(hDlgTmpl)))
3781 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3784 } else { /* get it from internal Wine resource */
3786 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3787 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3789 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3792 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3793 !(lfs->template = LockResource( hDlgTmpl )))
3795 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3803 /************************************************************************
3804 * FD32_Init [internal]
3805 * called from the common 16/32 code to initialize 32 bit data
3807 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3809 BOOL IsUnicode = (BOOL) data;
3812 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3813 lfs->private1632 = priv;
3814 if (NULL == lfs->private1632) return FALSE;
3817 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3818 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3819 if (lfs->ofnW->lpfnHook)
3824 priv->ofnA = (LPOPENFILENAMEA) lParam;
3825 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3826 if (priv->ofnA->lpfnHook)
3828 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3829 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3832 if (! FD32_GetTemplate(lfs)) return FALSE;
3837 /***********************************************************************
3838 * FD32_CallWindowProc [internal]
3840 * called from the common 16/32 code to call the appropriate hook
3842 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3846 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3850 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3851 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3852 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3853 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3854 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3858 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3859 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3860 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3861 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3862 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3866 /***********************************************************************
3867 * FD32_UpdateResult [internal]
3868 * update the real client structures if any
3870 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3872 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3873 LPOPENFILENAMEW ofnW = lfs->ofnW;
3878 if (ofnW->nMaxFile &&
3879 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3880 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3881 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3883 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3884 /* set filename offset */
3885 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3886 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3888 /* set extension offset */
3889 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3890 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3894 /***********************************************************************
3895 * FD32_UpdateFileTitle [internal]
3896 * update the real client structures if any
3898 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3900 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3901 LPOPENFILENAMEW ofnW = lfs->ofnW;
3905 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3906 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3907 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3912 /***********************************************************************
3913 * FD32_SendLbGetCurSel [internal]
3914 * retrieve selected listbox item
3916 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3918 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3922 /************************************************************************
3923 * FD32_Destroy [internal]
3924 * called from the common 16/32 code to cleanup 32 bit data
3926 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3928 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3930 /* if ofnW has been allocated, have to free everything in it */
3931 if (NULL != priv && NULL != priv->ofnA)
3933 FD31_FreeOfnW(lfs->ofnW);
3934 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3938 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3940 callbacks->Init = FD32_Init;
3941 callbacks->CWP = FD32_CallWindowProc;
3942 callbacks->UpdateResult = FD32_UpdateResult;
3943 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3944 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3945 callbacks->Destroy = FD32_Destroy;
3948 /***********************************************************************
3949 * FD32_WMMeasureItem [internal]
3951 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3953 LPMEASUREITEMSTRUCT lpmeasure;
3955 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3956 lpmeasure->itemHeight = FD31_GetFldrHeight();
3961 /***********************************************************************
3962 * FileOpenDlgProc [internal]
3963 * Used for open and save, in fact.
3965 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3966 WPARAM wParam, LPARAM lParam)
3968 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3970 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3971 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3974 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3976 return lRet; /* else continue message processing */
3981 return FD31_WMInitDialog(hWnd, wParam, lParam);
3983 case WM_MEASUREITEM:
3984 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3987 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3990 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3993 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3994 switch (HIWORD(lParam))
3997 SetTextColor((HDC16)wParam, 0x00000000);
3999 case CTLCOLOR_STATIC:
4000 SetTextColor((HDC16)wParam, 0x00000000);
4010 /***********************************************************************
4011 * GetFileName31A [internal]
4013 * Creates a win31 style dialog box for the user to select a file to open/save.
4015 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4016 UINT dlgType /* type dialogue : open/save */
4022 FD31_CALLBACKS callbacks;
4024 if (!lpofn || !FD31_Init()) return FALSE;
4026 TRACE("ofn flags %08x\n", lpofn->Flags);
4027 FD32_SetupCallbacks(&callbacks);
4028 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
4031 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4032 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
4033 FD32_FileOpenDlgProc, (LPARAM)lfs);
4034 FD31_DestroyPrivate(lfs);
4037 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4041 /***********************************************************************
4042 * GetFileName31W [internal]
4044 * Creates a win31 style dialog box for the user to select a file to open/save
4046 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4047 UINT dlgType /* type dialogue : open/save */
4053 FD31_CALLBACKS callbacks;
4055 if (!lpofn || !FD31_Init()) return FALSE;
4057 FD32_SetupCallbacks(&callbacks);
4058 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
4061 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4062 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
4063 FD32_FileOpenDlgProc, (LPARAM)lfs);
4064 FD31_DestroyPrivate(lfs);
4067 TRACE("file %s, file offset %d, ext offset %d\n",
4068 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4072 /* ------------------ APIs ---------------------- */
4074 /***********************************************************************
4075 * GetOpenFileNameA (COMDLG32.@)
4077 * Creates a dialog box for the user to select a file to open.
4080 * TRUE on success: user enters a valid file
4081 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4084 BOOL WINAPI GetOpenFileNameA(
4085 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4087 BOOL win16look = FALSE;
4089 TRACE("flags %08x\n", ofn->Flags);
4091 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4092 if (ofn->Flags & OFN_FILEMUSTEXIST)
4093 ofn->Flags |= OFN_PATHMUSTEXIST;
4095 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4096 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4099 return GetFileName31A(ofn, OPEN_DIALOG);
4101 return GetFileDialog95A(ofn, OPEN_DIALOG);
4104 /***********************************************************************
4105 * GetOpenFileNameW (COMDLG32.@)
4107 * Creates a dialog box for the user to select a file to open.
4110 * TRUE on success: user enters a valid file
4111 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4114 BOOL WINAPI GetOpenFileNameW(
4115 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4117 BOOL win16look = FALSE;
4119 TRACE("flags %08x\n", ofn->Flags);
4121 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4122 if (ofn->Flags & OFN_FILEMUSTEXIST)
4123 ofn->Flags |= OFN_PATHMUSTEXIST;
4125 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4126 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4129 return GetFileName31W(ofn, OPEN_DIALOG);
4131 return GetFileDialog95W(ofn, OPEN_DIALOG);
4135 /***********************************************************************
4136 * GetSaveFileNameA (COMDLG32.@)
4138 * Creates a dialog box for the user to select a file to save.
4141 * TRUE on success: user enters a valid file
4142 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4145 BOOL WINAPI GetSaveFileNameA(
4146 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4148 BOOL win16look = FALSE;
4150 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4151 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4154 return GetFileName31A(ofn, SAVE_DIALOG);
4156 return GetFileDialog95A(ofn, SAVE_DIALOG);
4159 /***********************************************************************
4160 * GetSaveFileNameW (COMDLG32.@)
4162 * Creates a dialog box for the user to select a file to save.
4165 * TRUE on success: user enters a valid file
4166 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4169 BOOL WINAPI GetSaveFileNameW(
4170 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4172 BOOL win16look = FALSE;
4174 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4175 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4178 return GetFileName31W(ofn, SAVE_DIALOG);
4180 return GetFileDialog95W(ofn, SAVE_DIALOG);
4183 /***********************************************************************
4184 * GetFileTitleA (COMDLG32.@)
4186 * See GetFileTitleW.
4188 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4191 UNICODE_STRING strWFile;
4194 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4195 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4196 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4197 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4198 RtlFreeUnicodeString( &strWFile );
4199 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4204 /***********************************************************************
4205 * GetFileTitleW (COMDLG32.@)
4207 * Get the name of a file.
4210 * lpFile [I] name and location of file
4211 * lpTitle [O] returned file name
4212 * cbBuf [I] buffer size of lpTitle
4216 * Failure: negative number.
4218 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4221 static const WCHAR brkpoint[] = {'*','[',']',0};
4222 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4224 if(lpFile == NULL || lpTitle == NULL)
4227 len = lstrlenW(lpFile);
4232 if(strpbrkW(lpFile, brkpoint))
4237 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4240 for(i = len; i >= 0; i--)
4242 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4252 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4254 len = lstrlenW(lpFile+i)+1;
4258 lstrcpyW(lpTitle, &lpFile[i]);