2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
50 #include "wine/port.h"
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
67 #include "wine/unicode.h"
73 #include "filedlg31.h"
74 #include "wine/debug.h"
79 #include "filedlgbrowser.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
122 #define XTEXTOFFSET 3
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBAddStringW(hwnd,str) \
144 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
146 #define CBInsertString(hwnd,str,pos) \
147 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
149 #define CBDeleteString(hwnd,pos) \
150 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
152 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
153 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
155 #define CBGetItemDataPtr(hwnd,iItemId) \
156 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
158 #define CBGetLBText(hwnd,iItemId,str) \
159 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
161 #define CBGetCurSel(hwnd) \
162 SendMessageA(hwnd,CB_GETCURSEL,0,0);
164 #define CBSetCurSel(hwnd,pos) \
165 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
167 #define CBGetCount(hwnd) \
168 SendMessageA(hwnd,CB_GETCOUNT,0,0);
169 #define CBShowDropDown(hwnd,show) \
170 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
171 #define CBSetItemHeight(hwnd,index,height) \
172 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
174 #define CBSetExtendedUI(hwnd,flag) \
175 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
177 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
178 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
180 /***********************************************************************
184 /* Internal functions used by the dialog */
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the filetype combo box */
200 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
201 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
202 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
203 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
205 /* Functions used by the Look In combo box */
206 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
207 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
208 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
209 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
210 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
211 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
212 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
213 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
214 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
216 /* Miscellaneous tool functions */
217 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
218 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
221 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
223 /* Shell memory allocation */
224 static void *MemAlloc(UINT size);
225 static void MemFree(void *mem);
227 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
228 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
230 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08lx not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
282 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
283 (LPDLGTEMPLATEA) template,
284 fodInfos->ofnInfos->hwndOwner,
288 /* Unable to create the dialog */
295 /***********************************************************************
298 * Call GetFileName95 with this structure and clean the memory.
300 * IN : The OPENFILENAMEA initialisation structure passed to
301 * GetOpenFileNameA win api function (see filedlg.c)
303 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
306 FileOpenDlgInfos fodInfos;
307 LPSTR lpstrSavDir = NULL;
309 LPWSTR defext = NULL;
310 LPWSTR filter = NULL;
311 LPWSTR customfilter = NULL;
313 /* Initialize FileOpenDlgInfos structure */
314 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
316 /* Pass in the original ofn */
317 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
319 /* save current directory */
320 if (ofn->Flags & OFN_NOCHANGEDIR)
322 lpstrSavDir = MemAlloc(MAX_PATH);
323 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
326 fodInfos.unicode = FALSE;
328 /* convert all the input strings to unicode */
329 if(ofn->lpstrInitialDir)
331 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
332 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
333 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
336 fodInfos.initdir = NULL;
340 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
341 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
344 fodInfos.filename = NULL;
348 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
349 defext = MemAlloc((len+1)*sizeof(WCHAR));
350 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
352 fodInfos.defext = defext;
356 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
357 title = MemAlloc((len+1)*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
360 fodInfos.title = title;
362 if (ofn->lpstrFilter)
367 /* filter is a list... title\0ext\0......\0\0 */
368 s = ofn->lpstrFilter;
369 while (*s) s = s+strlen(s)+1;
371 n = s - ofn->lpstrFilter;
372 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
373 filter = MemAlloc(len*sizeof(WCHAR));
374 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
376 fodInfos.filter = filter;
378 /* convert lpstrCustomFilter */
379 if (ofn->lpstrCustomFilter)
384 /* customfilter contains a pair of strings... title\0ext\0 */
385 s = ofn->lpstrCustomFilter;
386 if (*s) s = s+strlen(s)+1;
387 if (*s) s = s+strlen(s)+1;
388 n = s - ofn->lpstrCustomFilter;
389 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
390 customfilter = MemAlloc(len*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
393 fodInfos.customfilter = customfilter;
395 /* Initialize the dialog property */
396 fodInfos.DlgInfos.dwDlgProp = 0;
397 fodInfos.DlgInfos.hwndCustomDlg = NULL;
402 ret = GetFileName95(&fodInfos);
405 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
406 ret = GetFileName95(&fodInfos);
414 SetCurrentDirectoryA(lpstrSavDir);
415 MemFree(lpstrSavDir);
425 MemFree(customfilter);
427 MemFree(fodInfos.initdir);
429 if(fodInfos.filename)
430 MemFree(fodInfos.filename);
432 TRACE("selected file: %s\n",ofn->lpstrFile);
437 /***********************************************************************
440 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
441 * Call GetFileName95 with this structure and clean the memory.
444 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
447 FileOpenDlgInfos fodInfos;
448 LPWSTR lpstrSavDir = NULL;
450 /* Initialize FileOpenDlgInfos structure */
451 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
453 /* Pass in the original ofn */
454 fodInfos.ofnInfos = ofn;
456 fodInfos.title = ofn->lpstrTitle;
457 fodInfos.defext = ofn->lpstrDefExt;
458 fodInfos.filter = ofn->lpstrFilter;
459 fodInfos.customfilter = ofn->lpstrCustomFilter;
461 /* convert string arguments, save others */
464 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
465 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
468 fodInfos.filename = NULL;
470 if(ofn->lpstrInitialDir)
472 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
473 DWORD len = strlenW(ofn->lpstrInitialDir)+1;
474 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
475 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
478 fodInfos.initdir = NULL;
480 /* save current directory */
481 if (ofn->Flags & OFN_NOCHANGEDIR)
483 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
484 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
487 fodInfos.unicode = TRUE;
492 ret = GetFileName95(&fodInfos);
495 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
496 ret = GetFileName95(&fodInfos);
504 SetCurrentDirectoryW(lpstrSavDir);
505 MemFree(lpstrSavDir);
508 /* restore saved IN arguments and convert OUT arguments back */
509 MemFree(fodInfos.filename);
510 MemFree(fodInfos.initdir);
514 /***********************************************************************
515 * ArrangeCtrlPositions [internal]
517 * NOTE: Do not change anything here without a lot of testing.
519 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
521 HWND hwndChild, hwndStc32;
522 RECT rectParent, rectChild, rectStc32;
523 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
525 /* Take into account if open as read only checkbox and help button
530 RECT rectHelp, rectCancel;
531 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
532 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
533 /* subtract the height of the help button plus the space between
534 * the help button and the cancel button to the height of the dialog
536 help_fixup = rectHelp.bottom - rectCancel.bottom;
540 There are two possibilities to add components to the default file dialog box.
542 By default, all the new components are added below the standard dialog box (the else case).
544 However, if there is a static text component with the stc32 id, a special case happens.
545 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
546 in the window and the cx and cy indicate how to size the window.
547 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
548 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
552 GetClientRect(hwndParentDlg, &rectParent);
554 /* when arranging controls we have to use fixed parent size */
555 rectParent.bottom -= help_fixup;
557 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
560 GetWindowRect(hwndStc32, &rectStc32);
561 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
563 /* set the size of the stc32 control according to the size of
564 * client area of the parent dialog
566 SetWindowPos(hwndStc32, 0,
568 rectParent.right, rectParent.bottom,
569 SWP_NOMOVE | SWP_NOZORDER);
572 SetRectEmpty(&rectStc32);
574 /* this part moves controls of the child dialog */
575 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
578 if (hwndChild != hwndStc32)
580 GetWindowRect(hwndChild, &rectChild);
581 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
583 /* move only if stc32 exist */
584 if (hwndStc32 && rectChild.left > rectStc32.right)
586 LONG old_left = rectChild.left;
588 /* move to the right of visible controls of the parent dialog */
589 rectChild.left += rectParent.right;
590 rectChild.left -= rectStc32.right;
592 child_width_fixup = rectChild.left - old_left;
594 /* move even if stc32 doesn't exist */
595 if (rectChild.top >= rectStc32.bottom)
597 LONG old_top = rectChild.top;
599 /* move below visible controls of the parent dialog */
600 rectChild.top += rectParent.bottom;
601 rectChild.top -= rectStc32.bottom - rectStc32.top;
603 child_height_fixup = rectChild.top - old_top;
606 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
607 0, 0, SWP_NOSIZE | SWP_NOZORDER);
609 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
612 /* this part moves controls of the parent dialog */
613 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
616 if (hwndChild != hwndChildDlg)
618 GetWindowRect(hwndChild, &rectChild);
619 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
621 /* left,top of stc32 marks the position of controls
622 * from the parent dialog
624 rectChild.left += rectStc32.left;
625 rectChild.top += rectStc32.top;
627 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
628 0, 0, SWP_NOSIZE | SWP_NOZORDER);
630 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
633 /* calculate the size of the resulting dialog */
635 /* here we have to use original parent size */
636 GetClientRect(hwndParentDlg, &rectParent);
637 GetClientRect(hwndChildDlg, &rectChild);
641 rectChild.right += child_width_fixup;
642 rectChild.bottom += child_height_fixup;
644 if (rectParent.right > rectChild.right)
646 rectParent.right += rectChild.right;
647 rectParent.right -= rectStc32.right - rectStc32.left;
651 rectParent.right = rectChild.right;
654 if (rectParent.bottom > rectChild.bottom)
656 rectParent.bottom += rectChild.bottom;
657 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
661 /* child dialog is higher, unconditionally set new dialog
662 * height to its size (help_fixup will be subtracted below)
664 rectParent.bottom = rectChild.bottom + help_fixup;
669 rectParent.bottom += rectChild.bottom;
672 /* finally use fixed parent size */
673 rectParent.bottom -= help_fixup;
675 /* save the size of the parent's client area */
676 rectChild.right = rectParent.right;
677 rectChild.bottom = rectParent.bottom;
679 /* set the size of the parent dialog */
680 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
681 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
682 SetWindowPos(hwndParentDlg, 0,
684 rectParent.right - rectParent.left,
685 rectParent.bottom - rectParent.top,
686 SWP_NOMOVE | SWP_NOZORDER);
688 /* set the size of the child dialog */
689 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
690 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
693 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
702 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
712 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
713 * structure's hInstance parameter is not a HINSTANCE, but
714 * instead a pointer to a template resource to use.
716 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
719 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
722 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
724 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
730 hinst = fodInfos->ofnInfos->hInstance;
731 if(fodInfos->unicode)
733 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
734 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
738 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
739 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
743 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
746 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
747 !(template = LockResource( hDlgTmpl )))
749 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
753 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
754 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
755 (LPARAM)fodInfos->ofnInfos);
758 ShowWindow(hChildDlg,SW_SHOW);
762 else if( IsHooked(fodInfos))
767 WORD menu,class,title;
769 GetClientRect(hwnd,&rectHwnd);
770 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
771 temp.tmplate.dwExtendedStyle = 0;
772 temp.tmplate.cdit = 0;
777 temp.menu = temp.class = temp.title = 0;
779 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
780 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
787 /***********************************************************************
788 * SendCustomDlgNotificationMessage
790 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
793 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
795 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
797 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
799 if(!fodInfos) return 0;
801 if(fodInfos->DlgInfos.hwndCustomDlg)
804 TRACE("CALL NOTIFY for %x\n", uCode);
805 if(fodInfos->unicode)
808 ofnNotify.hdr.hwndFrom=hwndParentDlg;
809 ofnNotify.hdr.idFrom=0;
810 ofnNotify.hdr.code = uCode;
811 ofnNotify.lpOFN = fodInfos->ofnInfos;
812 ofnNotify.pszFile = NULL;
813 ret = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
818 ofnNotify.hdr.hwndFrom=hwndParentDlg;
819 ofnNotify.hdr.idFrom=0;
820 ofnNotify.hdr.code = uCode;
821 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
822 ofnNotify.pszFile = NULL;
823 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
825 TRACE("RET NOTIFY\n");
831 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
833 UINT sizeUsed = 0, n, total;
834 LPWSTR lpstrFileList = NULL;
835 WCHAR lpstrCurrentDir[MAX_PATH];
836 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
838 TRACE("CDM_GETFILEPATH:\n");
840 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
843 /* get path and filenames */
844 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
845 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
847 TRACE("path >%s< filespec >%s< %d files\n",
848 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
850 if( fodInfos->unicode )
852 LPWSTR bufW = buffer;
853 total = strlenW(lpstrCurrentDir) + 1 + sizeUsed;
855 /* Prepend the current path */
856 n = strlenW(lpstrCurrentDir) + 1;
857 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
860 /* 'n' includes trailing \0 */
862 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
864 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
869 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
870 NULL, 0, NULL, NULL);
871 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
872 NULL, 0, NULL, NULL);
874 /* Prepend the current path */
875 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
876 bufA, size, NULL, NULL);
880 /* 'n' includes trailing \0 */
882 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
883 &bufA[n], size-n, NULL, NULL);
886 TRACE("returned -> %s\n",debugstr_an(bufA, total));
888 MemFree(lpstrFileList);
893 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
896 LPWSTR lpstrFileList = NULL;
897 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
899 TRACE("CDM_GETSPEC:\n");
901 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
902 if( fodInfos->unicode )
904 LPWSTR bufW = buffer;
905 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
910 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
911 NULL, 0, NULL, NULL);
912 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
913 bufA, size, NULL, NULL);
915 MemFree(lpstrFileList);
920 /***********************************************************************
921 * FILEDLG95_HandleCustomDialogMessages
923 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
925 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
927 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
928 if(!fodInfos) return -1;
932 case CDM_GETFILEPATH:
933 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
935 case CDM_GETFOLDERPATH:
936 TRACE("CDM_GETFOLDERPATH:\n");
937 if( fodInfos->unicode )
939 WCHAR lpstrPath[MAX_PATH], *bufW = (LPWSTR)lParam;
940 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
942 lstrcpynW(bufW,lpstrPath,(int)wParam);
943 return strlenW(lpstrPath);
947 char lpstrPath[MAX_PATH], *bufA = (LPSTR)lParam;
948 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
950 lstrcpynA(bufA,lpstrPath,(int)wParam);
951 return strlen(lpstrPath);
955 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
957 case CDM_SETCONTROLTEXT:
958 TRACE("CDM_SETCONTROLTEXT:\n");
961 if( fodInfos->unicode )
962 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
964 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
968 case CDM_HIDECONTROL:
970 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
976 /***********************************************************************
979 * File open dialog procedure
981 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
984 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
991 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
993 /* Adds the FileOpenDlgInfos in the property list of the dialog
994 so it will be easily accessible through a GetPropA(...) */
995 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
997 fodInfos->DlgInfos.hwndCustomDlg =
998 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1000 FILEDLG95_InitControls(hwnd);
1002 if (fodInfos->DlgInfos.hwndCustomDlg)
1003 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1004 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1006 FILEDLG95_FillControls(hwnd, wParam, lParam);
1008 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1009 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1010 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1014 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1017 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1020 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1026 case WM_GETISHELLBROWSER:
1027 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1030 RemovePropA(hwnd, FileOpenDlgInfosStr);
1035 LPNMHDR lpnmh = (LPNMHDR)lParam;
1038 /* set up the button tooltips strings */
1039 if(TTN_GETDISPINFOA == lpnmh->code )
1041 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1042 switch(lpnmh->idFrom )
1044 /* Up folder button */
1045 case FCIDM_TB_UPFOLDER:
1046 stringId = IDS_UPFOLDER;
1048 /* New folder button */
1049 case FCIDM_TB_NEWFOLDER:
1050 stringId = IDS_NEWFOLDER;
1052 /* List option button */
1053 case FCIDM_TB_SMALLICON:
1054 stringId = IDS_LISTVIEW;
1056 /* Details option button */
1057 case FCIDM_TB_REPORTVIEW:
1058 stringId = IDS_REPORTVIEW;
1060 /* Desktop button */
1061 case FCIDM_TB_DESKTOP:
1062 stringId = IDS_TODESKTOP;
1067 lpdi->hinst = COMDLG32_hInstance;
1068 lpdi->lpszText = (LPSTR) stringId;
1073 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1074 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1079 /***********************************************************************
1080 * FILEDLG95_InitControls
1082 * WM_INITDIALOG message handler (before hook notification)
1084 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1086 int win2000plus = 0;
1088 int handledPath = FALSE;
1089 OSVERSIONINFOA osVi;
1090 static const WCHAR szwSlash[] = { '\\', 0 };
1091 static const WCHAR szwStar[] = { '*',0 };
1095 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1096 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1097 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1098 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1099 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1100 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1101 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1102 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1103 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1108 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1110 tba[0].hInst = HINST_COMMCTRL;
1111 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1112 tba[1].hInst = COMDLG32_hInstance;
1115 TRACE("%p\n", fodInfos);
1117 /* Get windows version emulating */
1118 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1119 GetVersionExA(&osVi);
1120 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1121 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1122 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1123 win2000plus = (osVi.dwMajorVersion > 4);
1124 if (win2000plus) win98plus = TRUE;
1126 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1128 /* Get the hwnd of the controls */
1129 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1130 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1131 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1133 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1134 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1136 /* construct the toolbar */
1137 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1138 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1140 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1141 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1142 rectTB.left = rectlook.right;
1143 rectTB.top = rectlook.top-1;
1145 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1146 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1147 rectTB.left, rectTB.top,
1148 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1149 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1151 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1153 /* FIXME: use TB_LOADIMAGES when implemented */
1154 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1155 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1156 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1158 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1159 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1161 /* Set the window text with the text specified in the OPENFILENAME structure */
1164 SetWindowTextW(hwnd,fodInfos->title);
1166 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1169 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1170 SetWindowTextW(hwnd, buf);
1173 /* Initialise the file name edit control */
1174 handledPath = FALSE;
1175 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1177 if(fodInfos->filename)
1179 /* 1. If win2000 or higher and filename contains a path, use it
1180 in preference over the lpstrInitialDir */
1181 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1182 WCHAR tmpBuf[MAX_PATH];
1186 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1189 /* nameBit is always shorter than the original filename */
1190 strcpyW(fodInfos->filename,nameBit);
1193 if (fodInfos->initdir == NULL)
1194 MemFree(fodInfos->initdir);
1195 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1196 strcpyW(fodInfos->initdir, tmpBuf);
1198 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1199 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1201 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1204 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1208 /* 2. (All platforms) If initdir is not null, then use it */
1209 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1210 (*fodInfos->initdir!=0x00))
1212 /* Work out the proper path as supplied one might be relative */
1213 /* (Here because supplying '.' as dir browses to My Computer) */
1214 if (handledPath==FALSE) {
1215 WCHAR tmpBuf[MAX_PATH];
1216 WCHAR tmpBuf2[MAX_PATH];
1220 strcpyW(tmpBuf, fodInfos->initdir);
1221 if( PathFileExistsW(tmpBuf) ) {
1222 /* initdir does not have to be a directory. If a file is
1223 * specified, the dir part is taken */
1224 if( PathIsDirectoryW(tmpBuf)) {
1225 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1226 strcatW(tmpBuf, szwSlash);
1228 strcatW(tmpBuf, szwStar);
1230 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1233 if (fodInfos->initdir)
1234 MemFree(fodInfos->initdir);
1235 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1236 strcpyW(fodInfos->initdir, tmpBuf2);
1238 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1241 else if (fodInfos->initdir)
1243 MemFree(fodInfos->initdir);
1244 fodInfos->initdir = NULL;
1245 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1250 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1251 (*fodInfos->initdir==0x00)))
1253 /* 3. All except w2k+: if filename contains a path use it */
1254 if (!win2000plus && fodInfos->filename &&
1255 *fodInfos->filename &&
1256 strpbrkW(fodInfos->filename, szwSlash)) {
1257 WCHAR tmpBuf[MAX_PATH];
1261 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1266 /* nameBit is always shorter than the original filename */
1267 strcpyW(fodInfos->filename, nameBit);
1270 len = strlenW(tmpBuf);
1271 if(fodInfos->initdir)
1272 MemFree(fodInfos->initdir);
1273 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1274 strcpyW(fodInfos->initdir, tmpBuf);
1277 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1278 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1280 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1283 /* 4. win98+ and win2000+ if any files of specified filter types in
1284 current directory, use it */
1285 if ( win98plus && handledPath == FALSE &&
1286 fodInfos->filter && *fodInfos->filter) {
1288 BOOL searchMore = TRUE;
1289 LPCWSTR lpstrPos = fodInfos->filter;
1290 WIN32_FIND_DATAW FindFileData;
1295 /* filter is a list... title\0ext\0......\0\0 */
1297 /* Skip the title */
1298 if(! *lpstrPos) break; /* end */
1299 lpstrPos += strlenW(lpstrPos) + 1;
1301 /* See if any files exist in the current dir with this extension */
1302 if(! *lpstrPos) break; /* end */
1304 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1306 if (hFind == INVALID_HANDLE_VALUE) {
1307 /* None found - continue search */
1308 lpstrPos += strlenW(lpstrPos) + 1;
1313 if(fodInfos->initdir)
1314 MemFree(fodInfos->initdir);
1315 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1316 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1319 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1320 debugstr_w(lpstrPos));
1326 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1328 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1329 if (handledPath == FALSE && (win2000plus || win98plus)) {
1330 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1332 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1334 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1337 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1338 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1340 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1343 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1346 } else if (handledPath==FALSE) {
1347 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1348 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1350 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1353 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1354 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1356 /* Must the open as read only check box be checked ?*/
1357 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1359 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1362 /* Must the open as read only check box be hidden? */
1363 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1365 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1366 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1369 /* Must the help button be hidden? */
1370 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1372 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1373 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1376 /* Resize the height, if open as read only checkbox ad help button
1377 are hidden and we are not using a custom template nor a customDialog
1379 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1380 (!(fodInfos->ofnInfos->Flags &
1381 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1382 (!fodInfos->DlgInfos.hwndCustomDlg ))
1384 RECT rectDlg, rectHelp, rectCancel;
1385 GetWindowRect(hwnd, &rectDlg);
1386 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1387 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1388 /* subtract the height of the help button plus the space between
1389 the help button and the cancel button to the height of the dialog */
1390 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1391 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1392 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1394 /* change Open to Save */
1395 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1398 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1399 SetDlgItemTextW(hwnd, IDOK, buf);
1400 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1401 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1406 /***********************************************************************
1407 * FILEDLG95_FillControls
1409 * WM_INITDIALOG message handler (after hook notification)
1411 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1413 LPITEMIDLIST pidlItemId = NULL;
1415 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1417 TRACE("dir=%s file=%s\n",
1418 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1420 /* Get the initial directory pidl */
1422 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1424 WCHAR path[MAX_PATH];
1426 GetCurrentDirectoryW(MAX_PATH,path);
1427 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1430 /* Initialise shell objects */
1431 FILEDLG95_SHELL_Init(hwnd);
1433 /* Initialize the Look In combo box */
1434 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1436 /* Initialize the filter combo box */
1437 FILEDLG95_FILETYPE_Init(hwnd);
1439 /* Browse to the initial directory */
1440 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1442 /* Free pidlItem memory */
1443 COMDLG32_SHFree(pidlItemId);
1447 /***********************************************************************
1450 * Regroups all the cleaning functions of the filedlg
1452 void FILEDLG95_Clean(HWND hwnd)
1454 FILEDLG95_FILETYPE_Clean(hwnd);
1455 FILEDLG95_LOOKIN_Clean(hwnd);
1456 FILEDLG95_SHELL_Clean(hwnd);
1458 /***********************************************************************
1459 * FILEDLG95_OnWMCommand
1461 * WM_COMMAND message handler
1463 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1465 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1466 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1467 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1473 FILEDLG95_OnOpen(hwnd);
1477 FILEDLG95_Clean(hwnd);
1478 EndDialog(hwnd, FALSE);
1480 /* Filetype combo box */
1482 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1484 /* LookIn combo box */
1486 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1489 /* --- toolbar --- */
1490 /* Up folder button */
1491 case FCIDM_TB_UPFOLDER:
1492 FILEDLG95_SHELL_UpFolder(hwnd);
1494 /* New folder button */
1495 case FCIDM_TB_NEWFOLDER:
1496 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1498 /* List option button */
1499 case FCIDM_TB_SMALLICON:
1500 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1502 /* Details option button */
1503 case FCIDM_TB_REPORTVIEW:
1504 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1506 /* Details option button */
1507 case FCIDM_TB_DESKTOP:
1508 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1515 /* Do not use the listview selection anymore */
1516 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1520 /***********************************************************************
1521 * FILEDLG95_OnWMGetIShellBrowser
1523 * WM_GETISHELLBROWSER message handler
1525 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1528 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1532 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1538 /***********************************************************************
1539 * FILEDLG95_SendFileOK
1541 * Sends the CDN_FILEOK notification if required
1544 * TRUE if the dialog should close
1545 * FALSE if the dialog should not be closed
1547 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1549 /* ask the hook if we can close */
1550 if(IsHooked(fodInfos))
1553 /* First send CDN_FILEOK as MSDN doc says */
1554 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1555 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1557 TRACE("canceled\n");
1561 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1562 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1563 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1564 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1566 TRACE("canceled\n");
1573 /***********************************************************************
1574 * FILEDLG95_OnOpenMultipleFiles
1576 * Handles the opening of multiple files.
1579 * check destination buffer size
1581 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1583 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1584 UINT nCount, nSizePath;
1585 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1589 if(fodInfos->unicode)
1591 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1592 ofn->lpstrFile[0] = '\0';
1596 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1597 ofn->lpstrFile[0] = '\0';
1600 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1602 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1603 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1604 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1606 LPWSTR lpstrTemp = lpstrFileList;
1608 for ( nCount = 0; nCount < nFileCount; nCount++ )
1612 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1615 WCHAR lpstrNotFound[100];
1616 WCHAR lpstrMsg[100];
1618 static const WCHAR nl[] = {'\n',0};
1620 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1621 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1623 strcpyW(tmp, lpstrTemp);
1625 strcatW(tmp, lpstrNotFound);
1627 strcatW(tmp, lpstrMsg);
1629 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1633 /* move to the next file in the list of files */
1634 lpstrTemp += strlenW(lpstrTemp) + 1;
1635 COMDLG32_SHFree(pidl);
1639 nSizePath = strlenW(lpstrPathSpec) + 1;
1640 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1642 /* For "oldstyle" dialog the components have to
1643 be separated by blanks (not '\0'!) and short
1644 filenames have to be used! */
1645 FIXME("Components have to be separated by blanks\n");
1647 if(fodInfos->unicode)
1649 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1650 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1651 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1655 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1657 if (ofn->lpstrFile != NULL)
1659 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1660 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1661 if (ofn->nMaxFile > nSizePath)
1663 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1664 ofn->lpstrFile + nSizePath,
1665 ofn->nMaxFile - nSizePath, NULL, NULL);
1670 fodInfos->ofnInfos->nFileOffset = nSizePath;
1671 fodInfos->ofnInfos->nFileExtension = 0;
1673 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1676 /* clean and exit */
1677 FILEDLG95_Clean(hwnd);
1678 return EndDialog(hwnd,TRUE);
1681 /***********************************************************************
1684 * Ok button WM_COMMAND message handler
1686 * If the function succeeds, the return value is nonzero.
1688 #define ONOPEN_BROWSE 1
1689 #define ONOPEN_OPEN 2
1690 #define ONOPEN_SEARCH 3
1691 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1693 WCHAR strMsgTitle[MAX_PATH];
1694 WCHAR strMsgText [MAX_PATH];
1696 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1698 strMsgTitle[0] = '\0';
1699 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1700 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1703 BOOL FILEDLG95_OnOpen(HWND hwnd)
1705 LPWSTR lpstrFileList;
1706 UINT nFileCount = 0;
1709 WCHAR lpstrPathAndFile[MAX_PATH];
1710 WCHAR lpstrTemp[MAX_PATH];
1711 LPSHELLFOLDER lpsf = NULL;
1713 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1715 TRACE("hwnd=%p\n", hwnd);
1717 /* get the files from the edit control */
1718 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1720 /* try if the user selected a folder in the shellview */
1723 BrowseSelectedFolder(hwnd);
1729 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1733 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1736 Step 1: Build a complete path name from the current folder and
1737 the filename or path in the edit box.
1739 - the path in the edit box is a root path
1740 (with or without drive letter)
1741 - the edit box contains ".." (or a path with ".." in it)
1744 /* Get the current directory name */
1745 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1747 /* we are in a special folder, default to desktop */
1748 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1751 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1754 PathAddBackslashW(lpstrPathAndFile);
1756 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1758 /* if the user specifyed a fully qualified path use it */
1759 if(PathIsRelativeW(lpstrFileList))
1761 strcatW(lpstrPathAndFile, lpstrFileList);
1765 /* does the path have a drive letter? */
1766 if (PathGetDriveNumberW(lpstrFileList) == -1)
1767 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1769 strcpyW(lpstrPathAndFile, lpstrFileList);
1772 /* resolve "." and ".." */
1773 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1774 strcpyW(lpstrPathAndFile, lpstrTemp);
1775 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1777 MemFree(lpstrFileList);
1780 Step 2: here we have a cleaned up path
1782 We have to parse the path step by step to see if we have to browse
1783 to a folder if the path points to a directory or the last
1784 valid element is a directory.
1787 lpstrPathAndFile: cleaned up path
1790 nOpenAction = ONOPEN_BROWSE;
1792 /* don't apply any checks with OFN_NOVALIDATE */
1794 LPWSTR lpszTemp, lpszTemp1;
1795 LPITEMIDLIST pidl = NULL;
1796 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1798 /* check for invalid chars */
1799 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1801 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1806 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1808 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1811 LPSHELLFOLDER lpsfChild;
1812 WCHAR lpwstrTemp[MAX_PATH];
1813 DWORD dwEaten, dwAttributes;
1816 strcpyW(lpwstrTemp, lpszTemp);
1817 p = PathFindNextComponentW(lpwstrTemp);
1819 if (!p) break; /* end of path */
1822 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1826 static const WCHAR wszWild[] = { '*', '?', 0 };
1827 /* if the last element is a wildcard do a search */
1828 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1830 nOpenAction = ONOPEN_SEARCH;
1834 lpszTemp1 = lpszTemp;
1836 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1838 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1840 dwAttributes = SFGAO_FOLDER;
1841 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1843 /* the path component is valid, we have a pidl of the next path component */
1844 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1845 if(dwAttributes & SFGAO_FOLDER)
1847 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1849 ERR("bind to failed\n"); /* should not fail */
1852 IShellFolder_Release(lpsf);
1860 /* end dialog, return value */
1861 nOpenAction = ONOPEN_OPEN;
1864 COMDLG32_SHFree(pidl);
1867 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1869 if(*lpszTemp) /* points to trailing null for last path element */
1871 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1873 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1879 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1880 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1882 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1886 /* change to the current folder */
1887 nOpenAction = ONOPEN_OPEN;
1892 nOpenAction = ONOPEN_OPEN;
1896 if(pidl) COMDLG32_SHFree(pidl);
1900 Step 3: here we have a cleaned up and validated path
1903 lpsf: ShellFolder bound to the rightmost valid path component
1904 lpstrPathAndFile: cleaned up path
1905 nOpenAction: action to do
1907 TRACE("end validate sf=%p\n", lpsf);
1911 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1912 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1915 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1918 /* replace the current filter */
1919 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1920 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1921 len = strlenW(lpszTemp)+1;
1922 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1923 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1925 /* set the filter cb to the extension when possible */
1926 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1927 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1930 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1931 TRACE("ONOPEN_BROWSE\n");
1933 IPersistFolder2 * ppf2;
1934 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1936 LPITEMIDLIST pidlCurrent;
1937 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1938 IPersistFolder2_Release(ppf2);
1939 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1941 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1943 else if( nOpenAction == ONOPEN_SEARCH )
1945 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1947 COMDLG32_SHFree(pidlCurrent);
1952 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1953 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1957 /* update READONLY check box flag */
1958 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1959 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1961 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1963 /* Attach the file extension with file name*/
1964 ext = PathFindExtensionW(lpstrPathAndFile);
1967 /* if no extension is specified with file name, then */
1968 /* attach the extension from file filter or default one */
1970 WCHAR *filterExt = NULL;
1971 LPWSTR lpstrFilter = NULL;
1972 static const WCHAR szwDot[] = {'.',0};
1973 int PathLength = strlenW(lpstrPathAndFile);
1976 strcatW(lpstrPathAndFile, szwDot);
1978 /*Get the file extension from file type filter*/
1979 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1980 fodInfos->ofnInfos->nFilterIndex-1);
1982 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
1983 filterExt = PathFindExtensionW(lpstrFilter);
1985 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
1986 strcatW(lpstrPathAndFile, filterExt + 1);
1987 else if ( fodInfos->defext ) /* attach the default file extension*/
1988 strcatW(lpstrPathAndFile, fodInfos->defext);
1990 /* In Open dialog: if file does not exist try without extension */
1991 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
1992 lpstrPathAndFile[PathLength] = '\0';
1995 if (fodInfos->defext) /* add default extension */
1997 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2000 if (!lstrcmpiW(fodInfos->defext, ext))
2001 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2003 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2006 /* In Save dialog: check if the file already exists */
2007 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2008 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2009 && PathFileExistsW(lpstrPathAndFile))
2011 WCHAR lpstrOverwrite[100];
2014 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2015 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2016 MB_YESNO | MB_ICONEXCLAMATION);
2024 /* Check that the size of the file does not exceed buffer size.
2025 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2026 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2027 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2031 /* fill destination buffer */
2032 if (fodInfos->ofnInfos->lpstrFile)
2034 if(fodInfos->unicode)
2036 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2038 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2039 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2040 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2044 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2046 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2047 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2048 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2049 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2053 /* set filename offset */
2054 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2055 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2057 /* set extension offset */
2058 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2059 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2061 /* set the lpstrFileTitle */
2062 if(fodInfos->ofnInfos->lpstrFileTitle)
2064 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2065 if(fodInfos->unicode)
2067 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2068 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2072 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2073 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2074 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2078 /* copy currently selected filter to lpstrCustomFilter */
2079 if (fodInfos->ofnInfos->lpstrCustomFilter)
2081 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2082 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2083 NULL, 0, NULL, NULL);
2084 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2086 LPSTR s = ofn->lpstrCustomFilter;
2087 s += strlen(ofn->lpstrCustomFilter)+1;
2088 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2089 s, len, NULL, NULL);
2094 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2098 FILEDLG95_Clean(hwnd);
2099 ret = EndDialog(hwnd, TRUE);
2105 size = strlenW(lpstrPathAndFile) + 1;
2106 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2108 /* return needed size in first two bytes of lpstrFile */
2109 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2110 FILEDLG95_Clean(hwnd);
2111 ret = EndDialog(hwnd, FALSE);
2112 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2120 if(lpsf) IShellFolder_Release(lpsf);
2124 /***********************************************************************
2125 * FILEDLG95_SHELL_Init
2127 * Initialisation of the shell objects
2129 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2131 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2136 * Initialisation of the FileOpenDialogInfos structure
2142 fodInfos->ShellInfos.hwndOwner = hwnd;
2144 /* Disable multi-select if flag not set */
2145 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2147 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2149 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2150 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2152 /* Construct the IShellBrowser interface */
2153 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2158 /***********************************************************************
2159 * FILEDLG95_SHELL_ExecuteCommand
2161 * Change the folder option and refresh the view
2162 * If the function succeeds, the return value is nonzero.
2164 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2166 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2169 TRACE("(%p,%p)\n", hwnd, lpVerb);
2171 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2176 CMINVOKECOMMANDINFO ci;
2177 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2178 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2182 IContextMenu_InvokeCommand(pcm, &ci);
2183 IContextMenu_Release(pcm);
2189 /***********************************************************************
2190 * FILEDLG95_SHELL_UpFolder
2192 * Browse to the specified object
2193 * If the function succeeds, the return value is nonzero.
2195 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2197 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2201 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2210 /***********************************************************************
2211 * FILEDLG95_SHELL_BrowseToDesktop
2213 * Browse to the Desktop
2214 * If the function succeeds, the return value is nonzero.
2216 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2218 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2224 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2225 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2226 COMDLG32_SHFree(pidl);
2227 return SUCCEEDED(hres);
2229 /***********************************************************************
2230 * FILEDLG95_SHELL_Clean
2232 * Cleans the memory used by shell objects
2234 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2236 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2240 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2242 /* clean Shell interfaces */
2243 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2244 IShellView_Release(fodInfos->Shell.FOIShellView);
2245 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2246 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2247 if (fodInfos->Shell.FOIDataObject)
2248 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2251 /***********************************************************************
2252 * FILEDLG95_FILETYPE_Init
2254 * Initialisation of the file type combo box
2256 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2258 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2259 int nFilters = 0; /* number of filters */
2264 if(fodInfos->customfilter)
2266 /* customfilter has one entry... title\0ext\0
2267 * Set first entry of combo box item with customfilter
2270 LPCWSTR lpstrPos = fodInfos->customfilter;
2273 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2275 /* Copy the extensions */
2276 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2277 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2278 strcpyW(lpstrExt,lpstrPos);
2280 /* Add the item at the end of the combo */
2281 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2282 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2285 if(fodInfos->filter)
2287 LPCWSTR lpstrPos = fodInfos->filter;
2291 /* filter is a list... title\0ext\0......\0\0
2292 * Set the combo item text to the title and the item data
2295 LPCWSTR lpstrDisplay;
2299 if(! *lpstrPos) break; /* end */
2300 lpstrDisplay = lpstrPos;
2301 lpstrPos += strlenW(lpstrPos) + 1;
2303 /* Copy the extensions */
2304 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2305 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2306 strcpyW(lpstrExt,lpstrPos);
2307 lpstrPos += strlenW(lpstrPos) + 1;
2309 /* Add the item at the end of the combo */
2310 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2311 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2317 * Set the current filter to the one specified
2318 * in the initialisation structure
2320 if (fodInfos->filter || fodInfos->customfilter)
2324 /* Check to make sure our index isn't out of bounds. */
2325 if ( fodInfos->ofnInfos->nFilterIndex >
2326 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2327 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2329 /* set default filter index */
2330 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2331 fodInfos->ofnInfos->nFilterIndex = 1;
2333 /* calculate index of Combo Box item */
2334 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2335 if (fodInfos->customfilter == NULL)
2338 /* Set the current index selection. */
2339 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2341 /* Get the corresponding text string from the combo box. */
2342 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2345 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2351 CharLowerW(lpstrFilter); /* lowercase */
2352 len = strlenW(lpstrFilter)+1;
2353 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2354 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2357 fodInfos->ofnInfos->nFilterIndex = 0;
2362 /***********************************************************************
2363 * FILEDLG95_FILETYPE_OnCommand
2365 * WM_COMMAND of the file type combo box
2366 * If the function succeeds, the return value is nonzero.
2368 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2370 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2378 /* Get the current item of the filetype combo box */
2379 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2381 /* set the current filter index */
2382 fodInfos->ofnInfos->nFilterIndex = iItem +
2383 (fodInfos->customfilter == NULL ? 1 : 0);
2385 /* Set the current filter with the current selection */
2386 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2387 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2389 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2391 if((int)lpstrFilter != CB_ERR)
2394 CharLowerW(lpstrFilter); /* lowercase */
2395 len = strlenW(lpstrFilter)+1;
2396 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2397 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2398 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2401 /* Refresh the actual view to display the included items*/
2402 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2407 /***********************************************************************
2408 * FILEDLG95_FILETYPE_SearchExt
2410 * searches for an extension in the filetype box
2412 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2414 int i, iCount = CBGetCount(hwnd);
2416 TRACE("%s\n", debugstr_w(lpstrExt));
2418 if(iCount != CB_ERR)
2420 for(i=0;i<iCount;i++)
2422 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2429 /***********************************************************************
2430 * FILEDLG95_FILETYPE_Clean
2432 * Clean the memory used by the filetype combo box
2434 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2436 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2438 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2442 /* Delete each string of the combo and their associated data */
2443 if(iCount != CB_ERR)
2445 for(iPos = iCount-1;iPos>=0;iPos--)
2447 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2448 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2451 /* Current filter */
2452 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2453 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2457 /***********************************************************************
2458 * FILEDLG95_LOOKIN_Init
2460 * Initialisation of the look in combo box
2462 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2464 IShellFolder *psfRoot, *psfDrives;
2465 IEnumIDList *lpeRoot, *lpeDrives;
2466 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2468 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2472 liInfos->iMaxIndentation = 0;
2474 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2476 /* set item height for both text field and listbox */
2477 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2478 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2480 /* Turn on the extended UI for the combo box like Windows does */
2481 CBSetExtendedUI(hwndCombo, TRUE);
2483 /* Initialise data of Desktop folder */
2484 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2485 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2486 COMDLG32_SHFree(pidlTmp);
2488 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2490 SHGetDesktopFolder(&psfRoot);
2494 /* enumerate the contents of the desktop */
2495 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2497 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2499 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2501 /* special handling for CSIDL_DRIVES */
2502 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2504 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2506 /* enumerate the drives */
2507 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2509 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2511 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2512 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2513 COMDLG32_SHFree(pidlAbsTmp);
2514 COMDLG32_SHFree(pidlTmp1);
2516 IEnumIDList_Release(lpeDrives);
2518 IShellFolder_Release(psfDrives);
2521 COMDLG32_SHFree(pidlTmp);
2523 IEnumIDList_Release(lpeRoot);
2525 IShellFolder_Release(psfRoot);
2528 COMDLG32_SHFree(pidlDrives);
2532 /***********************************************************************
2533 * FILEDLG95_LOOKIN_DrawItem
2535 * WM_DRAWITEM message handler
2537 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2539 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2540 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2541 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2545 HIMAGELIST ilItemImage;
2548 LPSFOLDER tmpFolder;
2551 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2555 if(pDIStruct->itemID == -1)
2558 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2559 pDIStruct->itemID)))
2563 if(pDIStruct->itemID == liInfos->uSelectedItem)
2565 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2568 sizeof (SHFILEINFOA),
2569 SHGFI_PIDL | SHGFI_SMALLICON |
2570 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2571 SHGFI_DISPLAYNAME );
2575 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2578 sizeof (SHFILEINFOA),
2579 SHGFI_PIDL | SHGFI_SMALLICON |
2580 SHGFI_SYSICONINDEX |
2584 /* Is this item selected ? */
2585 if(pDIStruct->itemState & ODS_SELECTED)
2587 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2588 SetBkColor(pDIStruct->hDC,crHighLight);
2589 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2593 SetTextColor(pDIStruct->hDC,crText);
2594 SetBkColor(pDIStruct->hDC,crWin);
2595 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2598 /* Do not indent item if drawing in the edit of the combo */
2599 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2602 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2605 sizeof (SHFILEINFOA),
2606 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2607 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2612 iIndentation = tmpFolder->m_iIndent;
2614 /* Draw text and icon */
2616 /* Initialise the icon display area */
2617 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2618 rectIcon.top = pDIStruct->rcItem.top;
2619 rectIcon.right = rectIcon.left + ICONWIDTH;
2620 rectIcon.bottom = pDIStruct->rcItem.bottom;
2622 /* Initialise the text display area */
2623 GetTextMetricsA(pDIStruct->hDC, &tm);
2624 rectText.left = rectIcon.right;
2626 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2627 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2629 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2631 /* Draw the icon from the image list */
2632 ImageList_Draw(ilItemImage,
2639 /* Draw the associated text */
2640 if(sfi.szDisplayName)
2641 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2647 /***********************************************************************
2648 * FILEDLG95_LOOKIN_OnCommand
2650 * LookIn combo box WM_COMMAND message handler
2651 * If the function succeeds, the return value is nonzero.
2653 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2655 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2657 TRACE("%p\n", fodInfos);
2663 LPSFOLDER tmpFolder;
2666 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2668 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2673 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2674 tmpFolder->pidlItem,
2686 /***********************************************************************
2687 * FILEDLG95_LOOKIN_AddItem
2689 * Adds an absolute pidl item to the lookin combo box
2690 * returns the index of the inserted item
2692 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2694 LPITEMIDLIST pidlNext;
2697 LookInInfos *liInfos;
2699 TRACE("%08x\n", iInsertId);
2704 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2707 tmpFolder = MemAlloc(sizeof(SFOLDER));
2708 tmpFolder->m_iIndent = 0;
2710 /* Calculate the indentation of the item in the lookin*/
2712 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2714 tmpFolder->m_iIndent++;
2717 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2719 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2720 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2722 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2723 SHGetFileInfoA((LPSTR)pidl,
2727 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2728 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2730 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2732 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2736 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2738 /* Add the item at the end of the list */
2741 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2743 /* Insert the item at the iInsertId position*/
2746 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2749 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2753 COMDLG32_SHFree( tmpFolder->pidlItem );
2754 MemFree( tmpFolder );
2759 /***********************************************************************
2760 * FILEDLG95_LOOKIN_InsertItemAfterParent
2762 * Insert an item below its parent
2764 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2767 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2772 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2776 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2779 /* Free pidlParent memory */
2780 COMDLG32_SHFree((LPVOID)pidlParent);
2782 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2785 /***********************************************************************
2786 * FILEDLG95_LOOKIN_SelectItem
2788 * Adds an absolute pidl item to the lookin combo box
2789 * returns the index of the inserted item
2791 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2794 LookInInfos *liInfos;
2798 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2800 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2804 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2805 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2810 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2811 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2815 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2817 if(iRemovedItem < iItemPos)
2822 CBSetCurSel(hwnd,iItemPos);
2823 liInfos->uSelectedItem = iItemPos;
2829 /***********************************************************************
2830 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2832 * Remove the item with an expansion level over iExpansionLevel
2834 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2838 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2842 if(liInfos->iMaxIndentation <= 2)
2845 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2847 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2848 COMDLG32_SHFree(tmpFolder->pidlItem);
2850 CBDeleteString(hwnd,iItemPos);
2851 liInfos->iMaxIndentation--;
2859 /***********************************************************************
2860 * FILEDLG95_LOOKIN_SearchItem
2862 * Search for pidl in the lookin combo box
2863 * returns the index of the found item
2865 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2868 int iCount = CBGetCount(hwnd);
2870 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2872 if (iCount != CB_ERR)
2876 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2878 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2880 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2888 /***********************************************************************
2889 * FILEDLG95_LOOKIN_Clean
2891 * Clean the memory used by the lookin combo box
2893 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2895 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2897 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2901 /* Delete each string of the combo and their associated data */
2902 if (iCount != CB_ERR)
2904 for(iPos = iCount-1;iPos>=0;iPos--)
2906 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2907 COMDLG32_SHFree(tmpFolder->pidlItem);
2909 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2913 /* LookInInfos structure */
2914 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2917 /***********************************************************************
2918 * FILEDLG95_FILENAME_FillFromSelection
2920 * fills the edit box from the cached DataObject
2922 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2924 FileOpenDlgInfos *fodInfos;
2926 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2927 char lpstrTemp[MAX_PATH];
2928 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2931 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2933 /* Count how many files we have */
2934 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2936 /* calculate the string length, count files */
2937 if (nFileSelected >= 1)
2939 nLength += 3; /* first and last quotes, trailing \0 */
2940 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2942 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2946 /* get the total length of the selected file names */
2947 lpstrTemp[0] = '\0';
2948 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2950 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2952 nLength += strlen( lpstrTemp ) + 3;
2955 COMDLG32_SHFree( pidl );
2960 /* allocate the buffer */
2961 if (nFiles <= 1) nLength = MAX_PATH;
2962 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2963 lpstrAllFile[0] = '\0';
2965 /* Generate the string for the edit control */
2968 lpstrCurrFile = lpstrAllFile;
2969 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2971 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2975 /* get the file name */
2976 lpstrTemp[0] = '\0';
2977 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2979 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2983 *lpstrCurrFile++ = '\"';
2984 strcpy( lpstrCurrFile, lpstrTemp );
2985 lpstrCurrFile += strlen( lpstrTemp );
2986 strcpy( lpstrCurrFile, "\" " );
2991 strcpy( lpstrAllFile, lpstrTemp );
2994 COMDLG32_SHFree( (LPVOID) pidl );
2997 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2999 /* Select the file name like Windows does */
3000 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
3002 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3006 /* copied from shell32 to avoid linking to it */
3007 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3012 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
3013 COMDLG32_SHFree(src->u.pOleStr);
3017 lstrcpynA((LPSTR)dest, src->u.cStr, len);
3021 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
3025 FIXME("unknown type!\n");
3028 *(LPSTR)dest = '\0';
3035 /***********************************************************************
3036 * FILEDLG95_FILENAME_GetFileNames
3038 * Copies the filenames to a delimited string list.
3039 * The delimiter is specified by the parameter 'separator',
3040 * usually either a space or a nul
3042 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3044 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3045 UINT nStrCharCount = 0; /* index in src buffer */
3046 UINT nFileIndex = 0; /* index in dest buffer */
3047 UINT nFileCount = 0; /* number of files */
3048 UINT nStrLen = 0; /* length of string in edit control */
3049 LPWSTR lpstrEdit; /* buffer for string from edit control */
3053 /* get the filenames from the edit control */
3054 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3055 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3056 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3058 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3060 /* we might get single filename without any '"',
3061 * so we need nStrLen + terminating \0 + end-of-list \0 */
3062 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3065 /* build delimited file list from filenames */
3066 while ( nStrCharCount <= nStrLen )
3068 if ( lpstrEdit[nStrCharCount]=='"' )
3071 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3073 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3077 (*lpstrFileList)[nFileIndex++] = separator;
3084 /* single, unquoted string */
3085 if ((nStrLen > 0) && (*sizeUsed == 0) )
3087 strcpyW(*lpstrFileList, lpstrEdit);
3088 nFileIndex = strlenW(lpstrEdit) + 1;
3089 (*sizeUsed) = nFileIndex;
3094 (*lpstrFileList)[nFileIndex] = '\0';
3101 #define SETDefFormatEtc(fe,cf,med) \
3103 (fe).cfFormat = cf;\
3104 (fe).dwAspect = DVASPECT_CONTENT; \
3111 * DATAOBJECT Helper functions
3114 /***********************************************************************
3115 * COMCTL32_ReleaseStgMedium
3117 * like ReleaseStgMedium from ole32
3119 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3121 if(medium.pUnkForRelease)
3123 IUnknown_Release(medium.pUnkForRelease);
3127 GlobalUnlock(medium.u.hGlobal);
3128 GlobalFree(medium.u.hGlobal);
3132 /***********************************************************************
3133 * GetPidlFromDataObject
3135 * Return pidl(s) by number from the cached DataObject
3137 * nPidlIndex=0 gets the fully qualified root path
3139 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3143 FORMATETC formatetc;
3144 LPITEMIDLIST pidl = NULL;
3146 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3148 /* Set the FORMATETC structure*/
3149 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3151 /* Get the pidls from IDataObject */
3152 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3154 LPIDA cida = GlobalLock(medium.u.hGlobal);
3155 if(nPidlIndex <= cida->cidl)
3157 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3159 COMCTL32_ReleaseStgMedium(medium);
3164 /***********************************************************************
3167 * Return the number of selected items in the DataObject.
3170 UINT GetNumSelected( IDataObject *doSelected )
3174 FORMATETC formatetc;
3176 TRACE("sv=%p\n", doSelected);
3178 if (!doSelected) return 0;
3180 /* Set the FORMATETC structure*/
3181 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3183 /* Get the pidls from IDataObject */
3184 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3186 LPIDA cida = GlobalLock(medium.u.hGlobal);
3187 retVal = cida->cidl;
3188 COMCTL32_ReleaseStgMedium(medium);
3198 /***********************************************************************
3201 * Get the pidl's display name (relative to folder) and
3202 * put it in lpstrFileName.
3204 * Return NOERROR on success,
3208 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3213 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3217 SHGetDesktopFolder(&lpsf);
3218 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3219 IShellFolder_Release(lpsf);
3223 /* Get the display name of the pidl relative to the folder */
3224 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3226 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3231 /***********************************************************************
3232 * GetShellFolderFromPidl
3234 * pidlRel is the item pidl relative
3235 * Return the IShellFolder of the absolute pidl
3237 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3239 IShellFolder *psf = NULL,*psfParent;
3241 TRACE("%p\n", pidlAbs);
3243 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3246 if(pidlAbs && pidlAbs->mkid.cb)
3248 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3250 IShellFolder_Release(psfParent);
3254 /* return the desktop */
3260 /***********************************************************************
3263 * Return the LPITEMIDLIST to the parent of the pidl in the list
3265 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3267 LPITEMIDLIST pidlParent;
3269 TRACE("%p\n", pidl);
3271 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3272 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3277 /***********************************************************************
3280 * returns the pidl of the file name relative to folder
3281 * NULL if an error occurred
3283 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3285 LPITEMIDLIST pidl = NULL;
3288 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3290 if(!lpcstrFileName) return NULL;
3291 if(!*lpcstrFileName) return NULL;
3295 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3296 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3297 IShellFolder_Release(lpsf);
3302 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3309 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3311 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3314 TRACE("%p, %p\n", psf, pidl);
3316 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3318 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3319 /* see documentation shell 4.1*/
3320 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3323 /***********************************************************************
3324 * BrowseSelectedFolder
3326 static BOOL BrowseSelectedFolder(HWND hwnd)
3328 BOOL bBrowseSelFolder = FALSE;
3329 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3333 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3335 LPITEMIDLIST pidlSelection;
3337 /* get the file selected */
3338 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3339 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3341 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3342 pidlSelection, SBSP_RELATIVE ) ) )
3344 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3345 ' ','n','o','t',' ','e','x','i','s','t',0};
3346 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3349 bBrowseSelFolder = TRUE;
3351 COMDLG32_SHFree( pidlSelection );
3354 return bBrowseSelFolder;
3358 * Memory allocation methods */
3359 static void *MemAlloc(UINT size)
3361 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3364 static void MemFree(void *mem)
3366 HeapFree(GetProcessHeap(),0,mem);
3370 * Old-style (win3.1) dialogs */
3372 /***********************************************************************
3373 * FD32_GetTemplate [internal]
3375 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3376 * by a 32 bits application
3379 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3381 LPOPENFILENAMEW ofnW = lfs->ofnW;
3382 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3385 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3387 if (!(lfs->template = LockResource( ofnW->hInstance )))
3389 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3393 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3397 hResInfo = FindResourceA(priv->ofnA->hInstance,
3398 priv->ofnA->lpTemplateName,
3401 hResInfo = FindResourceW(ofnW->hInstance,
3402 ofnW->lpTemplateName,
3406 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3409 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3411 !(lfs->template = LockResource(hDlgTmpl)))
3413 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3416 } else { /* get it from internal Wine resource */
3418 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3419 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3421 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3424 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3425 !(lfs->template = LockResource( hDlgTmpl )))
3427 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3435 /************************************************************************
3436 * FD32_Init [internal]
3437 * called from the common 16/32 code to initialize 32 bit data
3439 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3441 BOOL IsUnicode = (BOOL) data;
3444 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3445 lfs->private1632 = priv;
3446 if (NULL == lfs->private1632) return FALSE;
3449 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3450 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3451 if (lfs->ofnW->lpfnHook)
3456 priv->ofnA = (LPOPENFILENAMEA) lParam;
3457 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3458 if (priv->ofnA->lpfnHook)
3460 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3461 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3464 if (! FD32_GetTemplate(lfs)) return FALSE;
3469 /***********************************************************************
3470 * FD32_CallWindowProc [internal]
3472 * called from the common 16/32 code to call the appropriate hook
3474 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3478 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3482 TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n",
3483 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3484 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3485 TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n",
3486 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3490 TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n",
3491 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3492 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3493 TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n",
3494 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3498 /***********************************************************************
3499 * FD32_UpdateResult [internal]
3500 * update the real client structures if any
3502 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3504 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3505 LPOPENFILENAMEW ofnW = lfs->ofnW;
3509 if (ofnW->nMaxFile &&
3510 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3511 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3512 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3513 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3514 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3518 /***********************************************************************
3519 * FD32_UpdateFileTitle [internal]
3520 * update the real client structures if any
3522 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3524 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3525 LPOPENFILENAMEW ofnW = lfs->ofnW;
3529 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3530 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3531 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3536 /***********************************************************************
3537 * FD32_SendLbGetCurSel [internal]
3538 * retrieve selected listbox item
3540 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3542 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3546 /************************************************************************
3547 * FD32_Destroy [internal]
3548 * called from the common 16/32 code to cleanup 32 bit data
3550 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3552 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3554 /* if ofnW has been allocated, have to free everything in it */
3555 if (NULL != priv && NULL != priv->ofnA)
3557 FD31_FreeOfnW(lfs->ofnW);
3558 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3562 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3564 callbacks->Init = FD32_Init;
3565 callbacks->CWP = FD32_CallWindowProc;
3566 callbacks->UpdateResult = FD32_UpdateResult;
3567 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3568 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3569 callbacks->Destroy = FD32_Destroy;
3572 /***********************************************************************
3573 * FD32_WMMeasureItem [internal]
3575 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3577 LPMEASUREITEMSTRUCT lpmeasure;
3579 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3580 lpmeasure->itemHeight = FD31_GetFldrHeight();
3585 /***********************************************************************
3586 * FileOpenDlgProc [internal]
3587 * Used for open and save, in fact.
3589 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3590 WPARAM wParam, LPARAM lParam)
3592 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3594 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3595 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3598 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3600 return lRet; /* else continue message processing */
3605 return FD31_WMInitDialog(hWnd, wParam, lParam);
3607 case WM_MEASUREITEM:
3608 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3611 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3614 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3617 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3618 switch (HIWORD(lParam))
3621 SetTextColor((HDC16)wParam, 0x00000000);
3623 case CTLCOLOR_STATIC:
3624 SetTextColor((HDC16)wParam, 0x00000000);
3634 /***********************************************************************
3635 * GetFileName31A [internal]
3637 * Creates a win31 style dialog box for the user to select a file to open/save.
3639 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3640 UINT dlgType /* type dialogue : open/save */
3646 FD31_CALLBACKS callbacks;
3648 if (!lpofn || !FD31_Init()) return FALSE;
3650 TRACE("ofn flags %08lx\n", lpofn->Flags);
3651 FD32_SetupCallbacks(&callbacks);
3652 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3655 hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE );
3656 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3657 FD32_FileOpenDlgProc, (LPARAM)lfs);
3658 FD31_DestroyPrivate(lfs);
3661 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3665 /***********************************************************************
3666 * GetFileName31W [internal]
3668 * Creates a win31 style dialog box for the user to select a file to open/save
3670 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3671 UINT dlgType /* type dialogue : open/save */
3677 FD31_CALLBACKS callbacks;
3679 if (!lpofn || !FD31_Init()) return FALSE;
3681 FD32_SetupCallbacks(&callbacks);
3682 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3685 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3686 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3687 FD32_FileOpenDlgProc, (LPARAM)lfs);
3688 FD31_DestroyPrivate(lfs);
3691 TRACE("file %s, file offset %d, ext offset %d\n",
3692 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3696 /* ------------------ APIs ---------------------- */
3698 /***********************************************************************
3699 * GetOpenFileNameA (COMDLG32.@)
3701 * Creates a dialog box for the user to select a file to open.
3704 * TRUE on success: user enters a valid file
3705 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3708 BOOL WINAPI GetOpenFileNameA(
3709 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3711 BOOL win16look = FALSE;
3713 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3714 if (ofn->Flags & OFN_FILEMUSTEXIST)
3715 ofn->Flags |= OFN_PATHMUSTEXIST;
3717 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3718 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3721 return GetFileName31A(ofn, OPEN_DIALOG);
3723 return GetFileDialog95A(ofn, OPEN_DIALOG);
3726 /***********************************************************************
3727 * GetOpenFileNameW (COMDLG32.@)
3729 * Creates a dialog box for the user to select a file to open.
3732 * TRUE on success: user enters a valid file
3733 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3736 BOOL WINAPI GetOpenFileNameW(
3737 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3739 BOOL win16look = FALSE;
3741 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3742 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3745 return GetFileName31W(ofn, OPEN_DIALOG);
3747 return GetFileDialog95W(ofn, OPEN_DIALOG);
3751 /***********************************************************************
3752 * GetSaveFileNameA (COMDLG32.@)
3754 * Creates a dialog box for the user to select a file to save.
3757 * TRUE on success: user enters a valid file
3758 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3761 BOOL WINAPI GetSaveFileNameA(
3762 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3764 BOOL win16look = FALSE;
3766 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3767 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3770 return GetFileName31A(ofn, SAVE_DIALOG);
3772 return GetFileDialog95A(ofn, SAVE_DIALOG);
3775 /***********************************************************************
3776 * GetSaveFileNameW (COMDLG32.@)
3778 * Creates a dialog box for the user to select a file to save.
3781 * TRUE on success: user enters a valid file
3782 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3785 BOOL WINAPI GetSaveFileNameW(
3786 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3788 BOOL win16look = FALSE;
3790 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3791 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3794 return GetFileName31W(ofn, SAVE_DIALOG);
3796 return GetFileDialog95W(ofn, SAVE_DIALOG);