push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blob6e7f985dbc9c85796c108f5f482e76db7a6128b6
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wingdi.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "filedlg31.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlobj.h"
75 #include "filedlgbrowser.h"
76 #include "shlwapi.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
96 HIMAGELIST hImgList;
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
104 int iMaxIndentation;
105 UINT uSelectedItem;
106 } LookInInfos;
108 typedef struct tagFD32_PRIVATE
110 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
111 } FD32_PRIVATE, *PFD32_PRIVATE;
114 /***********************************************************************
115 * Defines and global variables
118 /* Draw item constant */
119 #define ICONWIDTH 18
120 #define XTEXTOFFSET 3
122 /* AddItem flags*/
123 #define LISTEND -1
125 /* SearchItem methods */
126 #define SEARCH_PIDL 1
127 #define SEARCH_EXP 2
128 #define ITEM_NOTFOUND -1
130 /* Undefined windows message sent by CreateViewObject*/
131 #define WM_GETISHELLBROWSER WM_USER+7
133 /* NOTE
134 * Those macros exist in windowsx.h. However, you can't really use them since
135 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 /* Combo box macros */
139 #define CBAddString(hwnd,str) \
140 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
142 #define CBInsertString(hwnd,str,pos) \
143 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
145 #define CBDeleteString(hwnd,pos) \
146 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
148 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
149 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
151 #define CBGetItemDataPtr(hwnd,iItemId) \
152 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
154 #define CBGetLBText(hwnd,iItemId,str) \
155 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
157 #define CBGetCurSel(hwnd) \
158 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
160 #define CBSetCurSel(hwnd,pos) \
161 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
163 #define CBGetCount(hwnd) \
164 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
165 #define CBShowDropDown(hwnd,show) \
166 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
167 #define CBSetItemHeight(hwnd,index,height) \
168 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
170 #define CBSetExtendedUI(hwnd,flag) \
171 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
173 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
174 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
176 /***********************************************************************
177 * Prototypes
180 /* Internal functions used by the dialog */
181 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
182 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
185 static BOOL FILEDLG95_OnOpen(HWND hwnd);
186 static LRESULT FILEDLG95_InitControls(HWND hwnd);
187 static void FILEDLG95_Clean(HWND hwnd);
189 /* Functions used by the shell navigation */
190 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
191 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
193 static void FILEDLG95_SHELL_Clean(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
196 /* Functions used by the EDIT box */
197 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
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 void 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 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
218 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
219 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
220 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
221 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
222 static UINT GetNumSelected( IDataObject *doSelected );
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size);
226 static void MemFree(void *mem);
228 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
231 static BOOL BrowseSelectedFolder(HWND hwnd);
233 /***********************************************************************
234 * GetFileName95
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
246 LRESULT lRes;
247 LPCVOID template;
248 HRSRC hRes;
249 HANDLE hDlgTmpl = 0;
250 HRESULT hr;
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
273 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
275 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
276 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
277 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
280 /* old style hook messages */
281 if (IsHooked(fodInfos))
283 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
284 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
285 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
286 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
289 /* Some shell namespace extensions depend on COM being initialized. */
290 hr = OleInitialize(NULL);
292 if (fodInfos->unicode)
293 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
294 template,
295 fodInfos->ofnInfos->hwndOwner,
296 FileOpenDlgProc95,
297 (LPARAM) fodInfos);
298 else
299 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
300 template,
301 fodInfos->ofnInfos->hwndOwner,
302 FileOpenDlgProc95,
303 (LPARAM) fodInfos);
304 if (SUCCEEDED(hr))
305 OleUninitialize();
307 /* Unable to create the dialog */
308 if( lRes == -1)
309 return FALSE;
311 return lRes;
314 /***********************************************************************
315 * GetFileDialog95A
317 * Call GetFileName95 with this structure and clean the memory.
319 * IN : The OPENFILENAMEA initialisation structure passed to
320 * GetOpenFileNameA win api function (see filedlg.c)
322 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
324 BOOL ret;
325 FileOpenDlgInfos fodInfos;
326 LPSTR lpstrSavDir = NULL;
327 LPWSTR title = NULL;
328 LPWSTR defext = NULL;
329 LPWSTR filter = NULL;
330 LPWSTR customfilter = NULL;
332 /* Initialize CommDlgExtendedError() */
333 COMDLG32_SetCommDlgExtendedError(0);
335 /* Initialize FileOpenDlgInfos structure */
336 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
338 /* Pass in the original ofn */
339 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
341 /* save current directory */
342 if (ofn->Flags & OFN_NOCHANGEDIR)
344 lpstrSavDir = MemAlloc(MAX_PATH);
345 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
348 fodInfos.unicode = FALSE;
350 /* convert all the input strings to unicode */
351 if(ofn->lpstrInitialDir)
353 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
354 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
355 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
357 else
358 fodInfos.initdir = NULL;
360 if(ofn->lpstrFile)
362 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
363 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
365 else
366 fodInfos.filename = NULL;
368 if(ofn->lpstrDefExt)
370 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
371 defext = MemAlloc((len+1)*sizeof(WCHAR));
372 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
374 fodInfos.defext = defext;
376 if(ofn->lpstrTitle)
378 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
379 title = MemAlloc((len+1)*sizeof(WCHAR));
380 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
382 fodInfos.title = title;
384 if (ofn->lpstrFilter)
386 LPCSTR s;
387 int n, len;
389 /* filter is a list... title\0ext\0......\0\0 */
390 s = ofn->lpstrFilter;
391 while (*s) s = s+strlen(s)+1;
392 s++;
393 n = s - ofn->lpstrFilter;
394 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
395 filter = MemAlloc(len*sizeof(WCHAR));
396 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
398 fodInfos.filter = filter;
400 /* convert lpstrCustomFilter */
401 if (ofn->lpstrCustomFilter)
403 LPCSTR s;
404 int n, len;
406 /* customfilter contains a pair of strings... title\0ext\0 */
407 s = ofn->lpstrCustomFilter;
408 if (*s) s = s+strlen(s)+1;
409 if (*s) s = s+strlen(s)+1;
410 n = s - ofn->lpstrCustomFilter;
411 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
412 customfilter = MemAlloc(len*sizeof(WCHAR));
413 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
415 fodInfos.customfilter = customfilter;
417 /* Initialize the dialog property */
418 fodInfos.DlgInfos.dwDlgProp = 0;
419 fodInfos.DlgInfos.hwndCustomDlg = NULL;
421 switch(iDlgType)
423 case OPEN_DIALOG :
424 ret = GetFileName95(&fodInfos);
425 break;
426 case SAVE_DIALOG :
427 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
428 ret = GetFileName95(&fodInfos);
429 break;
430 default :
431 ret = 0;
434 if (lpstrSavDir)
436 SetCurrentDirectoryA(lpstrSavDir);
437 MemFree(lpstrSavDir);
440 MemFree(title);
441 MemFree(defext);
442 MemFree(filter);
443 MemFree(customfilter);
444 MemFree(fodInfos.initdir);
445 MemFree(fodInfos.filename);
447 TRACE("selected file: %s\n",ofn->lpstrFile);
449 return ret;
452 /***********************************************************************
453 * GetFileDialog95W
455 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
456 * Call GetFileName95 with this structure and clean the memory.
459 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
461 BOOL ret;
462 FileOpenDlgInfos fodInfos;
463 LPWSTR lpstrSavDir = NULL;
465 /* Initialize CommDlgExtendedError() */
466 COMDLG32_SetCommDlgExtendedError(0);
468 /* Initialize FileOpenDlgInfos structure */
469 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
471 /* Pass in the original ofn */
472 fodInfos.ofnInfos = ofn;
474 fodInfos.title = ofn->lpstrTitle;
475 fodInfos.defext = ofn->lpstrDefExt;
476 fodInfos.filter = ofn->lpstrFilter;
477 fodInfos.customfilter = ofn->lpstrCustomFilter;
479 /* convert string arguments, save others */
480 if(ofn->lpstrFile)
482 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
483 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
485 else
486 fodInfos.filename = NULL;
488 if(ofn->lpstrInitialDir)
490 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
491 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
492 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
493 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
495 else
496 fodInfos.initdir = NULL;
498 /* save current directory */
499 if (ofn->Flags & OFN_NOCHANGEDIR)
501 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
502 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
505 fodInfos.unicode = TRUE;
507 switch(iDlgType)
509 case OPEN_DIALOG :
510 ret = GetFileName95(&fodInfos);
511 break;
512 case SAVE_DIALOG :
513 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
514 ret = GetFileName95(&fodInfos);
515 break;
516 default :
517 ret = 0;
520 if (lpstrSavDir)
522 SetCurrentDirectoryW(lpstrSavDir);
523 MemFree(lpstrSavDir);
526 /* restore saved IN arguments and convert OUT arguments back */
527 MemFree(fodInfos.filename);
528 MemFree(fodInfos.initdir);
529 return ret;
532 /******************************************************************************
533 * COMDLG32_GetDisplayNameOf [internal]
535 * Helper function to get the display name for a pidl.
537 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
538 LPSHELLFOLDER psfDesktop;
539 STRRET strret;
541 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
542 return FALSE;
544 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
545 IShellFolder_Release(psfDesktop);
546 return FALSE;
549 IShellFolder_Release(psfDesktop);
550 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
553 /***********************************************************************
554 * ArrangeCtrlPositions [internal]
556 * NOTE: Do not change anything here without a lot of testing.
558 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
560 HWND hwndChild, hwndStc32;
561 RECT rectParent, rectChild, rectStc32;
562 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
564 /* Take into account if open as read only checkbox and help button
565 * are hidden
567 if (hide_help)
569 RECT rectHelp, rectCancel;
570 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
571 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
572 /* subtract the height of the help button plus the space between
573 * the help button and the cancel button to the height of the dialog
575 help_fixup = rectHelp.bottom - rectCancel.bottom;
579 There are two possibilities to add components to the default file dialog box.
581 By default, all the new components are added below the standard dialog box (the else case).
583 However, if there is a static text component with the stc32 id, a special case happens.
584 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
585 in the window and the cx and cy indicate how to size the window.
586 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
587 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
591 GetClientRect(hwndParentDlg, &rectParent);
593 /* when arranging controls we have to use fixed parent size */
594 rectParent.bottom -= help_fixup;
596 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
597 if (hwndStc32)
599 GetWindowRect(hwndStc32, &rectStc32);
600 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
602 /* set the size of the stc32 control according to the size of
603 * client area of the parent dialog
605 SetWindowPos(hwndStc32, 0,
606 0, 0,
607 rectParent.right, rectParent.bottom,
608 SWP_NOMOVE | SWP_NOZORDER);
610 else
611 SetRectEmpty(&rectStc32);
613 /* this part moves controls of the child dialog */
614 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
615 while (hwndChild)
617 if (hwndChild != hwndStc32)
619 GetWindowRect(hwndChild, &rectChild);
620 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
622 /* move only if stc32 exist */
623 if (hwndStc32 && rectChild.left > rectStc32.right)
625 LONG old_left = rectChild.left;
627 /* move to the right of visible controls of the parent dialog */
628 rectChild.left += rectParent.right;
629 rectChild.left -= rectStc32.right;
631 child_width_fixup = rectChild.left - old_left;
633 /* move even if stc32 doesn't exist */
634 if (rectChild.top >= rectStc32.bottom)
636 LONG old_top = rectChild.top;
638 /* move below visible controls of the parent dialog */
639 rectChild.top += rectParent.bottom;
640 rectChild.top -= rectStc32.bottom - rectStc32.top;
642 child_height_fixup = rectChild.top - old_top;
645 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
646 0, 0, SWP_NOSIZE | SWP_NOZORDER);
648 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
651 /* this part moves controls of the parent dialog */
652 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
653 while (hwndChild)
655 if (hwndChild != hwndChildDlg)
657 GetWindowRect(hwndChild, &rectChild);
658 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
660 /* left,top of stc32 marks the position of controls
661 * from the parent dialog
663 rectChild.left += rectStc32.left;
664 rectChild.top += rectStc32.top;
666 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
667 0, 0, SWP_NOSIZE | SWP_NOZORDER);
669 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
672 /* calculate the size of the resulting dialog */
674 /* here we have to use original parent size */
675 GetClientRect(hwndParentDlg, &rectParent);
676 GetClientRect(hwndChildDlg, &rectChild);
678 if (hwndStc32)
680 rectChild.right += child_width_fixup;
681 rectChild.bottom += child_height_fixup;
683 if (rectParent.right > rectChild.right)
685 rectParent.right += rectChild.right;
686 rectParent.right -= rectStc32.right - rectStc32.left;
688 else
690 rectParent.right = rectChild.right;
693 if (rectParent.bottom > rectChild.bottom)
695 rectParent.bottom += rectChild.bottom;
696 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
698 else
700 /* child dialog is higher, unconditionally set new dialog
701 * height to its size (help_fixup will be subtracted below)
703 rectParent.bottom = rectChild.bottom + help_fixup;
706 else
708 rectParent.bottom += rectChild.bottom;
711 /* finally use fixed parent size */
712 rectParent.bottom -= help_fixup;
714 /* set the size of the parent dialog */
715 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
716 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
717 SetWindowPos(hwndParentDlg, 0,
718 0, 0,
719 rectParent.right - rectParent.left,
720 rectParent.bottom - rectParent.top,
721 SWP_NOMOVE | SWP_NOZORDER);
724 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
726 switch(uMsg) {
727 case WM_INITDIALOG:
728 return TRUE;
730 return FALSE;
733 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
735 LPCVOID template;
736 HRSRC hRes;
737 HANDLE hDlgTmpl = 0;
738 HWND hChildDlg = 0;
740 TRACE("\n");
743 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
744 * structure's hInstance parameter is not a HINSTANCE, but
745 * instead a pointer to a template resource to use.
747 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
749 HINSTANCE hinst;
750 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
752 hinst = COMDLG32_hInstance;
753 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
755 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
756 return NULL;
759 else
761 hinst = fodInfos->ofnInfos->hInstance;
762 if(fodInfos->unicode)
764 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
765 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
767 else
769 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
770 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
772 if (!hRes)
774 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
775 return NULL;
777 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
778 !(template = LockResource( hDlgTmpl )))
780 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
781 return NULL;
784 if (fodInfos->unicode)
785 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
786 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
787 (LPARAM)fodInfos->ofnInfos);
788 else
789 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
790 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
791 (LPARAM)fodInfos->ofnInfos);
792 if(hChildDlg)
794 ShowWindow(hChildDlg,SW_SHOW);
795 return hChildDlg;
798 else if( IsHooked(fodInfos))
800 RECT rectHwnd;
801 struct {
802 DLGTEMPLATE tmplate;
803 WORD menu,class,title;
804 } temp;
805 GetClientRect(hwnd,&rectHwnd);
806 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
807 temp.tmplate.dwExtendedStyle = 0;
808 temp.tmplate.cdit = 0;
809 temp.tmplate.x = 0;
810 temp.tmplate.y = 0;
811 temp.tmplate.cx = 0;
812 temp.tmplate.cy = 0;
813 temp.menu = temp.class = temp.title = 0;
815 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
816 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
818 return hChildDlg;
820 return NULL;
823 /***********************************************************************
824 * SendCustomDlgNotificationMessage
826 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
829 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
831 LRESULT hook_result = 0;
832 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
834 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
836 if(!fodInfos) return 0;
838 if(fodInfos->DlgInfos.hwndCustomDlg)
840 TRACE("CALL NOTIFY for %x\n", uCode);
841 if(fodInfos->unicode)
843 OFNOTIFYW ofnNotify;
844 ofnNotify.hdr.hwndFrom=hwndParentDlg;
845 ofnNotify.hdr.idFrom=0;
846 ofnNotify.hdr.code = uCode;
847 ofnNotify.lpOFN = fodInfos->ofnInfos;
848 ofnNotify.pszFile = NULL;
849 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
851 else
853 OFNOTIFYA ofnNotify;
854 ofnNotify.hdr.hwndFrom=hwndParentDlg;
855 ofnNotify.hdr.idFrom=0;
856 ofnNotify.hdr.code = uCode;
857 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
858 ofnNotify.pszFile = NULL;
859 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
861 TRACE("RET NOTIFY\n");
863 TRACE("Retval: 0x%08lx\n", hook_result);
864 return hook_result;
867 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
869 UINT len, total;
870 WCHAR *p, *buffer;
871 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
873 TRACE("CDM_GETFILEPATH:\n");
875 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
876 return -1;
878 /* get path and filenames */
879 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
880 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
881 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
882 if (len)
884 p = buffer + strlenW(buffer);
885 *p++ = '\\';
886 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
888 if (fodInfos->unicode)
890 total = strlenW( buffer) + 1;
891 if (result) lstrcpynW( result, buffer, size );
892 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
894 else
896 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
897 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
898 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
900 HeapFree( GetProcessHeap(), 0, buffer );
901 return total;
904 /***********************************************************************
905 * FILEDLG95_HandleCustomDialogMessages
907 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
909 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
911 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
912 WCHAR lpstrPath[MAX_PATH];
913 INT_PTR retval;
915 if(!fodInfos) return FALSE;
917 switch(uMsg)
919 case CDM_GETFILEPATH:
920 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
921 break;
923 case CDM_GETFOLDERPATH:
924 TRACE("CDM_GETFOLDERPATH:\n");
925 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
926 if (lParam)
928 if (fodInfos->unicode)
929 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
930 else
931 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
932 (LPSTR)lParam, (int)wParam, NULL, NULL);
934 retval = lstrlenW(lpstrPath);
935 break;
937 case CDM_GETFOLDERIDLIST:
938 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
939 if (retval <= wParam)
940 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
941 break;
943 case CDM_GETSPEC:
944 TRACE("CDM_GETSPEC:\n");
945 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
946 if (lParam)
948 if (fodInfos->unicode)
949 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
950 else
951 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
953 break;
955 case CDM_SETCONTROLTEXT:
956 TRACE("CDM_SETCONTROLTEXT:\n");
957 if ( lParam )
959 if( fodInfos->unicode )
960 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
961 else
962 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
964 retval = TRUE;
965 break;
967 case CDM_HIDECONTROL:
968 /* MSDN states that it should fail for not OFN_EXPLORER case */
969 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
971 HWND control = GetDlgItem( hwnd, wParam );
972 if (control) ShowWindow( control, SW_HIDE );
973 retval = TRUE;
975 else retval = FALSE;
976 break;
978 default:
979 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
980 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
981 return FALSE;
983 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
984 return TRUE;
987 /***********************************************************************
988 * FILEDLG95_OnWMGetMMI
990 * WM_GETMINMAXINFO message handler for resizable dialogs
992 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
994 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
995 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
996 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
998 mmiptr->ptMinTrackSize = fodInfos->initial_size;
1000 return TRUE;
1003 /***********************************************************************
1004 * FILEDLG95_OnWMSize
1006 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1008 * FIXME: this could be made more elaborate. Now use a simple scheme
1009 * where the file view is enlarged and the controls are either moved
1010 * vertically or horizontally to get out of the way. Only the "grip"
1011 * is moved in both directions to stay in the corner.
1013 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1015 RECT rc, rcview;
1016 int chgx, chgy;
1017 HWND ctrl;
1018 HDWP hdwp;
1019 FileOpenDlgInfos *fodInfos;
1021 if( wParam != SIZE_RESTORED) return FALSE;
1022 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1023 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1024 /* get the new dialog rectangle */
1025 GetWindowRect( hwnd, &rc);
1026 /* not initialized yet */
1027 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1028 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1029 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1030 return FALSE;
1031 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1032 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1033 fodInfos->sizedlg.cx = rc.right - rc.left;
1034 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1035 /* change the size of the view window */
1036 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1037 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1038 hdwp = BeginDeferWindowPos( 10);
1039 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1040 rcview.right - rcview.left + chgx,
1041 rcview.bottom - rcview.top + chgy,
1042 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1043 /* change position and sizes of the controls */
1044 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1046 GetWindowRect( ctrl, &rc);
1047 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1048 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1050 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1051 0, 0,
1052 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1054 else if( rc.top > rcview.bottom)
1056 /* if it was below the shell view
1057 * move to bottom */
1058 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1059 rc.right - rc.left, rc.bottom - rc.top,
1060 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1062 else if( rc.left > rcview.right)
1064 /* if it was to the right of the shell view
1065 * move to right */
1066 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1067 rc.right - rc.left, rc.bottom - rc.top,
1068 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1071 if(fodInfos->DlgInfos.hwndCustomDlg &&
1072 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1074 GetClientRect(hwnd, &rc);
1075 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1076 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1077 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1078 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1080 GetWindowRect( ctrl, &rc);
1081 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1082 if( rc.top > rcview.bottom)
1084 /* if it was below the shell view
1085 * move to bottom */
1086 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1087 rc.right - rc.left, rc.bottom - rc.top,
1088 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1090 else if( rc.left > rcview.right)
1092 /* if it was to the right of the shell view
1093 * move to right */
1094 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1095 rc.right - rc.left, rc.bottom - rc.top,
1096 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1100 EndDeferWindowPos( hdwp);
1101 /* should not be needed */
1102 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1103 return TRUE;
1106 /***********************************************************************
1107 * FileOpenDlgProc95
1109 * File open dialog procedure
1111 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1113 #if 0
1114 TRACE("%p 0x%04x\n", hwnd, uMsg);
1115 #endif
1117 switch(uMsg)
1119 case WM_INITDIALOG:
1121 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1122 RECT rc;
1123 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1124 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1126 /* Adds the FileOpenDlgInfos in the property list of the dialog
1127 so it will be easily accessible through a GetPropA(...) */
1128 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1130 FILEDLG95_InitControls(hwnd);
1132 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1134 GetWindowRect( hwnd, &rc);
1135 fodInfos->DlgInfos.hwndGrip =
1136 CreateWindowExA( 0, "SCROLLBAR", NULL,
1137 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1138 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1139 rc.right - gripx, rc.bottom - gripy,
1140 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1143 fodInfos->DlgInfos.hwndCustomDlg =
1144 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1146 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1147 FILEDLG95_FillControls(hwnd, wParam, lParam);
1149 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1150 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1152 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1154 GetWindowRect( hwnd, &rc);
1155 /* FIXME: should remember sizes of last invocation */
1156 fodInfos->sizedlg.cx = rc.right - rc.left;
1157 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1158 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1159 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1160 GetClientRect( hwnd, &rc);
1161 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1162 rc.right - gripx, rc.bottom - gripy,
1163 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1166 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1168 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1169 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1171 return 0;
1173 case WM_SIZE:
1174 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1175 case WM_GETMINMAXINFO:
1176 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1177 case WM_COMMAND:
1178 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1179 case WM_DRAWITEM:
1181 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1183 case IDC_LOOKIN:
1184 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1185 return TRUE;
1188 return FALSE;
1190 case WM_GETISHELLBROWSER:
1191 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1193 case WM_DESTROY:
1194 RemovePropA(hwnd, FileOpenDlgInfosStr);
1195 return FALSE;
1197 case WM_NOTIFY:
1199 LPNMHDR lpnmh = (LPNMHDR)lParam;
1200 UINT stringId = -1;
1202 /* set up the button tooltips strings */
1203 if(TTN_GETDISPINFOA == lpnmh->code )
1205 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1206 switch(lpnmh->idFrom )
1208 /* Up folder button */
1209 case FCIDM_TB_UPFOLDER:
1210 stringId = IDS_UPFOLDER;
1211 break;
1212 /* New folder button */
1213 case FCIDM_TB_NEWFOLDER:
1214 stringId = IDS_NEWFOLDER;
1215 break;
1216 /* List option button */
1217 case FCIDM_TB_SMALLICON:
1218 stringId = IDS_LISTVIEW;
1219 break;
1220 /* Details option button */
1221 case FCIDM_TB_REPORTVIEW:
1222 stringId = IDS_REPORTVIEW;
1223 break;
1224 /* Desktop button */
1225 case FCIDM_TB_DESKTOP:
1226 stringId = IDS_TODESKTOP;
1227 break;
1228 default:
1229 stringId = 0;
1231 lpdi->hinst = COMDLG32_hInstance;
1232 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1234 return FALSE;
1236 default :
1237 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1238 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1239 return FALSE;
1243 /***********************************************************************
1244 * FILEDLG95_InitControls
1246 * WM_INITDIALOG message handler (before hook notification)
1248 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1250 int win2000plus = 0;
1251 int win98plus = 0;
1252 int handledPath = FALSE;
1253 OSVERSIONINFOW osVi;
1254 static const WCHAR szwSlash[] = { '\\', 0 };
1255 static const WCHAR szwStar[] = { '*',0 };
1257 static const TBBUTTON tbb[] =
1259 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1260 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1261 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1262 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1263 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1264 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1265 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1266 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1267 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1269 TBADDBITMAP tba[2];
1270 RECT rectTB;
1271 RECT rectlook;
1272 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1274 tba[0].hInst = HINST_COMMCTRL;
1275 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1276 tba[1].hInst = COMDLG32_hInstance;
1277 tba[1].nID = 800;
1279 TRACE("%p\n", fodInfos);
1281 /* Get windows version emulating */
1282 osVi.dwOSVersionInfoSize = sizeof(osVi);
1283 GetVersionExW(&osVi);
1284 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1285 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1286 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1287 win2000plus = (osVi.dwMajorVersion > 4);
1288 if (win2000plus) win98plus = TRUE;
1290 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1292 /* Get the hwnd of the controls */
1293 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1294 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1295 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1297 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1298 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1300 /* construct the toolbar */
1301 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1302 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1304 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1305 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1306 rectTB.left = rectlook.right;
1307 rectTB.top = rectlook.top-1;
1309 if (fodInfos->unicode)
1310 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1311 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1312 rectTB.left, rectTB.top,
1313 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1314 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1315 else
1316 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1317 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1318 rectTB.left, rectTB.top,
1319 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1320 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1322 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1324 /* FIXME: use TB_LOADIMAGES when implemented */
1325 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1326 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1327 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1329 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1330 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1332 /* Set the window text with the text specified in the OPENFILENAME structure */
1333 if(fodInfos->title)
1335 SetWindowTextW(hwnd,fodInfos->title);
1337 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1339 WCHAR buf[16];
1340 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1341 SetWindowTextW(hwnd, buf);
1344 /* Initialise the file name edit control */
1345 handledPath = FALSE;
1346 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1348 if(fodInfos->filename)
1350 /* 1. If win2000 or higher and filename contains a path, use it
1351 in preference over the lpstrInitialDir */
1352 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1353 WCHAR tmpBuf[MAX_PATH];
1354 WCHAR *nameBit;
1355 DWORD result;
1357 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1358 if (result) {
1360 /* nameBit is always shorter than the original filename */
1361 lstrcpyW(fodInfos->filename,nameBit);
1363 *nameBit = 0x00;
1364 if (fodInfos->initdir == NULL)
1365 MemFree(fodInfos->initdir);
1366 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1367 lstrcpyW(fodInfos->initdir, tmpBuf);
1368 handledPath = TRUE;
1369 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1370 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1372 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1374 } else {
1375 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1379 /* 2. (All platforms) If initdir is not null, then use it */
1380 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1381 (*fodInfos->initdir!=0x00))
1383 /* Work out the proper path as supplied one might be relative */
1384 /* (Here because supplying '.' as dir browses to My Computer) */
1385 if (handledPath==FALSE) {
1386 WCHAR tmpBuf[MAX_PATH];
1387 WCHAR tmpBuf2[MAX_PATH];
1388 WCHAR *nameBit;
1389 DWORD result;
1391 lstrcpyW(tmpBuf, fodInfos->initdir);
1392 if( PathFileExistsW(tmpBuf) ) {
1393 /* initdir does not have to be a directory. If a file is
1394 * specified, the dir part is taken */
1395 if( PathIsDirectoryW(tmpBuf)) {
1396 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1397 lstrcatW(tmpBuf, szwSlash);
1399 lstrcatW(tmpBuf, szwStar);
1401 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1402 if (result) {
1403 *nameBit = 0x00;
1404 MemFree(fodInfos->initdir);
1405 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1406 lstrcpyW(fodInfos->initdir, tmpBuf2);
1407 handledPath = TRUE;
1408 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1411 else if (fodInfos->initdir)
1413 MemFree(fodInfos->initdir);
1414 fodInfos->initdir = NULL;
1415 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1420 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1421 (*fodInfos->initdir==0x00)))
1423 /* 3. All except w2k+: if filename contains a path use it */
1424 if (!win2000plus && fodInfos->filename &&
1425 *fodInfos->filename &&
1426 strpbrkW(fodInfos->filename, szwSlash)) {
1427 WCHAR tmpBuf[MAX_PATH];
1428 WCHAR *nameBit;
1429 DWORD result;
1431 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1432 tmpBuf, &nameBit);
1433 if (result) {
1434 int len;
1436 /* nameBit is always shorter than the original filename */
1437 lstrcpyW(fodInfos->filename, nameBit);
1438 *nameBit = 0x00;
1440 len = lstrlenW(tmpBuf);
1441 MemFree(fodInfos->initdir);
1442 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1443 lstrcpyW(fodInfos->initdir, tmpBuf);
1445 handledPath = TRUE;
1446 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1447 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1449 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1452 /* 4. win98+ and win2000+ if any files of specified filter types in
1453 current directory, use it */
1454 if ( win98plus && handledPath == FALSE &&
1455 fodInfos->filter && *fodInfos->filter) {
1457 BOOL searchMore = TRUE;
1458 LPCWSTR lpstrPos = fodInfos->filter;
1459 WIN32_FIND_DATAW FindFileData;
1460 HANDLE hFind;
1462 while (searchMore)
1464 /* filter is a list... title\0ext\0......\0\0 */
1466 /* Skip the title */
1467 if(! *lpstrPos) break; /* end */
1468 lpstrPos += lstrlenW(lpstrPos) + 1;
1470 /* See if any files exist in the current dir with this extension */
1471 if(! *lpstrPos) break; /* end */
1473 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1475 if (hFind == INVALID_HANDLE_VALUE) {
1476 /* None found - continue search */
1477 lpstrPos += lstrlenW(lpstrPos) + 1;
1479 } else {
1480 searchMore = FALSE;
1482 MemFree(fodInfos->initdir);
1483 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1484 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1486 handledPath = TRUE;
1487 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1488 debugstr_w(lpstrPos));
1489 break;
1494 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1496 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1497 if (handledPath == FALSE && (win2000plus || win98plus)) {
1498 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1500 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1502 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1504 /* last fallback */
1505 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1506 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1507 } else {
1508 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1510 } else {
1511 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1513 handledPath = TRUE;
1514 } else if (handledPath==FALSE) {
1515 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1516 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1517 handledPath = TRUE;
1518 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1521 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1522 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1524 /* Must the open as read only check box be checked ?*/
1525 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1527 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1530 /* Must the open as read only check box be hidden? */
1531 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1533 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1534 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1537 /* Must the help button be hidden? */
1538 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1540 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1541 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1544 /* change Open to Save */
1545 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1547 WCHAR buf[16];
1548 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1549 SetDlgItemTextW(hwnd, IDOK, buf);
1550 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1551 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1554 /* Initialize the filter combo box */
1555 FILEDLG95_FILETYPE_Init(hwnd);
1557 return 0;
1560 /***********************************************************************
1561 * FILEDLG95_ResizeControls
1563 * WM_INITDIALOG message handler (after hook notification)
1565 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1567 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1569 if (fodInfos->DlgInfos.hwndCustomDlg)
1571 RECT rc;
1572 UINT flags = SWP_NOACTIVATE;
1574 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1575 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1577 /* resize the custom dialog to the parent size */
1578 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1579 GetClientRect(hwnd, &rc);
1580 else
1582 /* our own fake template is zero sized and doesn't have children, so
1583 * there is no need to resize it. Picasa depends on it.
1585 flags |= SWP_NOSIZE;
1586 SetRectEmpty(&rc);
1588 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1589 0, 0, rc.right, rc.bottom, flags);
1591 else
1593 /* Resize the height, if open as read only checkbox ad help button are
1594 * hidden and we are not using a custom template nor a customDialog
1596 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1597 (!(fodInfos->ofnInfos->Flags &
1598 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1600 RECT rectDlg, rectHelp, rectCancel;
1601 GetWindowRect(hwnd, &rectDlg);
1602 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1603 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1604 /* subtract the height of the help button plus the space between the help
1605 * button and the cancel button to the height of the dialog
1607 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1608 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1609 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1612 return TRUE;
1615 /***********************************************************************
1616 * FILEDLG95_FillControls
1618 * WM_INITDIALOG message handler (after hook notification)
1620 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1622 LPITEMIDLIST pidlItemId = NULL;
1624 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1626 TRACE("dir=%s file=%s\n",
1627 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1629 /* Get the initial directory pidl */
1631 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1633 WCHAR path[MAX_PATH];
1635 GetCurrentDirectoryW(MAX_PATH,path);
1636 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1639 /* Initialise shell objects */
1640 FILEDLG95_SHELL_Init(hwnd);
1642 /* Initialize the Look In combo box */
1643 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1645 /* Browse to the initial directory */
1646 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1648 /* Free pidlItem memory */
1649 COMDLG32_SHFree(pidlItemId);
1651 return TRUE;
1653 /***********************************************************************
1654 * FILEDLG95_Clean
1656 * Regroups all the cleaning functions of the filedlg
1658 void FILEDLG95_Clean(HWND hwnd)
1660 FILEDLG95_FILETYPE_Clean(hwnd);
1661 FILEDLG95_LOOKIN_Clean(hwnd);
1662 FILEDLG95_SHELL_Clean(hwnd);
1664 /***********************************************************************
1665 * FILEDLG95_OnWMCommand
1667 * WM_COMMAND message handler
1669 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1671 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1672 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1673 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1675 switch(wID)
1677 /* OK button */
1678 case IDOK:
1679 FILEDLG95_OnOpen(hwnd);
1680 break;
1681 /* Cancel button */
1682 case IDCANCEL:
1683 FILEDLG95_Clean(hwnd);
1684 EndDialog(hwnd, FALSE);
1685 break;
1686 /* Filetype combo box */
1687 case IDC_FILETYPE:
1688 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1689 break;
1690 /* LookIn combo box */
1691 case IDC_LOOKIN:
1692 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1693 break;
1695 /* --- toolbar --- */
1696 /* Up folder button */
1697 case FCIDM_TB_UPFOLDER:
1698 FILEDLG95_SHELL_UpFolder(hwnd);
1699 break;
1700 /* New folder button */
1701 case FCIDM_TB_NEWFOLDER:
1702 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1703 break;
1704 /* List option button */
1705 case FCIDM_TB_SMALLICON:
1706 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1707 break;
1708 /* Details option button */
1709 case FCIDM_TB_REPORTVIEW:
1710 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1711 break;
1712 /* Details option button */
1713 case FCIDM_TB_DESKTOP:
1714 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1715 break;
1717 case IDC_FILENAME:
1718 break;
1721 /* Do not use the listview selection anymore */
1722 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1723 return 0;
1726 /***********************************************************************
1727 * FILEDLG95_OnWMGetIShellBrowser
1729 * WM_GETISHELLBROWSER message handler
1731 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1733 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1735 TRACE("\n");
1737 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1739 return TRUE;
1743 /***********************************************************************
1744 * FILEDLG95_SendFileOK
1746 * Sends the CDN_FILEOK notification if required
1748 * RETURNS
1749 * TRUE if the dialog should close
1750 * FALSE if the dialog should not be closed
1752 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1754 /* ask the hook if we can close */
1755 if(IsHooked(fodInfos))
1757 LRESULT retval = 0;
1759 TRACE("---\n");
1760 /* First send CDN_FILEOK as MSDN doc says */
1761 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1762 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1763 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1765 TRACE("canceled\n");
1766 return (retval == 0);
1769 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1770 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1771 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1772 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1774 TRACE("canceled\n");
1775 return (retval == 0);
1778 return TRUE;
1781 /***********************************************************************
1782 * FILEDLG95_OnOpenMultipleFiles
1784 * Handles the opening of multiple files.
1786 * FIXME
1787 * check destination buffer size
1789 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1791 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1792 UINT nCount, nSizePath;
1793 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1795 TRACE("\n");
1797 if(fodInfos->unicode)
1799 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1800 ofn->lpstrFile[0] = '\0';
1802 else
1804 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1805 ofn->lpstrFile[0] = '\0';
1808 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1810 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1811 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1812 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1814 LPWSTR lpstrTemp = lpstrFileList;
1816 for ( nCount = 0; nCount < nFileCount; nCount++ )
1818 LPITEMIDLIST pidl;
1820 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1821 if (!pidl)
1823 WCHAR lpstrNotFound[100];
1824 WCHAR lpstrMsg[100];
1825 WCHAR tmp[400];
1826 static const WCHAR nl[] = {'\n',0};
1828 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1829 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1831 lstrcpyW(tmp, lpstrTemp);
1832 lstrcatW(tmp, nl);
1833 lstrcatW(tmp, lpstrNotFound);
1834 lstrcatW(tmp, nl);
1835 lstrcatW(tmp, lpstrMsg);
1837 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1838 return FALSE;
1841 /* move to the next file in the list of files */
1842 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1843 COMDLG32_SHFree(pidl);
1847 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1848 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1850 /* For "oldstyle" dialog the components have to
1851 be separated by blanks (not '\0'!) and short
1852 filenames have to be used! */
1853 FIXME("Components have to be separated by blanks\n");
1855 if(fodInfos->unicode)
1857 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1858 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1859 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1861 else
1863 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1865 if (ofn->lpstrFile != NULL)
1867 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1868 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1869 if (ofn->nMaxFile > nSizePath)
1871 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1872 ofn->lpstrFile + nSizePath,
1873 ofn->nMaxFile - nSizePath, NULL, NULL);
1878 fodInfos->ofnInfos->nFileOffset = nSizePath;
1879 fodInfos->ofnInfos->nFileExtension = 0;
1881 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1882 return FALSE;
1884 /* clean and exit */
1885 FILEDLG95_Clean(hwnd);
1886 return EndDialog(hwnd,TRUE);
1889 /***********************************************************************
1890 * FILEDLG95_OnOpen
1892 * Ok button WM_COMMAND message handler
1894 * If the function succeeds, the return value is nonzero.
1896 #define ONOPEN_BROWSE 1
1897 #define ONOPEN_OPEN 2
1898 #define ONOPEN_SEARCH 3
1899 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1901 WCHAR strMsgTitle[MAX_PATH];
1902 WCHAR strMsgText [MAX_PATH];
1903 if (idCaption)
1904 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1905 else
1906 strMsgTitle[0] = '\0';
1907 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1908 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1911 BOOL FILEDLG95_OnOpen(HWND hwnd)
1913 LPWSTR lpstrFileList;
1914 UINT nFileCount = 0;
1915 UINT sizeUsed = 0;
1916 BOOL ret = TRUE;
1917 WCHAR lpstrPathAndFile[MAX_PATH];
1918 WCHAR lpstrTemp[MAX_PATH];
1919 LPSHELLFOLDER lpsf = NULL;
1920 int nOpenAction;
1921 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1923 TRACE("hwnd=%p\n", hwnd);
1925 /* get the files from the edit control */
1926 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1928 /* try if the user selected a folder in the shellview */
1929 if(nFileCount == 0)
1931 BrowseSelectedFolder(hwnd);
1932 return FALSE;
1935 if(nFileCount > 1)
1937 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1938 goto ret;
1941 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1944 Step 1: Build a complete path name from the current folder and
1945 the filename or path in the edit box.
1946 Special cases:
1947 - the path in the edit box is a root path
1948 (with or without drive letter)
1949 - the edit box contains ".." (or a path with ".." in it)
1952 /* Get the current directory name */
1953 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1955 /* last fallback */
1956 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1958 PathAddBackslashW(lpstrPathAndFile);
1960 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1962 /* if the user specified a fully qualified path use it */
1963 if(PathIsRelativeW(lpstrFileList))
1965 lstrcatW(lpstrPathAndFile, lpstrFileList);
1967 else
1969 /* does the path have a drive letter? */
1970 if (PathGetDriveNumberW(lpstrFileList) == -1)
1971 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1972 else
1973 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1976 /* resolve "." and ".." */
1977 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1978 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1979 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1981 MemFree(lpstrFileList);
1984 Step 2: here we have a cleaned up path
1986 We have to parse the path step by step to see if we have to browse
1987 to a folder if the path points to a directory or the last
1988 valid element is a directory.
1990 valid variables:
1991 lpstrPathAndFile: cleaned up path
1994 if (nFileCount &&
1995 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1996 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1997 nOpenAction = ONOPEN_OPEN;
1998 else
1999 nOpenAction = ONOPEN_BROWSE;
2001 /* don't apply any checks with OFN_NOVALIDATE */
2003 LPWSTR lpszTemp, lpszTemp1;
2004 LPITEMIDLIST pidl = NULL;
2005 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2007 /* check for invalid chars */
2008 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2010 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2011 ret = FALSE;
2012 goto ret;
2015 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2017 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2018 while (lpszTemp1)
2020 LPSHELLFOLDER lpsfChild;
2021 WCHAR lpwstrTemp[MAX_PATH];
2022 DWORD dwEaten, dwAttributes;
2023 LPWSTR p;
2025 lstrcpyW(lpwstrTemp, lpszTemp);
2026 p = PathFindNextComponentW(lpwstrTemp);
2028 if (!p) break; /* end of path */
2030 *p = 0;
2031 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2033 /* There are no wildcards when OFN_NOVALIDATE is set */
2034 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2036 static const WCHAR wszWild[] = { '*', '?', 0 };
2037 /* if the last element is a wildcard do a search */
2038 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2040 nOpenAction = ONOPEN_SEARCH;
2041 break;
2044 lpszTemp1 = lpszTemp;
2046 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2048 /* append a backslash to drive letters */
2049 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2050 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2051 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2053 PathAddBackslashW(lpwstrTemp);
2056 dwAttributes = SFGAO_FOLDER;
2057 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2059 /* the path component is valid, we have a pidl of the next path component */
2060 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2061 if(dwAttributes & SFGAO_FOLDER)
2063 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2065 ERR("bind to failed\n"); /* should not fail */
2066 break;
2068 IShellFolder_Release(lpsf);
2069 lpsf = lpsfChild;
2070 lpsfChild = NULL;
2072 else
2074 TRACE("value\n");
2076 /* end dialog, return value */
2077 nOpenAction = ONOPEN_OPEN;
2078 break;
2080 COMDLG32_SHFree(pidl);
2081 pidl = NULL;
2083 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2085 if(*lpszTemp || /* points to trailing null for last path element */
2086 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2088 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2090 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2091 break;
2094 else
2096 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2097 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2099 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2100 break;
2103 /* change to the current folder */
2104 nOpenAction = ONOPEN_OPEN;
2105 break;
2107 else
2109 nOpenAction = ONOPEN_OPEN;
2110 break;
2113 if(pidl) COMDLG32_SHFree(pidl);
2117 Step 3: here we have a cleaned up and validated path
2119 valid variables:
2120 lpsf: ShellFolder bound to the rightmost valid path component
2121 lpstrPathAndFile: cleaned up path
2122 nOpenAction: action to do
2124 TRACE("end validate sf=%p\n", lpsf);
2126 switch(nOpenAction)
2128 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2129 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2131 int iPos;
2132 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2133 DWORD len;
2135 /* replace the current filter */
2136 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2137 len = lstrlenW(lpszTemp)+1;
2138 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2139 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2141 /* set the filter cb to the extension when possible */
2142 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2143 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2145 /* fall through */
2146 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2147 TRACE("ONOPEN_BROWSE\n");
2149 IPersistFolder2 * ppf2;
2150 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2152 LPITEMIDLIST pidlCurrent;
2153 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2154 IPersistFolder2_Release(ppf2);
2155 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2157 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2158 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2160 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2163 else if( nOpenAction == ONOPEN_SEARCH )
2165 if (fodInfos->Shell.FOIShellView)
2166 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2168 COMDLG32_SHFree(pidlCurrent);
2169 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2172 ret = FALSE;
2173 break;
2174 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2175 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2177 WCHAR *ext = NULL;
2179 /* update READONLY check box flag */
2180 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2181 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2182 else
2183 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2185 /* Attach the file extension with file name*/
2186 ext = PathFindExtensionW(lpstrPathAndFile);
2187 if (! *ext)
2189 /* if no extension is specified with file name, then */
2190 /* attach the extension from file filter or default one */
2192 WCHAR *filterExt = NULL;
2193 LPWSTR lpstrFilter = NULL;
2194 static const WCHAR szwDot[] = {'.',0};
2195 int PathLength = lstrlenW(lpstrPathAndFile);
2197 /* Attach the dot*/
2198 lstrcatW(lpstrPathAndFile, szwDot);
2200 /*Get the file extension from file type filter*/
2201 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2202 fodInfos->ofnInfos->nFilterIndex-1);
2204 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2205 filterExt = PathFindExtensionW(lpstrFilter);
2207 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2208 lstrcatW(lpstrPathAndFile, filterExt + 1);
2209 else if ( fodInfos->defext ) /* attach the default file extension*/
2210 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2212 /* In Open dialog: if file does not exist try without extension */
2213 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2214 lpstrPathAndFile[PathLength] = '\0';
2217 if (fodInfos->defext) /* add default extension */
2219 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2220 if (*ext)
2221 ext++;
2222 if (!lstrcmpiW(fodInfos->defext, ext))
2223 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2224 else
2225 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2228 /* In Save dialog: check if the file already exists */
2229 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2230 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2231 && PathFileExistsW(lpstrPathAndFile))
2233 WCHAR lpstrOverwrite[100];
2234 int answer;
2236 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2237 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2238 MB_YESNO | MB_ICONEXCLAMATION);
2239 if (answer == IDNO)
2241 ret = FALSE;
2242 goto ret;
2246 /* In Open dialog: check if it should be created if it doesn't exist */
2247 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2248 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2249 && !PathFileExistsW(lpstrPathAndFile))
2251 WCHAR lpstrCreate[100];
2252 int answer;
2254 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2255 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2256 MB_YESNO | MB_ICONEXCLAMATION);
2257 if (answer == IDNO)
2259 ret = FALSE;
2260 goto ret;
2264 /* Check that the size of the file does not exceed buffer size.
2265 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2266 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2267 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2270 /* fill destination buffer */
2271 if (fodInfos->ofnInfos->lpstrFile)
2273 if(fodInfos->unicode)
2275 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2277 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2278 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2279 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2281 else
2283 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2285 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2286 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2287 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2288 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2292 if(fodInfos->unicode)
2294 LPWSTR lpszTemp;
2296 /* set filename offset */
2297 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2298 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2300 /* set extension offset */
2301 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2302 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2304 else
2306 LPSTR lpszTemp;
2307 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2309 /* set filename offset */
2310 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2311 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2313 /* set extension offset */
2314 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2315 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2318 /* set the lpstrFileTitle */
2319 if(fodInfos->ofnInfos->lpstrFileTitle)
2321 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2322 if(fodInfos->unicode)
2324 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2325 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2327 else
2329 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2330 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2331 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2335 /* copy currently selected filter to lpstrCustomFilter */
2336 if (fodInfos->ofnInfos->lpstrCustomFilter)
2338 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2339 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2340 NULL, 0, NULL, NULL);
2341 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2343 LPSTR s = ofn->lpstrCustomFilter;
2344 s += strlen(ofn->lpstrCustomFilter)+1;
2345 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2346 s, len, NULL, NULL);
2351 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2352 goto ret;
2354 TRACE("close\n");
2355 FILEDLG95_Clean(hwnd);
2356 ret = EndDialog(hwnd, TRUE);
2358 else
2360 WORD size;
2362 size = lstrlenW(lpstrPathAndFile) + 1;
2363 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2364 size += 1;
2365 /* return needed size in first two bytes of lpstrFile */
2366 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2367 FILEDLG95_Clean(hwnd);
2368 ret = EndDialog(hwnd, FALSE);
2369 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2372 break;
2375 ret:
2376 if(lpsf) IShellFolder_Release(lpsf);
2377 return ret;
2380 /***********************************************************************
2381 * FILEDLG95_SHELL_Init
2383 * Initialisation of the shell objects
2385 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2387 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2389 TRACE("\n");
2392 * Initialisation of the FileOpenDialogInfos structure
2395 /* Shell */
2397 /*ShellInfos */
2398 fodInfos->ShellInfos.hwndOwner = hwnd;
2400 /* Disable multi-select if flag not set */
2401 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2403 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2405 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2406 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2408 /* Construct the IShellBrowser interface */
2409 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2411 return NOERROR;
2414 /***********************************************************************
2415 * FILEDLG95_SHELL_ExecuteCommand
2417 * Change the folder option and refresh the view
2418 * If the function succeeds, the return value is nonzero.
2420 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2422 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2423 IContextMenu * pcm;
2425 TRACE("(%p,%p)\n", hwnd, lpVerb);
2427 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2428 SVGIO_BACKGROUND,
2429 &IID_IContextMenu,
2430 (LPVOID*)&pcm)))
2432 CMINVOKECOMMANDINFO ci;
2433 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2434 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2435 ci.lpVerb = lpVerb;
2436 ci.hwnd = hwnd;
2438 IContextMenu_InvokeCommand(pcm, &ci);
2439 IContextMenu_Release(pcm);
2442 return FALSE;
2445 /***********************************************************************
2446 * FILEDLG95_SHELL_UpFolder
2448 * Browse to the specified object
2449 * If the function succeeds, the return value is nonzero.
2451 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2453 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2455 TRACE("\n");
2457 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2458 NULL,
2459 SBSP_PARENT)))
2461 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2462 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2463 return TRUE;
2465 return FALSE;
2468 /***********************************************************************
2469 * FILEDLG95_SHELL_BrowseToDesktop
2471 * Browse to the Desktop
2472 * If the function succeeds, the return value is nonzero.
2474 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2476 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2477 LPITEMIDLIST pidl;
2478 HRESULT hres;
2480 TRACE("\n");
2482 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2483 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2484 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2485 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2486 COMDLG32_SHFree(pidl);
2487 return SUCCEEDED(hres);
2489 /***********************************************************************
2490 * FILEDLG95_SHELL_Clean
2492 * Cleans the memory used by shell objects
2494 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2496 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2498 TRACE("\n");
2500 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2502 /* clean Shell interfaces */
2503 if (fodInfos->Shell.FOIShellView)
2505 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2506 IShellView_Release(fodInfos->Shell.FOIShellView);
2508 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2509 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2510 if (fodInfos->Shell.FOIDataObject)
2511 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2514 /***********************************************************************
2515 * FILEDLG95_FILETYPE_Init
2517 * Initialisation of the file type combo box
2519 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2521 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2522 int nFilters = 0; /* number of filters */
2523 int nFilterIndexCB;
2525 TRACE("\n");
2527 if(fodInfos->customfilter)
2529 /* customfilter has one entry... title\0ext\0
2530 * Set first entry of combo box item with customfilter
2532 LPWSTR lpstrExt;
2533 LPCWSTR lpstrPos = fodInfos->customfilter;
2535 /* Get the title */
2536 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2538 /* Copy the extensions */
2539 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2540 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2541 lstrcpyW(lpstrExt,lpstrPos);
2543 /* Add the item at the end of the combo */
2544 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2545 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2546 nFilters++;
2548 if(fodInfos->filter)
2550 LPCWSTR lpstrPos = fodInfos->filter;
2552 for(;;)
2554 /* filter is a list... title\0ext\0......\0\0
2555 * Set the combo item text to the title and the item data
2556 * to the ext
2558 LPCWSTR lpstrDisplay;
2559 LPWSTR lpstrExt;
2561 /* Get the title */
2562 if(! *lpstrPos) break; /* end */
2563 lpstrDisplay = lpstrPos;
2564 lpstrPos += lstrlenW(lpstrPos) + 1;
2566 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2568 nFilters++;
2570 /* Copy the extensions */
2571 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2572 lstrcpyW(lpstrExt,lpstrPos);
2573 lpstrPos += lstrlenW(lpstrPos) + 1;
2575 /* Add the item at the end of the combo */
2576 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2578 /* malformed filters are added anyway... */
2579 if (!*lpstrExt) break;
2584 * Set the current filter to the one specified
2585 * in the initialisation structure
2587 if (fodInfos->filter || fodInfos->customfilter)
2589 LPWSTR lpstrFilter;
2591 /* Check to make sure our index isn't out of bounds. */
2592 if ( fodInfos->ofnInfos->nFilterIndex >
2593 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2594 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2596 /* set default filter index */
2597 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2598 fodInfos->ofnInfos->nFilterIndex = 1;
2600 /* calculate index of Combo Box item */
2601 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2602 if (fodInfos->customfilter == NULL)
2603 nFilterIndexCB--;
2605 /* Set the current index selection. */
2606 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2608 /* Get the corresponding text string from the combo box. */
2609 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2610 nFilterIndexCB);
2612 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2613 lpstrFilter = NULL;
2615 if(lpstrFilter)
2617 DWORD len;
2618 CharLowerW(lpstrFilter); /* lowercase */
2619 len = lstrlenW(lpstrFilter)+1;
2620 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2621 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2623 } else
2624 fodInfos->ofnInfos->nFilterIndex = 0;
2625 return S_OK;
2628 /***********************************************************************
2629 * FILEDLG95_FILETYPE_OnCommand
2631 * WM_COMMAND of the file type combo box
2632 * If the function succeeds, the return value is nonzero.
2634 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2636 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2638 switch(wNotifyCode)
2640 case CBN_SELENDOK:
2642 LPWSTR lpstrFilter;
2644 /* Get the current item of the filetype combo box */
2645 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2647 /* set the current filter index */
2648 fodInfos->ofnInfos->nFilterIndex = iItem +
2649 (fodInfos->customfilter == NULL ? 1 : 0);
2651 /* Set the current filter with the current selection */
2652 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2654 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2655 iItem);
2656 if((INT_PTR)lpstrFilter != CB_ERR)
2658 DWORD len;
2659 CharLowerW(lpstrFilter); /* lowercase */
2660 len = lstrlenW(lpstrFilter)+1;
2661 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2662 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2663 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2664 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2667 /* Refresh the actual view to display the included items*/
2668 if (fodInfos->Shell.FOIShellView)
2669 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2672 return FALSE;
2674 /***********************************************************************
2675 * FILEDLG95_FILETYPE_SearchExt
2677 * searches for an extension in the filetype box
2679 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2681 int i, iCount = CBGetCount(hwnd);
2683 TRACE("%s\n", debugstr_w(lpstrExt));
2685 if(iCount != CB_ERR)
2687 for(i=0;i<iCount;i++)
2689 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2690 return i;
2693 return -1;
2696 /***********************************************************************
2697 * FILEDLG95_FILETYPE_Clean
2699 * Clean the memory used by the filetype combo box
2701 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2703 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2704 int iPos;
2705 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2707 TRACE("\n");
2709 /* Delete each string of the combo and their associated data */
2710 if(iCount != CB_ERR)
2712 for(iPos = iCount-1;iPos>=0;iPos--)
2714 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2715 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2718 /* Current filter */
2719 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2723 /***********************************************************************
2724 * FILEDLG95_LOOKIN_Init
2726 * Initialisation of the look in combo box
2729 /* Small helper function, to determine if the unixfs shell extension is rooted
2730 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2732 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2733 HKEY hKey;
2734 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2735 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2736 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2737 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2738 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2739 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2740 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2742 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2743 return FALSE;
2745 RegCloseKey(hKey);
2746 return TRUE;
2749 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2751 IShellFolder *psfRoot, *psfDrives;
2752 IEnumIDList *lpeRoot, *lpeDrives;
2753 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2755 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2757 TRACE("\n");
2759 liInfos->iMaxIndentation = 0;
2761 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2763 /* set item height for both text field and listbox */
2764 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2765 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2767 /* Turn on the extended UI for the combo box like Windows does */
2768 CBSetExtendedUI(hwndCombo, TRUE);
2770 /* Initialise data of Desktop folder */
2771 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2772 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2773 COMDLG32_SHFree(pidlTmp);
2775 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2777 SHGetDesktopFolder(&psfRoot);
2779 if (psfRoot)
2781 /* enumerate the contents of the desktop */
2782 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2784 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2786 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2788 /* If the unixfs extension is rooted, we don't expand the drives by default */
2789 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2791 /* special handling for CSIDL_DRIVES */
2792 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2794 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2796 /* enumerate the drives */
2797 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2799 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2801 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2802 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2803 COMDLG32_SHFree(pidlAbsTmp);
2804 COMDLG32_SHFree(pidlTmp1);
2806 IEnumIDList_Release(lpeDrives);
2808 IShellFolder_Release(psfDrives);
2813 COMDLG32_SHFree(pidlTmp);
2815 IEnumIDList_Release(lpeRoot);
2817 IShellFolder_Release(psfRoot);
2820 COMDLG32_SHFree(pidlDrives);
2823 /***********************************************************************
2824 * FILEDLG95_LOOKIN_DrawItem
2826 * WM_DRAWITEM message handler
2828 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2830 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2831 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2832 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2833 RECT rectText;
2834 RECT rectIcon;
2835 SHFILEINFOW sfi;
2836 HIMAGELIST ilItemImage;
2837 int iIndentation;
2838 TEXTMETRICW tm;
2839 LPSFOLDER tmpFolder;
2840 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2842 TRACE("\n");
2844 if(pDIStruct->itemID == -1)
2845 return 0;
2847 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2848 pDIStruct->itemID)))
2849 return 0;
2852 if(pDIStruct->itemID == liInfos->uSelectedItem)
2854 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2856 &sfi,
2857 sizeof (sfi),
2858 SHGFI_PIDL | SHGFI_SMALLICON |
2859 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2860 SHGFI_DISPLAYNAME );
2862 else
2864 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2866 &sfi,
2867 sizeof (sfi),
2868 SHGFI_PIDL | SHGFI_SMALLICON |
2869 SHGFI_SYSICONINDEX |
2870 SHGFI_DISPLAYNAME);
2873 /* Is this item selected ? */
2874 if(pDIStruct->itemState & ODS_SELECTED)
2876 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2877 SetBkColor(pDIStruct->hDC,crHighLight);
2878 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2880 else
2882 SetTextColor(pDIStruct->hDC,crText);
2883 SetBkColor(pDIStruct->hDC,crWin);
2884 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2887 /* Do not indent item if drawing in the edit of the combo */
2888 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2890 iIndentation = 0;
2891 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2893 &sfi,
2894 sizeof (sfi),
2895 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2896 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2899 else
2901 iIndentation = tmpFolder->m_iIndent;
2903 /* Draw text and icon */
2905 /* Initialise the icon display area */
2906 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2907 rectIcon.top = pDIStruct->rcItem.top;
2908 rectIcon.right = rectIcon.left + ICONWIDTH;
2909 rectIcon.bottom = pDIStruct->rcItem.bottom;
2911 /* Initialise the text display area */
2912 GetTextMetricsW(pDIStruct->hDC, &tm);
2913 rectText.left = rectIcon.right;
2914 rectText.top =
2915 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2916 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2917 rectText.bottom =
2918 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2920 /* Draw the icon from the image list */
2921 ImageList_Draw(ilItemImage,
2922 sfi.iIcon,
2923 pDIStruct->hDC,
2924 rectIcon.left,
2925 rectIcon.top,
2926 ILD_TRANSPARENT );
2928 /* Draw the associated text */
2929 if(sfi.szDisplayName)
2930 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2933 return NOERROR;
2936 /***********************************************************************
2937 * FILEDLG95_LOOKIN_OnCommand
2939 * LookIn combo box WM_COMMAND message handler
2940 * If the function succeeds, the return value is nonzero.
2942 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2944 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2946 TRACE("%p\n", fodInfos);
2948 switch(wNotifyCode)
2950 case CBN_SELENDOK:
2952 LPSFOLDER tmpFolder;
2953 int iItem;
2955 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2957 if( iItem == CB_ERR) return FALSE;
2959 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2960 iItem)))
2961 return FALSE;
2964 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2965 tmpFolder->pidlItem,
2966 SBSP_ABSOLUTE)))
2968 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2969 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2970 return TRUE;
2972 break;
2976 return FALSE;
2979 /***********************************************************************
2980 * FILEDLG95_LOOKIN_AddItem
2982 * Adds an absolute pidl item to the lookin combo box
2983 * returns the index of the inserted item
2985 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2987 LPITEMIDLIST pidlNext;
2988 SHFILEINFOW sfi;
2989 SFOLDER *tmpFolder;
2990 LookInInfos *liInfos;
2992 TRACE("%08x\n", iInsertId);
2994 if(!pidl)
2995 return -1;
2997 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
2998 return -1;
3000 tmpFolder = MemAlloc(sizeof(SFOLDER));
3001 tmpFolder->m_iIndent = 0;
3003 /* Calculate the indentation of the item in the lookin*/
3004 pidlNext = pidl;
3005 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3007 tmpFolder->m_iIndent++;
3010 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3012 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3013 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3015 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3016 SHGetFileInfoW((LPCWSTR)pidl,
3018 &sfi,
3019 sizeof(sfi),
3020 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3021 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3023 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3025 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3027 int iItemID;
3029 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3031 /* Add the item at the end of the list */
3032 if(iInsertId < 0)
3034 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3036 /* Insert the item at the iInsertId position*/
3037 else
3039 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3042 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3043 return iItemID;
3046 COMDLG32_SHFree( tmpFolder->pidlItem );
3047 MemFree( tmpFolder );
3048 return -1;
3052 /***********************************************************************
3053 * FILEDLG95_LOOKIN_InsertItemAfterParent
3055 * Insert an item below its parent
3057 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3060 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3061 int iParentPos;
3063 TRACE("\n");
3065 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3067 if(iParentPos < 0)
3069 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3072 /* Free pidlParent memory */
3073 COMDLG32_SHFree(pidlParent);
3075 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3078 /***********************************************************************
3079 * FILEDLG95_LOOKIN_SelectItem
3081 * Adds an absolute pidl item to the lookin combo box
3082 * returns the index of the inserted item
3084 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3086 int iItemPos;
3087 LookInInfos *liInfos;
3089 TRACE("\n");
3091 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3093 liInfos = GetPropA(hwnd,LookInInfosStr);
3095 if(iItemPos < 0)
3097 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3098 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3101 else
3103 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3104 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3106 int iRemovedItem;
3108 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3109 break;
3110 if(iRemovedItem < iItemPos)
3111 iItemPos--;
3115 CBSetCurSel(hwnd,iItemPos);
3116 liInfos->uSelectedItem = iItemPos;
3118 return 0;
3122 /***********************************************************************
3123 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3125 * Remove the item with an expansion level over iExpansionLevel
3127 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3129 int iItemPos;
3130 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3132 TRACE("\n");
3134 if(liInfos->iMaxIndentation <= 2)
3135 return -1;
3137 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3139 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3140 COMDLG32_SHFree(tmpFolder->pidlItem);
3141 MemFree(tmpFolder);
3142 CBDeleteString(hwnd,iItemPos);
3143 liInfos->iMaxIndentation--;
3145 return iItemPos;
3148 return -1;
3151 /***********************************************************************
3152 * FILEDLG95_LOOKIN_SearchItem
3154 * Search for pidl in the lookin combo box
3155 * returns the index of the found item
3157 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3159 int i = 0;
3160 int iCount = CBGetCount(hwnd);
3162 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3164 if (iCount != CB_ERR)
3166 for(;i<iCount;i++)
3168 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3170 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3171 return i;
3172 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3173 return i;
3177 return -1;
3180 /***********************************************************************
3181 * FILEDLG95_LOOKIN_Clean
3183 * Clean the memory used by the lookin combo box
3185 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3187 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3188 int iPos;
3189 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3191 TRACE("\n");
3193 /* Delete each string of the combo and their associated data */
3194 if (iCount != CB_ERR)
3196 for(iPos = iCount-1;iPos>=0;iPos--)
3198 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3199 COMDLG32_SHFree(tmpFolder->pidlItem);
3200 MemFree(tmpFolder);
3201 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3205 /* LookInInfos structure */
3206 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3209 /***********************************************************************
3210 * FILEDLG95_FILENAME_FillFromSelection
3212 * fills the edit box from the cached DataObject
3214 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3216 FileOpenDlgInfos *fodInfos;
3217 LPITEMIDLIST pidl;
3218 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3219 WCHAR lpstrTemp[MAX_PATH];
3220 LPWSTR lpstrAllFile, lpstrCurrFile;
3222 TRACE("\n");
3223 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3225 /* Count how many files we have */
3226 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3228 /* calculate the string length, count files */
3229 if (nFileSelected >= 1)
3231 nLength += 3; /* first and last quotes, trailing \0 */
3232 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3234 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3236 if (pidl)
3238 /* get the total length of the selected file names */
3239 lpstrTemp[0] = '\0';
3240 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3242 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3244 nLength += lstrlenW( lpstrTemp ) + 3;
3245 nFiles++;
3247 COMDLG32_SHFree( pidl );
3252 /* allocate the buffer */
3253 if (nFiles <= 1) nLength = MAX_PATH;
3254 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3256 /* Generate the string for the edit control */
3257 if(nFiles >= 1)
3259 lpstrCurrFile = lpstrAllFile;
3260 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3262 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3264 if (pidl)
3266 /* get the file name */
3267 lpstrTemp[0] = '\0';
3268 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3270 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3272 if ( nFiles > 1)
3274 *lpstrCurrFile++ = '\"';
3275 lstrcpyW( lpstrCurrFile, lpstrTemp );
3276 lpstrCurrFile += lstrlenW( lpstrTemp );
3277 *lpstrCurrFile++ = '\"';
3278 *lpstrCurrFile++ = ' ';
3279 *lpstrCurrFile = 0;
3281 else
3283 lstrcpyW( lpstrAllFile, lpstrTemp );
3286 COMDLG32_SHFree( pidl );
3289 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3291 /* Select the file name like Windows does */
3292 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3294 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3298 /* copied from shell32 to avoid linking to it
3299 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3300 * is dependent on whether emulated OS is unicode or not.
3302 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3304 switch (src->uType)
3306 case STRRET_WSTR:
3307 lstrcpynW(dest, src->u.pOleStr, len);
3308 COMDLG32_SHFree(src->u.pOleStr);
3309 break;
3311 case STRRET_CSTR:
3312 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3313 dest[len-1] = 0;
3314 break;
3316 case STRRET_OFFSET:
3317 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3318 dest[len-1] = 0;
3319 break;
3321 default:
3322 FIXME("unknown type %x!\n", src->uType);
3323 if (len) *dest = '\0';
3324 return E_FAIL;
3326 return S_OK;
3329 /***********************************************************************
3330 * FILEDLG95_FILENAME_GetFileNames
3332 * Copies the filenames to a delimited string list.
3333 * The delimiter is specified by the parameter 'separator',
3334 * usually either a space or a nul
3336 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3338 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3339 UINT nStrCharCount = 0; /* index in src buffer */
3340 UINT nFileIndex = 0; /* index in dest buffer */
3341 UINT nFileCount = 0; /* number of files */
3342 UINT nStrLen = 0; /* length of string in edit control */
3343 LPWSTR lpstrEdit; /* buffer for string from edit control */
3345 TRACE("\n");
3347 /* get the filenames from the edit control */
3348 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3349 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3350 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3352 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3354 /* we might get single filename without any '"',
3355 * so we need nStrLen + terminating \0 + end-of-list \0 */
3356 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3357 *sizeUsed = 0;
3359 /* build delimited file list from filenames */
3360 while ( nStrCharCount <= nStrLen )
3362 if ( lpstrEdit[nStrCharCount]=='"' )
3364 nStrCharCount++;
3365 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3367 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3368 nStrCharCount++;
3370 (*lpstrFileList)[nFileIndex++] = 0;
3371 nFileCount++;
3373 nStrCharCount++;
3376 /* single, unquoted string */
3377 if ((nStrLen > 0) && (nFileIndex == 0) )
3379 lstrcpyW(*lpstrFileList, lpstrEdit);
3380 nFileIndex = lstrlenW(lpstrEdit) + 1;
3381 nFileCount = 1;
3384 /* trailing \0 */
3385 (*lpstrFileList)[nFileIndex++] = '\0';
3387 *sizeUsed = nFileIndex;
3388 MemFree(lpstrEdit);
3389 return nFileCount;
3392 #define SETDefFormatEtc(fe,cf,med) \
3394 (fe).cfFormat = cf;\
3395 (fe).dwAspect = DVASPECT_CONTENT; \
3396 (fe).ptd =NULL;\
3397 (fe).tymed = med;\
3398 (fe).lindex = -1;\
3402 * DATAOBJECT Helper functions
3405 /***********************************************************************
3406 * COMCTL32_ReleaseStgMedium
3408 * like ReleaseStgMedium from ole32
3410 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3412 if(medium.pUnkForRelease)
3414 IUnknown_Release(medium.pUnkForRelease);
3416 else
3418 GlobalUnlock(medium.u.hGlobal);
3419 GlobalFree(medium.u.hGlobal);
3423 /***********************************************************************
3424 * GetPidlFromDataObject
3426 * Return pidl(s) by number from the cached DataObject
3428 * nPidlIndex=0 gets the fully qualified root path
3430 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3433 STGMEDIUM medium;
3434 FORMATETC formatetc;
3435 LPITEMIDLIST pidl = NULL;
3437 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3439 if (!doSelected)
3440 return NULL;
3442 /* Set the FORMATETC structure*/
3443 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3445 /* Get the pidls from IDataObject */
3446 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3448 LPIDA cida = GlobalLock(medium.u.hGlobal);
3449 if(nPidlIndex <= cida->cidl)
3451 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3453 COMCTL32_ReleaseStgMedium(medium);
3455 return pidl;
3458 /***********************************************************************
3459 * GetNumSelected
3461 * Return the number of selected items in the DataObject.
3464 static UINT GetNumSelected( IDataObject *doSelected )
3466 UINT retVal = 0;
3467 STGMEDIUM medium;
3468 FORMATETC formatetc;
3470 TRACE("sv=%p\n", doSelected);
3472 if (!doSelected) return 0;
3474 /* Set the FORMATETC structure*/
3475 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3477 /* Get the pidls from IDataObject */
3478 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3480 LPIDA cida = GlobalLock(medium.u.hGlobal);
3481 retVal = cida->cidl;
3482 COMCTL32_ReleaseStgMedium(medium);
3483 return retVal;
3485 return 0;
3489 * TOOLS
3492 /***********************************************************************
3493 * GetName
3495 * Get the pidl's display name (relative to folder) and
3496 * put it in lpstrFileName.
3498 * Return NOERROR on success,
3499 * E_FAIL otherwise
3502 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3504 STRRET str;
3505 HRESULT hRes;
3507 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3509 if(!lpsf)
3511 SHGetDesktopFolder(&lpsf);
3512 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3513 IShellFolder_Release(lpsf);
3514 return hRes;
3517 /* Get the display name of the pidl relative to the folder */
3518 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3520 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3522 return E_FAIL;
3525 /***********************************************************************
3526 * GetShellFolderFromPidl
3528 * pidlRel is the item pidl relative
3529 * Return the IShellFolder of the absolute pidl
3531 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3533 IShellFolder *psf = NULL,*psfParent;
3535 TRACE("%p\n", pidlAbs);
3537 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3539 psf = psfParent;
3540 if(pidlAbs && pidlAbs->mkid.cb)
3542 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3544 IShellFolder_Release(psfParent);
3545 return psf;
3548 /* return the desktop */
3549 return psfParent;
3551 return NULL;
3554 /***********************************************************************
3555 * GetParentPidl
3557 * Return the LPITEMIDLIST to the parent of the pidl in the list
3559 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3561 LPITEMIDLIST pidlParent;
3563 TRACE("%p\n", pidl);
3565 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3566 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3568 return pidlParent;
3571 /***********************************************************************
3572 * GetPidlFromName
3574 * returns the pidl of the file name relative to folder
3575 * NULL if an error occurred
3577 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3579 LPITEMIDLIST pidl = NULL;
3580 ULONG ulEaten;
3582 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3584 if(!lpcstrFileName) return NULL;
3585 if(!*lpcstrFileName) return NULL;
3587 if(!lpsf)
3589 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3590 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3591 IShellFolder_Release(lpsf);
3594 else
3596 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3598 return pidl;
3603 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3605 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3606 HRESULT ret;
3608 TRACE("%p, %p\n", psf, pidl);
3610 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3612 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3613 /* see documentation shell 4.1*/
3614 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3617 /***********************************************************************
3618 * BrowseSelectedFolder
3620 static BOOL BrowseSelectedFolder(HWND hwnd)
3622 BOOL bBrowseSelFolder = FALSE;
3623 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3625 TRACE("\n");
3627 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3629 LPITEMIDLIST pidlSelection;
3631 /* get the file selected */
3632 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3633 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3635 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3636 pidlSelection, SBSP_RELATIVE ) ) )
3638 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3639 ' ','n','o','t',' ','e','x','i','s','t',0};
3640 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3642 bBrowseSelFolder = TRUE;
3643 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3644 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3646 COMDLG32_SHFree( pidlSelection );
3649 return bBrowseSelFolder;
3653 * Memory allocation methods */
3654 static void *MemAlloc(UINT size)
3656 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3659 static void MemFree(void *mem)
3661 HeapFree(GetProcessHeap(),0,mem);
3665 * Old-style (win3.1) dialogs */
3667 /***********************************************************************
3668 * FD32_GetTemplate [internal]
3670 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3671 * by a 32 bits application
3674 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3676 LPOPENFILENAMEW ofnW = lfs->ofnW;
3677 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3678 HANDLE hDlgTmpl;
3680 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3682 if (!(lfs->template = LockResource( ofnW->hInstance )))
3684 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3685 return FALSE;
3688 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3690 HRSRC hResInfo;
3691 if (priv->ofnA)
3692 hResInfo = FindResourceA(priv->ofnA->hInstance,
3693 priv->ofnA->lpTemplateName,
3694 (LPSTR)RT_DIALOG);
3695 else
3696 hResInfo = FindResourceW(ofnW->hInstance,
3697 ofnW->lpTemplateName,
3698 (LPWSTR)RT_DIALOG);
3699 if (!hResInfo)
3701 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3702 return FALSE;
3704 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3705 hResInfo)) ||
3706 !(lfs->template = LockResource(hDlgTmpl)))
3708 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3709 return FALSE;
3711 } else { /* get it from internal Wine resource */
3712 HRSRC hResInfo;
3713 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3714 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3716 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3717 return FALSE;
3719 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3720 !(lfs->template = LockResource( hDlgTmpl )))
3722 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3723 return FALSE;
3726 return TRUE;
3730 /************************************************************************
3731 * FD32_Init [internal]
3732 * called from the common 16/32 code to initialize 32 bit data
3734 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3736 BOOL IsUnicode = (BOOL) data;
3737 PFD32_PRIVATE priv;
3739 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3740 lfs->private1632 = priv;
3741 if (NULL == lfs->private1632) return FALSE;
3742 if (IsUnicode)
3744 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3745 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3746 if (lfs->ofnW->lpfnHook)
3747 lfs->hook = TRUE;
3749 else
3751 priv->ofnA = (LPOPENFILENAMEA) lParam;
3752 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3753 if (priv->ofnA->lpfnHook)
3754 lfs->hook = TRUE;
3755 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3756 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3759 if (! FD32_GetTemplate(lfs)) return FALSE;
3761 return TRUE;
3764 /***********************************************************************
3765 * FD32_CallWindowProc [internal]
3767 * called from the common 16/32 code to call the appropriate hook
3769 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3770 LPARAM lParam)
3772 BOOL ret;
3773 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3775 if (priv->ofnA)
3777 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3778 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3779 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3780 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3781 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3782 return ret;
3785 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3786 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3787 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3788 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3789 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3790 return ret;
3793 /***********************************************************************
3794 * FD32_UpdateResult [internal]
3795 * update the real client structures if any
3797 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3799 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3800 LPOPENFILENAMEW ofnW = lfs->ofnW;
3802 if (priv->ofnA)
3804 LPSTR lpszTemp;
3805 if (ofnW->nMaxFile &&
3806 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3807 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3808 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3810 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3811 /* set filename offset */
3812 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3813 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3815 /* set extension offset */
3816 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3817 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3821 /***********************************************************************
3822 * FD32_UpdateFileTitle [internal]
3823 * update the real client structures if any
3825 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3827 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3828 LPOPENFILENAMEW ofnW = lfs->ofnW;
3830 if (priv->ofnA)
3832 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3833 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3834 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3839 /***********************************************************************
3840 * FD32_SendLbGetCurSel [internal]
3841 * retrieve selected listbox item
3843 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3845 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3849 /************************************************************************
3850 * FD32_Destroy [internal]
3851 * called from the common 16/32 code to cleanup 32 bit data
3853 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3855 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3857 /* if ofnW has been allocated, have to free everything in it */
3858 if (NULL != priv && NULL != priv->ofnA)
3860 FD31_FreeOfnW(lfs->ofnW);
3861 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3865 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3867 callbacks->Init = FD32_Init;
3868 callbacks->CWP = FD32_CallWindowProc;
3869 callbacks->UpdateResult = FD32_UpdateResult;
3870 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3871 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3872 callbacks->Destroy = FD32_Destroy;
3875 /***********************************************************************
3876 * FD32_WMMeasureItem [internal]
3878 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3880 LPMEASUREITEMSTRUCT lpmeasure;
3882 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3883 lpmeasure->itemHeight = FD31_GetFldrHeight();
3884 return TRUE;
3888 /***********************************************************************
3889 * FileOpenDlgProc [internal]
3890 * Used for open and save, in fact.
3892 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3893 WPARAM wParam, LPARAM lParam)
3895 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3897 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3898 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3900 INT_PTR lRet;
3901 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3902 if (lRet)
3903 return lRet; /* else continue message processing */
3905 switch (wMsg)
3907 case WM_INITDIALOG:
3908 return FD31_WMInitDialog(hWnd, wParam, lParam);
3910 case WM_MEASUREITEM:
3911 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3913 case WM_DRAWITEM:
3914 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3916 case WM_COMMAND:
3917 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3918 #if 0
3919 case WM_CTLCOLOR:
3920 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3921 switch (HIWORD(lParam))
3923 case CTLCOLOR_BTN:
3924 SetTextColor((HDC16)wParam, 0x00000000);
3925 return hGRAYBrush;
3926 case CTLCOLOR_STATIC:
3927 SetTextColor((HDC16)wParam, 0x00000000);
3928 return hGRAYBrush;
3930 break;
3931 #endif
3933 return FALSE;
3937 /***********************************************************************
3938 * GetFileName31A [internal]
3940 * Creates a win31 style dialog box for the user to select a file to open/save.
3942 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3943 UINT dlgType /* type dialogue : open/save */
3946 HINSTANCE hInst;
3947 BOOL bRet = FALSE;
3948 PFD31_DATA lfs;
3949 FD31_CALLBACKS callbacks;
3951 if (!lpofn || !FD31_Init()) return FALSE;
3953 TRACE("ofn flags %08x\n", lpofn->Flags);
3954 FD32_SetupCallbacks(&callbacks);
3955 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3956 if (lfs)
3958 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3959 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3960 FD32_FileOpenDlgProc, (LPARAM)lfs);
3961 FD31_DestroyPrivate(lfs);
3964 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3965 return bRet;
3968 /***********************************************************************
3969 * GetFileName31W [internal]
3971 * Creates a win31 style dialog box for the user to select a file to open/save
3973 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3974 UINT dlgType /* type dialogue : open/save */
3977 HINSTANCE hInst;
3978 BOOL bRet = FALSE;
3979 PFD31_DATA lfs;
3980 FD31_CALLBACKS callbacks;
3982 if (!lpofn || !FD31_Init()) return FALSE;
3984 FD32_SetupCallbacks(&callbacks);
3985 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3986 if (lfs)
3988 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3989 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3990 FD32_FileOpenDlgProc, (LPARAM)lfs);
3991 FD31_DestroyPrivate(lfs);
3994 TRACE("file %s, file offset %d, ext offset %d\n",
3995 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3996 return bRet;
3999 /* ------------------ APIs ---------------------- */
4001 /***********************************************************************
4002 * GetOpenFileNameA (COMDLG32.@)
4004 * Creates a dialog box for the user to select a file to open.
4006 * RETURNS
4007 * TRUE on success: user enters a valid file
4008 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4011 BOOL WINAPI GetOpenFileNameA(
4012 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4014 BOOL win16look = FALSE;
4016 TRACE("flags %08x\n", ofn->Flags);
4018 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4019 if (ofn->Flags & OFN_FILEMUSTEXIST)
4020 ofn->Flags |= OFN_PATHMUSTEXIST;
4022 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4023 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4025 if (win16look)
4026 return GetFileName31A(ofn, OPEN_DIALOG);
4027 else
4028 return GetFileDialog95A(ofn, OPEN_DIALOG);
4031 /***********************************************************************
4032 * GetOpenFileNameW (COMDLG32.@)
4034 * Creates a dialog box for the user to select a file to open.
4036 * RETURNS
4037 * TRUE on success: user enters a valid file
4038 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4041 BOOL WINAPI GetOpenFileNameW(
4042 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4044 BOOL win16look = FALSE;
4046 TRACE("flags %08x\n", ofn->Flags);
4048 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4049 if (ofn->Flags & OFN_FILEMUSTEXIST)
4050 ofn->Flags |= OFN_PATHMUSTEXIST;
4052 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4053 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4055 if (win16look)
4056 return GetFileName31W(ofn, OPEN_DIALOG);
4057 else
4058 return GetFileDialog95W(ofn, OPEN_DIALOG);
4062 /***********************************************************************
4063 * GetSaveFileNameA (COMDLG32.@)
4065 * Creates a dialog box for the user to select a file to save.
4067 * RETURNS
4068 * TRUE on success: user enters a valid file
4069 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4072 BOOL WINAPI GetSaveFileNameA(
4073 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4075 BOOL win16look = FALSE;
4077 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4078 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4080 if (win16look)
4081 return GetFileName31A(ofn, SAVE_DIALOG);
4082 else
4083 return GetFileDialog95A(ofn, SAVE_DIALOG);
4086 /***********************************************************************
4087 * GetSaveFileNameW (COMDLG32.@)
4089 * Creates a dialog box for the user to select a file to save.
4091 * RETURNS
4092 * TRUE on success: user enters a valid file
4093 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4096 BOOL WINAPI GetSaveFileNameW(
4097 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4099 BOOL win16look = FALSE;
4101 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4102 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4104 if (win16look)
4105 return GetFileName31W(ofn, SAVE_DIALOG);
4106 else
4107 return GetFileDialog95W(ofn, SAVE_DIALOG);
4110 /***********************************************************************
4111 * GetFileTitleA (COMDLG32.@)
4113 * See GetFileTitleW.
4115 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4117 int ret;
4118 UNICODE_STRING strWFile;
4119 LPWSTR lpWTitle;
4121 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4122 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4123 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4124 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4125 RtlFreeUnicodeString( &strWFile );
4126 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4127 return ret;
4131 /***********************************************************************
4132 * GetFileTitleW (COMDLG32.@)
4134 * Get the name of a file.
4136 * PARAMS
4137 * lpFile [I] name and location of file
4138 * lpTitle [O] returned file name
4139 * cbBuf [I] buffer size of lpTitle
4141 * RETURNS
4142 * Success: zero
4143 * Failure: negative number.
4145 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4147 int i, len;
4148 static const WCHAR brkpoint[] = {'*','[',']',0};
4149 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4151 if(lpFile == NULL || lpTitle == NULL)
4152 return -1;
4154 len = lstrlenW(lpFile);
4156 if (len == 0)
4157 return -1;
4159 if(strpbrkW(lpFile, brkpoint))
4160 return -1;
4162 len--;
4164 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4165 return -1;
4167 for(i = len; i >= 0; i--)
4169 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4171 i++;
4172 break;
4176 if(i == -1)
4177 i++;
4179 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4181 len = lstrlenW(lpFile+i)+1;
4182 if(cbBuf < len)
4183 return len;
4185 lstrcpyW(lpTitle, &lpFile[i]);
4186 return 0;