push 573c111636dcd80fa61914ac833187ced6019cb7
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blobb8206243c1914fb0d2a53f0f8cf378e74a2f4224
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("0x%04x 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_ENABLESIZING)
1151 GetWindowRect( hwnd, &rc);
1152 /* FIXME: should remember sizes of last invocation */
1153 fodInfos->sizedlg.cx = rc.right - rc.left;
1154 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1155 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1156 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1157 GetClientRect( hwnd, &rc);
1158 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1159 rc.right - gripx, rc.bottom - gripy,
1160 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1163 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1165 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1166 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1167 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1169 return 0;
1171 case WM_SIZE:
1172 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1173 case WM_GETMINMAXINFO:
1174 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1175 case WM_COMMAND:
1176 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1177 case WM_DRAWITEM:
1179 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1181 case IDC_LOOKIN:
1182 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1183 return TRUE;
1186 return FALSE;
1188 case WM_GETISHELLBROWSER:
1189 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1191 case WM_DESTROY:
1192 RemovePropA(hwnd, FileOpenDlgInfosStr);
1193 return FALSE;
1195 case WM_NOTIFY:
1197 LPNMHDR lpnmh = (LPNMHDR)lParam;
1198 UINT stringId = -1;
1200 /* set up the button tooltips strings */
1201 if(TTN_GETDISPINFOA == lpnmh->code )
1203 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1204 switch(lpnmh->idFrom )
1206 /* Up folder button */
1207 case FCIDM_TB_UPFOLDER:
1208 stringId = IDS_UPFOLDER;
1209 break;
1210 /* New folder button */
1211 case FCIDM_TB_NEWFOLDER:
1212 stringId = IDS_NEWFOLDER;
1213 break;
1214 /* List option button */
1215 case FCIDM_TB_SMALLICON:
1216 stringId = IDS_LISTVIEW;
1217 break;
1218 /* Details option button */
1219 case FCIDM_TB_REPORTVIEW:
1220 stringId = IDS_REPORTVIEW;
1221 break;
1222 /* Desktop button */
1223 case FCIDM_TB_DESKTOP:
1224 stringId = IDS_TODESKTOP;
1225 break;
1226 default:
1227 stringId = 0;
1229 lpdi->hinst = COMDLG32_hInstance;
1230 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1232 return FALSE;
1234 default :
1235 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1236 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1237 return FALSE;
1241 /***********************************************************************
1242 * FILEDLG95_InitControls
1244 * WM_INITDIALOG message handler (before hook notification)
1246 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1248 int win2000plus = 0;
1249 int win98plus = 0;
1250 int handledPath = FALSE;
1251 OSVERSIONINFOW osVi;
1252 static const WCHAR szwSlash[] = { '\\', 0 };
1253 static const WCHAR szwStar[] = { '*',0 };
1255 static const TBBUTTON tbb[] =
1257 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1258 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1259 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1260 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1261 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1262 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1263 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1264 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1265 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1267 TBADDBITMAP tba[2];
1268 RECT rectTB;
1269 RECT rectlook;
1270 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1272 tba[0].hInst = HINST_COMMCTRL;
1273 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1274 tba[1].hInst = COMDLG32_hInstance;
1275 tba[1].nID = 800;
1277 TRACE("%p\n", fodInfos);
1279 /* Get windows version emulating */
1280 osVi.dwOSVersionInfoSize = sizeof(osVi);
1281 GetVersionExW(&osVi);
1282 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1283 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1284 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1285 win2000plus = (osVi.dwMajorVersion > 4);
1286 if (win2000plus) win98plus = TRUE;
1288 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1290 /* Get the hwnd of the controls */
1291 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1292 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1293 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1295 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1296 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1298 /* construct the toolbar */
1299 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1300 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1302 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1303 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1304 rectTB.left = rectlook.right;
1305 rectTB.top = rectlook.top-1;
1307 if (fodInfos->unicode)
1308 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1309 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1310 rectTB.left, rectTB.top,
1311 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1312 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1313 else
1314 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1315 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1316 rectTB.left, rectTB.top,
1317 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1318 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1320 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1322 /* FIXME: use TB_LOADIMAGES when implemented */
1323 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1324 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1325 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1327 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1328 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1330 /* Set the window text with the text specified in the OPENFILENAME structure */
1331 if(fodInfos->title)
1333 SetWindowTextW(hwnd,fodInfos->title);
1335 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1337 WCHAR buf[16];
1338 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1339 SetWindowTextW(hwnd, buf);
1342 /* Initialise the file name edit control */
1343 handledPath = FALSE;
1344 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1346 if(fodInfos->filename)
1348 /* 1. If win2000 or higher and filename contains a path, use it
1349 in preference over the lpstrInitialDir */
1350 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1351 WCHAR tmpBuf[MAX_PATH];
1352 WCHAR *nameBit;
1353 DWORD result;
1355 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1356 if (result) {
1358 /* nameBit is always shorter than the original filename */
1359 lstrcpyW(fodInfos->filename,nameBit);
1361 *nameBit = 0x00;
1362 if (fodInfos->initdir == NULL)
1363 MemFree(fodInfos->initdir);
1364 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1365 lstrcpyW(fodInfos->initdir, tmpBuf);
1366 handledPath = TRUE;
1367 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1368 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1370 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1372 } else {
1373 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1377 /* 2. (All platforms) If initdir is not null, then use it */
1378 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1379 (*fodInfos->initdir!=0x00))
1381 /* Work out the proper path as supplied one might be relative */
1382 /* (Here because supplying '.' as dir browses to My Computer) */
1383 if (handledPath==FALSE) {
1384 WCHAR tmpBuf[MAX_PATH];
1385 WCHAR tmpBuf2[MAX_PATH];
1386 WCHAR *nameBit;
1387 DWORD result;
1389 lstrcpyW(tmpBuf, fodInfos->initdir);
1390 if( PathFileExistsW(tmpBuf) ) {
1391 /* initdir does not have to be a directory. If a file is
1392 * specified, the dir part is taken */
1393 if( PathIsDirectoryW(tmpBuf)) {
1394 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1395 lstrcatW(tmpBuf, szwSlash);
1397 lstrcatW(tmpBuf, szwStar);
1399 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1400 if (result) {
1401 *nameBit = 0x00;
1402 MemFree(fodInfos->initdir);
1403 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1404 lstrcpyW(fodInfos->initdir, tmpBuf2);
1405 handledPath = TRUE;
1406 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1409 else if (fodInfos->initdir)
1411 MemFree(fodInfos->initdir);
1412 fodInfos->initdir = NULL;
1413 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1418 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1419 (*fodInfos->initdir==0x00)))
1421 /* 3. All except w2k+: if filename contains a path use it */
1422 if (!win2000plus && fodInfos->filename &&
1423 *fodInfos->filename &&
1424 strpbrkW(fodInfos->filename, szwSlash)) {
1425 WCHAR tmpBuf[MAX_PATH];
1426 WCHAR *nameBit;
1427 DWORD result;
1429 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1430 tmpBuf, &nameBit);
1431 if (result) {
1432 int len;
1434 /* nameBit is always shorter than the original filename */
1435 lstrcpyW(fodInfos->filename, nameBit);
1436 *nameBit = 0x00;
1438 len = lstrlenW(tmpBuf);
1439 MemFree(fodInfos->initdir);
1440 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1441 lstrcpyW(fodInfos->initdir, tmpBuf);
1443 handledPath = TRUE;
1444 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1445 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1447 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1450 /* 4. win98+ and win2000+ if any files of specified filter types in
1451 current directory, use it */
1452 if ( win98plus && handledPath == FALSE &&
1453 fodInfos->filter && *fodInfos->filter) {
1455 BOOL searchMore = TRUE;
1456 LPCWSTR lpstrPos = fodInfos->filter;
1457 WIN32_FIND_DATAW FindFileData;
1458 HANDLE hFind;
1460 while (searchMore)
1462 /* filter is a list... title\0ext\0......\0\0 */
1464 /* Skip the title */
1465 if(! *lpstrPos) break; /* end */
1466 lpstrPos += lstrlenW(lpstrPos) + 1;
1468 /* See if any files exist in the current dir with this extension */
1469 if(! *lpstrPos) break; /* end */
1471 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1473 if (hFind == INVALID_HANDLE_VALUE) {
1474 /* None found - continue search */
1475 lpstrPos += lstrlenW(lpstrPos) + 1;
1477 } else {
1478 searchMore = FALSE;
1480 MemFree(fodInfos->initdir);
1481 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1482 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1484 handledPath = TRUE;
1485 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1486 debugstr_w(lpstrPos));
1487 break;
1492 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1494 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1495 if (handledPath == FALSE && (win2000plus || win98plus)) {
1496 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1498 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1500 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1502 /* last fallback */
1503 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1504 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1505 } else {
1506 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1508 } else {
1509 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1511 handledPath = TRUE;
1512 } else if (handledPath==FALSE) {
1513 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1514 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1515 handledPath = TRUE;
1516 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1519 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1520 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1522 /* Must the open as read only check box be checked ?*/
1523 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1525 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1528 /* Must the open as read only check box be hidden? */
1529 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1531 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1532 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1535 /* Must the help button be hidden? */
1536 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1538 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1539 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1542 /* change Open to Save */
1543 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1545 WCHAR buf[16];
1546 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1547 SetDlgItemTextW(hwnd, IDOK, buf);
1548 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1549 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1552 /* Initialize the filter combo box */
1553 FILEDLG95_FILETYPE_Init(hwnd);
1555 return 0;
1558 /***********************************************************************
1559 * FILEDLG95_ResizeControls
1561 * WM_INITDIALOG message handler (after hook notification)
1563 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1565 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1567 if (fodInfos->DlgInfos.hwndCustomDlg)
1569 RECT rc;
1570 UINT flags = SWP_NOACTIVATE;
1572 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1573 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1575 /* resize the custom dialog to the parent size */
1576 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1577 GetClientRect(hwnd, &rc);
1578 else
1580 /* our own fake template is zero sized and doesn't have children, so
1581 * there is no need to resize it. Picasa depends on it.
1583 flags |= SWP_NOSIZE;
1584 SetRectEmpty(&rc);
1586 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1587 0, 0, rc.right, rc.bottom, flags);
1589 else
1591 /* Resize the height, if open as read only checkbox ad help button are
1592 * hidden and we are not using a custom template nor a customDialog
1594 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1595 (!(fodInfos->ofnInfos->Flags &
1596 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1598 RECT rectDlg, rectHelp, rectCancel;
1599 GetWindowRect(hwnd, &rectDlg);
1600 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1601 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1602 /* subtract the height of the help button plus the space between the help
1603 * button and the cancel button to the height of the dialog
1605 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1606 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1607 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1610 return TRUE;
1613 /***********************************************************************
1614 * FILEDLG95_FillControls
1616 * WM_INITDIALOG message handler (after hook notification)
1618 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1620 LPITEMIDLIST pidlItemId = NULL;
1622 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1624 TRACE("dir=%s file=%s\n",
1625 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1627 /* Get the initial directory pidl */
1629 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1631 WCHAR path[MAX_PATH];
1633 GetCurrentDirectoryW(MAX_PATH,path);
1634 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1637 /* Initialise shell objects */
1638 FILEDLG95_SHELL_Init(hwnd);
1640 /* Initialize the Look In combo box */
1641 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1643 /* Browse to the initial directory */
1644 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1646 /* Free pidlItem memory */
1647 COMDLG32_SHFree(pidlItemId);
1649 return TRUE;
1651 /***********************************************************************
1652 * FILEDLG95_Clean
1654 * Regroups all the cleaning functions of the filedlg
1656 void FILEDLG95_Clean(HWND hwnd)
1658 FILEDLG95_FILETYPE_Clean(hwnd);
1659 FILEDLG95_LOOKIN_Clean(hwnd);
1660 FILEDLG95_SHELL_Clean(hwnd);
1662 /***********************************************************************
1663 * FILEDLG95_OnWMCommand
1665 * WM_COMMAND message handler
1667 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1669 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1670 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1671 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1673 switch(wID)
1675 /* OK button */
1676 case IDOK:
1677 FILEDLG95_OnOpen(hwnd);
1678 break;
1679 /* Cancel button */
1680 case IDCANCEL:
1681 FILEDLG95_Clean(hwnd);
1682 EndDialog(hwnd, FALSE);
1683 break;
1684 /* Filetype combo box */
1685 case IDC_FILETYPE:
1686 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1687 break;
1688 /* LookIn combo box */
1689 case IDC_LOOKIN:
1690 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1691 break;
1693 /* --- toolbar --- */
1694 /* Up folder button */
1695 case FCIDM_TB_UPFOLDER:
1696 FILEDLG95_SHELL_UpFolder(hwnd);
1697 break;
1698 /* New folder button */
1699 case FCIDM_TB_NEWFOLDER:
1700 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1701 break;
1702 /* List option button */
1703 case FCIDM_TB_SMALLICON:
1704 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1705 break;
1706 /* Details option button */
1707 case FCIDM_TB_REPORTVIEW:
1708 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1709 break;
1710 /* Details option button */
1711 case FCIDM_TB_DESKTOP:
1712 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1713 break;
1715 case IDC_FILENAME:
1716 break;
1719 /* Do not use the listview selection anymore */
1720 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1721 return 0;
1724 /***********************************************************************
1725 * FILEDLG95_OnWMGetIShellBrowser
1727 * WM_GETISHELLBROWSER message handler
1729 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1731 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1733 TRACE("\n");
1735 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1737 return TRUE;
1741 /***********************************************************************
1742 * FILEDLG95_SendFileOK
1744 * Sends the CDN_FILEOK notification if required
1746 * RETURNS
1747 * TRUE if the dialog should close
1748 * FALSE if the dialog should not be closed
1750 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1752 /* ask the hook if we can close */
1753 if(IsHooked(fodInfos))
1755 LRESULT retval = 0;
1757 TRACE("---\n");
1758 /* First send CDN_FILEOK as MSDN doc says */
1759 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1760 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1761 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1763 TRACE("canceled\n");
1764 return (retval == 0);
1767 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1768 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1769 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1770 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1772 TRACE("canceled\n");
1773 return (retval == 0);
1776 return TRUE;
1779 /***********************************************************************
1780 * FILEDLG95_OnOpenMultipleFiles
1782 * Handles the opening of multiple files.
1784 * FIXME
1785 * check destination buffer size
1787 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1789 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1790 UINT nCount, nSizePath;
1791 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1793 TRACE("\n");
1795 if(fodInfos->unicode)
1797 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1798 ofn->lpstrFile[0] = '\0';
1800 else
1802 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1803 ofn->lpstrFile[0] = '\0';
1806 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1808 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1809 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1810 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1812 LPWSTR lpstrTemp = lpstrFileList;
1814 for ( nCount = 0; nCount < nFileCount; nCount++ )
1816 LPITEMIDLIST pidl;
1818 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1819 if (!pidl)
1821 WCHAR lpstrNotFound[100];
1822 WCHAR lpstrMsg[100];
1823 WCHAR tmp[400];
1824 static const WCHAR nl[] = {'\n',0};
1826 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1827 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1829 lstrcpyW(tmp, lpstrTemp);
1830 lstrcatW(tmp, nl);
1831 lstrcatW(tmp, lpstrNotFound);
1832 lstrcatW(tmp, nl);
1833 lstrcatW(tmp, lpstrMsg);
1835 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1836 return FALSE;
1839 /* move to the next file in the list of files */
1840 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1841 COMDLG32_SHFree(pidl);
1845 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1846 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1848 /* For "oldstyle" dialog the components have to
1849 be separated by blanks (not '\0'!) and short
1850 filenames have to be used! */
1851 FIXME("Components have to be separated by blanks\n");
1853 if(fodInfos->unicode)
1855 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1856 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1857 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1859 else
1861 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1863 if (ofn->lpstrFile != NULL)
1865 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1866 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1867 if (ofn->nMaxFile > nSizePath)
1869 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1870 ofn->lpstrFile + nSizePath,
1871 ofn->nMaxFile - nSizePath, NULL, NULL);
1876 fodInfos->ofnInfos->nFileOffset = nSizePath;
1877 fodInfos->ofnInfos->nFileExtension = 0;
1879 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1880 return FALSE;
1882 /* clean and exit */
1883 FILEDLG95_Clean(hwnd);
1884 return EndDialog(hwnd,TRUE);
1887 /***********************************************************************
1888 * FILEDLG95_OnOpen
1890 * Ok button WM_COMMAND message handler
1892 * If the function succeeds, the return value is nonzero.
1894 #define ONOPEN_BROWSE 1
1895 #define ONOPEN_OPEN 2
1896 #define ONOPEN_SEARCH 3
1897 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1899 WCHAR strMsgTitle[MAX_PATH];
1900 WCHAR strMsgText [MAX_PATH];
1901 if (idCaption)
1902 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1903 else
1904 strMsgTitle[0] = '\0';
1905 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1906 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1909 BOOL FILEDLG95_OnOpen(HWND hwnd)
1911 LPWSTR lpstrFileList;
1912 UINT nFileCount = 0;
1913 UINT sizeUsed = 0;
1914 BOOL ret = TRUE;
1915 WCHAR lpstrPathAndFile[MAX_PATH];
1916 WCHAR lpstrTemp[MAX_PATH];
1917 LPSHELLFOLDER lpsf = NULL;
1918 int nOpenAction;
1919 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1921 TRACE("hwnd=%p\n", hwnd);
1923 /* get the files from the edit control */
1924 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1926 /* try if the user selected a folder in the shellview */
1927 if(nFileCount == 0)
1929 BrowseSelectedFolder(hwnd);
1930 return FALSE;
1933 if(nFileCount > 1)
1935 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1936 goto ret;
1939 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1942 Step 1: Build a complete path name from the current folder and
1943 the filename or path in the edit box.
1944 Special cases:
1945 - the path in the edit box is a root path
1946 (with or without drive letter)
1947 - the edit box contains ".." (or a path with ".." in it)
1950 /* Get the current directory name */
1951 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1953 /* last fallback */
1954 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1956 PathAddBackslashW(lpstrPathAndFile);
1958 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1960 /* if the user specified a fully qualified path use it */
1961 if(PathIsRelativeW(lpstrFileList))
1963 lstrcatW(lpstrPathAndFile, lpstrFileList);
1965 else
1967 /* does the path have a drive letter? */
1968 if (PathGetDriveNumberW(lpstrFileList) == -1)
1969 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1970 else
1971 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1974 /* resolve "." and ".." */
1975 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1976 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1977 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1979 MemFree(lpstrFileList);
1982 Step 2: here we have a cleaned up path
1984 We have to parse the path step by step to see if we have to browse
1985 to a folder if the path points to a directory or the last
1986 valid element is a directory.
1988 valid variables:
1989 lpstrPathAndFile: cleaned up path
1992 if (nFileCount &&
1993 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1994 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1995 nOpenAction = ONOPEN_OPEN;
1996 else
1997 nOpenAction = ONOPEN_BROWSE;
1999 /* don't apply any checks with OFN_NOVALIDATE */
2001 LPWSTR lpszTemp, lpszTemp1;
2002 LPITEMIDLIST pidl = NULL;
2003 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2005 /* check for invalid chars */
2006 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2008 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2009 ret = FALSE;
2010 goto ret;
2013 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2015 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2016 while (lpszTemp1)
2018 LPSHELLFOLDER lpsfChild;
2019 WCHAR lpwstrTemp[MAX_PATH];
2020 DWORD dwEaten, dwAttributes;
2021 LPWSTR p;
2023 lstrcpyW(lpwstrTemp, lpszTemp);
2024 p = PathFindNextComponentW(lpwstrTemp);
2026 if (!p) break; /* end of path */
2028 *p = 0;
2029 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2031 /* There are no wildcards when OFN_NOVALIDATE is set */
2032 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2034 static const WCHAR wszWild[] = { '*', '?', 0 };
2035 /* if the last element is a wildcard do a search */
2036 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2038 nOpenAction = ONOPEN_SEARCH;
2039 break;
2042 lpszTemp1 = lpszTemp;
2044 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2046 /* append a backslash to drive letters */
2047 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2048 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2049 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2051 PathAddBackslashW(lpwstrTemp);
2054 dwAttributes = SFGAO_FOLDER;
2055 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2057 /* the path component is valid, we have a pidl of the next path component */
2058 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2059 if(dwAttributes & SFGAO_FOLDER)
2061 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2063 ERR("bind to failed\n"); /* should not fail */
2064 break;
2066 IShellFolder_Release(lpsf);
2067 lpsf = lpsfChild;
2068 lpsfChild = NULL;
2070 else
2072 TRACE("value\n");
2074 /* end dialog, return value */
2075 nOpenAction = ONOPEN_OPEN;
2076 break;
2078 COMDLG32_SHFree(pidl);
2079 pidl = NULL;
2081 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2083 if(*lpszTemp || /* points to trailing null for last path element */
2084 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2086 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2088 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2089 break;
2092 else
2094 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2095 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2097 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2098 break;
2101 /* change to the current folder */
2102 nOpenAction = ONOPEN_OPEN;
2103 break;
2105 else
2107 nOpenAction = ONOPEN_OPEN;
2108 break;
2111 if(pidl) COMDLG32_SHFree(pidl);
2115 Step 3: here we have a cleaned up and validated path
2117 valid variables:
2118 lpsf: ShellFolder bound to the rightmost valid path component
2119 lpstrPathAndFile: cleaned up path
2120 nOpenAction: action to do
2122 TRACE("end validate sf=%p\n", lpsf);
2124 switch(nOpenAction)
2126 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2127 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2129 int iPos;
2130 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2131 DWORD len;
2133 /* replace the current filter */
2134 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2135 len = lstrlenW(lpszTemp)+1;
2136 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2137 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2139 /* set the filter cb to the extension when possible */
2140 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2141 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2143 /* fall through */
2144 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2145 TRACE("ONOPEN_BROWSE\n");
2147 IPersistFolder2 * ppf2;
2148 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2150 LPITEMIDLIST pidlCurrent;
2151 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2152 IPersistFolder2_Release(ppf2);
2153 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2155 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2156 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2158 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2161 else if( nOpenAction == ONOPEN_SEARCH )
2163 if (fodInfos->Shell.FOIShellView)
2164 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2166 COMDLG32_SHFree(pidlCurrent);
2167 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2170 ret = FALSE;
2171 break;
2172 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2173 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2175 WCHAR *ext = NULL;
2177 /* update READONLY check box flag */
2178 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2179 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2180 else
2181 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2183 /* Attach the file extension with file name*/
2184 ext = PathFindExtensionW(lpstrPathAndFile);
2185 if (! *ext)
2187 /* if no extension is specified with file name, then */
2188 /* attach the extension from file filter or default one */
2190 WCHAR *filterExt = NULL;
2191 LPWSTR lpstrFilter = NULL;
2192 static const WCHAR szwDot[] = {'.',0};
2193 int PathLength = lstrlenW(lpstrPathAndFile);
2195 /* Attach the dot*/
2196 lstrcatW(lpstrPathAndFile, szwDot);
2198 /*Get the file extension from file type filter*/
2199 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2200 fodInfos->ofnInfos->nFilterIndex-1);
2202 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2203 filterExt = PathFindExtensionW(lpstrFilter);
2205 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2206 lstrcatW(lpstrPathAndFile, filterExt + 1);
2207 else if ( fodInfos->defext ) /* attach the default file extension*/
2208 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2210 /* In Open dialog: if file does not exist try without extension */
2211 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2212 lpstrPathAndFile[PathLength] = '\0';
2215 if (fodInfos->defext) /* add default extension */
2217 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2218 if (*ext)
2219 ext++;
2220 if (!lstrcmpiW(fodInfos->defext, ext))
2221 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2222 else
2223 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2226 /* In Save dialog: check if the file already exists */
2227 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2228 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2229 && PathFileExistsW(lpstrPathAndFile))
2231 WCHAR lpstrOverwrite[100];
2232 int answer;
2234 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2235 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2236 MB_YESNO | MB_ICONEXCLAMATION);
2237 if (answer == IDNO)
2239 ret = FALSE;
2240 goto ret;
2244 /* In Open dialog: check if it should be created if it doesn't exist */
2245 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2246 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2247 && !PathFileExistsW(lpstrPathAndFile))
2249 WCHAR lpstrCreate[100];
2250 int answer;
2252 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2253 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2254 MB_YESNO | MB_ICONEXCLAMATION);
2255 if (answer == IDNO)
2257 ret = FALSE;
2258 goto ret;
2262 /* Check that the size of the file does not exceed buffer size.
2263 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2264 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2265 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2268 /* fill destination buffer */
2269 if (fodInfos->ofnInfos->lpstrFile)
2271 if(fodInfos->unicode)
2273 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2275 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2276 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2277 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2279 else
2281 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2283 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2284 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2285 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2286 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2290 if(fodInfos->unicode)
2292 LPWSTR lpszTemp;
2294 /* set filename offset */
2295 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2296 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2298 /* set extension offset */
2299 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2300 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2302 else
2304 LPSTR lpszTemp;
2305 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2307 /* set filename offset */
2308 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2309 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2311 /* set extension offset */
2312 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2313 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2316 /* set the lpstrFileTitle */
2317 if(fodInfos->ofnInfos->lpstrFileTitle)
2319 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2320 if(fodInfos->unicode)
2322 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2323 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2325 else
2327 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2328 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2329 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2333 /* copy currently selected filter to lpstrCustomFilter */
2334 if (fodInfos->ofnInfos->lpstrCustomFilter)
2336 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2337 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2338 NULL, 0, NULL, NULL);
2339 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2341 LPSTR s = ofn->lpstrCustomFilter;
2342 s += strlen(ofn->lpstrCustomFilter)+1;
2343 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2344 s, len, NULL, NULL);
2349 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2350 goto ret;
2352 TRACE("close\n");
2353 FILEDLG95_Clean(hwnd);
2354 ret = EndDialog(hwnd, TRUE);
2356 else
2358 WORD size;
2360 size = lstrlenW(lpstrPathAndFile) + 1;
2361 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2362 size += 1;
2363 /* return needed size in first two bytes of lpstrFile */
2364 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2365 FILEDLG95_Clean(hwnd);
2366 ret = EndDialog(hwnd, FALSE);
2367 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2370 break;
2373 ret:
2374 if(lpsf) IShellFolder_Release(lpsf);
2375 return ret;
2378 /***********************************************************************
2379 * FILEDLG95_SHELL_Init
2381 * Initialisation of the shell objects
2383 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2385 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2387 TRACE("\n");
2390 * Initialisation of the FileOpenDialogInfos structure
2393 /* Shell */
2395 /*ShellInfos */
2396 fodInfos->ShellInfos.hwndOwner = hwnd;
2398 /* Disable multi-select if flag not set */
2399 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2401 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2403 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2404 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2406 /* Construct the IShellBrowser interface */
2407 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2409 return NOERROR;
2412 /***********************************************************************
2413 * FILEDLG95_SHELL_ExecuteCommand
2415 * Change the folder option and refresh the view
2416 * If the function succeeds, the return value is nonzero.
2418 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2420 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2421 IContextMenu * pcm;
2423 TRACE("(%p,%p)\n", hwnd, lpVerb);
2425 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2426 SVGIO_BACKGROUND,
2427 &IID_IContextMenu,
2428 (LPVOID*)&pcm)))
2430 CMINVOKECOMMANDINFO ci;
2431 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2432 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2433 ci.lpVerb = lpVerb;
2434 ci.hwnd = hwnd;
2436 IContextMenu_InvokeCommand(pcm, &ci);
2437 IContextMenu_Release(pcm);
2440 return FALSE;
2443 /***********************************************************************
2444 * FILEDLG95_SHELL_UpFolder
2446 * Browse to the specified object
2447 * If the function succeeds, the return value is nonzero.
2449 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2451 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2453 TRACE("\n");
2455 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2456 NULL,
2457 SBSP_PARENT)))
2459 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2460 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2461 return TRUE;
2463 return FALSE;
2466 /***********************************************************************
2467 * FILEDLG95_SHELL_BrowseToDesktop
2469 * Browse to the Desktop
2470 * If the function succeeds, the return value is nonzero.
2472 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2474 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2475 LPITEMIDLIST pidl;
2476 HRESULT hres;
2478 TRACE("\n");
2480 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2481 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2482 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2483 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2484 COMDLG32_SHFree(pidl);
2485 return SUCCEEDED(hres);
2487 /***********************************************************************
2488 * FILEDLG95_SHELL_Clean
2490 * Cleans the memory used by shell objects
2492 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2494 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2496 TRACE("\n");
2498 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2500 /* clean Shell interfaces */
2501 if (fodInfos->Shell.FOIShellView)
2503 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2504 IShellView_Release(fodInfos->Shell.FOIShellView);
2506 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2507 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2508 if (fodInfos->Shell.FOIDataObject)
2509 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2512 /***********************************************************************
2513 * FILEDLG95_FILETYPE_Init
2515 * Initialisation of the file type combo box
2517 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2519 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2520 int nFilters = 0; /* number of filters */
2521 int nFilterIndexCB;
2523 TRACE("\n");
2525 if(fodInfos->customfilter)
2527 /* customfilter has one entry... title\0ext\0
2528 * Set first entry of combo box item with customfilter
2530 LPWSTR lpstrExt;
2531 LPCWSTR lpstrPos = fodInfos->customfilter;
2533 /* Get the title */
2534 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2536 /* Copy the extensions */
2537 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2538 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2539 lstrcpyW(lpstrExt,lpstrPos);
2541 /* Add the item at the end of the combo */
2542 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2543 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2544 nFilters++;
2546 if(fodInfos->filter)
2548 LPCWSTR lpstrPos = fodInfos->filter;
2550 for(;;)
2552 /* filter is a list... title\0ext\0......\0\0
2553 * Set the combo item text to the title and the item data
2554 * to the ext
2556 LPCWSTR lpstrDisplay;
2557 LPWSTR lpstrExt;
2559 /* Get the title */
2560 if(! *lpstrPos) break; /* end */
2561 lpstrDisplay = lpstrPos;
2562 lpstrPos += lstrlenW(lpstrPos) + 1;
2564 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2566 nFilters++;
2568 /* Copy the extensions */
2569 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2570 lstrcpyW(lpstrExt,lpstrPos);
2571 lpstrPos += lstrlenW(lpstrPos) + 1;
2573 /* Add the item at the end of the combo */
2574 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2576 /* malformed filters are added anyway... */
2577 if (!*lpstrExt) break;
2582 * Set the current filter to the one specified
2583 * in the initialisation structure
2585 if (fodInfos->filter || fodInfos->customfilter)
2587 LPWSTR lpstrFilter;
2589 /* Check to make sure our index isn't out of bounds. */
2590 if ( fodInfos->ofnInfos->nFilterIndex >
2591 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2592 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2594 /* set default filter index */
2595 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2596 fodInfos->ofnInfos->nFilterIndex = 1;
2598 /* calculate index of Combo Box item */
2599 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2600 if (fodInfos->customfilter == NULL)
2601 nFilterIndexCB--;
2603 /* Set the current index selection. */
2604 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2606 /* Get the corresponding text string from the combo box. */
2607 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2608 nFilterIndexCB);
2610 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2611 lpstrFilter = NULL;
2613 if(lpstrFilter)
2615 DWORD len;
2616 CharLowerW(lpstrFilter); /* lowercase */
2617 len = lstrlenW(lpstrFilter)+1;
2618 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2619 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2621 } else
2622 fodInfos->ofnInfos->nFilterIndex = 0;
2623 return S_OK;
2626 /***********************************************************************
2627 * FILEDLG95_FILETYPE_OnCommand
2629 * WM_COMMAND of the file type combo box
2630 * If the function succeeds, the return value is nonzero.
2632 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2634 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2636 switch(wNotifyCode)
2638 case CBN_SELENDOK:
2640 LPWSTR lpstrFilter;
2642 /* Get the current item of the filetype combo box */
2643 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2645 /* set the current filter index */
2646 fodInfos->ofnInfos->nFilterIndex = iItem +
2647 (fodInfos->customfilter == NULL ? 1 : 0);
2649 /* Set the current filter with the current selection */
2650 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2652 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2653 iItem);
2654 if((INT_PTR)lpstrFilter != CB_ERR)
2656 DWORD len;
2657 CharLowerW(lpstrFilter); /* lowercase */
2658 len = lstrlenW(lpstrFilter)+1;
2659 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2660 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2661 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2662 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2665 /* Refresh the actual view to display the included items*/
2666 if (fodInfos->Shell.FOIShellView)
2667 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2670 return FALSE;
2672 /***********************************************************************
2673 * FILEDLG95_FILETYPE_SearchExt
2675 * searches for an extension in the filetype box
2677 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2679 int i, iCount = CBGetCount(hwnd);
2681 TRACE("%s\n", debugstr_w(lpstrExt));
2683 if(iCount != CB_ERR)
2685 for(i=0;i<iCount;i++)
2687 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2688 return i;
2691 return -1;
2694 /***********************************************************************
2695 * FILEDLG95_FILETYPE_Clean
2697 * Clean the memory used by the filetype combo box
2699 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2701 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2702 int iPos;
2703 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2705 TRACE("\n");
2707 /* Delete each string of the combo and their associated data */
2708 if(iCount != CB_ERR)
2710 for(iPos = iCount-1;iPos>=0;iPos--)
2712 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2713 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2716 /* Current filter */
2717 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2721 /***********************************************************************
2722 * FILEDLG95_LOOKIN_Init
2724 * Initialisation of the look in combo box
2727 /* Small helper function, to determine if the unixfs shell extension is rooted
2728 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2730 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2731 HKEY hKey;
2732 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2733 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2734 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2735 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2736 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2737 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2738 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2740 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2741 return FALSE;
2743 RegCloseKey(hKey);
2744 return TRUE;
2747 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2749 IShellFolder *psfRoot, *psfDrives;
2750 IEnumIDList *lpeRoot, *lpeDrives;
2751 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2753 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2755 TRACE("\n");
2757 liInfos->iMaxIndentation = 0;
2759 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2761 /* set item height for both text field and listbox */
2762 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2763 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2765 /* Turn on the extended UI for the combo box like Windows does */
2766 CBSetExtendedUI(hwndCombo, TRUE);
2768 /* Initialise data of Desktop folder */
2769 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2770 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2771 COMDLG32_SHFree(pidlTmp);
2773 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2775 SHGetDesktopFolder(&psfRoot);
2777 if (psfRoot)
2779 /* enumerate the contents of the desktop */
2780 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2782 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2784 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2786 /* If the unixfs extension is rooted, we don't expand the drives by default */
2787 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2789 /* special handling for CSIDL_DRIVES */
2790 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2792 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2794 /* enumerate the drives */
2795 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2797 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2799 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2800 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2801 COMDLG32_SHFree(pidlAbsTmp);
2802 COMDLG32_SHFree(pidlTmp1);
2804 IEnumIDList_Release(lpeDrives);
2806 IShellFolder_Release(psfDrives);
2811 COMDLG32_SHFree(pidlTmp);
2813 IEnumIDList_Release(lpeRoot);
2815 IShellFolder_Release(psfRoot);
2818 COMDLG32_SHFree(pidlDrives);
2821 /***********************************************************************
2822 * FILEDLG95_LOOKIN_DrawItem
2824 * WM_DRAWITEM message handler
2826 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2828 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2829 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2830 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2831 RECT rectText;
2832 RECT rectIcon;
2833 SHFILEINFOW sfi;
2834 HIMAGELIST ilItemImage;
2835 int iIndentation;
2836 TEXTMETRICW tm;
2837 LPSFOLDER tmpFolder;
2838 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2840 TRACE("\n");
2842 if(pDIStruct->itemID == -1)
2843 return 0;
2845 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2846 pDIStruct->itemID)))
2847 return 0;
2850 if(pDIStruct->itemID == liInfos->uSelectedItem)
2852 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2854 &sfi,
2855 sizeof (sfi),
2856 SHGFI_PIDL | SHGFI_SMALLICON |
2857 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2858 SHGFI_DISPLAYNAME );
2860 else
2862 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2864 &sfi,
2865 sizeof (sfi),
2866 SHGFI_PIDL | SHGFI_SMALLICON |
2867 SHGFI_SYSICONINDEX |
2868 SHGFI_DISPLAYNAME);
2871 /* Is this item selected ? */
2872 if(pDIStruct->itemState & ODS_SELECTED)
2874 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2875 SetBkColor(pDIStruct->hDC,crHighLight);
2876 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2878 else
2880 SetTextColor(pDIStruct->hDC,crText);
2881 SetBkColor(pDIStruct->hDC,crWin);
2882 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2885 /* Do not indent item if drawing in the edit of the combo */
2886 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2888 iIndentation = 0;
2889 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2891 &sfi,
2892 sizeof (sfi),
2893 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2894 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2897 else
2899 iIndentation = tmpFolder->m_iIndent;
2901 /* Draw text and icon */
2903 /* Initialise the icon display area */
2904 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2905 rectIcon.top = pDIStruct->rcItem.top;
2906 rectIcon.right = rectIcon.left + ICONWIDTH;
2907 rectIcon.bottom = pDIStruct->rcItem.bottom;
2909 /* Initialise the text display area */
2910 GetTextMetricsW(pDIStruct->hDC, &tm);
2911 rectText.left = rectIcon.right;
2912 rectText.top =
2913 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2914 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2915 rectText.bottom =
2916 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2918 /* Draw the icon from the image list */
2919 ImageList_Draw(ilItemImage,
2920 sfi.iIcon,
2921 pDIStruct->hDC,
2922 rectIcon.left,
2923 rectIcon.top,
2924 ILD_TRANSPARENT );
2926 /* Draw the associated text */
2927 if(sfi.szDisplayName)
2928 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2931 return NOERROR;
2934 /***********************************************************************
2935 * FILEDLG95_LOOKIN_OnCommand
2937 * LookIn combo box WM_COMMAND message handler
2938 * If the function succeeds, the return value is nonzero.
2940 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2942 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2944 TRACE("%p\n", fodInfos);
2946 switch(wNotifyCode)
2948 case CBN_SELENDOK:
2950 LPSFOLDER tmpFolder;
2951 int iItem;
2953 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2955 if( iItem == CB_ERR) return FALSE;
2957 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2958 iItem)))
2959 return FALSE;
2962 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2963 tmpFolder->pidlItem,
2964 SBSP_ABSOLUTE)))
2966 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2967 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2968 return TRUE;
2970 break;
2974 return FALSE;
2977 /***********************************************************************
2978 * FILEDLG95_LOOKIN_AddItem
2980 * Adds an absolute pidl item to the lookin combo box
2981 * returns the index of the inserted item
2983 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2985 LPITEMIDLIST pidlNext;
2986 SHFILEINFOW sfi;
2987 SFOLDER *tmpFolder;
2988 LookInInfos *liInfos;
2990 TRACE("%08x\n", iInsertId);
2992 if(!pidl)
2993 return -1;
2995 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
2996 return -1;
2998 tmpFolder = MemAlloc(sizeof(SFOLDER));
2999 tmpFolder->m_iIndent = 0;
3001 /* Calculate the indentation of the item in the lookin*/
3002 pidlNext = pidl;
3003 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3005 tmpFolder->m_iIndent++;
3008 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3010 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3011 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3013 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3014 SHGetFileInfoW((LPCWSTR)pidl,
3016 &sfi,
3017 sizeof(sfi),
3018 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3019 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3021 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3023 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3025 int iItemID;
3027 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3029 /* Add the item at the end of the list */
3030 if(iInsertId < 0)
3032 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3034 /* Insert the item at the iInsertId position*/
3035 else
3037 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3040 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3041 return iItemID;
3044 COMDLG32_SHFree( tmpFolder->pidlItem );
3045 MemFree( tmpFolder );
3046 return -1;
3050 /***********************************************************************
3051 * FILEDLG95_LOOKIN_InsertItemAfterParent
3053 * Insert an item below its parent
3055 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3058 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3059 int iParentPos;
3061 TRACE("\n");
3063 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3065 if(iParentPos < 0)
3067 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3070 /* Free pidlParent memory */
3071 COMDLG32_SHFree(pidlParent);
3073 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3076 /***********************************************************************
3077 * FILEDLG95_LOOKIN_SelectItem
3079 * Adds an absolute pidl item to the lookin combo box
3080 * returns the index of the inserted item
3082 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3084 int iItemPos;
3085 LookInInfos *liInfos;
3087 TRACE("\n");
3089 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3091 liInfos = GetPropA(hwnd,LookInInfosStr);
3093 if(iItemPos < 0)
3095 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3096 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3099 else
3101 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3102 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3104 int iRemovedItem;
3106 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3107 break;
3108 if(iRemovedItem < iItemPos)
3109 iItemPos--;
3113 CBSetCurSel(hwnd,iItemPos);
3114 liInfos->uSelectedItem = iItemPos;
3116 return 0;
3120 /***********************************************************************
3121 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3123 * Remove the item with an expansion level over iExpansionLevel
3125 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3127 int iItemPos;
3128 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3130 TRACE("\n");
3132 if(liInfos->iMaxIndentation <= 2)
3133 return -1;
3135 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3137 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3138 COMDLG32_SHFree(tmpFolder->pidlItem);
3139 MemFree(tmpFolder);
3140 CBDeleteString(hwnd,iItemPos);
3141 liInfos->iMaxIndentation--;
3143 return iItemPos;
3146 return -1;
3149 /***********************************************************************
3150 * FILEDLG95_LOOKIN_SearchItem
3152 * Search for pidl in the lookin combo box
3153 * returns the index of the found item
3155 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3157 int i = 0;
3158 int iCount = CBGetCount(hwnd);
3160 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3162 if (iCount != CB_ERR)
3164 for(;i<iCount;i++)
3166 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3168 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3169 return i;
3170 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3171 return i;
3175 return -1;
3178 /***********************************************************************
3179 * FILEDLG95_LOOKIN_Clean
3181 * Clean the memory used by the lookin combo box
3183 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3185 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3186 int iPos;
3187 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3189 TRACE("\n");
3191 /* Delete each string of the combo and their associated data */
3192 if (iCount != CB_ERR)
3194 for(iPos = iCount-1;iPos>=0;iPos--)
3196 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3197 COMDLG32_SHFree(tmpFolder->pidlItem);
3198 MemFree(tmpFolder);
3199 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3203 /* LookInInfos structure */
3204 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3207 /***********************************************************************
3208 * FILEDLG95_FILENAME_FillFromSelection
3210 * fills the edit box from the cached DataObject
3212 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3214 FileOpenDlgInfos *fodInfos;
3215 LPITEMIDLIST pidl;
3216 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3217 WCHAR lpstrTemp[MAX_PATH];
3218 LPWSTR lpstrAllFile, lpstrCurrFile;
3220 TRACE("\n");
3221 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3223 /* Count how many files we have */
3224 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3226 /* calculate the string length, count files */
3227 if (nFileSelected >= 1)
3229 nLength += 3; /* first and last quotes, trailing \0 */
3230 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3232 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3234 if (pidl)
3236 /* get the total length of the selected file names */
3237 lpstrTemp[0] = '\0';
3238 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3240 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3242 nLength += lstrlenW( lpstrTemp ) + 3;
3243 nFiles++;
3245 COMDLG32_SHFree( pidl );
3250 /* allocate the buffer */
3251 if (nFiles <= 1) nLength = MAX_PATH;
3252 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3254 /* Generate the string for the edit control */
3255 if(nFiles >= 1)
3257 lpstrCurrFile = lpstrAllFile;
3258 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3260 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3262 if (pidl)
3264 /* get the file name */
3265 lpstrTemp[0] = '\0';
3266 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3268 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3270 if ( nFiles > 1)
3272 *lpstrCurrFile++ = '\"';
3273 lstrcpyW( lpstrCurrFile, lpstrTemp );
3274 lpstrCurrFile += lstrlenW( lpstrTemp );
3275 *lpstrCurrFile++ = '\"';
3276 *lpstrCurrFile++ = ' ';
3277 *lpstrCurrFile = 0;
3279 else
3281 lstrcpyW( lpstrAllFile, lpstrTemp );
3284 COMDLG32_SHFree( pidl );
3287 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3289 /* Select the file name like Windows does */
3290 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3292 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3296 /* copied from shell32 to avoid linking to it
3297 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3298 * is dependent on whether emulated OS is unicode or not.
3300 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3302 switch (src->uType)
3304 case STRRET_WSTR:
3305 lstrcpynW(dest, src->u.pOleStr, len);
3306 COMDLG32_SHFree(src->u.pOleStr);
3307 break;
3309 case STRRET_CSTR:
3310 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3311 dest[len-1] = 0;
3312 break;
3314 case STRRET_OFFSET:
3315 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3316 dest[len-1] = 0;
3317 break;
3319 default:
3320 FIXME("unknown type %x!\n", src->uType);
3321 if (len) *dest = '\0';
3322 return E_FAIL;
3324 return S_OK;
3327 /***********************************************************************
3328 * FILEDLG95_FILENAME_GetFileNames
3330 * Copies the filenames to a delimited string list.
3331 * The delimiter is specified by the parameter 'separator',
3332 * usually either a space or a nul
3334 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3336 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3337 UINT nStrCharCount = 0; /* index in src buffer */
3338 UINT nFileIndex = 0; /* index in dest buffer */
3339 UINT nFileCount = 0; /* number of files */
3340 UINT nStrLen = 0; /* length of string in edit control */
3341 LPWSTR lpstrEdit; /* buffer for string from edit control */
3343 TRACE("\n");
3345 /* get the filenames from the edit control */
3346 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3347 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3348 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3350 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3352 /* we might get single filename without any '"',
3353 * so we need nStrLen + terminating \0 + end-of-list \0 */
3354 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3355 *sizeUsed = 0;
3357 /* build delimited file list from filenames */
3358 while ( nStrCharCount <= nStrLen )
3360 if ( lpstrEdit[nStrCharCount]=='"' )
3362 nStrCharCount++;
3363 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3365 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3366 nStrCharCount++;
3368 (*lpstrFileList)[nFileIndex++] = 0;
3369 nFileCount++;
3371 nStrCharCount++;
3374 /* single, unquoted string */
3375 if ((nStrLen > 0) && (nFileIndex == 0) )
3377 lstrcpyW(*lpstrFileList, lpstrEdit);
3378 nFileIndex = lstrlenW(lpstrEdit) + 1;
3379 nFileCount = 1;
3382 /* trailing \0 */
3383 (*lpstrFileList)[nFileIndex++] = '\0';
3385 *sizeUsed = nFileIndex;
3386 MemFree(lpstrEdit);
3387 return nFileCount;
3390 #define SETDefFormatEtc(fe,cf,med) \
3392 (fe).cfFormat = cf;\
3393 (fe).dwAspect = DVASPECT_CONTENT; \
3394 (fe).ptd =NULL;\
3395 (fe).tymed = med;\
3396 (fe).lindex = -1;\
3400 * DATAOBJECT Helper functions
3403 /***********************************************************************
3404 * COMCTL32_ReleaseStgMedium
3406 * like ReleaseStgMedium from ole32
3408 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3410 if(medium.pUnkForRelease)
3412 IUnknown_Release(medium.pUnkForRelease);
3414 else
3416 GlobalUnlock(medium.u.hGlobal);
3417 GlobalFree(medium.u.hGlobal);
3421 /***********************************************************************
3422 * GetPidlFromDataObject
3424 * Return pidl(s) by number from the cached DataObject
3426 * nPidlIndex=0 gets the fully qualified root path
3428 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3431 STGMEDIUM medium;
3432 FORMATETC formatetc;
3433 LPITEMIDLIST pidl = NULL;
3435 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3437 if (!doSelected)
3438 return NULL;
3440 /* Set the FORMATETC structure*/
3441 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3443 /* Get the pidls from IDataObject */
3444 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3446 LPIDA cida = GlobalLock(medium.u.hGlobal);
3447 if(nPidlIndex <= cida->cidl)
3449 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3451 COMCTL32_ReleaseStgMedium(medium);
3453 return pidl;
3456 /***********************************************************************
3457 * GetNumSelected
3459 * Return the number of selected items in the DataObject.
3462 static UINT GetNumSelected( IDataObject *doSelected )
3464 UINT retVal = 0;
3465 STGMEDIUM medium;
3466 FORMATETC formatetc;
3468 TRACE("sv=%p\n", doSelected);
3470 if (!doSelected) return 0;
3472 /* Set the FORMATETC structure*/
3473 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3475 /* Get the pidls from IDataObject */
3476 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3478 LPIDA cida = GlobalLock(medium.u.hGlobal);
3479 retVal = cida->cidl;
3480 COMCTL32_ReleaseStgMedium(medium);
3481 return retVal;
3483 return 0;
3487 * TOOLS
3490 /***********************************************************************
3491 * GetName
3493 * Get the pidl's display name (relative to folder) and
3494 * put it in lpstrFileName.
3496 * Return NOERROR on success,
3497 * E_FAIL otherwise
3500 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3502 STRRET str;
3503 HRESULT hRes;
3505 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3507 if(!lpsf)
3509 SHGetDesktopFolder(&lpsf);
3510 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3511 IShellFolder_Release(lpsf);
3512 return hRes;
3515 /* Get the display name of the pidl relative to the folder */
3516 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3518 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3520 return E_FAIL;
3523 /***********************************************************************
3524 * GetShellFolderFromPidl
3526 * pidlRel is the item pidl relative
3527 * Return the IShellFolder of the absolute pidl
3529 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3531 IShellFolder *psf = NULL,*psfParent;
3533 TRACE("%p\n", pidlAbs);
3535 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3537 psf = psfParent;
3538 if(pidlAbs && pidlAbs->mkid.cb)
3540 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3542 IShellFolder_Release(psfParent);
3543 return psf;
3546 /* return the desktop */
3547 return psfParent;
3549 return NULL;
3552 /***********************************************************************
3553 * GetParentPidl
3555 * Return the LPITEMIDLIST to the parent of the pidl in the list
3557 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3559 LPITEMIDLIST pidlParent;
3561 TRACE("%p\n", pidl);
3563 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3564 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3566 return pidlParent;
3569 /***********************************************************************
3570 * GetPidlFromName
3572 * returns the pidl of the file name relative to folder
3573 * NULL if an error occurred
3575 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3577 LPITEMIDLIST pidl = NULL;
3578 ULONG ulEaten;
3580 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3582 if(!lpcstrFileName) return NULL;
3583 if(!*lpcstrFileName) return NULL;
3585 if(!lpsf)
3587 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3588 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3589 IShellFolder_Release(lpsf);
3592 else
3594 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3596 return pidl;
3601 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3603 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3604 HRESULT ret;
3606 TRACE("%p, %p\n", psf, pidl);
3608 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3610 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3611 /* see documentation shell 4.1*/
3612 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3615 /***********************************************************************
3616 * BrowseSelectedFolder
3618 static BOOL BrowseSelectedFolder(HWND hwnd)
3620 BOOL bBrowseSelFolder = FALSE;
3621 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3623 TRACE("\n");
3625 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3627 LPITEMIDLIST pidlSelection;
3629 /* get the file selected */
3630 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3631 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3633 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3634 pidlSelection, SBSP_RELATIVE ) ) )
3636 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3637 ' ','n','o','t',' ','e','x','i','s','t',0};
3638 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3640 bBrowseSelFolder = TRUE;
3641 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3642 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3644 COMDLG32_SHFree( pidlSelection );
3647 return bBrowseSelFolder;
3651 * Memory allocation methods */
3652 static void *MemAlloc(UINT size)
3654 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3657 static void MemFree(void *mem)
3659 HeapFree(GetProcessHeap(),0,mem);
3663 * Old-style (win3.1) dialogs */
3665 /***********************************************************************
3666 * FD32_GetTemplate [internal]
3668 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3669 * by a 32 bits application
3672 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3674 LPOPENFILENAMEW ofnW = lfs->ofnW;
3675 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3676 HANDLE hDlgTmpl;
3678 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3680 if (!(lfs->template = LockResource( ofnW->hInstance )))
3682 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3683 return FALSE;
3686 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3688 HRSRC hResInfo;
3689 if (priv->ofnA)
3690 hResInfo = FindResourceA(priv->ofnA->hInstance,
3691 priv->ofnA->lpTemplateName,
3692 (LPSTR)RT_DIALOG);
3693 else
3694 hResInfo = FindResourceW(ofnW->hInstance,
3695 ofnW->lpTemplateName,
3696 (LPWSTR)RT_DIALOG);
3697 if (!hResInfo)
3699 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3700 return FALSE;
3702 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3703 hResInfo)) ||
3704 !(lfs->template = LockResource(hDlgTmpl)))
3706 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3707 return FALSE;
3709 } else { /* get it from internal Wine resource */
3710 HRSRC hResInfo;
3711 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3712 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3714 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3715 return FALSE;
3717 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3718 !(lfs->template = LockResource( hDlgTmpl )))
3720 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3721 return FALSE;
3724 return TRUE;
3728 /************************************************************************
3729 * FD32_Init [internal]
3730 * called from the common 16/32 code to initialize 32 bit data
3732 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3734 BOOL IsUnicode = (BOOL) data;
3735 PFD32_PRIVATE priv;
3737 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3738 lfs->private1632 = priv;
3739 if (NULL == lfs->private1632) return FALSE;
3740 if (IsUnicode)
3742 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3743 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3744 if (lfs->ofnW->lpfnHook)
3745 lfs->hook = TRUE;
3747 else
3749 priv->ofnA = (LPOPENFILENAMEA) lParam;
3750 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3751 if (priv->ofnA->lpfnHook)
3752 lfs->hook = TRUE;
3753 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3754 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3757 if (! FD32_GetTemplate(lfs)) return FALSE;
3759 return TRUE;
3762 /***********************************************************************
3763 * FD32_CallWindowProc [internal]
3765 * called from the common 16/32 code to call the appropriate hook
3767 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3768 LPARAM lParam)
3770 BOOL ret;
3771 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3773 if (priv->ofnA)
3775 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3776 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3777 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3778 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3779 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3780 return ret;
3783 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3784 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3785 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3786 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3787 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3788 return ret;
3791 /***********************************************************************
3792 * FD32_UpdateResult [internal]
3793 * update the real client structures if any
3795 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3797 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3798 LPOPENFILENAMEW ofnW = lfs->ofnW;
3800 if (priv->ofnA)
3802 LPSTR lpszTemp;
3803 if (ofnW->nMaxFile &&
3804 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3805 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3806 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3808 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3809 /* set filename offset */
3810 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3811 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3813 /* set extension offset */
3814 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3815 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3819 /***********************************************************************
3820 * FD32_UpdateFileTitle [internal]
3821 * update the real client structures if any
3823 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3825 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3826 LPOPENFILENAMEW ofnW = lfs->ofnW;
3828 if (priv->ofnA)
3830 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3831 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3832 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3837 /***********************************************************************
3838 * FD32_SendLbGetCurSel [internal]
3839 * retrieve selected listbox item
3841 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3843 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3847 /************************************************************************
3848 * FD32_Destroy [internal]
3849 * called from the common 16/32 code to cleanup 32 bit data
3851 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3853 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3855 /* if ofnW has been allocated, have to free everything in it */
3856 if (NULL != priv && NULL != priv->ofnA)
3858 FD31_FreeOfnW(lfs->ofnW);
3859 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3863 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3865 callbacks->Init = FD32_Init;
3866 callbacks->CWP = FD32_CallWindowProc;
3867 callbacks->UpdateResult = FD32_UpdateResult;
3868 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3869 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3870 callbacks->Destroy = FD32_Destroy;
3873 /***********************************************************************
3874 * FD32_WMMeasureItem [internal]
3876 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3878 LPMEASUREITEMSTRUCT lpmeasure;
3880 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3881 lpmeasure->itemHeight = FD31_GetFldrHeight();
3882 return TRUE;
3886 /***********************************************************************
3887 * FileOpenDlgProc [internal]
3888 * Used for open and save, in fact.
3890 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3891 WPARAM wParam, LPARAM lParam)
3893 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3895 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3896 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3898 INT_PTR lRet;
3899 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3900 if (lRet)
3901 return lRet; /* else continue message processing */
3903 switch (wMsg)
3905 case WM_INITDIALOG:
3906 return FD31_WMInitDialog(hWnd, wParam, lParam);
3908 case WM_MEASUREITEM:
3909 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3911 case WM_DRAWITEM:
3912 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3914 case WM_COMMAND:
3915 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3916 #if 0
3917 case WM_CTLCOLOR:
3918 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3919 switch (HIWORD(lParam))
3921 case CTLCOLOR_BTN:
3922 SetTextColor((HDC16)wParam, 0x00000000);
3923 return hGRAYBrush;
3924 case CTLCOLOR_STATIC:
3925 SetTextColor((HDC16)wParam, 0x00000000);
3926 return hGRAYBrush;
3928 break;
3929 #endif
3931 return FALSE;
3935 /***********************************************************************
3936 * GetFileName31A [internal]
3938 * Creates a win31 style dialog box for the user to select a file to open/save.
3940 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3941 UINT dlgType /* type dialogue : open/save */
3944 HINSTANCE hInst;
3945 BOOL bRet = FALSE;
3946 PFD31_DATA lfs;
3947 FD31_CALLBACKS callbacks;
3949 if (!lpofn || !FD31_Init()) return FALSE;
3951 TRACE("ofn flags %08x\n", lpofn->Flags);
3952 FD32_SetupCallbacks(&callbacks);
3953 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3954 if (lfs)
3956 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3957 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3958 FD32_FileOpenDlgProc, (LPARAM)lfs);
3959 FD31_DestroyPrivate(lfs);
3962 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3963 return bRet;
3966 /***********************************************************************
3967 * GetFileName31W [internal]
3969 * Creates a win31 style dialog box for the user to select a file to open/save
3971 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3972 UINT dlgType /* type dialogue : open/save */
3975 HINSTANCE hInst;
3976 BOOL bRet = FALSE;
3977 PFD31_DATA lfs;
3978 FD31_CALLBACKS callbacks;
3980 if (!lpofn || !FD31_Init()) return FALSE;
3982 FD32_SetupCallbacks(&callbacks);
3983 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3984 if (lfs)
3986 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3987 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3988 FD32_FileOpenDlgProc, (LPARAM)lfs);
3989 FD31_DestroyPrivate(lfs);
3992 TRACE("file %s, file offset %d, ext offset %d\n",
3993 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3994 return bRet;
3997 /* ------------------ APIs ---------------------- */
3999 /***********************************************************************
4000 * GetOpenFileNameA (COMDLG32.@)
4002 * Creates a dialog box for the user to select a file to open.
4004 * RETURNS
4005 * TRUE on success: user enters a valid file
4006 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4009 BOOL WINAPI GetOpenFileNameA(
4010 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4012 BOOL win16look = FALSE;
4014 TRACE("flags %08x\n", ofn->Flags);
4016 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4017 if (ofn->Flags & OFN_FILEMUSTEXIST)
4018 ofn->Flags |= OFN_PATHMUSTEXIST;
4020 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4021 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4023 if (win16look)
4024 return GetFileName31A(ofn, OPEN_DIALOG);
4025 else
4026 return GetFileDialog95A(ofn, OPEN_DIALOG);
4029 /***********************************************************************
4030 * GetOpenFileNameW (COMDLG32.@)
4032 * Creates a dialog box for the user to select a file to open.
4034 * RETURNS
4035 * TRUE on success: user enters a valid file
4036 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4039 BOOL WINAPI GetOpenFileNameW(
4040 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4042 BOOL win16look = FALSE;
4044 TRACE("flags %08x\n", ofn->Flags);
4046 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4047 if (ofn->Flags & OFN_FILEMUSTEXIST)
4048 ofn->Flags |= OFN_PATHMUSTEXIST;
4050 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4051 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4053 if (win16look)
4054 return GetFileName31W(ofn, OPEN_DIALOG);
4055 else
4056 return GetFileDialog95W(ofn, OPEN_DIALOG);
4060 /***********************************************************************
4061 * GetSaveFileNameA (COMDLG32.@)
4063 * Creates a dialog box for the user to select a file to save.
4065 * RETURNS
4066 * TRUE on success: user enters a valid file
4067 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4070 BOOL WINAPI GetSaveFileNameA(
4071 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4073 BOOL win16look = FALSE;
4075 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4076 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4078 if (win16look)
4079 return GetFileName31A(ofn, SAVE_DIALOG);
4080 else
4081 return GetFileDialog95A(ofn, SAVE_DIALOG);
4084 /***********************************************************************
4085 * GetSaveFileNameW (COMDLG32.@)
4087 * Creates a dialog box for the user to select a file to save.
4089 * RETURNS
4090 * TRUE on success: user enters a valid file
4091 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4094 BOOL WINAPI GetSaveFileNameW(
4095 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4097 BOOL win16look = FALSE;
4099 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4100 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4102 if (win16look)
4103 return GetFileName31W(ofn, SAVE_DIALOG);
4104 else
4105 return GetFileDialog95W(ofn, SAVE_DIALOG);
4108 /***********************************************************************
4109 * GetFileTitleA (COMDLG32.@)
4111 * See GetFileTitleW.
4113 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4115 int ret;
4116 UNICODE_STRING strWFile;
4117 LPWSTR lpWTitle;
4119 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4120 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4121 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4122 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4123 RtlFreeUnicodeString( &strWFile );
4124 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4125 return ret;
4129 /***********************************************************************
4130 * GetFileTitleW (COMDLG32.@)
4132 * Get the name of a file.
4134 * PARAMS
4135 * lpFile [I] name and location of file
4136 * lpTitle [O] returned file name
4137 * cbBuf [I] buffer size of lpTitle
4139 * RETURNS
4140 * Success: zero
4141 * Failure: negative number.
4143 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4145 int i, len;
4146 static const WCHAR brkpoint[] = {'*','[',']',0};
4147 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4149 if(lpFile == NULL || lpTitle == NULL)
4150 return -1;
4152 len = lstrlenW(lpFile);
4154 if (len == 0)
4155 return -1;
4157 if(strpbrkW(lpFile, brkpoint))
4158 return -1;
4160 len--;
4162 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4163 return -1;
4165 for(i = len; i >= 0; i--)
4167 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4169 i++;
4170 break;
4174 if(i == -1)
4175 i++;
4177 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4179 len = lstrlenW(lpFile+i)+1;
4180 if(cbBuf < len)
4181 return len;
4183 lstrcpyW(lpTitle, &lpFile[i]);
4184 return 0;