DIB Engine: Implement Polygon
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blobae357f6098dbf61addece40c17eeea0b85793de0
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;
109 /***********************************************************************
110 * Defines and global variables
113 /* Draw item constant */
114 #define ICONWIDTH 18
115 #define XTEXTOFFSET 3
117 /* AddItem flags*/
118 #define LISTEND -1
120 /* SearchItem methods */
121 #define SEARCH_PIDL 1
122 #define SEARCH_EXP 2
123 #define ITEM_NOTFOUND -1
125 /* Undefined windows message sent by CreateViewObject*/
126 #define WM_GETISHELLBROWSER WM_USER+7
128 /* NOTE
129 * Those macros exist in windowsx.h. However, you can't really use them since
130 * they rely on the UNICODE defines and can't be used inside Wine itself.
133 /* Combo box macros */
134 #define CBAddString(hwnd,str) \
135 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
137 #define CBInsertString(hwnd,str,pos) \
138 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
140 #define CBDeleteString(hwnd,pos) \
141 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
143 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
144 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
146 #define CBGetItemDataPtr(hwnd,iItemId) \
147 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
149 #define CBGetLBText(hwnd,iItemId,str) \
150 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
152 #define CBGetCurSel(hwnd) \
153 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
155 #define CBSetCurSel(hwnd,pos) \
156 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
158 #define CBGetCount(hwnd) \
159 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
160 #define CBShowDropDown(hwnd,show) \
161 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
162 #define CBSetItemHeight(hwnd,index,height) \
163 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
165 #define CBSetExtendedUI(hwnd,flag) \
166 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
168 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
169 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
170 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
172 /***********************************************************************
173 * Prototypes
176 /* Internal functions used by the dialog */
177 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
178 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
179 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam);
180 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
181 static BOOL FILEDLG95_OnOpen(HWND hwnd);
182 static LRESULT FILEDLG95_InitControls(HWND hwnd);
183 static void FILEDLG95_Clean(HWND hwnd);
185 /* Functions used by the shell navigation */
186 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
187 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
188 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
189 static void FILEDLG95_SHELL_Clean(HWND hwnd);
190 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
192 /* Functions used by the EDIT box */
193 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
195 /* Functions used by the filetype combo box */
196 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
197 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
198 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
199 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
201 /* Functions used by the Look In combo box */
202 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
203 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
204 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
206 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
207 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
208 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
209 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
210 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
212 /* Miscellaneous tool functions */
213 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
214 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
215 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
216 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
217 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
218 static UINT GetNumSelected( IDataObject *doSelected );
220 /* Shell memory allocation */
221 static void *MemAlloc(UINT size);
222 static void MemFree(void *mem);
224 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
225 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
226 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
227 static BOOL BrowseSelectedFolder(HWND hwnd);
229 /***********************************************************************
230 * GetFileName95
232 * Creates an Open common dialog box that lets the user select
233 * the drive, directory, and the name of a file or set of files to open.
235 * IN : The FileOpenDlgInfos structure associated with the dialog
236 * OUT : TRUE on success
237 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
239 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
242 LRESULT lRes;
243 LPVOID template;
244 HRSRC hRes;
245 HANDLE hDlgTmpl = 0;
246 HRESULT hr;
248 /* test for missing functionality */
249 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
251 FIXME("Flags 0x%08x not yet implemented\n",
252 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
255 /* Create the dialog from a template */
257 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
259 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
260 return FALSE;
262 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
263 !(template = LockResource( hDlgTmpl )))
265 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
266 return FALSE;
269 /* msdn: explorer style dialogs permit sizing by default.
270 * The OFN_ENABLESIZING flag is only needed when a hook or
271 * custom tmeplate is provided */
272 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
273 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
274 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
276 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
278 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
279 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
280 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
282 else
283 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
286 /* old style hook messages */
287 if (IsHooked(fodInfos))
289 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
290 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
291 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
292 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
295 /* Some shell namespace extensions depend on COM being initialized. */
296 hr = OleInitialize(NULL);
298 if (fodInfos->unicode)
299 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
300 template,
301 fodInfos->ofnInfos->hwndOwner,
302 FileOpenDlgProc95,
303 (LPARAM) fodInfos);
304 else
305 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
306 template,
307 fodInfos->ofnInfos->hwndOwner,
308 FileOpenDlgProc95,
309 (LPARAM) fodInfos);
310 if (SUCCEEDED(hr))
311 OleUninitialize();
313 /* Unable to create the dialog */
314 if( lRes == -1)
315 return FALSE;
317 return lRes;
320 /***********************************************************************
321 * GetFileDialog95A
323 * Call GetFileName95 with this structure and clean the memory.
325 * IN : The OPENFILENAMEA initialisation structure passed to
326 * GetOpenFileNameA win api function (see filedlg.c)
328 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
330 BOOL ret;
331 FileOpenDlgInfos fodInfos;
332 LPSTR lpstrSavDir = NULL;
333 LPWSTR title = NULL;
334 LPWSTR defext = NULL;
335 LPWSTR filter = NULL;
336 LPWSTR customfilter = NULL;
338 /* Initialize CommDlgExtendedError() */
339 COMDLG32_SetCommDlgExtendedError(0);
341 /* Initialize FileOpenDlgInfos structure */
342 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
344 /* Pass in the original ofn */
345 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
347 /* save current directory */
348 if (ofn->Flags & OFN_NOCHANGEDIR)
350 lpstrSavDir = MemAlloc(MAX_PATH);
351 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
354 fodInfos.unicode = FALSE;
356 /* convert all the input strings to unicode */
357 if(ofn->lpstrInitialDir)
359 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
360 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
361 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
363 else
364 fodInfos.initdir = NULL;
366 if(ofn->lpstrFile)
368 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
369 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
371 else
372 fodInfos.filename = NULL;
374 if(ofn->lpstrDefExt)
376 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
377 defext = MemAlloc((len+1)*sizeof(WCHAR));
378 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
380 fodInfos.defext = defext;
382 if(ofn->lpstrTitle)
384 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
385 title = MemAlloc((len+1)*sizeof(WCHAR));
386 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
388 fodInfos.title = title;
390 if (ofn->lpstrFilter)
392 LPCSTR s;
393 int n, len;
395 /* filter is a list... title\0ext\0......\0\0 */
396 s = ofn->lpstrFilter;
397 while (*s) s = s+strlen(s)+1;
398 s++;
399 n = s - ofn->lpstrFilter;
400 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
401 filter = MemAlloc(len*sizeof(WCHAR));
402 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
404 fodInfos.filter = filter;
406 /* convert lpstrCustomFilter */
407 if (ofn->lpstrCustomFilter)
409 LPCSTR s;
410 int n, len;
412 /* customfilter contains a pair of strings... title\0ext\0 */
413 s = ofn->lpstrCustomFilter;
414 if (*s) s = s+strlen(s)+1;
415 if (*s) s = s+strlen(s)+1;
416 n = s - ofn->lpstrCustomFilter;
417 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
418 customfilter = MemAlloc(len*sizeof(WCHAR));
419 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
421 fodInfos.customfilter = customfilter;
423 /* Initialize the dialog property */
424 fodInfos.DlgInfos.dwDlgProp = 0;
425 fodInfos.DlgInfos.hwndCustomDlg = NULL;
427 switch(iDlgType)
429 case OPEN_DIALOG :
430 ret = GetFileName95(&fodInfos);
431 break;
432 case SAVE_DIALOG :
433 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
434 ret = GetFileName95(&fodInfos);
435 break;
436 default :
437 ret = 0;
440 if (lpstrSavDir)
442 SetCurrentDirectoryA(lpstrSavDir);
443 MemFree(lpstrSavDir);
446 MemFree(title);
447 MemFree(defext);
448 MemFree(filter);
449 MemFree(customfilter);
450 MemFree(fodInfos.initdir);
451 MemFree(fodInfos.filename);
453 TRACE("selected file: %s\n",ofn->lpstrFile);
455 return ret;
458 /***********************************************************************
459 * GetFileDialog95W
461 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
462 * Call GetFileName95 with this structure and clean the memory.
465 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
467 BOOL ret;
468 FileOpenDlgInfos fodInfos;
469 LPWSTR lpstrSavDir = NULL;
471 /* Initialize CommDlgExtendedError() */
472 COMDLG32_SetCommDlgExtendedError(0);
474 /* Initialize FileOpenDlgInfos structure */
475 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
477 /* Pass in the original ofn */
478 fodInfos.ofnInfos = ofn;
480 fodInfos.title = ofn->lpstrTitle;
481 fodInfos.defext = ofn->lpstrDefExt;
482 fodInfos.filter = ofn->lpstrFilter;
483 fodInfos.customfilter = ofn->lpstrCustomFilter;
485 /* convert string arguments, save others */
486 if(ofn->lpstrFile)
488 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
489 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
491 else
492 fodInfos.filename = NULL;
494 if(ofn->lpstrInitialDir)
496 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
497 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
498 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
499 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
501 else
502 fodInfos.initdir = NULL;
504 /* save current directory */
505 if (ofn->Flags & OFN_NOCHANGEDIR)
507 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
508 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
511 fodInfos.unicode = TRUE;
513 switch(iDlgType)
515 case OPEN_DIALOG :
516 ret = GetFileName95(&fodInfos);
517 break;
518 case SAVE_DIALOG :
519 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
520 ret = GetFileName95(&fodInfos);
521 break;
522 default :
523 ret = 0;
526 if (lpstrSavDir)
528 SetCurrentDirectoryW(lpstrSavDir);
529 MemFree(lpstrSavDir);
532 /* restore saved IN arguments and convert OUT arguments back */
533 MemFree(fodInfos.filename);
534 MemFree(fodInfos.initdir);
535 return ret;
538 /******************************************************************************
539 * COMDLG32_GetDisplayNameOf [internal]
541 * Helper function to get the display name for a pidl.
543 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
544 LPSHELLFOLDER psfDesktop;
545 STRRET strret;
547 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
548 return FALSE;
550 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
551 IShellFolder_Release(psfDesktop);
552 return FALSE;
555 IShellFolder_Release(psfDesktop);
556 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
559 /***********************************************************************
560 * ArrangeCtrlPositions [internal]
562 * NOTE: Make sure to add testcases for any changes made here.
564 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
566 HWND hwndChild, hwndStc32;
567 RECT rectParent, rectChild, rectStc32;
568 INT help_fixup = 0;
569 int chgx, chgy;
571 /* Take into account if open as read only checkbox and help button
572 * are hidden
574 if (hide_help)
576 RECT rectHelp, rectCancel;
577 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
578 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
579 /* subtract the height of the help button plus the space between
580 * the help button and the cancel button to the height of the dialog
582 help_fixup = rectHelp.bottom - rectCancel.bottom;
586 There are two possibilities to add components to the default file dialog box.
588 By default, all the new components are added below the standard dialog box (the else case).
590 However, if there is a static text component with the stc32 id, a special case happens.
591 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
592 in the window and the cx and cy indicate how to size the window.
593 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
594 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
598 GetClientRect(hwndParentDlg, &rectParent);
600 /* when arranging controls we have to use fixed parent size */
601 rectParent.bottom -= help_fixup;
603 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
604 if (hwndStc32)
606 GetWindowRect(hwndStc32, &rectStc32);
607 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
609 /* set the size of the stc32 control according to the size of
610 * client area of the parent dialog
612 SetWindowPos(hwndStc32, 0,
613 0, 0,
614 rectParent.right, rectParent.bottom,
615 SWP_NOMOVE | SWP_NOZORDER);
617 else
618 SetRectEmpty(&rectStc32);
620 /* this part moves controls of the child dialog */
621 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
622 while (hwndChild)
624 if (hwndChild != hwndStc32)
626 GetWindowRect(hwndChild, &rectChild);
627 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
629 /* move only if stc32 exist */
630 if (hwndStc32 && rectChild.left > rectStc32.right)
632 /* move to the right of visible controls of the parent dialog */
633 rectChild.left += rectParent.right;
634 rectChild.left -= rectStc32.right;
636 /* move even if stc32 doesn't exist */
637 if (rectChild.top >= rectStc32.bottom)
639 /* move below visible controls of the parent dialog */
640 rectChild.top += rectParent.bottom;
641 rectChild.top -= rectStc32.bottom - rectStc32.top;
644 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
645 0, 0, SWP_NOSIZE | SWP_NOZORDER);
647 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
650 /* this part moves controls of the parent dialog */
651 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
652 while (hwndChild)
654 if (hwndChild != hwndChildDlg)
656 GetWindowRect(hwndChild, &rectChild);
657 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
659 /* left,top of stc32 marks the position of controls
660 * from the parent dialog
662 rectChild.left += rectStc32.left;
663 rectChild.top += rectStc32.top;
665 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
666 0, 0, SWP_NOSIZE | SWP_NOZORDER);
668 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
671 /* calculate the size of the resulting dialog */
673 /* here we have to use original parent size */
674 GetClientRect(hwndParentDlg, &rectParent);
675 GetClientRect(hwndChildDlg, &rectChild);
676 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
677 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
679 if (hwndStc32)
681 /* width */
682 if (rectParent.right > rectStc32.right - rectStc32.left)
683 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
684 else
685 chgx = rectChild.right - rectParent.right;
686 /* height */
687 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
688 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
689 else
690 /* Unconditionally set new dialog
691 * height to that of the child
693 chgy = rectChild.bottom - rectParent.bottom;
695 else
697 chgx = 0;
698 chgy = rectChild.bottom - help_fixup;
700 /* set the size of the parent dialog */
701 GetWindowRect(hwndParentDlg, &rectParent);
702 SetWindowPos(hwndParentDlg, 0,
703 0, 0,
704 rectParent.right - rectParent.left + chgx,
705 rectParent.bottom - rectParent.top + chgy,
706 SWP_NOMOVE | SWP_NOZORDER);
709 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
711 switch(uMsg) {
712 case WM_INITDIALOG:
713 return TRUE;
715 return FALSE;
718 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
720 LPCVOID template;
721 HRSRC hRes;
722 HANDLE hDlgTmpl = 0;
723 HWND hChildDlg = 0;
725 TRACE("\n");
728 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
729 * structure's hInstance parameter is not a HINSTANCE, but
730 * instead a pointer to a template resource to use.
732 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
734 HINSTANCE hinst;
735 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
737 hinst = COMDLG32_hInstance;
738 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
740 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
741 return NULL;
744 else
746 hinst = fodInfos->ofnInfos->hInstance;
747 if(fodInfos->unicode)
749 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
750 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
752 else
754 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
755 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
757 if (!hRes)
759 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
760 return NULL;
762 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
763 !(template = LockResource( hDlgTmpl )))
765 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
766 return NULL;
769 if (fodInfos->unicode)
770 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
771 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
772 (LPARAM)fodInfos->ofnInfos);
773 else
774 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
775 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
776 (LPARAM)fodInfos->ofnInfos);
777 return hChildDlg;
779 else if( IsHooked(fodInfos))
781 RECT rectHwnd;
782 struct {
783 DLGTEMPLATE tmplate;
784 WORD menu,class,title;
785 } temp;
786 GetClientRect(hwnd,&rectHwnd);
787 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
788 temp.tmplate.dwExtendedStyle = 0;
789 temp.tmplate.cdit = 0;
790 temp.tmplate.x = 0;
791 temp.tmplate.y = 0;
792 temp.tmplate.cx = 0;
793 temp.tmplate.cy = 0;
794 temp.menu = temp.class = temp.title = 0;
796 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
797 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
799 return hChildDlg;
801 return NULL;
804 /***********************************************************************
805 * SendCustomDlgNotificationMessage
807 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
810 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
812 LRESULT hook_result = 0;
813 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
815 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
817 if(!fodInfos) return 0;
819 if(fodInfos->DlgInfos.hwndCustomDlg)
821 TRACE("CALL NOTIFY for %x\n", uCode);
822 if(fodInfos->unicode)
824 OFNOTIFYW ofnNotify;
825 ofnNotify.hdr.hwndFrom=hwndParentDlg;
826 ofnNotify.hdr.idFrom=0;
827 ofnNotify.hdr.code = uCode;
828 ofnNotify.lpOFN = fodInfos->ofnInfos;
829 ofnNotify.pszFile = NULL;
830 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
832 else
834 OFNOTIFYA ofnNotify;
835 ofnNotify.hdr.hwndFrom=hwndParentDlg;
836 ofnNotify.hdr.idFrom=0;
837 ofnNotify.hdr.code = uCode;
838 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
839 ofnNotify.pszFile = NULL;
840 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
842 TRACE("RET NOTIFY\n");
844 TRACE("Retval: 0x%08lx\n", hook_result);
845 return hook_result;
848 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
850 UINT len, total;
851 WCHAR *p, *buffer;
852 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
854 TRACE("CDM_GETFILEPATH:\n");
856 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
857 return -1;
859 /* get path and filenames */
860 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
861 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
862 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
863 if (len)
865 p = buffer + strlenW(buffer);
866 *p++ = '\\';
867 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
869 if (fodInfos->unicode)
871 total = strlenW( buffer) + 1;
872 if (result) lstrcpynW( result, buffer, size );
873 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
875 else
877 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
878 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
879 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
881 HeapFree( GetProcessHeap(), 0, buffer );
882 return total;
885 /***********************************************************************
886 * FILEDLG95_HandleCustomDialogMessages
888 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
890 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
892 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
893 WCHAR lpstrPath[MAX_PATH];
894 INT_PTR retval;
896 if(!fodInfos) return FALSE;
898 switch(uMsg)
900 case CDM_GETFILEPATH:
901 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
902 break;
904 case CDM_GETFOLDERPATH:
905 TRACE("CDM_GETFOLDERPATH:\n");
906 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
907 if (lParam)
909 if (fodInfos->unicode)
910 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
911 else
912 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
913 (LPSTR)lParam, (int)wParam, NULL, NULL);
915 retval = lstrlenW(lpstrPath) + 1;
916 break;
918 case CDM_GETFOLDERIDLIST:
919 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
920 if (retval <= wParam)
921 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
922 break;
924 case CDM_GETSPEC:
925 TRACE("CDM_GETSPEC:\n");
926 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
927 if (lParam)
929 if (fodInfos->unicode)
930 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
931 else
932 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
934 break;
936 case CDM_SETCONTROLTEXT:
937 TRACE("CDM_SETCONTROLTEXT:\n");
938 if ( lParam )
940 if( fodInfos->unicode )
941 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
942 else
943 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
945 retval = TRUE;
946 break;
948 case CDM_HIDECONTROL:
949 /* MSDN states that it should fail for not OFN_EXPLORER case */
950 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
952 HWND control = GetDlgItem( hwnd, wParam );
953 if (control) ShowWindow( control, SW_HIDE );
954 retval = TRUE;
956 else retval = FALSE;
957 break;
959 default:
960 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
961 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
962 return FALSE;
964 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
965 return TRUE;
968 /***********************************************************************
969 * FILEDLG95_OnWMGetMMI
971 * WM_GETMINMAXINFO message handler for resizable dialogs
973 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
975 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
976 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
977 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
979 mmiptr->ptMinTrackSize = fodInfos->initial_size;
981 return TRUE;
984 /***********************************************************************
985 * FILEDLG95_OnWMSize
987 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
989 * FIXME: this could be made more elaborate. Now use a simple scheme
990 * where the file view is enlarged and the controls are either moved
991 * vertically or horizontally to get out of the way. Only the "grip"
992 * is moved in both directions to stay in the corner.
994 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam)
996 RECT rc, rcview;
997 int chgx, chgy;
998 HWND ctrl;
999 HDWP hdwp;
1000 FileOpenDlgInfos *fodInfos;
1002 if( wParam != SIZE_RESTORED) return FALSE;
1003 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1004 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1005 /* get the new dialog rectangle */
1006 GetWindowRect( hwnd, &rc);
1007 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1008 rc.right -rc.left, rc.bottom -rc.top);
1009 /* not initialized yet */
1010 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1011 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1012 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1013 return FALSE;
1014 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1015 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1016 fodInfos->sizedlg.cx = rc.right - rc.left;
1017 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1018 /* change the size of the view window */
1019 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1020 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1021 hdwp = BeginDeferWindowPos( 10);
1022 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1023 rcview.right - rcview.left + chgx,
1024 rcview.bottom - rcview.top + chgy,
1025 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1026 /* change position and sizes of the controls */
1027 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1029 int ctrlid = GetDlgCtrlID( ctrl);
1030 GetWindowRect( ctrl, &rc);
1031 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1032 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1034 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1035 0, 0,
1036 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1038 else if( rc.top > rcview.bottom)
1040 /* if it was below the shell view
1041 * move to bottom */
1042 switch( ctrlid)
1044 /* file name box and file types combo change also width */
1045 case edt1:
1046 case cmb1:
1047 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1048 rc.right - rc.left + chgx, rc.bottom - rc.top,
1049 SWP_NOACTIVATE | SWP_NOZORDER);
1050 break;
1051 /* then these buttons must move out of the way */
1052 case IDOK:
1053 case IDCANCEL:
1054 case pshHelp:
1055 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1056 0, 0,
1057 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1058 break;
1059 default:
1060 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1061 0, 0,
1062 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1065 else if( rc.left > rcview.right)
1067 /* if it was to the right of the shell view
1068 * move to right */
1069 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1070 0, 0,
1071 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1073 else
1074 /* special cases */
1076 switch( ctrlid)
1078 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1079 case IDC_LOOKIN:
1080 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1081 rc.right - rc.left + chgx, rc.bottom - rc.top,
1082 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1083 break;
1084 case IDC_TOOLBARSTATIC:
1085 case IDC_TOOLBAR:
1086 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1087 0, 0,
1088 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1089 break;
1090 #endif
1091 /* not resized in windows. Since wine uses this invisible control
1092 * to size the browser view it needs to be resized */
1093 case IDC_SHELLSTATIC:
1094 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1095 rc.right - rc.left + chgx,
1096 rc.bottom - rc.top + chgy,
1097 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1098 break;
1102 if(fodInfos->DlgInfos.hwndCustomDlg &&
1103 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1105 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1106 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1108 GetWindowRect( ctrl, &rc);
1109 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1110 if( rc.top > rcview.bottom)
1112 /* if it was below the shell view
1113 * move to bottom */
1114 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1115 rc.right - rc.left, rc.bottom - rc.top,
1116 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1118 else if( rc.left > rcview.right)
1120 /* if it was to the right of the shell view
1121 * move to right */
1122 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1123 rc.right - rc.left, rc.bottom - rc.top,
1124 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1127 /* size the custom dialog at the end: some applications do some
1128 * control re-arranging at this point */
1129 GetClientRect(hwnd, &rc);
1130 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1131 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1133 EndDeferWindowPos( hdwp);
1134 /* should not be needed */
1135 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1136 return TRUE;
1139 /***********************************************************************
1140 * FileOpenDlgProc95
1142 * File open dialog procedure
1144 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1146 #if 0
1147 TRACE("%p 0x%04x\n", hwnd, uMsg);
1148 #endif
1150 switch(uMsg)
1152 case WM_INITDIALOG:
1154 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1155 RECT rc, rcstc;
1156 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1157 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1159 /* Adds the FileOpenDlgInfos in the property list of the dialog
1160 so it will be easily accessible through a GetPropA(...) */
1161 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1163 FILEDLG95_InitControls(hwnd);
1165 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1167 GetWindowRect( hwnd, &rc);
1168 fodInfos->DlgInfos.hwndGrip =
1169 CreateWindowExA( 0, "SCROLLBAR", NULL,
1170 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1171 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1172 rc.right - gripx, rc.bottom - gripy,
1173 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1176 fodInfos->DlgInfos.hwndCustomDlg =
1177 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1179 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1180 FILEDLG95_FillControls(hwnd, wParam, lParam);
1182 if( fodInfos->DlgInfos.hwndCustomDlg)
1183 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1185 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1186 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1187 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1190 /* if the app has changed the position of the invisible listbox,
1191 * change that of the listview (browser) as well */
1192 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1193 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1194 if( !EqualRect( &rc, &rcstc))
1196 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1197 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1198 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1199 SWP_NOACTIVATE | SWP_NOZORDER);
1202 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1204 GetWindowRect( hwnd, &rc);
1205 fodInfos->sizedlg.cx = rc.right - rc.left;
1206 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1207 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1208 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1209 GetClientRect( hwnd, &rc);
1210 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1211 rc.right - gripx, rc.bottom - gripy,
1212 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1213 /* resize the dialog to the previous invocation */
1214 if( MemDialogSize.cx && MemDialogSize.cy)
1215 SetWindowPos( hwnd, NULL,
1216 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1217 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1220 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1221 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1223 return 0;
1225 case WM_SIZE:
1226 return FILEDLG95_OnWMSize(hwnd, wParam);
1227 case WM_GETMINMAXINFO:
1228 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1229 case WM_COMMAND:
1230 return FILEDLG95_OnWMCommand(hwnd, wParam);
1231 case WM_DRAWITEM:
1233 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1235 case IDC_LOOKIN:
1236 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1237 return TRUE;
1240 return FALSE;
1242 case WM_GETISHELLBROWSER:
1243 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1245 case WM_DESTROY:
1247 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1248 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1249 MemDialogSize = fodInfos->sizedlg;
1250 RemovePropA(hwnd, FileOpenDlgInfosStr);
1251 return FALSE;
1253 case WM_NOTIFY:
1255 LPNMHDR lpnmh = (LPNMHDR)lParam;
1256 UINT stringId = -1;
1258 /* set up the button tooltips strings */
1259 if(TTN_GETDISPINFOA == lpnmh->code )
1261 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1262 switch(lpnmh->idFrom )
1264 /* Up folder button */
1265 case FCIDM_TB_UPFOLDER:
1266 stringId = IDS_UPFOLDER;
1267 break;
1268 /* New folder button */
1269 case FCIDM_TB_NEWFOLDER:
1270 stringId = IDS_NEWFOLDER;
1271 break;
1272 /* List option button */
1273 case FCIDM_TB_SMALLICON:
1274 stringId = IDS_LISTVIEW;
1275 break;
1276 /* Details option button */
1277 case FCIDM_TB_REPORTVIEW:
1278 stringId = IDS_REPORTVIEW;
1279 break;
1280 /* Desktop button */
1281 case FCIDM_TB_DESKTOP:
1282 stringId = IDS_TODESKTOP;
1283 break;
1284 default:
1285 stringId = 0;
1287 lpdi->hinst = COMDLG32_hInstance;
1288 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1290 return FALSE;
1292 default :
1293 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1294 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1295 return FALSE;
1299 /***********************************************************************
1300 * FILEDLG95_InitControls
1302 * WM_INITDIALOG message handler (before hook notification)
1304 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1306 int win2000plus = 0;
1307 int win98plus = 0;
1308 int handledPath = FALSE;
1309 OSVERSIONINFOW osVi;
1310 static const WCHAR szwSlash[] = { '\\', 0 };
1311 static const WCHAR szwStar[] = { '*',0 };
1313 static const TBBUTTON tbb[] =
1315 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1316 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1317 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1318 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1319 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1320 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1321 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1322 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1323 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1325 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1327 RECT rectTB;
1328 RECT rectlook;
1330 HIMAGELIST toolbarImageList;
1331 SHFILEINFOA shFileInfo;
1332 ITEMIDLIST *desktopPidl;
1334 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1336 TRACE("%p\n", fodInfos);
1338 /* Get windows version emulating */
1339 osVi.dwOSVersionInfoSize = sizeof(osVi);
1340 GetVersionExW(&osVi);
1341 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1342 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1343 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1344 win2000plus = (osVi.dwMajorVersion > 4);
1345 if (win2000plus) win98plus = TRUE;
1347 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1349 /* Get the hwnd of the controls */
1350 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1351 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1352 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1354 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1355 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1357 /* construct the toolbar */
1358 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1359 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1361 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1362 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1363 rectTB.left = rectlook.right;
1364 rectTB.top = rectlook.top-1;
1366 if (fodInfos->unicode)
1367 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1368 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1369 rectTB.left, rectTB.top,
1370 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1371 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1372 else
1373 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1374 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1375 rectTB.left, rectTB.top,
1376 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1377 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1379 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1381 /* FIXME: use TB_LOADIMAGES when implemented */
1382 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1383 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1384 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1386 /* Retrieve and add desktop icon to the toolbar */
1387 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1388 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1389 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1390 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1391 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1393 DestroyIcon(shFileInfo.hIcon);
1394 CoTaskMemFree(desktopPidl);
1396 /* Finish Toolbar Construction */
1397 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1398 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1400 /* Set the window text with the text specified in the OPENFILENAME structure */
1401 if(fodInfos->title)
1403 SetWindowTextW(hwnd,fodInfos->title);
1405 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1407 WCHAR buf[16];
1408 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1409 SetWindowTextW(hwnd, buf);
1412 /* Initialise the file name edit control */
1413 handledPath = FALSE;
1414 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1416 if(fodInfos->filename)
1418 /* 1. If win2000 or higher and filename contains a path, use it
1419 in preference over the lpstrInitialDir */
1420 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1421 WCHAR tmpBuf[MAX_PATH];
1422 WCHAR *nameBit;
1423 DWORD result;
1425 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1426 if (result) {
1428 /* nameBit is always shorter than the original filename */
1429 lstrcpyW(fodInfos->filename,nameBit);
1431 *nameBit = 0x00;
1432 if (fodInfos->initdir == NULL)
1433 MemFree(fodInfos->initdir);
1434 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1435 lstrcpyW(fodInfos->initdir, tmpBuf);
1436 handledPath = TRUE;
1437 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1438 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1440 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1442 } else {
1443 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1447 /* 2. (All platforms) If initdir is not null, then use it */
1448 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1449 (*fodInfos->initdir!=0x00))
1451 /* Work out the proper path as supplied one might be relative */
1452 /* (Here because supplying '.' as dir browses to My Computer) */
1453 if (handledPath==FALSE) {
1454 WCHAR tmpBuf[MAX_PATH];
1455 WCHAR tmpBuf2[MAX_PATH];
1456 WCHAR *nameBit;
1457 DWORD result;
1459 lstrcpyW(tmpBuf, fodInfos->initdir);
1460 if( PathFileExistsW(tmpBuf) ) {
1461 /* initdir does not have to be a directory. If a file is
1462 * specified, the dir part is taken */
1463 if( PathIsDirectoryW(tmpBuf)) {
1464 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1465 lstrcatW(tmpBuf, szwSlash);
1467 lstrcatW(tmpBuf, szwStar);
1469 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1470 if (result) {
1471 *nameBit = 0x00;
1472 MemFree(fodInfos->initdir);
1473 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1474 lstrcpyW(fodInfos->initdir, tmpBuf2);
1475 handledPath = TRUE;
1476 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1479 else if (fodInfos->initdir)
1481 MemFree(fodInfos->initdir);
1482 fodInfos->initdir = NULL;
1483 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1488 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1489 (*fodInfos->initdir==0x00)))
1491 /* 3. All except w2k+: if filename contains a path use it */
1492 if (!win2000plus && fodInfos->filename &&
1493 *fodInfos->filename &&
1494 strpbrkW(fodInfos->filename, szwSlash)) {
1495 WCHAR tmpBuf[MAX_PATH];
1496 WCHAR *nameBit;
1497 DWORD result;
1499 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1500 tmpBuf, &nameBit);
1501 if (result) {
1502 int len;
1504 /* nameBit is always shorter than the original filename */
1505 lstrcpyW(fodInfos->filename, nameBit);
1506 *nameBit = 0x00;
1508 len = lstrlenW(tmpBuf);
1509 MemFree(fodInfos->initdir);
1510 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1511 lstrcpyW(fodInfos->initdir, tmpBuf);
1513 handledPath = TRUE;
1514 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1515 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1517 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1520 /* 4. win98+ and win2000+ if any files of specified filter types in
1521 current directory, use it */
1522 if ( win98plus && handledPath == FALSE &&
1523 fodInfos->filter && *fodInfos->filter) {
1525 LPCWSTR lpstrPos = fodInfos->filter;
1526 WIN32_FIND_DATAW FindFileData;
1527 HANDLE hFind;
1529 while (1)
1531 /* filter is a list... title\0ext\0......\0\0 */
1533 /* Skip the title */
1534 if(! *lpstrPos) break; /* end */
1535 lpstrPos += lstrlenW(lpstrPos) + 1;
1537 /* See if any files exist in the current dir with this extension */
1538 if(! *lpstrPos) break; /* end */
1540 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1542 if (hFind == INVALID_HANDLE_VALUE) {
1543 /* None found - continue search */
1544 lpstrPos += lstrlenW(lpstrPos) + 1;
1546 } else {
1548 MemFree(fodInfos->initdir);
1549 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1550 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1552 handledPath = TRUE;
1553 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1554 debugstr_w(lpstrPos));
1555 FindClose(hFind);
1556 break;
1561 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1563 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1564 if (handledPath == FALSE && (win2000plus || win98plus)) {
1565 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1567 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1569 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1571 /* last fallback */
1572 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1573 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1574 } else {
1575 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1577 } else {
1578 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1580 handledPath = TRUE;
1581 } else if (handledPath==FALSE) {
1582 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1583 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1584 handledPath = TRUE;
1585 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1588 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1589 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1591 /* Must the open as read only check box be checked ?*/
1592 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1594 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1597 /* Must the open as read only check box be hidden? */
1598 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1600 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1601 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1604 /* Must the help button be hidden? */
1605 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1607 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1608 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1611 /* change Open to Save */
1612 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1614 WCHAR buf[16];
1615 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1616 SetDlgItemTextW(hwnd, IDOK, buf);
1617 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1618 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1621 /* Initialize the filter combo box */
1622 FILEDLG95_FILETYPE_Init(hwnd);
1624 return 0;
1627 /***********************************************************************
1628 * FILEDLG95_ResizeControls
1630 * WM_INITDIALOG message handler (after hook notification)
1632 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1634 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1636 if (fodInfos->DlgInfos.hwndCustomDlg)
1638 RECT rc;
1639 UINT flags = SWP_NOACTIVATE;
1641 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1642 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1644 /* resize the custom dialog to the parent size */
1645 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1646 GetClientRect(hwnd, &rc);
1647 else
1649 /* our own fake template is zero sized and doesn't have children, so
1650 * there is no need to resize it. Picasa depends on it.
1652 flags |= SWP_NOSIZE;
1653 SetRectEmpty(&rc);
1655 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1656 0, 0, rc.right, rc.bottom, flags);
1658 else
1660 /* Resize the height, if open as read only checkbox ad help button are
1661 * hidden and we are not using a custom template nor a customDialog
1663 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1664 (!(fodInfos->ofnInfos->Flags &
1665 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1667 RECT rectDlg, rectHelp, rectCancel;
1668 GetWindowRect(hwnd, &rectDlg);
1669 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1670 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1671 /* subtract the height of the help button plus the space between the help
1672 * button and the cancel button to the height of the dialog
1674 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1675 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1676 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1679 return TRUE;
1682 /***********************************************************************
1683 * FILEDLG95_FillControls
1685 * WM_INITDIALOG message handler (after hook notification)
1687 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1689 LPITEMIDLIST pidlItemId = NULL;
1691 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1693 TRACE("dir=%s file=%s\n",
1694 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1696 /* Get the initial directory pidl */
1698 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1700 WCHAR path[MAX_PATH];
1702 GetCurrentDirectoryW(MAX_PATH,path);
1703 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1706 /* Initialise shell objects */
1707 FILEDLG95_SHELL_Init(hwnd);
1709 /* Initialize the Look In combo box */
1710 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1712 /* Browse to the initial directory */
1713 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1715 /* Free pidlItem memory */
1716 COMDLG32_SHFree(pidlItemId);
1718 return TRUE;
1720 /***********************************************************************
1721 * FILEDLG95_Clean
1723 * Regroups all the cleaning functions of the filedlg
1725 void FILEDLG95_Clean(HWND hwnd)
1727 FILEDLG95_FILETYPE_Clean(hwnd);
1728 FILEDLG95_LOOKIN_Clean(hwnd);
1729 FILEDLG95_SHELL_Clean(hwnd);
1731 /***********************************************************************
1732 * FILEDLG95_OnWMCommand
1734 * WM_COMMAND message handler
1736 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
1738 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1739 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1740 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1742 switch(wID)
1744 /* OK button */
1745 case IDOK:
1746 FILEDLG95_OnOpen(hwnd);
1747 break;
1748 /* Cancel button */
1749 case IDCANCEL:
1750 FILEDLG95_Clean(hwnd);
1751 EndDialog(hwnd, FALSE);
1752 break;
1753 /* Filetype combo box */
1754 case IDC_FILETYPE:
1755 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1756 break;
1757 /* LookIn combo box */
1758 case IDC_LOOKIN:
1759 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1760 break;
1762 /* --- toolbar --- */
1763 /* Up folder button */
1764 case FCIDM_TB_UPFOLDER:
1765 FILEDLG95_SHELL_UpFolder(hwnd);
1766 break;
1767 /* New folder button */
1768 case FCIDM_TB_NEWFOLDER:
1769 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1770 break;
1771 /* List option button */
1772 case FCIDM_TB_SMALLICON:
1773 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1774 break;
1775 /* Details option button */
1776 case FCIDM_TB_REPORTVIEW:
1777 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1778 break;
1779 /* Details option button */
1780 case FCIDM_TB_DESKTOP:
1781 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1782 break;
1784 case IDC_FILENAME:
1785 break;
1788 /* Do not use the listview selection anymore */
1789 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1790 return 0;
1793 /***********************************************************************
1794 * FILEDLG95_OnWMGetIShellBrowser
1796 * WM_GETISHELLBROWSER message handler
1798 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1800 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1802 TRACE("\n");
1804 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1806 return TRUE;
1810 /***********************************************************************
1811 * FILEDLG95_SendFileOK
1813 * Sends the CDN_FILEOK notification if required
1815 * RETURNS
1816 * TRUE if the dialog should close
1817 * FALSE if the dialog should not be closed
1819 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1821 /* ask the hook if we can close */
1822 if(IsHooked(fodInfos))
1824 LRESULT retval = 0;
1826 TRACE("---\n");
1827 /* First send CDN_FILEOK as MSDN doc says */
1828 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1829 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1830 if( retval)
1832 TRACE("canceled\n");
1833 return FALSE;
1836 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1837 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1838 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1839 if( retval)
1841 TRACE("canceled\n");
1842 return FALSE;
1845 return TRUE;
1848 /***********************************************************************
1849 * FILEDLG95_OnOpenMultipleFiles
1851 * Handles the opening of multiple files.
1853 * FIXME
1854 * check destination buffer size
1856 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1858 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1859 UINT nCount, nSizePath;
1860 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1862 TRACE("\n");
1864 if(fodInfos->unicode)
1866 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1867 ofn->lpstrFile[0] = '\0';
1869 else
1871 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1872 ofn->lpstrFile[0] = '\0';
1875 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1877 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1878 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1879 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1881 LPWSTR lpstrTemp = lpstrFileList;
1883 for ( nCount = 0; nCount < nFileCount; nCount++ )
1885 LPITEMIDLIST pidl;
1887 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1888 if (!pidl)
1890 WCHAR lpstrNotFound[100];
1891 WCHAR lpstrMsg[100];
1892 WCHAR tmp[400];
1893 static const WCHAR nl[] = {'\n',0};
1895 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1896 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1898 lstrcpyW(tmp, lpstrTemp);
1899 lstrcatW(tmp, nl);
1900 lstrcatW(tmp, lpstrNotFound);
1901 lstrcatW(tmp, nl);
1902 lstrcatW(tmp, lpstrMsg);
1904 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1905 return FALSE;
1908 /* move to the next file in the list of files */
1909 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1910 COMDLG32_SHFree(pidl);
1914 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1915 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1917 /* For "oldstyle" dialog the components have to
1918 be separated by blanks (not '\0'!) and short
1919 filenames have to be used! */
1920 FIXME("Components have to be separated by blanks\n");
1922 if(fodInfos->unicode)
1924 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1925 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1926 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1928 else
1930 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1932 if (ofn->lpstrFile != NULL)
1934 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1935 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1936 if (ofn->nMaxFile > nSizePath)
1938 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1939 ofn->lpstrFile + nSizePath,
1940 ofn->nMaxFile - nSizePath, NULL, NULL);
1945 fodInfos->ofnInfos->nFileOffset = nSizePath;
1946 fodInfos->ofnInfos->nFileExtension = 0;
1948 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1949 return FALSE;
1951 /* clean and exit */
1952 FILEDLG95_Clean(hwnd);
1953 return EndDialog(hwnd,TRUE);
1956 /***********************************************************************
1957 * FILEDLG95_OnOpen
1959 * Ok button WM_COMMAND message handler
1961 * If the function succeeds, the return value is nonzero.
1963 #define ONOPEN_BROWSE 1
1964 #define ONOPEN_OPEN 2
1965 #define ONOPEN_SEARCH 3
1966 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1968 WCHAR strMsgTitle[MAX_PATH];
1969 WCHAR strMsgText [MAX_PATH];
1970 if (idCaption)
1971 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1972 else
1973 strMsgTitle[0] = '\0';
1974 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1975 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1978 BOOL FILEDLG95_OnOpen(HWND hwnd)
1980 LPWSTR lpstrFileList;
1981 UINT nFileCount = 0;
1982 UINT sizeUsed = 0;
1983 BOOL ret = TRUE;
1984 WCHAR lpstrPathAndFile[MAX_PATH];
1985 WCHAR lpstrTemp[MAX_PATH];
1986 LPSHELLFOLDER lpsf = NULL;
1987 int nOpenAction;
1988 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1990 TRACE("hwnd=%p\n", hwnd);
1992 /* try to browse the selected item */
1993 if(BrowseSelectedFolder(hwnd))
1994 return FALSE;
1996 /* get the files from the edit control */
1997 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1999 if(nFileCount == 0)
2000 return FALSE;
2002 if(nFileCount > 1)
2004 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2005 goto ret;
2008 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2011 Step 1: Build a complete path name from the current folder and
2012 the filename or path in the edit box.
2013 Special cases:
2014 - the path in the edit box is a root path
2015 (with or without drive letter)
2016 - the edit box contains ".." (or a path with ".." in it)
2019 /* Get the current directory name */
2020 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2022 /* last fallback */
2023 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2025 PathAddBackslashW(lpstrPathAndFile);
2027 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2029 /* if the user specified a fully qualified path use it */
2030 if(PathIsRelativeW(lpstrFileList))
2032 lstrcatW(lpstrPathAndFile, lpstrFileList);
2034 else
2036 /* does the path have a drive letter? */
2037 if (PathGetDriveNumberW(lpstrFileList) == -1)
2038 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2039 else
2040 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2043 /* resolve "." and ".." */
2044 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2045 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2046 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2048 MemFree(lpstrFileList);
2051 Step 2: here we have a cleaned up path
2053 We have to parse the path step by step to see if we have to browse
2054 to a folder if the path points to a directory or the last
2055 valid element is a directory.
2057 valid variables:
2058 lpstrPathAndFile: cleaned up path
2061 if (nFileCount &&
2062 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2063 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2064 nOpenAction = ONOPEN_OPEN;
2065 else
2066 nOpenAction = ONOPEN_BROWSE;
2068 /* don't apply any checks with OFN_NOVALIDATE */
2070 LPWSTR lpszTemp, lpszTemp1;
2071 LPITEMIDLIST pidl = NULL;
2072 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2074 /* check for invalid chars */
2075 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2077 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2078 ret = FALSE;
2079 goto ret;
2082 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2084 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2085 while (lpszTemp1)
2087 LPSHELLFOLDER lpsfChild;
2088 WCHAR lpwstrTemp[MAX_PATH];
2089 DWORD dwEaten, dwAttributes;
2090 LPWSTR p;
2092 lstrcpyW(lpwstrTemp, lpszTemp);
2093 p = PathFindNextComponentW(lpwstrTemp);
2095 if (!p) break; /* end of path */
2097 *p = 0;
2098 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2100 /* There are no wildcards when OFN_NOVALIDATE is set */
2101 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2103 static const WCHAR wszWild[] = { '*', '?', 0 };
2104 /* if the last element is a wildcard do a search */
2105 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2107 nOpenAction = ONOPEN_SEARCH;
2108 break;
2111 lpszTemp1 = lpszTemp;
2113 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2115 /* append a backslash to drive letters */
2116 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2117 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2118 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2120 PathAddBackslashW(lpwstrTemp);
2123 dwAttributes = SFGAO_FOLDER;
2124 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2126 /* the path component is valid, we have a pidl of the next path component */
2127 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2128 if(dwAttributes & SFGAO_FOLDER)
2130 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2132 ERR("bind to failed\n"); /* should not fail */
2133 break;
2135 IShellFolder_Release(lpsf);
2136 lpsf = lpsfChild;
2137 lpsfChild = NULL;
2139 else
2141 TRACE("value\n");
2143 /* end dialog, return value */
2144 nOpenAction = ONOPEN_OPEN;
2145 break;
2147 COMDLG32_SHFree(pidl);
2148 pidl = NULL;
2150 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2152 if(*lpszTemp || /* points to trailing null for last path element */
2153 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2155 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2157 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2158 break;
2161 else
2163 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2164 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2166 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2167 break;
2170 /* change to the current folder */
2171 nOpenAction = ONOPEN_OPEN;
2172 break;
2174 else
2176 nOpenAction = ONOPEN_OPEN;
2177 break;
2180 if(pidl) COMDLG32_SHFree(pidl);
2184 Step 3: here we have a cleaned up and validated path
2186 valid variables:
2187 lpsf: ShellFolder bound to the rightmost valid path component
2188 lpstrPathAndFile: cleaned up path
2189 nOpenAction: action to do
2191 TRACE("end validate sf=%p\n", lpsf);
2193 switch(nOpenAction)
2195 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2196 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2198 int iPos;
2199 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2200 DWORD len;
2202 /* replace the current filter */
2203 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2204 len = lstrlenW(lpszTemp)+1;
2205 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2206 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2208 /* set the filter cb to the extension when possible */
2209 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2210 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2212 /* fall through */
2213 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2214 TRACE("ONOPEN_BROWSE\n");
2216 IPersistFolder2 * ppf2;
2217 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2219 LPITEMIDLIST pidlCurrent;
2220 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2221 IPersistFolder2_Release(ppf2);
2222 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2224 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2225 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2227 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2230 else if( nOpenAction == ONOPEN_SEARCH )
2232 if (fodInfos->Shell.FOIShellView)
2233 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2235 COMDLG32_SHFree(pidlCurrent);
2236 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2239 ret = FALSE;
2240 break;
2241 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2242 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2244 WCHAR *ext = NULL;
2246 /* update READONLY check box flag */
2247 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2248 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2249 else
2250 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2252 /* Attach the file extension with file name*/
2253 ext = PathFindExtensionW(lpstrPathAndFile);
2254 if (! *ext)
2256 /* if no extension is specified with file name, then */
2257 /* attach the extension from file filter or default one */
2259 WCHAR *filterExt = NULL;
2260 LPWSTR lpstrFilter = NULL;
2261 static const WCHAR szwDot[] = {'.',0};
2262 int PathLength = lstrlenW(lpstrPathAndFile);
2264 /* Attach the dot*/
2265 lstrcatW(lpstrPathAndFile, szwDot);
2267 /*Get the file extension from file type filter*/
2268 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2269 fodInfos->ofnInfos->nFilterIndex-1);
2271 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2272 filterExt = PathFindExtensionW(lpstrFilter);
2274 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2275 lstrcatW(lpstrPathAndFile, filterExt + 1);
2276 else if ( fodInfos->defext ) /* attach the default file extension*/
2277 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2279 /* In Open dialog: if file does not exist try without extension */
2280 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2281 lpstrPathAndFile[PathLength] = '\0';
2284 if (fodInfos->defext) /* add default extension */
2286 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2287 if (*ext)
2288 ext++;
2289 if (!lstrcmpiW(fodInfos->defext, ext))
2290 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2291 else
2292 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2295 /* In Save dialog: check if the file already exists */
2296 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2297 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2298 && PathFileExistsW(lpstrPathAndFile))
2300 WCHAR lpstrOverwrite[100];
2301 int answer;
2303 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2304 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2305 MB_YESNO | MB_ICONEXCLAMATION);
2306 if (answer == IDNO || answer == IDCANCEL)
2308 ret = FALSE;
2309 goto ret;
2313 /* In Open dialog: check if it should be created if it doesn't exist */
2314 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2315 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2316 && !PathFileExistsW(lpstrPathAndFile))
2318 WCHAR lpstrCreate[100];
2319 int answer;
2321 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2322 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2323 MB_YESNO | MB_ICONEXCLAMATION);
2324 if (answer == IDNO || answer == IDCANCEL)
2326 ret = FALSE;
2327 goto ret;
2331 /* Check that the size of the file does not exceed buffer size.
2332 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2333 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2334 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2337 /* fill destination buffer */
2338 if (fodInfos->ofnInfos->lpstrFile)
2340 if(fodInfos->unicode)
2342 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2344 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2345 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2346 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2348 else
2350 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2352 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2353 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2354 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2355 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2359 if(fodInfos->unicode)
2361 LPWSTR lpszTemp;
2363 /* set filename offset */
2364 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2365 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2367 /* set extension offset */
2368 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2369 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2371 else
2373 LPSTR lpszTemp;
2374 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2376 /* set filename offset */
2377 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2378 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2380 /* set extension offset */
2381 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2382 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2385 /* set the lpstrFileTitle */
2386 if(fodInfos->ofnInfos->lpstrFileTitle)
2388 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2389 if(fodInfos->unicode)
2391 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2392 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2394 else
2396 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2397 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2398 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2402 /* copy currently selected filter to lpstrCustomFilter */
2403 if (fodInfos->ofnInfos->lpstrCustomFilter)
2405 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2406 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2407 NULL, 0, NULL, NULL);
2408 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2410 LPSTR s = ofn->lpstrCustomFilter;
2411 s += strlen(ofn->lpstrCustomFilter)+1;
2412 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2413 s, len, NULL, NULL);
2418 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2419 goto ret;
2421 TRACE("close\n");
2422 FILEDLG95_Clean(hwnd);
2423 ret = EndDialog(hwnd, TRUE);
2425 else
2427 WORD size;
2429 size = lstrlenW(lpstrPathAndFile) + 1;
2430 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2431 size += 1;
2432 /* return needed size in first two bytes of lpstrFile */
2433 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2434 FILEDLG95_Clean(hwnd);
2435 ret = EndDialog(hwnd, FALSE);
2436 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2439 break;
2442 ret:
2443 if(lpsf) IShellFolder_Release(lpsf);
2444 return ret;
2447 /***********************************************************************
2448 * FILEDLG95_SHELL_Init
2450 * Initialisation of the shell objects
2452 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2454 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2456 TRACE("\n");
2459 * Initialisation of the FileOpenDialogInfos structure
2462 /* Shell */
2464 /*ShellInfos */
2465 fodInfos->ShellInfos.hwndOwner = hwnd;
2467 /* Disable multi-select if flag not set */
2468 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2470 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2472 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2473 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2475 /* Construct the IShellBrowser interface */
2476 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2478 return NOERROR;
2481 /***********************************************************************
2482 * FILEDLG95_SHELL_ExecuteCommand
2484 * Change the folder option and refresh the view
2485 * If the function succeeds, the return value is nonzero.
2487 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2489 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2490 IContextMenu * pcm;
2492 TRACE("(%p,%p)\n", hwnd, lpVerb);
2494 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2495 SVGIO_BACKGROUND,
2496 &IID_IContextMenu,
2497 (LPVOID*)&pcm)))
2499 CMINVOKECOMMANDINFO ci;
2500 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2501 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2502 ci.lpVerb = lpVerb;
2503 ci.hwnd = hwnd;
2505 IContextMenu_InvokeCommand(pcm, &ci);
2506 IContextMenu_Release(pcm);
2509 return FALSE;
2512 /***********************************************************************
2513 * FILEDLG95_SHELL_UpFolder
2515 * Browse to the specified object
2516 * If the function succeeds, the return value is nonzero.
2518 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2520 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2522 TRACE("\n");
2524 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2525 NULL,
2526 SBSP_PARENT)))
2528 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2529 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2530 return TRUE;
2532 return FALSE;
2535 /***********************************************************************
2536 * FILEDLG95_SHELL_BrowseToDesktop
2538 * Browse to the Desktop
2539 * If the function succeeds, the return value is nonzero.
2541 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2543 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2544 LPITEMIDLIST pidl;
2545 HRESULT hres;
2547 TRACE("\n");
2549 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2550 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2551 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2552 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2553 COMDLG32_SHFree(pidl);
2554 return SUCCEEDED(hres);
2556 /***********************************************************************
2557 * FILEDLG95_SHELL_Clean
2559 * Cleans the memory used by shell objects
2561 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2563 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2565 TRACE("\n");
2567 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2569 /* clean Shell interfaces */
2570 if (fodInfos->Shell.FOIShellView)
2572 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2573 IShellView_Release(fodInfos->Shell.FOIShellView);
2575 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2576 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2577 if (fodInfos->Shell.FOIDataObject)
2578 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2581 /***********************************************************************
2582 * FILEDLG95_FILETYPE_Init
2584 * Initialisation of the file type combo box
2586 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2588 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2589 int nFilters = 0; /* number of filters */
2590 int nFilterIndexCB;
2592 TRACE("\n");
2594 if(fodInfos->customfilter)
2596 /* customfilter has one entry... title\0ext\0
2597 * Set first entry of combo box item with customfilter
2599 LPWSTR lpstrExt;
2600 LPCWSTR lpstrPos = fodInfos->customfilter;
2602 /* Get the title */
2603 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2605 /* Copy the extensions */
2606 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2607 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2608 lstrcpyW(lpstrExt,lpstrPos);
2610 /* Add the item at the end of the combo */
2611 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2612 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2613 nFilters++;
2615 if(fodInfos->filter)
2617 LPCWSTR lpstrPos = fodInfos->filter;
2619 for(;;)
2621 /* filter is a list... title\0ext\0......\0\0
2622 * Set the combo item text to the title and the item data
2623 * to the ext
2625 LPCWSTR lpstrDisplay;
2626 LPWSTR lpstrExt;
2628 /* Get the title */
2629 if(! *lpstrPos) break; /* end */
2630 lpstrDisplay = lpstrPos;
2631 lpstrPos += lstrlenW(lpstrPos) + 1;
2633 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2635 nFilters++;
2637 /* Copy the extensions */
2638 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2639 lstrcpyW(lpstrExt,lpstrPos);
2640 lpstrPos += lstrlenW(lpstrPos) + 1;
2642 /* Add the item at the end of the combo */
2643 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2645 /* malformed filters are added anyway... */
2646 if (!*lpstrExt) break;
2651 * Set the current filter to the one specified
2652 * in the initialisation structure
2654 if (fodInfos->filter || fodInfos->customfilter)
2656 LPWSTR lpstrFilter;
2658 /* Check to make sure our index isn't out of bounds. */
2659 if ( fodInfos->ofnInfos->nFilterIndex >
2660 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2661 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2663 /* set default filter index */
2664 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2665 fodInfos->ofnInfos->nFilterIndex = 1;
2667 /* calculate index of Combo Box item */
2668 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2669 if (fodInfos->customfilter == NULL)
2670 nFilterIndexCB--;
2672 /* Set the current index selection. */
2673 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2675 /* Get the corresponding text string from the combo box. */
2676 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2677 nFilterIndexCB);
2679 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2680 lpstrFilter = NULL;
2682 if(lpstrFilter)
2684 DWORD len;
2685 CharLowerW(lpstrFilter); /* lowercase */
2686 len = lstrlenW(lpstrFilter)+1;
2687 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2688 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2690 } else
2691 fodInfos->ofnInfos->nFilterIndex = 0;
2692 return S_OK;
2695 /***********************************************************************
2696 * FILEDLG95_FILETYPE_OnCommand
2698 * WM_COMMAND of the file type combo box
2699 * If the function succeeds, the return value is nonzero.
2701 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2703 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2705 switch(wNotifyCode)
2707 case CBN_SELENDOK:
2709 LPWSTR lpstrFilter;
2711 /* Get the current item of the filetype combo box */
2712 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2714 /* set the current filter index */
2715 fodInfos->ofnInfos->nFilterIndex = iItem +
2716 (fodInfos->customfilter == NULL ? 1 : 0);
2718 /* Set the current filter with the current selection */
2719 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2721 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2722 iItem);
2723 if((INT_PTR)lpstrFilter != CB_ERR)
2725 DWORD len;
2726 CharLowerW(lpstrFilter); /* lowercase */
2727 len = lstrlenW(lpstrFilter)+1;
2728 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2729 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2730 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2731 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2734 /* Refresh the actual view to display the included items*/
2735 if (fodInfos->Shell.FOIShellView)
2736 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2739 return FALSE;
2741 /***********************************************************************
2742 * FILEDLG95_FILETYPE_SearchExt
2744 * searches for an extension in the filetype box
2746 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2748 int i, iCount = CBGetCount(hwnd);
2750 TRACE("%s\n", debugstr_w(lpstrExt));
2752 if(iCount != CB_ERR)
2754 for(i=0;i<iCount;i++)
2756 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2757 return i;
2760 return -1;
2763 /***********************************************************************
2764 * FILEDLG95_FILETYPE_Clean
2766 * Clean the memory used by the filetype combo box
2768 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2770 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2771 int iPos;
2772 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2774 TRACE("\n");
2776 /* Delete each string of the combo and their associated data */
2777 if(iCount != CB_ERR)
2779 for(iPos = iCount-1;iPos>=0;iPos--)
2781 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2782 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2785 /* Current filter */
2786 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2790 /***********************************************************************
2791 * FILEDLG95_LOOKIN_Init
2793 * Initialisation of the look in combo box
2796 /* Small helper function, to determine if the unixfs shell extension is rooted
2797 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2799 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2800 HKEY hKey;
2801 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2802 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2803 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2804 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2805 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2806 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2807 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2809 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2810 return FALSE;
2812 RegCloseKey(hKey);
2813 return TRUE;
2816 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2818 IShellFolder *psfRoot, *psfDrives;
2819 IEnumIDList *lpeRoot, *lpeDrives;
2820 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2822 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2824 TRACE("\n");
2826 liInfos->iMaxIndentation = 0;
2828 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2830 /* set item height for both text field and listbox */
2831 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2832 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2834 /* Turn on the extended UI for the combo box like Windows does */
2835 CBSetExtendedUI(hwndCombo, TRUE);
2837 /* Initialise data of Desktop folder */
2838 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2839 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2840 COMDLG32_SHFree(pidlTmp);
2842 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2844 SHGetDesktopFolder(&psfRoot);
2846 if (psfRoot)
2848 /* enumerate the contents of the desktop */
2849 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2851 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2853 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2855 /* If the unixfs extension is rooted, we don't expand the drives by default */
2856 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2858 /* special handling for CSIDL_DRIVES */
2859 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2861 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2863 /* enumerate the drives */
2864 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2866 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2868 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2869 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2870 COMDLG32_SHFree(pidlAbsTmp);
2871 COMDLG32_SHFree(pidlTmp1);
2873 IEnumIDList_Release(lpeDrives);
2875 IShellFolder_Release(psfDrives);
2880 COMDLG32_SHFree(pidlTmp);
2882 IEnumIDList_Release(lpeRoot);
2884 IShellFolder_Release(psfRoot);
2887 COMDLG32_SHFree(pidlDrives);
2890 /***********************************************************************
2891 * FILEDLG95_LOOKIN_DrawItem
2893 * WM_DRAWITEM message handler
2895 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2897 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2898 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2899 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2900 RECT rectText;
2901 RECT rectIcon;
2902 SHFILEINFOW sfi;
2903 HIMAGELIST ilItemImage;
2904 int iIndentation;
2905 TEXTMETRICW tm;
2906 LPSFOLDER tmpFolder;
2907 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2909 TRACE("\n");
2911 if(pDIStruct->itemID == -1)
2912 return 0;
2914 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2915 pDIStruct->itemID)))
2916 return 0;
2919 if(pDIStruct->itemID == liInfos->uSelectedItem)
2921 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2923 &sfi,
2924 sizeof (sfi),
2925 SHGFI_PIDL | SHGFI_SMALLICON |
2926 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2927 SHGFI_DISPLAYNAME );
2929 else
2931 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2933 &sfi,
2934 sizeof (sfi),
2935 SHGFI_PIDL | SHGFI_SMALLICON |
2936 SHGFI_SYSICONINDEX |
2937 SHGFI_DISPLAYNAME);
2940 /* Is this item selected ? */
2941 if(pDIStruct->itemState & ODS_SELECTED)
2943 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2944 SetBkColor(pDIStruct->hDC,crHighLight);
2945 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2947 else
2949 SetTextColor(pDIStruct->hDC,crText);
2950 SetBkColor(pDIStruct->hDC,crWin);
2951 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2954 /* Do not indent item if drawing in the edit of the combo */
2955 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2957 iIndentation = 0;
2958 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2960 &sfi,
2961 sizeof (sfi),
2962 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2963 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2966 else
2968 iIndentation = tmpFolder->m_iIndent;
2970 /* Draw text and icon */
2972 /* Initialise the icon display area */
2973 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2974 rectIcon.top = pDIStruct->rcItem.top;
2975 rectIcon.right = rectIcon.left + ICONWIDTH;
2976 rectIcon.bottom = pDIStruct->rcItem.bottom;
2978 /* Initialise the text display area */
2979 GetTextMetricsW(pDIStruct->hDC, &tm);
2980 rectText.left = rectIcon.right;
2981 rectText.top =
2982 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2983 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2984 rectText.bottom =
2985 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2987 /* Draw the icon from the image list */
2988 ImageList_Draw(ilItemImage,
2989 sfi.iIcon,
2990 pDIStruct->hDC,
2991 rectIcon.left,
2992 rectIcon.top,
2993 ILD_TRANSPARENT );
2995 /* Draw the associated text */
2996 if(sfi.szDisplayName)
2997 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3000 return NOERROR;
3003 /***********************************************************************
3004 * FILEDLG95_LOOKIN_OnCommand
3006 * LookIn combo box WM_COMMAND message handler
3007 * If the function succeeds, the return value is nonzero.
3009 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3011 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3013 TRACE("%p\n", fodInfos);
3015 switch(wNotifyCode)
3017 case CBN_SELENDOK:
3019 LPSFOLDER tmpFolder;
3020 int iItem;
3022 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3024 if( iItem == CB_ERR) return FALSE;
3026 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3027 iItem)))
3028 return FALSE;
3031 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3032 tmpFolder->pidlItem,
3033 SBSP_ABSOLUTE)))
3035 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3036 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3037 return TRUE;
3039 break;
3043 return FALSE;
3046 /***********************************************************************
3047 * FILEDLG95_LOOKIN_AddItem
3049 * Adds an absolute pidl item to the lookin combo box
3050 * returns the index of the inserted item
3052 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3054 LPITEMIDLIST pidlNext;
3055 SHFILEINFOW sfi;
3056 SFOLDER *tmpFolder;
3057 LookInInfos *liInfos;
3059 TRACE("%08x\n", iInsertId);
3061 if(!pidl)
3062 return -1;
3064 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3065 return -1;
3067 tmpFolder = MemAlloc(sizeof(SFOLDER));
3068 tmpFolder->m_iIndent = 0;
3070 /* Calculate the indentation of the item in the lookin*/
3071 pidlNext = pidl;
3072 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3074 tmpFolder->m_iIndent++;
3077 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3079 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3080 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3082 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3083 SHGetFileInfoW((LPCWSTR)pidl,
3085 &sfi,
3086 sizeof(sfi),
3087 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3088 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3090 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3092 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3094 int iItemID;
3096 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3098 /* Add the item at the end of the list */
3099 if(iInsertId < 0)
3101 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3103 /* Insert the item at the iInsertId position*/
3104 else
3106 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3109 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3110 return iItemID;
3113 COMDLG32_SHFree( tmpFolder->pidlItem );
3114 MemFree( tmpFolder );
3115 return -1;
3119 /***********************************************************************
3120 * FILEDLG95_LOOKIN_InsertItemAfterParent
3122 * Insert an item below its parent
3124 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3127 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3128 int iParentPos;
3130 TRACE("\n");
3132 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3134 if(iParentPos < 0)
3136 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3139 /* Free pidlParent memory */
3140 COMDLG32_SHFree(pidlParent);
3142 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3145 /***********************************************************************
3146 * FILEDLG95_LOOKIN_SelectItem
3148 * Adds an absolute pidl item to the lookin combo box
3149 * returns the index of the inserted item
3151 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3153 int iItemPos;
3154 LookInInfos *liInfos;
3156 TRACE("\n");
3158 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3160 liInfos = GetPropA(hwnd,LookInInfosStr);
3162 if(iItemPos < 0)
3164 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3165 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3168 else
3170 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3171 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3173 int iRemovedItem;
3175 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3176 break;
3177 if(iRemovedItem < iItemPos)
3178 iItemPos--;
3182 CBSetCurSel(hwnd,iItemPos);
3183 liInfos->uSelectedItem = iItemPos;
3185 return 0;
3189 /***********************************************************************
3190 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3192 * Remove the item with an expansion level over iExpansionLevel
3194 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3196 int iItemPos;
3197 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3199 TRACE("\n");
3201 if(liInfos->iMaxIndentation <= 2)
3202 return -1;
3204 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3206 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3207 COMDLG32_SHFree(tmpFolder->pidlItem);
3208 MemFree(tmpFolder);
3209 CBDeleteString(hwnd,iItemPos);
3210 liInfos->iMaxIndentation--;
3212 return iItemPos;
3215 return -1;
3218 /***********************************************************************
3219 * FILEDLG95_LOOKIN_SearchItem
3221 * Search for pidl in the lookin combo box
3222 * returns the index of the found item
3224 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3226 int i = 0;
3227 int iCount = CBGetCount(hwnd);
3229 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3231 if (iCount != CB_ERR)
3233 for(;i<iCount;i++)
3235 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3237 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3238 return i;
3239 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3240 return i;
3244 return -1;
3247 /***********************************************************************
3248 * FILEDLG95_LOOKIN_Clean
3250 * Clean the memory used by the lookin combo box
3252 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3254 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3255 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3256 int iPos;
3257 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3259 TRACE("\n");
3261 /* Delete each string of the combo and their associated data */
3262 if (iCount != CB_ERR)
3264 for(iPos = iCount-1;iPos>=0;iPos--)
3266 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3267 COMDLG32_SHFree(tmpFolder->pidlItem);
3268 MemFree(tmpFolder);
3269 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3273 /* LookInInfos structure */
3274 MemFree(liInfos);
3275 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3278 /***********************************************************************
3279 * FILEDLG95_FILENAME_FillFromSelection
3281 * fills the edit box from the cached DataObject
3283 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3285 FileOpenDlgInfos *fodInfos;
3286 LPITEMIDLIST pidl;
3287 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3288 WCHAR lpstrTemp[MAX_PATH];
3289 LPWSTR lpstrAllFile, lpstrCurrFile;
3291 TRACE("\n");
3292 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3294 /* Count how many files we have */
3295 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3297 /* calculate the string length, count files */
3298 if (nFileSelected >= 1)
3300 nLength += 3; /* first and last quotes, trailing \0 */
3301 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3303 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3305 if (pidl)
3307 /* get the total length of the selected file names */
3308 lpstrTemp[0] = '\0';
3309 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3311 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3313 nLength += lstrlenW( lpstrTemp ) + 3;
3314 nFiles++;
3316 COMDLG32_SHFree( pidl );
3321 /* allocate the buffer */
3322 if (nFiles <= 1) nLength = MAX_PATH;
3323 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3325 /* Generate the string for the edit control */
3326 if(nFiles >= 1)
3328 lpstrCurrFile = lpstrAllFile;
3329 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3331 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3333 if (pidl)
3335 /* get the file name */
3336 lpstrTemp[0] = '\0';
3337 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3339 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3341 if ( nFiles > 1)
3343 *lpstrCurrFile++ = '\"';
3344 lstrcpyW( lpstrCurrFile, lpstrTemp );
3345 lpstrCurrFile += lstrlenW( lpstrTemp );
3346 *lpstrCurrFile++ = '\"';
3347 *lpstrCurrFile++ = ' ';
3348 *lpstrCurrFile = 0;
3350 else
3352 lstrcpyW( lpstrAllFile, lpstrTemp );
3355 COMDLG32_SHFree( pidl );
3358 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3360 /* Select the file name like Windows does */
3361 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3363 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3367 /* copied from shell32 to avoid linking to it
3368 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3369 * is dependent on whether emulated OS is unicode or not.
3371 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3373 switch (src->uType)
3375 case STRRET_WSTR:
3376 lstrcpynW(dest, src->u.pOleStr, len);
3377 COMDLG32_SHFree(src->u.pOleStr);
3378 break;
3380 case STRRET_CSTR:
3381 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3382 dest[len-1] = 0;
3383 break;
3385 case STRRET_OFFSET:
3386 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3387 dest[len-1] = 0;
3388 break;
3390 default:
3391 FIXME("unknown type %x!\n", src->uType);
3392 if (len) *dest = '\0';
3393 return E_FAIL;
3395 return S_OK;
3398 /***********************************************************************
3399 * FILEDLG95_FILENAME_GetFileNames
3401 * Copies the filenames to a delimited string list.
3402 * The delimiter is specified by the parameter 'separator',
3403 * usually either a space or a nul
3405 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3407 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3408 UINT nStrCharCount = 0; /* index in src buffer */
3409 UINT nFileIndex = 0; /* index in dest buffer */
3410 UINT nFileCount = 0; /* number of files */
3411 UINT nStrLen = 0; /* length of string in edit control */
3412 LPWSTR lpstrEdit; /* buffer for string from edit control */
3414 TRACE("\n");
3416 /* get the filenames from the edit control */
3417 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3418 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3419 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3421 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3423 /* we might get single filename without any '"',
3424 * so we need nStrLen + terminating \0 + end-of-list \0 */
3425 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3426 *sizeUsed = 0;
3428 /* build delimited file list from filenames */
3429 while ( nStrCharCount <= nStrLen )
3431 if ( lpstrEdit[nStrCharCount]=='"' )
3433 nStrCharCount++;
3434 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3436 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3437 nStrCharCount++;
3439 (*lpstrFileList)[nFileIndex++] = 0;
3440 nFileCount++;
3442 nStrCharCount++;
3445 /* single, unquoted string */
3446 if ((nStrLen > 0) && (nFileIndex == 0) )
3448 lstrcpyW(*lpstrFileList, lpstrEdit);
3449 nFileIndex = lstrlenW(lpstrEdit) + 1;
3450 nFileCount = 1;
3453 /* trailing \0 */
3454 (*lpstrFileList)[nFileIndex++] = '\0';
3456 *sizeUsed = nFileIndex;
3457 MemFree(lpstrEdit);
3458 return nFileCount;
3461 #define SETDefFormatEtc(fe,cf,med) \
3463 (fe).cfFormat = cf;\
3464 (fe).dwAspect = DVASPECT_CONTENT; \
3465 (fe).ptd =NULL;\
3466 (fe).tymed = med;\
3467 (fe).lindex = -1;\
3471 * DATAOBJECT Helper functions
3474 /***********************************************************************
3475 * COMCTL32_ReleaseStgMedium
3477 * like ReleaseStgMedium from ole32
3479 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3481 if(medium.pUnkForRelease)
3483 IUnknown_Release(medium.pUnkForRelease);
3485 else
3487 GlobalUnlock(medium.u.hGlobal);
3488 GlobalFree(medium.u.hGlobal);
3492 /***********************************************************************
3493 * GetPidlFromDataObject
3495 * Return pidl(s) by number from the cached DataObject
3497 * nPidlIndex=0 gets the fully qualified root path
3499 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3502 STGMEDIUM medium;
3503 FORMATETC formatetc;
3504 LPITEMIDLIST pidl = NULL;
3506 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3508 if (!doSelected)
3509 return NULL;
3511 /* Set the FORMATETC structure*/
3512 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3514 /* Get the pidls from IDataObject */
3515 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3517 LPIDA cida = GlobalLock(medium.u.hGlobal);
3518 if(nPidlIndex <= cida->cidl)
3520 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3522 COMCTL32_ReleaseStgMedium(medium);
3524 return pidl;
3527 /***********************************************************************
3528 * GetNumSelected
3530 * Return the number of selected items in the DataObject.
3533 static UINT GetNumSelected( IDataObject *doSelected )
3535 UINT retVal = 0;
3536 STGMEDIUM medium;
3537 FORMATETC formatetc;
3539 TRACE("sv=%p\n", doSelected);
3541 if (!doSelected) return 0;
3543 /* Set the FORMATETC structure*/
3544 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3546 /* Get the pidls from IDataObject */
3547 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3549 LPIDA cida = GlobalLock(medium.u.hGlobal);
3550 retVal = cida->cidl;
3551 COMCTL32_ReleaseStgMedium(medium);
3552 return retVal;
3554 return 0;
3558 * TOOLS
3561 /***********************************************************************
3562 * GetName
3564 * Get the pidl's display name (relative to folder) and
3565 * put it in lpstrFileName.
3567 * Return NOERROR on success,
3568 * E_FAIL otherwise
3571 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3573 STRRET str;
3574 HRESULT hRes;
3576 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3578 if(!lpsf)
3580 SHGetDesktopFolder(&lpsf);
3581 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3582 IShellFolder_Release(lpsf);
3583 return hRes;
3586 /* Get the display name of the pidl relative to the folder */
3587 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3589 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3591 return E_FAIL;
3594 /***********************************************************************
3595 * GetShellFolderFromPidl
3597 * pidlRel is the item pidl relative
3598 * Return the IShellFolder of the absolute pidl
3600 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3602 IShellFolder *psf = NULL,*psfParent;
3604 TRACE("%p\n", pidlAbs);
3606 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3608 psf = psfParent;
3609 if(pidlAbs && pidlAbs->mkid.cb)
3611 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3613 IShellFolder_Release(psfParent);
3614 return psf;
3617 /* return the desktop */
3618 return psfParent;
3620 return NULL;
3623 /***********************************************************************
3624 * GetParentPidl
3626 * Return the LPITEMIDLIST to the parent of the pidl in the list
3628 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3630 LPITEMIDLIST pidlParent;
3632 TRACE("%p\n", pidl);
3634 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3635 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3637 return pidlParent;
3640 /***********************************************************************
3641 * GetPidlFromName
3643 * returns the pidl of the file name relative to folder
3644 * NULL if an error occurred
3646 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3648 LPITEMIDLIST pidl = NULL;
3649 ULONG ulEaten;
3651 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3653 if(!lpcstrFileName) return NULL;
3654 if(!*lpcstrFileName) return NULL;
3656 if(!lpsf)
3658 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3659 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3660 IShellFolder_Release(lpsf);
3663 else
3665 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3667 return pidl;
3672 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3674 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3675 HRESULT ret;
3677 TRACE("%p, %p\n", psf, pidl);
3679 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3681 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3682 /* see documentation shell 4.1*/
3683 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3686 /***********************************************************************
3687 * BrowseSelectedFolder
3689 static BOOL BrowseSelectedFolder(HWND hwnd)
3691 BOOL bBrowseSelFolder = FALSE;
3692 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3694 TRACE("\n");
3696 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3698 LPITEMIDLIST pidlSelection;
3700 /* get the file selected */
3701 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3702 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3704 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3705 pidlSelection, SBSP_RELATIVE ) ) )
3707 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3708 ' ','n','o','t',' ','e','x','i','s','t',0};
3709 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3711 bBrowseSelFolder = TRUE;
3712 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3713 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3715 COMDLG32_SHFree( pidlSelection );
3718 return bBrowseSelFolder;
3722 * Memory allocation methods */
3723 static void *MemAlloc(UINT size)
3725 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3728 static void MemFree(void *mem)
3730 HeapFree(GetProcessHeap(),0,mem);
3734 * Old-style (win3.1) dialogs */
3736 /***********************************************************************
3737 * FD32_GetTemplate [internal]
3739 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3740 * by a 32 bits application
3743 BOOL FD32_GetTemplate(PFD31_DATA lfs)
3745 LPOPENFILENAMEW ofnW = lfs->ofnW;
3746 LPOPENFILENAMEA ofnA = lfs->ofnA;
3747 HANDLE hDlgTmpl;
3749 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3751 if (!(lfs->template = LockResource( ofnW->hInstance )))
3753 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3754 return FALSE;
3757 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3759 HRSRC hResInfo;
3760 if (ofnA)
3761 hResInfo = FindResourceA(ofnA->hInstance,
3762 ofnA->lpTemplateName,
3763 (LPSTR)RT_DIALOG);
3764 else
3765 hResInfo = FindResourceW(ofnW->hInstance,
3766 ofnW->lpTemplateName,
3767 (LPWSTR)RT_DIALOG);
3768 if (!hResInfo)
3770 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3771 return FALSE;
3773 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3774 hResInfo)) ||
3775 !(lfs->template = LockResource(hDlgTmpl)))
3777 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3778 return FALSE;
3780 } else { /* get it from internal Wine resource */
3781 HRSRC hResInfo;
3782 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3783 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3785 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3786 return FALSE;
3788 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3789 !(lfs->template = LockResource( hDlgTmpl )))
3791 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3792 return FALSE;
3795 return TRUE;
3799 /***********************************************************************
3800 * FD32_WMMeasureItem [internal]
3802 static LONG FD32_WMMeasureItem(LPARAM lParam)
3804 LPMEASUREITEMSTRUCT lpmeasure;
3806 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3807 lpmeasure->itemHeight = FD31_GetFldrHeight();
3808 return TRUE;
3812 /***********************************************************************
3813 * FileOpenDlgProc [internal]
3814 * Used for open and save, in fact.
3816 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3817 WPARAM wParam, LPARAM lParam)
3819 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3821 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3822 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3824 INT_PTR lRet;
3825 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3826 if (lRet)
3827 return lRet; /* else continue message processing */
3829 switch (wMsg)
3831 case WM_INITDIALOG:
3832 return FD31_WMInitDialog(hWnd, wParam, lParam);
3834 case WM_MEASUREITEM:
3835 return FD32_WMMeasureItem(lParam);
3837 case WM_DRAWITEM:
3838 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3840 case WM_COMMAND:
3841 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3842 #if 0
3843 case WM_CTLCOLOR:
3844 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3845 switch (HIWORD(lParam))
3847 case CTLCOLOR_BTN:
3848 SetTextColor((HDC16)wParam, 0x00000000);
3849 return hGRAYBrush;
3850 case CTLCOLOR_STATIC:
3851 SetTextColor((HDC16)wParam, 0x00000000);
3852 return hGRAYBrush;
3854 break;
3855 #endif
3857 return FALSE;
3861 /***********************************************************************
3862 * GetFileName31A [internal]
3864 * Creates a win31 style dialog box for the user to select a file to open/save.
3866 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3867 UINT dlgType /* type dialogue : open/save */
3870 BOOL bRet = FALSE;
3871 PFD31_DATA lfs;
3873 if (!lpofn || !FD31_Init()) return FALSE;
3875 TRACE("ofn flags %08x\n", lpofn->Flags);
3876 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, FALSE);
3877 if (lfs)
3879 bRet = DialogBoxIndirectParamA( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
3880 FD32_FileOpenDlgProc, (LPARAM)lfs);
3881 FD31_DestroyPrivate(lfs);
3884 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3885 return bRet;
3888 /***********************************************************************
3889 * GetFileName31W [internal]
3891 * Creates a win31 style dialog box for the user to select a file to open/save
3893 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3894 UINT dlgType /* type dialogue : open/save */
3897 BOOL bRet = FALSE;
3898 PFD31_DATA lfs;
3900 if (!lpofn || !FD31_Init()) return FALSE;
3902 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, TRUE);
3903 if (lfs)
3905 bRet = DialogBoxIndirectParamW( COMDLG32_hInstance, lfs->template, lpofn->hwndOwner,
3906 FD32_FileOpenDlgProc, (LPARAM)lfs);
3907 FD31_DestroyPrivate(lfs);
3910 TRACE("file %s, file offset %d, ext offset %d\n",
3911 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3912 return bRet;
3915 /* ------------------ APIs ---------------------- */
3917 /***********************************************************************
3918 * GetOpenFileNameA (COMDLG32.@)
3920 * Creates a dialog box for the user to select a file to open.
3922 * RETURNS
3923 * TRUE on success: user enters a valid file
3924 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3927 BOOL WINAPI GetOpenFileNameA(
3928 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3930 BOOL win16look = FALSE;
3932 TRACE("flags %08x\n", ofn->Flags);
3934 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3935 if (ofn->Flags & OFN_FILEMUSTEXIST)
3936 ofn->Flags |= OFN_PATHMUSTEXIST;
3938 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3939 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3941 if (win16look)
3942 return GetFileName31A(ofn, OPEN_DIALOG);
3943 else
3944 return GetFileDialog95A(ofn, OPEN_DIALOG);
3947 /***********************************************************************
3948 * GetOpenFileNameW (COMDLG32.@)
3950 * Creates a dialog box for the user to select a file to open.
3952 * RETURNS
3953 * TRUE on success: user enters a valid file
3954 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3957 BOOL WINAPI GetOpenFileNameW(
3958 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3960 BOOL win16look = FALSE;
3962 TRACE("flags %08x\n", ofn->Flags);
3964 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3965 if (ofn->Flags & OFN_FILEMUSTEXIST)
3966 ofn->Flags |= OFN_PATHMUSTEXIST;
3968 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3969 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3971 if (win16look)
3972 return GetFileName31W(ofn, OPEN_DIALOG);
3973 else
3974 return GetFileDialog95W(ofn, OPEN_DIALOG);
3978 /***********************************************************************
3979 * GetSaveFileNameA (COMDLG32.@)
3981 * Creates a dialog box for the user to select a file to save.
3983 * RETURNS
3984 * TRUE on success: user enters a valid file
3985 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3988 BOOL WINAPI GetSaveFileNameA(
3989 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3991 BOOL win16look = FALSE;
3993 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3994 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3996 if (win16look)
3997 return GetFileName31A(ofn, SAVE_DIALOG);
3998 else
3999 return GetFileDialog95A(ofn, SAVE_DIALOG);
4002 /***********************************************************************
4003 * GetSaveFileNameW (COMDLG32.@)
4005 * Creates a dialog box for the user to select a file to save.
4007 * RETURNS
4008 * TRUE on success: user enters a valid file
4009 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4012 BOOL WINAPI GetSaveFileNameW(
4013 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4015 BOOL win16look = FALSE;
4017 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4018 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4020 if (win16look)
4021 return GetFileName31W(ofn, SAVE_DIALOG);
4022 else
4023 return GetFileDialog95W(ofn, SAVE_DIALOG);
4026 /***********************************************************************
4027 * GetFileTitleA (COMDLG32.@)
4029 * See GetFileTitleW.
4031 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4033 int ret;
4034 UNICODE_STRING strWFile;
4035 LPWSTR lpWTitle;
4037 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4038 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4039 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4040 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4041 RtlFreeUnicodeString( &strWFile );
4042 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4043 return ret;
4047 /***********************************************************************
4048 * GetFileTitleW (COMDLG32.@)
4050 * Get the name of a file.
4052 * PARAMS
4053 * lpFile [I] name and location of file
4054 * lpTitle [O] returned file name
4055 * cbBuf [I] buffer size of lpTitle
4057 * RETURNS
4058 * Success: zero
4059 * Failure: negative number.
4061 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4063 int i, len;
4064 static const WCHAR brkpoint[] = {'*','[',']',0};
4065 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4067 if(lpFile == NULL || lpTitle == NULL)
4068 return -1;
4070 len = lstrlenW(lpFile);
4072 if (len == 0)
4073 return -1;
4075 if(strpbrkW(lpFile, brkpoint))
4076 return -1;
4078 len--;
4080 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4081 return -1;
4083 for(i = len; i >= 0; i--)
4085 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4087 i++;
4088 break;
4092 if(i == -1)
4093 i++;
4095 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4097 len = lstrlenW(lpFile+i)+1;
4098 if(cbBuf < len)
4099 return len;
4101 lstrcpyW(lpTitle, &lpFile[i]);
4102 return 0;