push 46756c23c8ad9edb429a5c7b07633fa443e7b3ef
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blobb4239425a76613499f0717625e7608f1ee6588da
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 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1164 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1165 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1166 return 0;
1168 case WM_SIZE:
1169 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1170 case WM_GETMINMAXINFO:
1171 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1172 case WM_COMMAND:
1173 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1174 case WM_DRAWITEM:
1176 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1178 case IDC_LOOKIN:
1179 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1180 return TRUE;
1183 return FALSE;
1185 case WM_GETISHELLBROWSER:
1186 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1188 case WM_DESTROY:
1189 RemovePropA(hwnd, FileOpenDlgInfosStr);
1190 return FALSE;
1192 case WM_NOTIFY:
1194 LPNMHDR lpnmh = (LPNMHDR)lParam;
1195 UINT stringId = -1;
1197 /* set up the button tooltips strings */
1198 if(TTN_GETDISPINFOA == lpnmh->code )
1200 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1201 switch(lpnmh->idFrom )
1203 /* Up folder button */
1204 case FCIDM_TB_UPFOLDER:
1205 stringId = IDS_UPFOLDER;
1206 break;
1207 /* New folder button */
1208 case FCIDM_TB_NEWFOLDER:
1209 stringId = IDS_NEWFOLDER;
1210 break;
1211 /* List option button */
1212 case FCIDM_TB_SMALLICON:
1213 stringId = IDS_LISTVIEW;
1214 break;
1215 /* Details option button */
1216 case FCIDM_TB_REPORTVIEW:
1217 stringId = IDS_REPORTVIEW;
1218 break;
1219 /* Desktop button */
1220 case FCIDM_TB_DESKTOP:
1221 stringId = IDS_TODESKTOP;
1222 break;
1223 default:
1224 stringId = 0;
1226 lpdi->hinst = COMDLG32_hInstance;
1227 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1229 return FALSE;
1231 default :
1232 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1233 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1234 return FALSE;
1238 /***********************************************************************
1239 * FILEDLG95_InitControls
1241 * WM_INITDIALOG message handler (before hook notification)
1243 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1245 int win2000plus = 0;
1246 int win98plus = 0;
1247 int handledPath = FALSE;
1248 OSVERSIONINFOW osVi;
1249 static const WCHAR szwSlash[] = { '\\', 0 };
1250 static const WCHAR szwStar[] = { '*',0 };
1252 static const TBBUTTON tbb[] =
1254 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1255 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1256 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1257 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1258 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1259 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1260 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1261 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1262 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1264 TBADDBITMAP tba[2];
1265 RECT rectTB;
1266 RECT rectlook;
1267 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1269 tba[0].hInst = HINST_COMMCTRL;
1270 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1271 tba[1].hInst = COMDLG32_hInstance;
1272 tba[1].nID = 800;
1274 TRACE("%p\n", fodInfos);
1276 /* Get windows version emulating */
1277 osVi.dwOSVersionInfoSize = sizeof(osVi);
1278 GetVersionExW(&osVi);
1279 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1280 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1281 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1282 win2000plus = (osVi.dwMajorVersion > 4);
1283 if (win2000plus) win98plus = TRUE;
1285 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1287 /* Get the hwnd of the controls */
1288 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1289 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1290 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1292 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1293 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1295 /* construct the toolbar */
1296 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1297 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1299 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1300 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1301 rectTB.left = rectlook.right;
1302 rectTB.top = rectlook.top-1;
1304 if (fodInfos->unicode)
1305 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1306 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1307 rectTB.left, rectTB.top,
1308 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1309 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1310 else
1311 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1312 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1313 rectTB.left, rectTB.top,
1314 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1315 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1317 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1319 /* FIXME: use TB_LOADIMAGES when implemented */
1320 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1321 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1322 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1324 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1325 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1327 /* Set the window text with the text specified in the OPENFILENAME structure */
1328 if(fodInfos->title)
1330 SetWindowTextW(hwnd,fodInfos->title);
1332 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1334 WCHAR buf[16];
1335 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1336 SetWindowTextW(hwnd, buf);
1339 /* Initialise the file name edit control */
1340 handledPath = FALSE;
1341 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1343 if(fodInfos->filename)
1345 /* 1. If win2000 or higher and filename contains a path, use it
1346 in preference over the lpstrInitialDir */
1347 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1348 WCHAR tmpBuf[MAX_PATH];
1349 WCHAR *nameBit;
1350 DWORD result;
1352 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1353 if (result) {
1355 /* nameBit is always shorter than the original filename */
1356 lstrcpyW(fodInfos->filename,nameBit);
1358 *nameBit = 0x00;
1359 if (fodInfos->initdir == NULL)
1360 MemFree(fodInfos->initdir);
1361 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1362 lstrcpyW(fodInfos->initdir, tmpBuf);
1363 handledPath = TRUE;
1364 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1365 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1367 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1369 } else {
1370 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1374 /* 2. (All platforms) If initdir is not null, then use it */
1375 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1376 (*fodInfos->initdir!=0x00))
1378 /* Work out the proper path as supplied one might be relative */
1379 /* (Here because supplying '.' as dir browses to My Computer) */
1380 if (handledPath==FALSE) {
1381 WCHAR tmpBuf[MAX_PATH];
1382 WCHAR tmpBuf2[MAX_PATH];
1383 WCHAR *nameBit;
1384 DWORD result;
1386 lstrcpyW(tmpBuf, fodInfos->initdir);
1387 if( PathFileExistsW(tmpBuf) ) {
1388 /* initdir does not have to be a directory. If a file is
1389 * specified, the dir part is taken */
1390 if( PathIsDirectoryW(tmpBuf)) {
1391 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1392 lstrcatW(tmpBuf, szwSlash);
1394 lstrcatW(tmpBuf, szwStar);
1396 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1397 if (result) {
1398 *nameBit = 0x00;
1399 MemFree(fodInfos->initdir);
1400 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1401 lstrcpyW(fodInfos->initdir, tmpBuf2);
1402 handledPath = TRUE;
1403 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1406 else if (fodInfos->initdir)
1408 MemFree(fodInfos->initdir);
1409 fodInfos->initdir = NULL;
1410 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1415 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1416 (*fodInfos->initdir==0x00)))
1418 /* 3. All except w2k+: if filename contains a path use it */
1419 if (!win2000plus && fodInfos->filename &&
1420 *fodInfos->filename &&
1421 strpbrkW(fodInfos->filename, szwSlash)) {
1422 WCHAR tmpBuf[MAX_PATH];
1423 WCHAR *nameBit;
1424 DWORD result;
1426 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1427 tmpBuf, &nameBit);
1428 if (result) {
1429 int len;
1431 /* nameBit is always shorter than the original filename */
1432 lstrcpyW(fodInfos->filename, nameBit);
1433 *nameBit = 0x00;
1435 len = lstrlenW(tmpBuf);
1436 MemFree(fodInfos->initdir);
1437 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1438 lstrcpyW(fodInfos->initdir, tmpBuf);
1440 handledPath = TRUE;
1441 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1442 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1444 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1447 /* 4. win98+ and win2000+ if any files of specified filter types in
1448 current directory, use it */
1449 if ( win98plus && handledPath == FALSE &&
1450 fodInfos->filter && *fodInfos->filter) {
1452 BOOL searchMore = TRUE;
1453 LPCWSTR lpstrPos = fodInfos->filter;
1454 WIN32_FIND_DATAW FindFileData;
1455 HANDLE hFind;
1457 while (searchMore)
1459 /* filter is a list... title\0ext\0......\0\0 */
1461 /* Skip the title */
1462 if(! *lpstrPos) break; /* end */
1463 lpstrPos += lstrlenW(lpstrPos) + 1;
1465 /* See if any files exist in the current dir with this extension */
1466 if(! *lpstrPos) break; /* end */
1468 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1470 if (hFind == INVALID_HANDLE_VALUE) {
1471 /* None found - continue search */
1472 lpstrPos += lstrlenW(lpstrPos) + 1;
1474 } else {
1475 searchMore = FALSE;
1477 MemFree(fodInfos->initdir);
1478 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1479 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1481 handledPath = TRUE;
1482 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1483 debugstr_w(lpstrPos));
1484 break;
1489 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1491 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1492 if (handledPath == FALSE && (win2000plus || win98plus)) {
1493 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1495 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1497 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1499 /* last fallback */
1500 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1501 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1502 } else {
1503 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1505 } else {
1506 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1508 handledPath = TRUE;
1509 } else if (handledPath==FALSE) {
1510 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1511 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1512 handledPath = TRUE;
1513 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1516 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1517 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1519 /* Must the open as read only check box be checked ?*/
1520 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1522 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1525 /* Must the open as read only check box be hidden? */
1526 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1528 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1529 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1532 /* Must the help button be hidden? */
1533 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1535 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1536 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1539 /* change Open to Save */
1540 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1542 WCHAR buf[16];
1543 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1544 SetDlgItemTextW(hwnd, IDOK, buf);
1545 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1546 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1549 /* Initialize the filter combo box */
1550 FILEDLG95_FILETYPE_Init(hwnd);
1552 return 0;
1555 /***********************************************************************
1556 * FILEDLG95_ResizeControls
1558 * WM_INITDIALOG message handler (after hook notification)
1560 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1562 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1564 if (fodInfos->DlgInfos.hwndCustomDlg)
1566 RECT rc;
1567 UINT flags = SWP_NOACTIVATE;
1569 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1570 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1572 /* resize the custom dialog to the parent size */
1573 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1574 GetClientRect(hwnd, &rc);
1575 else
1577 /* our own fake template is zero sized and doesn't have children, so
1578 * there is no need to resize it. Picasa depends on it.
1580 flags |= SWP_NOSIZE;
1581 SetRectEmpty(&rc);
1583 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1584 0, 0, rc.right, rc.bottom, flags);
1586 else
1588 /* Resize the height, if open as read only checkbox ad help button are
1589 * hidden and we are not using a custom template nor a customDialog
1591 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1592 (!(fodInfos->ofnInfos->Flags &
1593 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1595 RECT rectDlg, rectHelp, rectCancel;
1596 GetWindowRect(hwnd, &rectDlg);
1597 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1598 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1599 /* subtract the height of the help button plus the space between the help
1600 * button and the cancel button to the height of the dialog
1602 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1603 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1604 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1607 return TRUE;
1610 /***********************************************************************
1611 * FILEDLG95_FillControls
1613 * WM_INITDIALOG message handler (after hook notification)
1615 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1617 LPITEMIDLIST pidlItemId = NULL;
1619 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1621 TRACE("dir=%s file=%s\n",
1622 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1624 /* Get the initial directory pidl */
1626 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1628 WCHAR path[MAX_PATH];
1630 GetCurrentDirectoryW(MAX_PATH,path);
1631 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1634 /* Initialise shell objects */
1635 FILEDLG95_SHELL_Init(hwnd);
1637 /* Initialize the Look In combo box */
1638 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1640 /* Browse to the initial directory */
1641 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1643 /* Free pidlItem memory */
1644 COMDLG32_SHFree(pidlItemId);
1646 return TRUE;
1648 /***********************************************************************
1649 * FILEDLG95_Clean
1651 * Regroups all the cleaning functions of the filedlg
1653 void FILEDLG95_Clean(HWND hwnd)
1655 FILEDLG95_FILETYPE_Clean(hwnd);
1656 FILEDLG95_LOOKIN_Clean(hwnd);
1657 FILEDLG95_SHELL_Clean(hwnd);
1659 /***********************************************************************
1660 * FILEDLG95_OnWMCommand
1662 * WM_COMMAND message handler
1664 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1666 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1667 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1668 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1670 switch(wID)
1672 /* OK button */
1673 case IDOK:
1674 FILEDLG95_OnOpen(hwnd);
1675 break;
1676 /* Cancel button */
1677 case IDCANCEL:
1678 FILEDLG95_Clean(hwnd);
1679 EndDialog(hwnd, FALSE);
1680 break;
1681 /* Filetype combo box */
1682 case IDC_FILETYPE:
1683 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1684 break;
1685 /* LookIn combo box */
1686 case IDC_LOOKIN:
1687 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1688 break;
1690 /* --- toolbar --- */
1691 /* Up folder button */
1692 case FCIDM_TB_UPFOLDER:
1693 FILEDLG95_SHELL_UpFolder(hwnd);
1694 break;
1695 /* New folder button */
1696 case FCIDM_TB_NEWFOLDER:
1697 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1698 break;
1699 /* List option button */
1700 case FCIDM_TB_SMALLICON:
1701 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1702 break;
1703 /* Details option button */
1704 case FCIDM_TB_REPORTVIEW:
1705 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1706 break;
1707 /* Details option button */
1708 case FCIDM_TB_DESKTOP:
1709 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1710 break;
1712 case IDC_FILENAME:
1713 break;
1716 /* Do not use the listview selection anymore */
1717 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1718 return 0;
1721 /***********************************************************************
1722 * FILEDLG95_OnWMGetIShellBrowser
1724 * WM_GETISHELLBROWSER message handler
1726 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1728 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1730 TRACE("\n");
1732 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1734 return TRUE;
1738 /***********************************************************************
1739 * FILEDLG95_SendFileOK
1741 * Sends the CDN_FILEOK notification if required
1743 * RETURNS
1744 * TRUE if the dialog should close
1745 * FALSE if the dialog should not be closed
1747 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1749 /* ask the hook if we can close */
1750 if(IsHooked(fodInfos))
1752 LRESULT retval;
1754 TRACE("---\n");
1755 /* First send CDN_FILEOK as MSDN doc says */
1756 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1757 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1759 TRACE("canceled\n");
1760 return (retval == 0);
1763 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1764 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1765 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1766 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1768 TRACE("canceled\n");
1769 return (retval == 0);
1772 return TRUE;
1775 /***********************************************************************
1776 * FILEDLG95_OnOpenMultipleFiles
1778 * Handles the opening of multiple files.
1780 * FIXME
1781 * check destination buffer size
1783 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1785 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1786 UINT nCount, nSizePath;
1787 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1789 TRACE("\n");
1791 if(fodInfos->unicode)
1793 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1794 ofn->lpstrFile[0] = '\0';
1796 else
1798 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1799 ofn->lpstrFile[0] = '\0';
1802 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1804 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1805 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1806 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1808 LPWSTR lpstrTemp = lpstrFileList;
1810 for ( nCount = 0; nCount < nFileCount; nCount++ )
1812 LPITEMIDLIST pidl;
1814 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1815 if (!pidl)
1817 WCHAR lpstrNotFound[100];
1818 WCHAR lpstrMsg[100];
1819 WCHAR tmp[400];
1820 static const WCHAR nl[] = {'\n',0};
1822 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1823 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1825 lstrcpyW(tmp, lpstrTemp);
1826 lstrcatW(tmp, nl);
1827 lstrcatW(tmp, lpstrNotFound);
1828 lstrcatW(tmp, nl);
1829 lstrcatW(tmp, lpstrMsg);
1831 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1832 return FALSE;
1835 /* move to the next file in the list of files */
1836 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1837 COMDLG32_SHFree(pidl);
1841 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1842 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1844 /* For "oldstyle" dialog the components have to
1845 be separated by blanks (not '\0'!) and short
1846 filenames have to be used! */
1847 FIXME("Components have to be separated by blanks\n");
1849 if(fodInfos->unicode)
1851 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1852 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1853 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1855 else
1857 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1859 if (ofn->lpstrFile != NULL)
1861 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1862 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1863 if (ofn->nMaxFile > nSizePath)
1865 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1866 ofn->lpstrFile + nSizePath,
1867 ofn->nMaxFile - nSizePath, NULL, NULL);
1872 fodInfos->ofnInfos->nFileOffset = nSizePath;
1873 fodInfos->ofnInfos->nFileExtension = 0;
1875 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1876 return FALSE;
1878 /* clean and exit */
1879 FILEDLG95_Clean(hwnd);
1880 return EndDialog(hwnd,TRUE);
1883 /***********************************************************************
1884 * FILEDLG95_OnOpen
1886 * Ok button WM_COMMAND message handler
1888 * If the function succeeds, the return value is nonzero.
1890 #define ONOPEN_BROWSE 1
1891 #define ONOPEN_OPEN 2
1892 #define ONOPEN_SEARCH 3
1893 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1895 WCHAR strMsgTitle[MAX_PATH];
1896 WCHAR strMsgText [MAX_PATH];
1897 if (idCaption)
1898 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1899 else
1900 strMsgTitle[0] = '\0';
1901 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1902 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1905 BOOL FILEDLG95_OnOpen(HWND hwnd)
1907 LPWSTR lpstrFileList;
1908 UINT nFileCount = 0;
1909 UINT sizeUsed = 0;
1910 BOOL ret = TRUE;
1911 WCHAR lpstrPathAndFile[MAX_PATH];
1912 WCHAR lpstrTemp[MAX_PATH];
1913 LPSHELLFOLDER lpsf = NULL;
1914 int nOpenAction;
1915 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1917 TRACE("hwnd=%p\n", hwnd);
1919 /* get the files from the edit control */
1920 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1922 /* try if the user selected a folder in the shellview */
1923 if(nFileCount == 0)
1925 BrowseSelectedFolder(hwnd);
1926 return FALSE;
1929 if(nFileCount > 1)
1931 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1932 goto ret;
1935 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1938 Step 1: Build a complete path name from the current folder and
1939 the filename or path in the edit box.
1940 Special cases:
1941 - the path in the edit box is a root path
1942 (with or without drive letter)
1943 - the edit box contains ".." (or a path with ".." in it)
1946 /* Get the current directory name */
1947 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1949 /* last fallback */
1950 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1952 PathAddBackslashW(lpstrPathAndFile);
1954 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1956 /* if the user specified a fully qualified path use it */
1957 if(PathIsRelativeW(lpstrFileList))
1959 lstrcatW(lpstrPathAndFile, lpstrFileList);
1961 else
1963 /* does the path have a drive letter? */
1964 if (PathGetDriveNumberW(lpstrFileList) == -1)
1965 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1966 else
1967 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1970 /* resolve "." and ".." */
1971 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1972 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1973 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1975 MemFree(lpstrFileList);
1978 Step 2: here we have a cleaned up path
1980 We have to parse the path step by step to see if we have to browse
1981 to a folder if the path points to a directory or the last
1982 valid element is a directory.
1984 valid variables:
1985 lpstrPathAndFile: cleaned up path
1988 if (nFileCount &&
1989 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1990 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1991 nOpenAction = ONOPEN_OPEN;
1992 else
1993 nOpenAction = ONOPEN_BROWSE;
1995 /* don't apply any checks with OFN_NOVALIDATE */
1997 LPWSTR lpszTemp, lpszTemp1;
1998 LPITEMIDLIST pidl = NULL;
1999 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2001 /* check for invalid chars */
2002 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2004 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2005 ret = FALSE;
2006 goto ret;
2009 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2011 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2012 while (lpszTemp1)
2014 LPSHELLFOLDER lpsfChild;
2015 WCHAR lpwstrTemp[MAX_PATH];
2016 DWORD dwEaten, dwAttributes;
2017 LPWSTR p;
2019 lstrcpyW(lpwstrTemp, lpszTemp);
2020 p = PathFindNextComponentW(lpwstrTemp);
2022 if (!p) break; /* end of path */
2024 *p = 0;
2025 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2027 /* There are no wildcards when OFN_NOVALIDATE is set */
2028 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2030 static const WCHAR wszWild[] = { '*', '?', 0 };
2031 /* if the last element is a wildcard do a search */
2032 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2034 nOpenAction = ONOPEN_SEARCH;
2035 break;
2038 lpszTemp1 = lpszTemp;
2040 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2042 /* append a backslash to drive letters */
2043 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2044 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2045 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2047 PathAddBackslashW(lpwstrTemp);
2050 dwAttributes = SFGAO_FOLDER;
2051 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2053 /* the path component is valid, we have a pidl of the next path component */
2054 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2055 if(dwAttributes & SFGAO_FOLDER)
2057 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2059 ERR("bind to failed\n"); /* should not fail */
2060 break;
2062 IShellFolder_Release(lpsf);
2063 lpsf = lpsfChild;
2064 lpsfChild = NULL;
2066 else
2068 TRACE("value\n");
2070 /* end dialog, return value */
2071 nOpenAction = ONOPEN_OPEN;
2072 break;
2074 COMDLG32_SHFree(pidl);
2075 pidl = NULL;
2077 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2079 if(*lpszTemp || /* points to trailing null for last path element */
2080 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2082 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2084 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2085 break;
2088 else
2090 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2091 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2093 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2094 break;
2097 /* change to the current folder */
2098 nOpenAction = ONOPEN_OPEN;
2099 break;
2101 else
2103 nOpenAction = ONOPEN_OPEN;
2104 break;
2107 if(pidl) COMDLG32_SHFree(pidl);
2111 Step 3: here we have a cleaned up and validated path
2113 valid variables:
2114 lpsf: ShellFolder bound to the rightmost valid path component
2115 lpstrPathAndFile: cleaned up path
2116 nOpenAction: action to do
2118 TRACE("end validate sf=%p\n", lpsf);
2120 switch(nOpenAction)
2122 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2123 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2125 int iPos;
2126 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2127 DWORD len;
2129 /* replace the current filter */
2130 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2131 len = lstrlenW(lpszTemp)+1;
2132 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2133 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2135 /* set the filter cb to the extension when possible */
2136 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2137 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2139 /* fall through */
2140 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2141 TRACE("ONOPEN_BROWSE\n");
2143 IPersistFolder2 * ppf2;
2144 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2146 LPITEMIDLIST pidlCurrent;
2147 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2148 IPersistFolder2_Release(ppf2);
2149 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2151 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2153 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2156 else if( nOpenAction == ONOPEN_SEARCH )
2158 if (fodInfos->Shell.FOIShellView)
2159 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2161 COMDLG32_SHFree(pidlCurrent);
2162 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2165 ret = FALSE;
2166 break;
2167 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2168 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2170 WCHAR *ext = NULL;
2172 /* update READONLY check box flag */
2173 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2174 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2175 else
2176 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2178 /* Attach the file extension with file name*/
2179 ext = PathFindExtensionW(lpstrPathAndFile);
2180 if (! *ext)
2182 /* if no extension is specified with file name, then */
2183 /* attach the extension from file filter or default one */
2185 WCHAR *filterExt = NULL;
2186 LPWSTR lpstrFilter = NULL;
2187 static const WCHAR szwDot[] = {'.',0};
2188 int PathLength = lstrlenW(lpstrPathAndFile);
2190 /* Attach the dot*/
2191 lstrcatW(lpstrPathAndFile, szwDot);
2193 /*Get the file extension from file type filter*/
2194 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2195 fodInfos->ofnInfos->nFilterIndex-1);
2197 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2198 filterExt = PathFindExtensionW(lpstrFilter);
2200 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2201 lstrcatW(lpstrPathAndFile, filterExt + 1);
2202 else if ( fodInfos->defext ) /* attach the default file extension*/
2203 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2205 /* In Open dialog: if file does not exist try without extension */
2206 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2207 lpstrPathAndFile[PathLength] = '\0';
2210 if (fodInfos->defext) /* add default extension */
2212 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2213 if (*ext)
2214 ext++;
2215 if (!lstrcmpiW(fodInfos->defext, ext))
2216 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2217 else
2218 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2221 /* In Save dialog: check if the file already exists */
2222 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2223 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2224 && PathFileExistsW(lpstrPathAndFile))
2226 WCHAR lpstrOverwrite[100];
2227 int answer;
2229 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2230 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2231 MB_YESNO | MB_ICONEXCLAMATION);
2232 if (answer == IDNO)
2234 ret = FALSE;
2235 goto ret;
2239 /* In Open dialog: check if it should be created if it doesn't exist */
2240 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2241 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2242 && !PathFileExistsW(lpstrPathAndFile))
2244 WCHAR lpstrCreate[100];
2245 int answer;
2247 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2248 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2249 MB_YESNO | MB_ICONEXCLAMATION);
2250 if (answer == IDNO)
2252 ret = FALSE;
2253 goto ret;
2257 /* Check that the size of the file does not exceed buffer size.
2258 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2259 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2260 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2263 /* fill destination buffer */
2264 if (fodInfos->ofnInfos->lpstrFile)
2266 if(fodInfos->unicode)
2268 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2270 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2271 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2272 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2274 else
2276 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2278 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2279 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2280 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2281 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2285 if(fodInfos->unicode)
2287 LPWSTR lpszTemp;
2289 /* set filename offset */
2290 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2291 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2293 /* set extension offset */
2294 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2295 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2297 else
2299 LPSTR lpszTemp;
2300 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2302 /* set filename offset */
2303 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2304 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2306 /* set extension offset */
2307 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2308 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2311 /* set the lpstrFileTitle */
2312 if(fodInfos->ofnInfos->lpstrFileTitle)
2314 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2315 if(fodInfos->unicode)
2317 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2318 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2320 else
2322 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2323 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2324 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2328 /* copy currently selected filter to lpstrCustomFilter */
2329 if (fodInfos->ofnInfos->lpstrCustomFilter)
2331 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2332 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2333 NULL, 0, NULL, NULL);
2334 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2336 LPSTR s = ofn->lpstrCustomFilter;
2337 s += strlen(ofn->lpstrCustomFilter)+1;
2338 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2339 s, len, NULL, NULL);
2344 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2345 goto ret;
2347 TRACE("close\n");
2348 FILEDLG95_Clean(hwnd);
2349 ret = EndDialog(hwnd, TRUE);
2351 else
2353 WORD size;
2355 size = lstrlenW(lpstrPathAndFile) + 1;
2356 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2357 size += 1;
2358 /* return needed size in first two bytes of lpstrFile */
2359 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2360 FILEDLG95_Clean(hwnd);
2361 ret = EndDialog(hwnd, FALSE);
2362 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2365 break;
2368 ret:
2369 if(lpsf) IShellFolder_Release(lpsf);
2370 return ret;
2373 /***********************************************************************
2374 * FILEDLG95_SHELL_Init
2376 * Initialisation of the shell objects
2378 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2380 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2382 TRACE("\n");
2385 * Initialisation of the FileOpenDialogInfos structure
2388 /* Shell */
2390 /*ShellInfos */
2391 fodInfos->ShellInfos.hwndOwner = hwnd;
2393 /* Disable multi-select if flag not set */
2394 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2396 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2398 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2399 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2401 /* Construct the IShellBrowser interface */
2402 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2404 return NOERROR;
2407 /***********************************************************************
2408 * FILEDLG95_SHELL_ExecuteCommand
2410 * Change the folder option and refresh the view
2411 * If the function succeeds, the return value is nonzero.
2413 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2415 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2416 IContextMenu * pcm;
2418 TRACE("(%p,%p)\n", hwnd, lpVerb);
2420 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2421 SVGIO_BACKGROUND,
2422 &IID_IContextMenu,
2423 (LPVOID*)&pcm)))
2425 CMINVOKECOMMANDINFO ci;
2426 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2427 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2428 ci.lpVerb = lpVerb;
2429 ci.hwnd = hwnd;
2431 IContextMenu_InvokeCommand(pcm, &ci);
2432 IContextMenu_Release(pcm);
2435 return FALSE;
2438 /***********************************************************************
2439 * FILEDLG95_SHELL_UpFolder
2441 * Browse to the specified object
2442 * If the function succeeds, the return value is nonzero.
2444 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2446 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2448 TRACE("\n");
2450 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2451 NULL,
2452 SBSP_PARENT)))
2454 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2455 return TRUE;
2457 return FALSE;
2460 /***********************************************************************
2461 * FILEDLG95_SHELL_BrowseToDesktop
2463 * Browse to the Desktop
2464 * If the function succeeds, the return value is nonzero.
2466 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2468 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2469 LPITEMIDLIST pidl;
2470 HRESULT hres;
2472 TRACE("\n");
2474 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2475 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2476 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2477 COMDLG32_SHFree(pidl);
2478 return SUCCEEDED(hres);
2480 /***********************************************************************
2481 * FILEDLG95_SHELL_Clean
2483 * Cleans the memory used by shell objects
2485 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2487 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2489 TRACE("\n");
2491 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2493 /* clean Shell interfaces */
2494 if (fodInfos->Shell.FOIShellView)
2496 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2497 IShellView_Release(fodInfos->Shell.FOIShellView);
2499 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2500 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2501 if (fodInfos->Shell.FOIDataObject)
2502 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2505 /***********************************************************************
2506 * FILEDLG95_FILETYPE_Init
2508 * Initialisation of the file type combo box
2510 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2512 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2513 int nFilters = 0; /* number of filters */
2514 int nFilterIndexCB;
2516 TRACE("\n");
2518 if(fodInfos->customfilter)
2520 /* customfilter has one entry... title\0ext\0
2521 * Set first entry of combo box item with customfilter
2523 LPWSTR lpstrExt;
2524 LPCWSTR lpstrPos = fodInfos->customfilter;
2526 /* Get the title */
2527 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2529 /* Copy the extensions */
2530 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2531 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2532 lstrcpyW(lpstrExt,lpstrPos);
2534 /* Add the item at the end of the combo */
2535 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2536 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2537 nFilters++;
2539 if(fodInfos->filter)
2541 LPCWSTR lpstrPos = fodInfos->filter;
2543 for(;;)
2545 /* filter is a list... title\0ext\0......\0\0
2546 * Set the combo item text to the title and the item data
2547 * to the ext
2549 LPCWSTR lpstrDisplay;
2550 LPWSTR lpstrExt;
2552 /* Get the title */
2553 if(! *lpstrPos) break; /* end */
2554 lpstrDisplay = lpstrPos;
2555 lpstrPos += lstrlenW(lpstrPos) + 1;
2557 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2559 nFilters++;
2561 /* Copy the extensions */
2562 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2563 lstrcpyW(lpstrExt,lpstrPos);
2564 lpstrPos += lstrlenW(lpstrPos) + 1;
2566 /* Add the item at the end of the combo */
2567 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2569 /* malformed filters are added anyway... */
2570 if (!*lpstrExt) break;
2575 * Set the current filter to the one specified
2576 * in the initialisation structure
2578 if (fodInfos->filter || fodInfos->customfilter)
2580 LPWSTR lpstrFilter;
2582 /* Check to make sure our index isn't out of bounds. */
2583 if ( fodInfos->ofnInfos->nFilterIndex >
2584 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2585 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2587 /* set default filter index */
2588 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2589 fodInfos->ofnInfos->nFilterIndex = 1;
2591 /* calculate index of Combo Box item */
2592 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2593 if (fodInfos->customfilter == NULL)
2594 nFilterIndexCB--;
2596 /* Set the current index selection. */
2597 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2599 /* Get the corresponding text string from the combo box. */
2600 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2601 nFilterIndexCB);
2603 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2604 lpstrFilter = NULL;
2606 if(lpstrFilter)
2608 DWORD len;
2609 CharLowerW(lpstrFilter); /* lowercase */
2610 len = lstrlenW(lpstrFilter)+1;
2611 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2612 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2614 } else
2615 fodInfos->ofnInfos->nFilterIndex = 0;
2616 return S_OK;
2619 /***********************************************************************
2620 * FILEDLG95_FILETYPE_OnCommand
2622 * WM_COMMAND of the file type combo box
2623 * If the function succeeds, the return value is nonzero.
2625 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2627 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2629 switch(wNotifyCode)
2631 case CBN_SELENDOK:
2633 LPWSTR lpstrFilter;
2635 /* Get the current item of the filetype combo box */
2636 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2638 /* set the current filter index */
2639 fodInfos->ofnInfos->nFilterIndex = iItem +
2640 (fodInfos->customfilter == NULL ? 1 : 0);
2642 /* Set the current filter with the current selection */
2643 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2645 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2646 iItem);
2647 if((INT_PTR)lpstrFilter != CB_ERR)
2649 DWORD len;
2650 CharLowerW(lpstrFilter); /* lowercase */
2651 len = lstrlenW(lpstrFilter)+1;
2652 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2653 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2654 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2657 /* Refresh the actual view to display the included items*/
2658 if (fodInfos->Shell.FOIShellView)
2659 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2662 return FALSE;
2664 /***********************************************************************
2665 * FILEDLG95_FILETYPE_SearchExt
2667 * searches for an extension in the filetype box
2669 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2671 int i, iCount = CBGetCount(hwnd);
2673 TRACE("%s\n", debugstr_w(lpstrExt));
2675 if(iCount != CB_ERR)
2677 for(i=0;i<iCount;i++)
2679 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2680 return i;
2683 return -1;
2686 /***********************************************************************
2687 * FILEDLG95_FILETYPE_Clean
2689 * Clean the memory used by the filetype combo box
2691 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2693 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2694 int iPos;
2695 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2697 TRACE("\n");
2699 /* Delete each string of the combo and their associated data */
2700 if(iCount != CB_ERR)
2702 for(iPos = iCount-1;iPos>=0;iPos--)
2704 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2705 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2708 /* Current filter */
2709 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2713 /***********************************************************************
2714 * FILEDLG95_LOOKIN_Init
2716 * Initialisation of the look in combo box
2719 /* Small helper function, to determine if the unixfs shell extension is rooted
2720 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2722 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2723 HKEY hKey;
2724 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2725 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2726 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2727 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2728 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2729 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2730 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2732 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2733 return FALSE;
2735 RegCloseKey(hKey);
2736 return TRUE;
2739 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2741 IShellFolder *psfRoot, *psfDrives;
2742 IEnumIDList *lpeRoot, *lpeDrives;
2743 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2745 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2747 TRACE("\n");
2749 liInfos->iMaxIndentation = 0;
2751 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2753 /* set item height for both text field and listbox */
2754 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2755 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2757 /* Turn on the extended UI for the combo box like Windows does */
2758 CBSetExtendedUI(hwndCombo, TRUE);
2760 /* Initialise data of Desktop folder */
2761 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2762 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2763 COMDLG32_SHFree(pidlTmp);
2765 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2767 SHGetDesktopFolder(&psfRoot);
2769 if (psfRoot)
2771 /* enumerate the contents of the desktop */
2772 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2774 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2776 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2778 /* If the unixfs extension is rooted, we don't expand the drives by default */
2779 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2781 /* special handling for CSIDL_DRIVES */
2782 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2784 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2786 /* enumerate the drives */
2787 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2789 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2791 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2792 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2793 COMDLG32_SHFree(pidlAbsTmp);
2794 COMDLG32_SHFree(pidlTmp1);
2796 IEnumIDList_Release(lpeDrives);
2798 IShellFolder_Release(psfDrives);
2803 COMDLG32_SHFree(pidlTmp);
2805 IEnumIDList_Release(lpeRoot);
2807 IShellFolder_Release(psfRoot);
2810 COMDLG32_SHFree(pidlDrives);
2813 /***********************************************************************
2814 * FILEDLG95_LOOKIN_DrawItem
2816 * WM_DRAWITEM message handler
2818 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2820 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2821 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2822 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2823 RECT rectText;
2824 RECT rectIcon;
2825 SHFILEINFOW sfi;
2826 HIMAGELIST ilItemImage;
2827 int iIndentation;
2828 TEXTMETRICW tm;
2829 LPSFOLDER tmpFolder;
2830 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2832 TRACE("\n");
2834 if(pDIStruct->itemID == -1)
2835 return 0;
2837 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2838 pDIStruct->itemID)))
2839 return 0;
2842 if(pDIStruct->itemID == liInfos->uSelectedItem)
2844 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2846 &sfi,
2847 sizeof (sfi),
2848 SHGFI_PIDL | SHGFI_SMALLICON |
2849 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2850 SHGFI_DISPLAYNAME );
2852 else
2854 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2856 &sfi,
2857 sizeof (sfi),
2858 SHGFI_PIDL | SHGFI_SMALLICON |
2859 SHGFI_SYSICONINDEX |
2860 SHGFI_DISPLAYNAME);
2863 /* Is this item selected ? */
2864 if(pDIStruct->itemState & ODS_SELECTED)
2866 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2867 SetBkColor(pDIStruct->hDC,crHighLight);
2868 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2870 else
2872 SetTextColor(pDIStruct->hDC,crText);
2873 SetBkColor(pDIStruct->hDC,crWin);
2874 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2877 /* Do not indent item if drawing in the edit of the combo */
2878 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2880 iIndentation = 0;
2881 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2883 &sfi,
2884 sizeof (sfi),
2885 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2886 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2889 else
2891 iIndentation = tmpFolder->m_iIndent;
2893 /* Draw text and icon */
2895 /* Initialise the icon display area */
2896 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2897 rectIcon.top = pDIStruct->rcItem.top;
2898 rectIcon.right = rectIcon.left + ICONWIDTH;
2899 rectIcon.bottom = pDIStruct->rcItem.bottom;
2901 /* Initialise the text display area */
2902 GetTextMetricsW(pDIStruct->hDC, &tm);
2903 rectText.left = rectIcon.right;
2904 rectText.top =
2905 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2906 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2907 rectText.bottom =
2908 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2910 /* Draw the icon from the image list */
2911 ImageList_Draw(ilItemImage,
2912 sfi.iIcon,
2913 pDIStruct->hDC,
2914 rectIcon.left,
2915 rectIcon.top,
2916 ILD_TRANSPARENT );
2918 /* Draw the associated text */
2919 if(sfi.szDisplayName)
2920 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2923 return NOERROR;
2926 /***********************************************************************
2927 * FILEDLG95_LOOKIN_OnCommand
2929 * LookIn combo box WM_COMMAND message handler
2930 * If the function succeeds, the return value is nonzero.
2932 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2934 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2936 TRACE("%p\n", fodInfos);
2938 switch(wNotifyCode)
2940 case CBN_SELENDOK:
2942 LPSFOLDER tmpFolder;
2943 int iItem;
2945 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2947 if( iItem == CB_ERR) return FALSE;
2949 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2950 iItem)))
2951 return FALSE;
2954 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2955 tmpFolder->pidlItem,
2956 SBSP_ABSOLUTE)))
2958 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2959 return TRUE;
2961 break;
2965 return FALSE;
2968 /***********************************************************************
2969 * FILEDLG95_LOOKIN_AddItem
2971 * Adds an absolute pidl item to the lookin combo box
2972 * returns the index of the inserted item
2974 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2976 LPITEMIDLIST pidlNext;
2977 SHFILEINFOW sfi;
2978 SFOLDER *tmpFolder;
2979 LookInInfos *liInfos;
2981 TRACE("%08x\n", iInsertId);
2983 if(!pidl)
2984 return -1;
2986 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
2987 return -1;
2989 tmpFolder = MemAlloc(sizeof(SFOLDER));
2990 tmpFolder->m_iIndent = 0;
2992 /* Calculate the indentation of the item in the lookin*/
2993 pidlNext = pidl;
2994 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2996 tmpFolder->m_iIndent++;
2999 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3001 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3002 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3004 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3005 SHGetFileInfoW((LPCWSTR)pidl,
3007 &sfi,
3008 sizeof(sfi),
3009 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3010 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3012 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3014 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3016 int iItemID;
3018 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3020 /* Add the item at the end of the list */
3021 if(iInsertId < 0)
3023 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3025 /* Insert the item at the iInsertId position*/
3026 else
3028 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3031 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3032 return iItemID;
3035 COMDLG32_SHFree( tmpFolder->pidlItem );
3036 MemFree( tmpFolder );
3037 return -1;
3041 /***********************************************************************
3042 * FILEDLG95_LOOKIN_InsertItemAfterParent
3044 * Insert an item below its parent
3046 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3049 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3050 int iParentPos;
3052 TRACE("\n");
3054 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3056 if(iParentPos < 0)
3058 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3061 /* Free pidlParent memory */
3062 COMDLG32_SHFree(pidlParent);
3064 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3067 /***********************************************************************
3068 * FILEDLG95_LOOKIN_SelectItem
3070 * Adds an absolute pidl item to the lookin combo box
3071 * returns the index of the inserted item
3073 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3075 int iItemPos;
3076 LookInInfos *liInfos;
3078 TRACE("\n");
3080 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3082 liInfos = GetPropA(hwnd,LookInInfosStr);
3084 if(iItemPos < 0)
3086 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3087 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3090 else
3092 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3093 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3095 int iRemovedItem;
3097 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3098 break;
3099 if(iRemovedItem < iItemPos)
3100 iItemPos--;
3104 CBSetCurSel(hwnd,iItemPos);
3105 liInfos->uSelectedItem = iItemPos;
3107 return 0;
3111 /***********************************************************************
3112 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3114 * Remove the item with an expansion level over iExpansionLevel
3116 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3118 int iItemPos;
3119 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3121 TRACE("\n");
3123 if(liInfos->iMaxIndentation <= 2)
3124 return -1;
3126 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3128 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3129 COMDLG32_SHFree(tmpFolder->pidlItem);
3130 MemFree(tmpFolder);
3131 CBDeleteString(hwnd,iItemPos);
3132 liInfos->iMaxIndentation--;
3134 return iItemPos;
3137 return -1;
3140 /***********************************************************************
3141 * FILEDLG95_LOOKIN_SearchItem
3143 * Search for pidl in the lookin combo box
3144 * returns the index of the found item
3146 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3148 int i = 0;
3149 int iCount = CBGetCount(hwnd);
3151 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3153 if (iCount != CB_ERR)
3155 for(;i<iCount;i++)
3157 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3159 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3160 return i;
3161 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3162 return i;
3166 return -1;
3169 /***********************************************************************
3170 * FILEDLG95_LOOKIN_Clean
3172 * Clean the memory used by the lookin combo box
3174 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3176 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3177 int iPos;
3178 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3180 TRACE("\n");
3182 /* Delete each string of the combo and their associated data */
3183 if (iCount != CB_ERR)
3185 for(iPos = iCount-1;iPos>=0;iPos--)
3187 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3188 COMDLG32_SHFree(tmpFolder->pidlItem);
3189 MemFree(tmpFolder);
3190 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3194 /* LookInInfos structure */
3195 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3198 /***********************************************************************
3199 * FILEDLG95_FILENAME_FillFromSelection
3201 * fills the edit box from the cached DataObject
3203 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3205 FileOpenDlgInfos *fodInfos;
3206 LPITEMIDLIST pidl;
3207 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3208 WCHAR lpstrTemp[MAX_PATH];
3209 LPWSTR lpstrAllFile, lpstrCurrFile;
3211 TRACE("\n");
3212 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3214 /* Count how many files we have */
3215 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3217 /* calculate the string length, count files */
3218 if (nFileSelected >= 1)
3220 nLength += 3; /* first and last quotes, trailing \0 */
3221 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3223 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3225 if (pidl)
3227 /* get the total length of the selected file names */
3228 lpstrTemp[0] = '\0';
3229 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3231 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3233 nLength += lstrlenW( lpstrTemp ) + 3;
3234 nFiles++;
3236 COMDLG32_SHFree( pidl );
3241 /* allocate the buffer */
3242 if (nFiles <= 1) nLength = MAX_PATH;
3243 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3245 /* Generate the string for the edit control */
3246 if(nFiles >= 1)
3248 lpstrCurrFile = lpstrAllFile;
3249 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3251 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3253 if (pidl)
3255 /* get the file name */
3256 lpstrTemp[0] = '\0';
3257 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3259 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3261 if ( nFiles > 1)
3263 *lpstrCurrFile++ = '\"';
3264 lstrcpyW( lpstrCurrFile, lpstrTemp );
3265 lpstrCurrFile += lstrlenW( lpstrTemp );
3266 *lpstrCurrFile++ = '\"';
3267 *lpstrCurrFile++ = ' ';
3268 *lpstrCurrFile = 0;
3270 else
3272 lstrcpyW( lpstrAllFile, lpstrTemp );
3275 COMDLG32_SHFree( pidl );
3278 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3280 /* Select the file name like Windows does */
3281 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3283 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3287 /* copied from shell32 to avoid linking to it
3288 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3289 * is dependent on whether emulated OS is unicode or not.
3291 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3293 switch (src->uType)
3295 case STRRET_WSTR:
3296 lstrcpynW(dest, src->u.pOleStr, len);
3297 COMDLG32_SHFree(src->u.pOleStr);
3298 break;
3300 case STRRET_CSTR:
3301 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3302 dest[len-1] = 0;
3303 break;
3305 case STRRET_OFFSET:
3306 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3307 dest[len-1] = 0;
3308 break;
3310 default:
3311 FIXME("unknown type %x!\n", src->uType);
3312 if (len) *dest = '\0';
3313 return E_FAIL;
3315 return S_OK;
3318 /***********************************************************************
3319 * FILEDLG95_FILENAME_GetFileNames
3321 * Copies the filenames to a delimited string list.
3322 * The delimiter is specified by the parameter 'separator',
3323 * usually either a space or a nul
3325 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3327 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3328 UINT nStrCharCount = 0; /* index in src buffer */
3329 UINT nFileIndex = 0; /* index in dest buffer */
3330 UINT nFileCount = 0; /* number of files */
3331 UINT nStrLen = 0; /* length of string in edit control */
3332 LPWSTR lpstrEdit; /* buffer for string from edit control */
3334 TRACE("\n");
3336 /* get the filenames from the edit control */
3337 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3338 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3339 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3341 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3343 /* we might get single filename without any '"',
3344 * so we need nStrLen + terminating \0 + end-of-list \0 */
3345 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3346 *sizeUsed = 0;
3348 /* build delimited file list from filenames */
3349 while ( nStrCharCount <= nStrLen )
3351 if ( lpstrEdit[nStrCharCount]=='"' )
3353 nStrCharCount++;
3354 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3356 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3357 nStrCharCount++;
3359 (*lpstrFileList)[nFileIndex++] = 0;
3360 nFileCount++;
3362 nStrCharCount++;
3365 /* single, unquoted string */
3366 if ((nStrLen > 0) && (nFileIndex == 0) )
3368 lstrcpyW(*lpstrFileList, lpstrEdit);
3369 nFileIndex = lstrlenW(lpstrEdit) + 1;
3370 nFileCount = 1;
3373 /* trailing \0 */
3374 (*lpstrFileList)[nFileIndex++] = '\0';
3376 *sizeUsed = nFileIndex;
3377 MemFree(lpstrEdit);
3378 return nFileCount;
3381 #define SETDefFormatEtc(fe,cf,med) \
3383 (fe).cfFormat = cf;\
3384 (fe).dwAspect = DVASPECT_CONTENT; \
3385 (fe).ptd =NULL;\
3386 (fe).tymed = med;\
3387 (fe).lindex = -1;\
3391 * DATAOBJECT Helper functions
3394 /***********************************************************************
3395 * COMCTL32_ReleaseStgMedium
3397 * like ReleaseStgMedium from ole32
3399 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3401 if(medium.pUnkForRelease)
3403 IUnknown_Release(medium.pUnkForRelease);
3405 else
3407 GlobalUnlock(medium.u.hGlobal);
3408 GlobalFree(medium.u.hGlobal);
3412 /***********************************************************************
3413 * GetPidlFromDataObject
3415 * Return pidl(s) by number from the cached DataObject
3417 * nPidlIndex=0 gets the fully qualified root path
3419 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3422 STGMEDIUM medium;
3423 FORMATETC formatetc;
3424 LPITEMIDLIST pidl = NULL;
3426 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3428 if (!doSelected)
3429 return NULL;
3431 /* Set the FORMATETC structure*/
3432 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3434 /* Get the pidls from IDataObject */
3435 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3437 LPIDA cida = GlobalLock(medium.u.hGlobal);
3438 if(nPidlIndex <= cida->cidl)
3440 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3442 COMCTL32_ReleaseStgMedium(medium);
3444 return pidl;
3447 /***********************************************************************
3448 * GetNumSelected
3450 * Return the number of selected items in the DataObject.
3453 static UINT GetNumSelected( IDataObject *doSelected )
3455 UINT retVal = 0;
3456 STGMEDIUM medium;
3457 FORMATETC formatetc;
3459 TRACE("sv=%p\n", doSelected);
3461 if (!doSelected) return 0;
3463 /* Set the FORMATETC structure*/
3464 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3466 /* Get the pidls from IDataObject */
3467 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3469 LPIDA cida = GlobalLock(medium.u.hGlobal);
3470 retVal = cida->cidl;
3471 COMCTL32_ReleaseStgMedium(medium);
3472 return retVal;
3474 return 0;
3478 * TOOLS
3481 /***********************************************************************
3482 * GetName
3484 * Get the pidl's display name (relative to folder) and
3485 * put it in lpstrFileName.
3487 * Return NOERROR on success,
3488 * E_FAIL otherwise
3491 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3493 STRRET str;
3494 HRESULT hRes;
3496 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3498 if(!lpsf)
3500 SHGetDesktopFolder(&lpsf);
3501 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3502 IShellFolder_Release(lpsf);
3503 return hRes;
3506 /* Get the display name of the pidl relative to the folder */
3507 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3509 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3511 return E_FAIL;
3514 /***********************************************************************
3515 * GetShellFolderFromPidl
3517 * pidlRel is the item pidl relative
3518 * Return the IShellFolder of the absolute pidl
3520 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3522 IShellFolder *psf = NULL,*psfParent;
3524 TRACE("%p\n", pidlAbs);
3526 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3528 psf = psfParent;
3529 if(pidlAbs && pidlAbs->mkid.cb)
3531 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3533 IShellFolder_Release(psfParent);
3534 return psf;
3537 /* return the desktop */
3538 return psfParent;
3540 return NULL;
3543 /***********************************************************************
3544 * GetParentPidl
3546 * Return the LPITEMIDLIST to the parent of the pidl in the list
3548 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3550 LPITEMIDLIST pidlParent;
3552 TRACE("%p\n", pidl);
3554 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3555 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3557 return pidlParent;
3560 /***********************************************************************
3561 * GetPidlFromName
3563 * returns the pidl of the file name relative to folder
3564 * NULL if an error occurred
3566 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3568 LPITEMIDLIST pidl = NULL;
3569 ULONG ulEaten;
3571 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3573 if(!lpcstrFileName) return NULL;
3574 if(!*lpcstrFileName) return NULL;
3576 if(!lpsf)
3578 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3579 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3580 IShellFolder_Release(lpsf);
3583 else
3585 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3587 return pidl;
3592 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3594 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3595 HRESULT ret;
3597 TRACE("%p, %p\n", psf, pidl);
3599 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3601 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3602 /* see documentation shell 4.1*/
3603 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3606 /***********************************************************************
3607 * BrowseSelectedFolder
3609 static BOOL BrowseSelectedFolder(HWND hwnd)
3611 BOOL bBrowseSelFolder = FALSE;
3612 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3614 TRACE("\n");
3616 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3618 LPITEMIDLIST pidlSelection;
3620 /* get the file selected */
3621 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3622 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3624 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3625 pidlSelection, SBSP_RELATIVE ) ) )
3627 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3628 ' ','n','o','t',' ','e','x','i','s','t',0};
3629 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3631 bBrowseSelFolder = TRUE;
3632 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3634 COMDLG32_SHFree( pidlSelection );
3637 return bBrowseSelFolder;
3641 * Memory allocation methods */
3642 static void *MemAlloc(UINT size)
3644 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3647 static void MemFree(void *mem)
3649 HeapFree(GetProcessHeap(),0,mem);
3653 * Old-style (win3.1) dialogs */
3655 /***********************************************************************
3656 * FD32_GetTemplate [internal]
3658 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3659 * by a 32 bits application
3662 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3664 LPOPENFILENAMEW ofnW = lfs->ofnW;
3665 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3666 HANDLE hDlgTmpl;
3668 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3670 if (!(lfs->template = LockResource( ofnW->hInstance )))
3672 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3673 return FALSE;
3676 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3678 HRSRC hResInfo;
3679 if (priv->ofnA)
3680 hResInfo = FindResourceA(priv->ofnA->hInstance,
3681 priv->ofnA->lpTemplateName,
3682 (LPSTR)RT_DIALOG);
3683 else
3684 hResInfo = FindResourceW(ofnW->hInstance,
3685 ofnW->lpTemplateName,
3686 (LPWSTR)RT_DIALOG);
3687 if (!hResInfo)
3689 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3690 return FALSE;
3692 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3693 hResInfo)) ||
3694 !(lfs->template = LockResource(hDlgTmpl)))
3696 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3697 return FALSE;
3699 } else { /* get it from internal Wine resource */
3700 HRSRC hResInfo;
3701 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3702 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3704 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3705 return FALSE;
3707 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3708 !(lfs->template = LockResource( hDlgTmpl )))
3710 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3711 return FALSE;
3714 return TRUE;
3718 /************************************************************************
3719 * FD32_Init [internal]
3720 * called from the common 16/32 code to initialize 32 bit data
3722 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3724 BOOL IsUnicode = (BOOL) data;
3725 PFD32_PRIVATE priv;
3727 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3728 lfs->private1632 = priv;
3729 if (NULL == lfs->private1632) return FALSE;
3730 if (IsUnicode)
3732 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3733 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3734 if (lfs->ofnW->lpfnHook)
3735 lfs->hook = TRUE;
3737 else
3739 priv->ofnA = (LPOPENFILENAMEA) lParam;
3740 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3741 if (priv->ofnA->lpfnHook)
3742 lfs->hook = TRUE;
3743 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3744 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3747 if (! FD32_GetTemplate(lfs)) return FALSE;
3749 return TRUE;
3752 /***********************************************************************
3753 * FD32_CallWindowProc [internal]
3755 * called from the common 16/32 code to call the appropriate hook
3757 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3758 LPARAM lParam)
3760 BOOL ret;
3761 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3763 if (priv->ofnA)
3765 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3766 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3767 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3768 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3769 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3770 return ret;
3773 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3774 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3775 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3776 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3777 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3778 return ret;
3781 /***********************************************************************
3782 * FD32_UpdateResult [internal]
3783 * update the real client structures if any
3785 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3787 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3788 LPOPENFILENAMEW ofnW = lfs->ofnW;
3790 if (priv->ofnA)
3792 LPSTR lpszTemp;
3793 if (ofnW->nMaxFile &&
3794 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3795 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3796 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3798 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3799 /* set filename offset */
3800 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3801 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3803 /* set extension offset */
3804 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3805 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3809 /***********************************************************************
3810 * FD32_UpdateFileTitle [internal]
3811 * update the real client structures if any
3813 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3815 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3816 LPOPENFILENAMEW ofnW = lfs->ofnW;
3818 if (priv->ofnA)
3820 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3821 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3822 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3827 /***********************************************************************
3828 * FD32_SendLbGetCurSel [internal]
3829 * retrieve selected listbox item
3831 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3833 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3837 /************************************************************************
3838 * FD32_Destroy [internal]
3839 * called from the common 16/32 code to cleanup 32 bit data
3841 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3843 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3845 /* if ofnW has been allocated, have to free everything in it */
3846 if (NULL != priv && NULL != priv->ofnA)
3848 FD31_FreeOfnW(lfs->ofnW);
3849 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3853 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3855 callbacks->Init = FD32_Init;
3856 callbacks->CWP = FD32_CallWindowProc;
3857 callbacks->UpdateResult = FD32_UpdateResult;
3858 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3859 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3860 callbacks->Destroy = FD32_Destroy;
3863 /***********************************************************************
3864 * FD32_WMMeasureItem [internal]
3866 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3868 LPMEASUREITEMSTRUCT lpmeasure;
3870 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3871 lpmeasure->itemHeight = FD31_GetFldrHeight();
3872 return TRUE;
3876 /***********************************************************************
3877 * FileOpenDlgProc [internal]
3878 * Used for open and save, in fact.
3880 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3881 WPARAM wParam, LPARAM lParam)
3883 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3885 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3886 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3888 INT_PTR lRet;
3889 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3890 if (lRet)
3891 return lRet; /* else continue message processing */
3893 switch (wMsg)
3895 case WM_INITDIALOG:
3896 return FD31_WMInitDialog(hWnd, wParam, lParam);
3898 case WM_MEASUREITEM:
3899 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3901 case WM_DRAWITEM:
3902 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3904 case WM_COMMAND:
3905 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3906 #if 0
3907 case WM_CTLCOLOR:
3908 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3909 switch (HIWORD(lParam))
3911 case CTLCOLOR_BTN:
3912 SetTextColor((HDC16)wParam, 0x00000000);
3913 return hGRAYBrush;
3914 case CTLCOLOR_STATIC:
3915 SetTextColor((HDC16)wParam, 0x00000000);
3916 return hGRAYBrush;
3918 break;
3919 #endif
3921 return FALSE;
3925 /***********************************************************************
3926 * GetFileName31A [internal]
3928 * Creates a win31 style dialog box for the user to select a file to open/save.
3930 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3931 UINT dlgType /* type dialogue : open/save */
3934 HINSTANCE hInst;
3935 BOOL bRet = FALSE;
3936 PFD31_DATA lfs;
3937 FD31_CALLBACKS callbacks;
3939 if (!lpofn || !FD31_Init()) return FALSE;
3941 TRACE("ofn flags %08x\n", lpofn->Flags);
3942 FD32_SetupCallbacks(&callbacks);
3943 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3944 if (lfs)
3946 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3947 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3948 FD32_FileOpenDlgProc, (LPARAM)lfs);
3949 FD31_DestroyPrivate(lfs);
3952 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3953 return bRet;
3956 /***********************************************************************
3957 * GetFileName31W [internal]
3959 * Creates a win31 style dialog box for the user to select a file to open/save
3961 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3962 UINT dlgType /* type dialogue : open/save */
3965 HINSTANCE hInst;
3966 BOOL bRet = FALSE;
3967 PFD31_DATA lfs;
3968 FD31_CALLBACKS callbacks;
3970 if (!lpofn || !FD31_Init()) return FALSE;
3972 FD32_SetupCallbacks(&callbacks);
3973 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3974 if (lfs)
3976 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3977 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3978 FD32_FileOpenDlgProc, (LPARAM)lfs);
3979 FD31_DestroyPrivate(lfs);
3982 TRACE("file %s, file offset %d, ext offset %d\n",
3983 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3984 return bRet;
3987 /* ------------------ APIs ---------------------- */
3989 /***********************************************************************
3990 * GetOpenFileNameA (COMDLG32.@)
3992 * Creates a dialog box for the user to select a file to open.
3994 * RETURNS
3995 * TRUE on success: user enters a valid file
3996 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3999 BOOL WINAPI GetOpenFileNameA(
4000 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4002 BOOL win16look = FALSE;
4004 TRACE("flags %08x\n", ofn->Flags);
4006 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4007 if (ofn->Flags & OFN_FILEMUSTEXIST)
4008 ofn->Flags |= OFN_PATHMUSTEXIST;
4010 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4011 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4013 if (win16look)
4014 return GetFileName31A(ofn, OPEN_DIALOG);
4015 else
4016 return GetFileDialog95A(ofn, OPEN_DIALOG);
4019 /***********************************************************************
4020 * GetOpenFileNameW (COMDLG32.@)
4022 * Creates a dialog box for the user to select a file to open.
4024 * RETURNS
4025 * TRUE on success: user enters a valid file
4026 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4029 BOOL WINAPI GetOpenFileNameW(
4030 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4032 BOOL win16look = FALSE;
4034 TRACE("flags %08x\n", ofn->Flags);
4036 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4037 if (ofn->Flags & OFN_FILEMUSTEXIST)
4038 ofn->Flags |= OFN_PATHMUSTEXIST;
4040 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4041 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4043 if (win16look)
4044 return GetFileName31W(ofn, OPEN_DIALOG);
4045 else
4046 return GetFileDialog95W(ofn, OPEN_DIALOG);
4050 /***********************************************************************
4051 * GetSaveFileNameA (COMDLG32.@)
4053 * Creates a dialog box for the user to select a file to save.
4055 * RETURNS
4056 * TRUE on success: user enters a valid file
4057 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4060 BOOL WINAPI GetSaveFileNameA(
4061 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4063 BOOL win16look = FALSE;
4065 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4066 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4068 if (win16look)
4069 return GetFileName31A(ofn, SAVE_DIALOG);
4070 else
4071 return GetFileDialog95A(ofn, SAVE_DIALOG);
4074 /***********************************************************************
4075 * GetSaveFileNameW (COMDLG32.@)
4077 * Creates a dialog box for the user to select a file to save.
4079 * RETURNS
4080 * TRUE on success: user enters a valid file
4081 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4084 BOOL WINAPI GetSaveFileNameW(
4085 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4087 BOOL win16look = FALSE;
4089 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4090 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4092 if (win16look)
4093 return GetFileName31W(ofn, SAVE_DIALOG);
4094 else
4095 return GetFileDialog95W(ofn, SAVE_DIALOG);
4098 /***********************************************************************
4099 * GetFileTitleA (COMDLG32.@)
4101 * See GetFileTitleW.
4103 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4105 int ret;
4106 UNICODE_STRING strWFile;
4107 LPWSTR lpWTitle;
4109 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4110 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4111 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4112 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4113 RtlFreeUnicodeString( &strWFile );
4114 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4115 return ret;
4119 /***********************************************************************
4120 * GetFileTitleW (COMDLG32.@)
4122 * Get the name of a file.
4124 * PARAMS
4125 * lpFile [I] name and location of file
4126 * lpTitle [O] returned file name
4127 * cbBuf [I] buffer size of lpTitle
4129 * RETURNS
4130 * Success: zero
4131 * Failure: negative number.
4133 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4135 int i, len;
4136 static const WCHAR brkpoint[] = {'*','[',']',0};
4137 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4139 if(lpFile == NULL || lpTitle == NULL)
4140 return -1;
4142 len = lstrlenW(lpFile);
4144 if (len == 0)
4145 return -1;
4147 if(strpbrkW(lpFile, brkpoint))
4148 return -1;
4150 len--;
4152 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4153 return -1;
4155 for(i = len; i >= 0; i--)
4157 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4159 i++;
4160 break;
4164 if(i == -1)
4165 i++;
4167 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4169 len = lstrlenW(lpFile+i)+1;
4170 if(cbBuf < len)
4171 return len;
4173 lstrcpyW(lpTitle, &lpFile[i]);
4174 return 0;