ReactOS  0.4.13-dev-73-gcfe54aa
filedlg.c
Go to the documentation of this file.
1 /*
2  * COMMDLG - File Open Dialogs Win95 look and feel
3  *
4  * Copyright 1999 Francois Boisvert
5  * Copyright 1999, 2000 Juergen Schmied
6  *
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.
11  *
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.
16  *
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
20  *
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).
28  *
29  * FIXME: any hook gets a OPENFILENAMEA structure
30  *
31  * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
32  *
33  * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
34  *
35  * FIXME: algorithm for selecting the initial directory is too simple
36  *
37  * FIXME: add to recent docs
38  *
39  * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40  * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41  * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
42  *
43  * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
44  *
45  *
46  */
47 
48 #include "config.h"
49 #include "wine/port.h"
50 
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
56 
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winternl.h"
63 #include "winnls.h"
64 #include "wingdi.h"
65 #ifdef __REACTOS__
66 /* RegGetValueW is supported by Win2k3 SP1 but headers need Win Vista */
67 #undef _WIN32_WINNT
68 #define _WIN32_WINNT 0x0600
69 #endif
70 #include "winreg.h"
71 #include "winuser.h"
72 #include "commdlg.h"
73 #include "dlgs.h"
74 #include "cdlg.h"
75 #include "cderr.h"
76 #include "shellapi.h"
77 #include "shlobj.h"
78 #include "filedlgbrowser.h"
79 #include "shlwapi.h"
80 
81 #include "wine/unicode.h"
82 #include "wine/debug.h"
83 #include "wine/heap.h"
84 
86 
87 #define UNIMPLEMENTED_FLAGS \
88 (OFN_DONTADDTORECENT |\
89 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
90 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 
92 /***********************************************************************
93  * Data structure and global variables
94  */
95 typedef struct SFolder
96 {
97  int m_iImageIndex; /* Index of picture in image list */
99  int m_iIndent; /* Indentation index */
100  LPITEMIDLIST pidlItem; /* absolute pidl of the item */
101 
102 } SFOLDER,*LPSFOLDER;
103 
104 typedef struct tagLookInInfo
105 {
108 } LookInInfos;
109 
110 
111 /***********************************************************************
112  * Defines and global variables
113  */
114 
115 /* Draw item constant */
116 #define XTEXTOFFSET 3
117 
118 /* AddItem flags*/
119 #define LISTEND -1
120 
121 /* SearchItem methods */
122 #define SEARCH_PIDL 1
123 #define SEARCH_EXP 2
124 #define ITEM_NOTFOUND -1
125 
126 /* Undefined windows message sent by CreateViewObject*/
127 #define WM_GETISHELLBROWSER WM_USER+7
128 
129 #define TBPLACES_CMDID_PLACE0 0xa064
130 #define TBPLACES_CMDID_PLACE1 0xa065
131 #define TBPLACES_CMDID_PLACE2 0xa066
132 #define TBPLACES_CMDID_PLACE3 0xa067
133 #define TBPLACES_CMDID_PLACE4 0xa068
134 
135 /* NOTE
136  * Those macros exist in windowsx.h. However, you can't really use them since
137  * they rely on the UNICODE defines and can't be used inside Wine itself.
138  */
139 
140 /* Combo box macros */
141 #define CBGetItemDataPtr(hwnd,iItemId) \
142  SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
143 
144 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
145 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
146 
147 static const WCHAR LastVisitedMRUW[] =
148  {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
149  'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
150  'E','x','p','l','o','r','e','r','\\','C','o','m','D','l','g','3','2','\\',
151  'L','a','s','t','V','i','s','i','t','e','d','M','R','U',0};
152 static const WCHAR MRUListW[] = {'M','R','U','L','i','s','t',0};
153 
154 static const WCHAR filedlg_info_propnameW[] = {'F','i','l','e','O','p','e','n','D','l','g','I','n','f','o','s',0};
155 
157 {
159 }
160 
162 {
163  return (info->ofnInfos->Flags & OFN_ENABLEHOOK) && info->ofnInfos->lpfnHook;
164 }
165 
167 {
168  return (info->ofnInfos->Flags & OFN_HIDEREADONLY) || (info->DlgInfos.dwDlgProp & FODPROP_SAVEDLG);
169 }
170 
171 /***********************************************************************
172  * Prototypes
173  */
174 
175 /* Internal functions used by the dialog */
182 static void FILEDLG95_Clean(HWND hwnd);
183 
184 /* Functions used by the shell navigation */
188 static void FILEDLG95_SHELL_Clean(HWND hwnd);
189 
190 /* Functions used by the EDIT box */
191 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
192 
193 /* Functions used by the filetype combo box */
195 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
196 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
197 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
198 
199 /* Functions used by the Look In combo box */
200 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
202 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
204 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
208 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
209 
210 /* Functions for dealing with the most-recently-used registry keys */
211 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path);
212 static WCHAR FILEDLG95_MRU_get_slot(LPCWSTR module_name, LPWSTR stored_path, PHKEY hkey_ret);
214 
215 /* Miscellaneous tool functions */
216 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
219 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
220 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
221 static UINT GetNumSelected( IDataObject *doSelected );
222 static void COMCTL32_ReleaseStgMedium(STGMEDIUM medium);
223 
226 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
228 
230 {
231  DWORD type, data, size;
232 
233  size = sizeof(data);
234  if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size))
235  {
236  *value = data;
237  return TRUE;
238  }
239 
240  return FALSE;
241 }
242 
244 {
245  DWORD type, data, size;
246 
247  size = sizeof(data);
248  if (hkey && !RegQueryValueExW(hkey, name, 0, &type, (BYTE *)&data, &size) && type == REG_DWORD)
249  {
250  *value = data;
251  return TRUE;
252  }
253 
254  return FALSE;
255 }
256 
258 {
259  DWORD type, size;
260  WCHAR *str;
261 
262  if (hkey && !RegQueryValueExW(hkey, name, 0, &type, NULL, &size))
263  {
264  if (type != REG_SZ && type != REG_EXPAND_SZ)
265  return FALSE;
266  }
267 
268  str = heap_alloc(size);
269  if (RegQueryValueExW(hkey, name, 0, &type, (BYTE *)str, &size))
270  {
271  heap_free(str);
272  return FALSE;
273  }
274 
275  *value = str;
276  return TRUE;
277 }
278 
280 {
281  static const WCHAR noplacesbarW[] = {'N','o','P','l','a','c','e','s','B','a','r',0};
282  DWORD value;
283  HKEY hkey;
284 
285  if (fodInfos->ofnInfos->lStructSize != sizeof(*fodInfos->ofnInfos) ||
286  (fodInfos->ofnInfos->FlagsEx & OFN_EX_NOPLACESBAR) ||
287  !(fodInfos->ofnInfos->Flags & OFN_EXPLORER))
288  {
289  return FALSE;
290  }
291 
292  if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32", &hkey))
293  return TRUE;
294 
295  value = 0;
296  get_config_key_as_dword(hkey, noplacesbarW, &value);
297  RegCloseKey(hkey);
298  return value == 0;
299 }
300 
302 {
303  static const int default_places[] =
304  {
307  CSIDL_DRIVES,
308  };
309  unsigned int i;
310  HKEY hkey;
311 
312  if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32\\Placesbar",
313  &hkey))
314  {
315  for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
316  {
317  static const WCHAR placeW[] = {'P','l','a','c','e','%','d',0};
318  WCHAR nameW[8];
319  DWORD value;
320  HRESULT hr;
321  WCHAR *str;
322 
323  sprintfW(nameW, placeW, i);
324  if (get_config_key_dword(hkey, nameW, &value))
325  {
326  hr = SHGetSpecialFolderLocation(NULL, value, &fodInfos->places[i]);
327  if (FAILED(hr))
328  WARN("Unrecognized special folder %u.\n", value);
329  }
330  else if (get_config_key_string(hkey, nameW, &str))
331  {
332  hr = SHParseDisplayName(str, NULL, &fodInfos->places[i], 0, NULL);
333  if (FAILED(hr))
334  WARN("Failed to parse custom places location, %s.\n", debugstr_w(str));
335  heap_free(str);
336  }
337  }
338 
339  /* FIXME: eliminate duplicates. */
340 
341  RegCloseKey(hkey);
342  return;
343  }
344 
345  for (i = 0; i < ARRAY_SIZE(default_places); i++)
346  SHGetSpecialFolderLocation(NULL, default_places[i], &fodInfos->places[i]);
347 }
348 
349 /***********************************************************************
350  * GetFileName95
351  *
352  * Creates an Open common dialog box that lets the user select
353  * the drive, directory, and the name of a file or set of files to open.
354  *
355  * IN : The FileOpenDlgInfos structure associated with the dialog
356  * OUT : TRUE on success
357  * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
358  */
360 {
361  LRESULT lRes;
362  void *template;
363  HRSRC hRes;
364  HANDLE hDlgTmpl = 0;
365  WORD templateid;
366 
367  /* test for missing functionality */
368  if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
369  {
370  FIXME("Flags 0x%08x not yet implemented\n",
371  fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
372  }
373 
374  /* Create the dialog from a template */
375 
376  if (is_places_bar_enabled(fodInfos))
377  templateid = NEWFILEOPENV2ORD;
378  else
379  templateid = NEWFILEOPENORD;
380 
381  if (!(hRes = FindResourceW(COMDLG32_hInstance, MAKEINTRESOURCEW(templateid), (LPCWSTR)RT_DIALOG)))
382  {
384  return FALSE;
385  }
386  if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
387  !(template = LockResource( hDlgTmpl )))
388  {
390  return FALSE;
391  }
392 
393  /* msdn: explorer style dialogs permit sizing by default.
394  * The OFN_ENABLESIZING flag is only needed when a hook or
395  * custom template is provided */
396  if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
398  fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
399 
400  if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
401  {
402  fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
403  fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
404  }
405 
406  /* old style hook messages */
407  if (is_dialog_hooked(fodInfos))
408  {
409  fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
410  fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
411  fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
412  fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
413  }
414 
415  if (fodInfos->unicode)
417  template,
418  fodInfos->ofnInfos->hwndOwner,
420  (LPARAM) fodInfos);
421  else
423  template,
424  fodInfos->ofnInfos->hwndOwner,
426  (LPARAM) fodInfos);
427  if (fodInfos->ole_initialized)
428  OleUninitialize();
429 
430  /* Unable to create the dialog */
431  if( lRes == -1)
432  return FALSE;
433 
434  return lRes;
435 }
436 
437 static WCHAR *heap_strdupAtoW(const char *str)
438 {
439  WCHAR *ret;
440  INT len;
441 
442  if (!str)
443  return NULL;
444 
445  len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
446  ret = heap_alloc(len * sizeof(WCHAR));
447  MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
448 
449  return ret;
450 }
451 
453 {
455 
456  /* Initialize ComboBoxEx32 */
457  icc.dwSize = sizeof(icc);
459  InitCommonControlsEx(&icc);
460 
461  /* Initialize CommDlgExtendedError() */
463 
464  memset(info, 0, sizeof(*info));
465 
466  /* Pass in the original ofn */
467  info->ofnInfos = ofn;
468 
469  info->title = ofn->lpstrTitle;
470  info->defext = ofn->lpstrDefExt;
471  info->filter = ofn->lpstrFilter;
472  info->customfilter = ofn->lpstrCustomFilter;
473 
474  if (ofn->lpstrFile)
475  {
476  info->filename = heap_alloc(ofn->nMaxFile * sizeof(WCHAR));
477  lstrcpynW(info->filename, ofn->lpstrFile, ofn->nMaxFile);
478  }
479 
480  if (ofn->lpstrInitialDir)
481  {
483  if (len)
484  {
485  info->initdir = heap_alloc(len * sizeof(WCHAR));
487  }
488  }
489 
490  info->unicode = TRUE;
491 }
492 
494 {
495  OPENFILENAMEW ofnW;
496  int len;
497 
498  ofnW = *(OPENFILENAMEW *)ofn;
499 
503 
504  if (ofn->lpstrFile)
505  {
507  ofnW.lpstrFile = heap_alloc(len * sizeof(WCHAR));
509  ofnW.nMaxFile = len;
510  }
511 
512  if (ofn->lpstrFilter)
513  {
514  LPCSTR s;
515  int n;
516 
517  /* filter is a list... title\0ext\0......\0\0 */
518  s = ofn->lpstrFilter;
519  while (*s) s = s+strlen(s)+1;
520  s++;
521  n = s - ofn->lpstrFilter;
523  ofnW.lpstrFilter = heap_alloc(len * sizeof(WCHAR));
525  }
526 
527  /* convert lpstrCustomFilter */
528  if (ofn->lpstrCustomFilter)
529  {
530  int n, len;
531  LPCSTR s;
532 
533  /* customfilter contains a pair of strings... title\0ext\0 */
535  if (*s) s = s+strlen(s)+1;
536  if (*s) s = s+strlen(s)+1;
537  n = s - ofn->lpstrCustomFilter;
539  ofnW.lpstrCustomFilter = heap_alloc(len * sizeof(WCHAR));
541  }
542 
543  init_filedlg_infoW(&ofnW, info);
544 
545  /* fixup A-specific fields */
546  info->ofnInfos = (OPENFILENAMEW *)ofn;
547  info->unicode = FALSE;
548 
549  /* free what was duplicated */
550  heap_free((void *)ofnW.lpstrInitialDir);
551  heap_free(ofnW.lpstrFile);
552 }
553 
554 /***********************************************************************
555  * GetFileDialog95
556  *
557  * Call GetFileName95 with this structure and clean the memory.
558  */
560 {
561  WCHAR *current_dir = NULL;
562  unsigned int i;
563  BOOL ret;
564 
565  /* save current directory */
566  if (info->ofnInfos->Flags & OFN_NOCHANGEDIR)
567  {
568  current_dir = heap_alloc(MAX_PATH * sizeof(WCHAR));
569  GetCurrentDirectoryW(MAX_PATH, current_dir);
570  }
571 
572  switch (dlg_type)
573  {
574  case OPEN_DIALOG:
576  break;
577  case SAVE_DIALOG:
578  info->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
580  break;
581  default:
582  ret = FALSE;
583  }
584 
585  /* set the lpstrFileTitle */
586  if (ret && info->ofnInfos->lpstrFile && info->ofnInfos->lpstrFileTitle)
587  {
588  if (info->unicode)
589  {
590  LPOPENFILENAMEW ofn = info->ofnInfos;
591  WCHAR *file_title = PathFindFileNameW(ofn->lpstrFile);
592  lstrcpynW(ofn->lpstrFileTitle, file_title, ofn->nMaxFileTitle);
593  }
594  else
595  {
597  char *file_title = PathFindFileNameA(ofn->lpstrFile);
598  lstrcpynA(ofn->lpstrFileTitle, file_title, ofn->nMaxFileTitle);
599  }
600  }
601 
602  if (current_dir)
603  {
604  SetCurrentDirectoryW(current_dir);
605  heap_free(current_dir);
606  }
607 
608  if (!info->unicode)
609  {
610  heap_free((void *)info->defext);
611  heap_free((void *)info->title);
612  heap_free((void *)info->filter);
613  heap_free((void *)info->customfilter);
614  }
615 
616  heap_free(info->filename);
617  heap_free(info->initdir);
618 
619  for (i = 0; i < ARRAY_SIZE(info->places); i++)
620  ILFree(info->places[i]);
621 
622  return ret;
623 }
624 
625 /******************************************************************************
626  * COMDLG32_GetDisplayNameOf [internal]
627  *
628  * Helper function to get the display name for a pidl.
629  */
631  LPSHELLFOLDER psfDesktop;
632  STRRET strret;
633 
634  if (FAILED(SHGetDesktopFolder(&psfDesktop)))
635  return FALSE;
636 
637  if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
638  IShellFolder_Release(psfDesktop);
639  return FALSE;
640  }
641 
642  IShellFolder_Release(psfDesktop);
643  return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
644 }
645 
646 /******************************************************************************
647  * COMDLG32_GetCanonicalPath [internal]
648  *
649  * Helper function to get the canonical path.
650  */
652  LPWSTR lpstrFile, LPWSTR lpstrPathAndFile)
653 {
654  WCHAR lpstrTemp[MAX_PATH];
655 
656  /* Get the current directory name */
657  if (!COMDLG32_GetDisplayNameOf(pidlAbsCurrent, lpstrPathAndFile))
658  {
659  /* last fallback */
660  GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
661  }
662  PathAddBackslashW(lpstrPathAndFile);
663 
664  TRACE("current directory=%s, file=%s\n", debugstr_w(lpstrPathAndFile), debugstr_w(lpstrFile));
665 
666  /* if the user specified a fully qualified path use it */
667  if(PathIsRelativeW(lpstrFile))
668  {
669  lstrcatW(lpstrPathAndFile, lpstrFile);
670  }
671  else
672  {
673  /* does the path have a drive letter? */
674  if (PathGetDriveNumberW(lpstrFile) == -1)
675  lstrcpyW(lpstrPathAndFile+2, lpstrFile);
676  else
677  lstrcpyW(lpstrPathAndFile, lpstrFile);
678  }
679 
680  /* resolve "." and ".." */
681  PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
682  lstrcpyW(lpstrPathAndFile, lpstrTemp);
683  TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
684 }
685 
686 /***********************************************************************
687  * COMDLG32_SplitFileNames [internal]
688  *
689  * Creates a delimited list of filenames.
690  */
691 int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed)
692 {
693  UINT nStrCharCount = 0; /* index in src buffer */
694  UINT nFileIndex = 0; /* index in dest buffer */
695  UINT nFileCount = 0; /* number of files */
696 
697  /* we might get single filename without any '"',
698  * so we need nStrLen + terminating \0 + end-of-list \0 */
699  *lpstrFileList = heap_alloc((nStrLen + 2) * sizeof(WCHAR));
700  *sizeUsed = 0;
701 
702  /* build delimited file list from filenames */
703  while ( nStrCharCount <= nStrLen )
704  {
705  if ( lpstrEdit[nStrCharCount]=='"' )
706  {
707  nStrCharCount++;
708  while ((nStrCharCount <= nStrLen) && (lpstrEdit[nStrCharCount]!='"'))
709  {
710  (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
711  nStrCharCount++;
712  }
713  (*lpstrFileList)[nFileIndex++] = 0;
714  nFileCount++;
715  }
716  nStrCharCount++;
717  }
718 
719  /* single, unquoted string */
720  if ((nStrLen > 0) && (nFileIndex == 0) )
721  {
722  lstrcpyW(*lpstrFileList, lpstrEdit);
723  nFileIndex = lstrlenW(lpstrEdit) + 1;
724  nFileCount = 1;
725  }
726 
727  /* trailing \0 */
728  (*lpstrFileList)[nFileIndex++] = '\0';
729 
730  *sizeUsed = nFileIndex;
731  return nFileCount;
732 }
733 
734 /***********************************************************************
735  * ArrangeCtrlPositions [internal]
736  *
737  * NOTE: Make sure to add testcases for any changes made here.
738  */
739 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
740 {
741  HWND hwndChild, hwndStc32;
742  RECT rectParent, rectChild, rectStc32;
743  INT help_fixup = 0;
744  int chgx, chgy;
745 
746  /* Take into account if open as read only checkbox and help button
747  * are hidden
748  */
749  if (hide_help)
750  {
751  RECT rectHelp, rectCancel;
752  GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
753  GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
754  /* subtract the height of the help button plus the space between
755  * the help button and the cancel button to the height of the dialog
756  */
757  help_fixup = rectHelp.bottom - rectCancel.bottom;
758  }
759 
760  /*
761  There are two possibilities to add components to the default file dialog box.
762 
763  By default, all the new components are added below the standard dialog box (the else case).
764 
765  However, if there is a static text component with the stc32 id, a special case happens.
766  The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
767  in the window and the cx and cy indicate how to size the window.
768  Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
769  of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
770 
771  */
772 
773  GetClientRect(hwndParentDlg, &rectParent);
774 
775  /* when arranging controls we have to use fixed parent size */
776  rectParent.bottom -= help_fixup;
777 
778  hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
779  if (hwndStc32)
780  {
781  GetWindowRect(hwndStc32, &rectStc32);
782  MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
783 
784  /* set the size of the stc32 control according to the size of
785  * client area of the parent dialog
786  */
787  SetWindowPos(hwndStc32, 0,
788  0, 0,
789  rectParent.right, rectParent.bottom,
791  }
792  else
793  SetRectEmpty(&rectStc32);
794 
795  /* this part moves controls of the child dialog */
796  hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
797  while (hwndChild)
798  {
799  if (hwndChild != hwndStc32)
800  {
801  GetWindowRect(hwndChild, &rectChild);
802  MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
803 
804  /* move only if stc32 exist */
805  if (hwndStc32 && rectChild.left > rectStc32.right)
806  {
807  /* move to the right of visible controls of the parent dialog */
808  rectChild.left += rectParent.right;
809  rectChild.left -= rectStc32.right;
810  }
811  /* move even if stc32 doesn't exist */
812  if (rectChild.top >= rectStc32.bottom)
813  {
814  /* move below visible controls of the parent dialog */
815  rectChild.top += rectParent.bottom;
816  rectChild.top -= rectStc32.bottom - rectStc32.top;
817  }
818 
819  SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
820  0, 0, SWP_NOSIZE | SWP_NOZORDER);
821  }
822  hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
823  }
824 
825  /* this part moves controls of the parent dialog */
826  hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
827  while (hwndChild)
828  {
829  if (hwndChild != hwndChildDlg)
830  {
831  GetWindowRect(hwndChild, &rectChild);
832  MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
833 
834  /* left,top of stc32 marks the position of controls
835  * from the parent dialog
836  */
837  rectChild.left += rectStc32.left;
838  rectChild.top += rectStc32.top;
839 
840  SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
841  0, 0, SWP_NOSIZE | SWP_NOZORDER);
842  }
843  hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
844  }
845 
846  /* calculate the size of the resulting dialog */
847 
848  /* here we have to use original parent size */
849  GetClientRect(hwndParentDlg, &rectParent);
850  GetClientRect(hwndChildDlg, &rectChild);
851  TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
852  wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
853 
854  if (hwndStc32)
855  {
856  /* width */
857  if (rectParent.right > rectStc32.right - rectStc32.left)
858  chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
859  else
860  chgx = rectChild.right - rectParent.right;
861  /* height */
862  if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
863  chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
864  else
865  /* Unconditionally set new dialog
866  * height to that of the child
867  */
868  chgy = rectChild.bottom - rectParent.bottom;
869  }
870  else
871  {
872  chgx = 0;
873  chgy = rectChild.bottom - help_fixup;
874  }
875  /* set the size of the parent dialog */
876  GetWindowRect(hwndParentDlg, &rectParent);
877  SetWindowPos(hwndParentDlg, 0,
878  0, 0,
879  rectParent.right - rectParent.left + chgx,
880  rectParent.bottom - rectParent.top + chgy,
882 }
883 
885 {
886  switch(uMsg) {
887  case WM_INITDIALOG:
888  return TRUE;
889  }
890  return FALSE;
891 }
892 
894 {
895  LPCVOID template;
896  HRSRC hRes;
897  HANDLE hDlgTmpl = 0;
898  HWND hChildDlg = 0;
899 
900  TRACE("%p, %p\n", fodInfos, hwnd);
901 
902  /*
903  * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
904  * structure's hInstance parameter is not a HINSTANCE, but
905  * instead a pointer to a template resource to use.
906  */
908  {
910  if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
911  {
913  if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
914  {
916  return NULL;
917  }
918  }
919  else
920  {
921  hinst = fodInfos->ofnInfos->hInstance;
922  if(fodInfos->unicode)
923  {
924  LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
926  }
927  else
928  {
931  }
932  if (!hRes)
933  {
935  return NULL;
936  }
937  if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
938  !(template = LockResource( hDlgTmpl )))
939  {
941  return NULL;
942  }
943  }
944  if (fodInfos->unicode)
945  hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
947  (LPARAM)fodInfos->ofnInfos);
948  else
949  hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
951  (LPARAM)fodInfos->ofnInfos);
952  return hChildDlg;
953  }
954  else if (is_dialog_hooked(fodInfos))
955  {
956  RECT rectHwnd;
957  struct {
958  DLGTEMPLATE tmplate;
959  WORD menu,class,title;
960  } temp;
961  GetClientRect(hwnd,&rectHwnd);
963  temp.tmplate.dwExtendedStyle = 0;
964  temp.tmplate.cdit = 0;
965  temp.tmplate.x = 0;
966  temp.tmplate.y = 0;
967  temp.tmplate.cx = 0;
968  temp.tmplate.cy = 0;
969  temp.menu = temp.class = temp.title = 0;
970 
971  hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
972  hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
973 
974  return hChildDlg;
975  }
976  return NULL;
977 }
978 
979 /***********************************************************************
980 * SendCustomDlgNotificationMessage
981 *
982 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
983 */
984 
986 {
987  FileOpenDlgInfos *fodInfos = get_filedlg_infoptr(hwndParentDlg);
988  LRESULT hook_result;
989  OFNOTIFYW ofnNotify;
990 
991  TRACE("%p %d\n", hwndParentDlg, uCode);
992 
993  if (!fodInfos || !fodInfos->DlgInfos.hwndCustomDlg)
994  return 0;
995 
996  TRACE("CALL NOTIFY for %d\n", uCode);
997 
998  ofnNotify.hdr.hwndFrom = hwndParentDlg;
999  ofnNotify.hdr.idFrom = 0;
1000  ofnNotify.hdr.code = uCode;
1001  ofnNotify.lpOFN = fodInfos->ofnInfos;
1002  ofnNotify.pszFile = NULL;
1003 
1004  if (fodInfos->unicode)
1005  hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
1006  else
1007  hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg, WM_NOTIFY, 0, (LPARAM)&ofnNotify);
1008 
1009  TRACE("RET NOTIFY retval %#lx\n", hook_result);
1010 
1011  return hook_result;
1012 }
1013 
1015 {
1016  UINT len, total;
1017  WCHAR *p, *buffer;
1019 
1020  TRACE("CDM_GETFILEPATH:\n");
1021 
1022  if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
1023  return -1;
1024 
1025  /* get path and filenames */
1026  len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
1027  buffer = heap_alloc( (len + 2 + MAX_PATH) * sizeof(WCHAR) );
1028  COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
1029  if (len)
1030  {
1031  p = buffer + strlenW(buffer);
1032  *p++ = '\\';
1033  SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
1034  }
1035  if (fodInfos->unicode)
1036  {
1037  total = strlenW( buffer) + 1;
1038  if (result) lstrcpynW( result, buffer, size );
1039  TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
1040  }
1041  else
1042  {
1043  total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
1044  if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
1045  TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
1046  }
1047  heap_free( buffer );
1048  return total;
1049 }
1050 
1051 /***********************************************************************
1052 * FILEDLG95_HandleCustomDialogMessages
1053 *
1054 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
1055 */
1057 {
1059  WCHAR lpstrPath[MAX_PATH];
1060  INT_PTR retval;
1061 
1062  if(!fodInfos) return FALSE;
1063 
1064  switch(uMsg)
1065  {
1066  case CDM_GETFILEPATH:
1068  break;
1069 
1070  case CDM_GETFOLDERPATH:
1071  TRACE("CDM_GETFOLDERPATH:\n");
1072  COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
1073  if (lParam)
1074  {
1075  if (fodInfos->unicode)
1076  lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
1077  else
1078  WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
1079  (LPSTR)lParam, (int)wParam, NULL, NULL);
1080  }
1081  retval = lstrlenW(lpstrPath) + 1;
1082  break;
1083 
1084  case CDM_GETFOLDERIDLIST:
1085  retval = ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
1086  if (retval <= wParam)
1087  memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
1088  break;
1089 
1090  case CDM_GETSPEC:
1091  TRACE("CDM_GETSPEC:\n");
1092  retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
1093  if (lParam)
1094  {
1095  if (fodInfos->unicode)
1096  SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1097  else
1098  SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
1099  }
1100  break;
1101 
1102  case CDM_SETCONTROLTEXT:
1103  TRACE("CDM_SETCONTROLTEXT:\n");
1104  if ( lParam )
1105  {
1106  if( fodInfos->unicode )
1108  else
1110  }
1111  retval = TRUE;
1112  break;
1113 
1114  case CDM_HIDECONTROL:
1115  /* MSDN states that it should fail for not OFN_EXPLORER case */
1116  if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1117  {
1118  HWND control = GetDlgItem( hwnd, wParam );
1119  if (control) ShowWindow( control, SW_HIDE );
1120  retval = TRUE;
1121  }
1122  else retval = FALSE;
1123  break;
1124 
1125  default:
1126  if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1127  FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1128  return FALSE;
1129  }
1131  return TRUE;
1132 }
1133 
1134 /***********************************************************************
1135  * FILEDLG95_OnWMGetMMI
1136  *
1137  * WM_GETMINMAXINFO message handler for resizable dialogs
1138  */
1140 {
1142  if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1143  if( fodInfos->initial_size.x || fodInfos->initial_size.y)
1144  {
1145  mmiptr->ptMinTrackSize = fodInfos->initial_size;
1146  }
1147  return TRUE;
1148 }
1149 
1150 /***********************************************************************
1151  * FILEDLG95_OnWMSize
1152  *
1153  * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1154  *
1155  * FIXME: this could be made more elaborate. Now use a simple scheme
1156  * where the file view is enlarged and the controls are either moved
1157  * vertically or horizontally to get out of the way. Only the "grip"
1158  * is moved in both directions to stay in the corner.
1159  */
1161 {
1162  RECT rc, rcview;
1163  int chgx, chgy;
1164  HWND ctrl;
1165  HDWP hdwp;
1166  FileOpenDlgInfos *fodInfos;
1167 
1168  if( wParam != SIZE_RESTORED) return FALSE;
1169  fodInfos = get_filedlg_infoptr(hwnd);
1170  if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1171  /* get the new dialog rectangle */
1172  GetWindowRect( hwnd, &rc);
1173  TRACE("%p, size from %d,%d to %d,%d\n", hwnd, fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1174  rc.right -rc.left, rc.bottom -rc.top);
1175  /* not initialized yet */
1176  if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1177  ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1178  (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1179  return FALSE;
1180  chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1181  chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1182  fodInfos->sizedlg.cx = rc.right - rc.left;
1183  fodInfos->sizedlg.cy = rc.bottom - rc.top;
1184  /* change the size of the view window */
1185  GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1186  MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1187  hdwp = BeginDeferWindowPos( 10);
1188  DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1189  rcview.right - rcview.left + chgx,
1190  rcview.bottom - rcview.top + chgy,
1192  /* change position and sizes of the controls */
1194  {
1195  int ctrlid = GetDlgCtrlID( ctrl);
1196  GetWindowRect( ctrl, &rc);
1197  MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1198  if( ctrl == fodInfos->DlgInfos.hwndGrip)
1199  {
1200  DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1201  0, 0,
1203  }
1204  else if( rc.top > rcview.bottom)
1205  {
1206  /* if it was below the shell view
1207  * move to bottom */
1208  switch( ctrlid)
1209  {
1210  /* file name (edit or comboboxex) and file types combo change also width */
1211  case edt1:
1212  case cmb13:
1213  case cmb1:
1214  DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1215  rc.right - rc.left + chgx, rc.bottom - rc.top,
1217  break;
1218  /* then these buttons must move out of the way */
1219  case IDOK:
1220  case IDCANCEL:
1221  case pshHelp:
1222  DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1223  0, 0,
1225  break;
1226  default:
1227  DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1228  0, 0,
1230  }
1231  }
1232  else if( rc.left > rcview.right)
1233  {
1234  /* if it was to the right of the shell view
1235  * move to right */
1236  DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1237  0, 0,
1239  }
1240  else
1241  /* special cases */
1242  {
1243  switch( ctrlid)
1244  {
1245 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1246  case IDC_LOOKIN:
1247  DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1248  rc.right - rc.left + chgx, rc.bottom - rc.top,
1250  break;
1251  case IDC_TOOLBARSTATIC:
1252  case IDC_TOOLBAR:
1253  DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1254  0, 0,
1256  break;
1257 #endif
1258  /* not resized in windows. Since wine uses this invisible control
1259  * to size the browser view it needs to be resized */
1260  case IDC_SHELLSTATIC:
1261  DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1262  rc.right - rc.left + chgx,
1263  rc.bottom - rc.top + chgy,
1265  break;
1266  case IDC_TOOLBARPLACES:
1267  DeferWindowPos( hdwp, ctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + chgy,
1269  break;
1270  }
1271  }
1272  }
1273  if(fodInfos->DlgInfos.hwndCustomDlg &&
1275  {
1276  for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1278  {
1279  GetWindowRect( ctrl, &rc);
1280  MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1281  if( rc.top > rcview.bottom)
1282  {
1283  /* if it was below the shell view
1284  * move to bottom */
1285  DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1286  rc.right - rc.left, rc.bottom - rc.top,
1288  }
1289  else if( rc.left > rcview.right)
1290  {
1291  /* if it was to the right of the shell view
1292  * move to right */
1293  DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1294  rc.right - rc.left, rc.bottom - rc.top,
1296  }
1297  }
1298  /* size the custom dialog at the end: some applications do some
1299  * control re-arranging at this point */
1300  GetClientRect(hwnd, &rc);
1301  DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1302  0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1303  }
1304  EndDeferWindowPos( hdwp);
1305  /* should not be needed */
1307  return TRUE;
1308 }
1309 
1310 /***********************************************************************
1311  * FileOpenDlgProc95
1312  *
1313  * File open dialog procedure
1314  */
1316 {
1317 #if 0
1318  TRACE("%p 0x%04x\n", hwnd, uMsg);
1319 #endif
1320 
1321  switch(uMsg)
1322  {
1323  case WM_INITDIALOG:
1324  {
1325  FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1326  RECT rc, rcstc;
1327  int gripx = GetSystemMetrics( SM_CYHSCROLL);
1328  int gripy = GetSystemMetrics( SM_CYVSCROLL);
1329 
1330  /* Some shell namespace extensions depend on COM being initialized. */
1332  fodInfos->ole_initialized = TRUE;
1333 
1334  SetPropW(hwnd, filedlg_info_propnameW, fodInfos);
1335 
1337 
1338  if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1339  {
1341  DWORD ex_style = GetWindowLongW(hwnd, GWL_EXSTYLE);
1342  RECT client, client_adjusted;
1343 
1344  if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1345  {
1346  style |= WS_SIZEBOX;
1347  ex_style |= WS_EX_WINDOWEDGE;
1348  }
1349  else
1350  style &= ~WS_SIZEBOX;
1352  SetWindowLongW(hwnd, GWL_EXSTYLE, ex_style);
1353 
1354  GetClientRect( hwnd, &client );
1355  GetClientRect( hwnd, &client_adjusted );
1356  AdjustWindowRectEx( &client_adjusted, style, FALSE, ex_style );
1357 
1358  GetWindowRect( hwnd, &rc );
1359  rc.right += client_adjusted.right - client.right;
1360  rc.bottom += client_adjusted.bottom - client.bottom;
1361  SetWindowPos(hwnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_FRAMECHANGED | SWP_NOACTIVATE |
1363 
1364  GetWindowRect( hwnd, &rc );
1365  fodInfos->DlgInfos.hwndGrip =
1366  CreateWindowExA( 0, "SCROLLBAR", NULL,
1369  rc.right - gripx, rc.bottom - gripy,
1370  gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1371  }
1372 
1373  fodInfos->DlgInfos.hwndCustomDlg =
1375 
1378 
1379  if( fodInfos->DlgInfos.hwndCustomDlg)
1380  ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1381 
1382  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1385  }
1386 
1387  /* if the app has changed the position of the invisible listbox,
1388  * change that of the listview (browser) as well */
1389  GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1391  if( !EqualRect( &rc, &rcstc))
1392  {
1393  MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1394  SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1395  rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1397  }
1398 
1399  if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1400  {
1401  GetWindowRect( hwnd, &rc);
1402  fodInfos->sizedlg.cx = rc.right - rc.left;
1403  fodInfos->sizedlg.cy = rc.bottom - rc.top;
1404  fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1405  fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1406  GetClientRect( hwnd, &rc);
1407  SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1408  rc.right - gripx, rc.bottom - gripy,
1410  /* resize the dialog to the previous invocation */
1415  }
1416 
1417  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1419 
1420  return 0;
1421  }
1422  case WM_SIZE:
1423  return FILEDLG95_OnWMSize(hwnd, wParam);
1424  case WM_GETMINMAXINFO:
1426  case WM_COMMAND:
1428  case WM_DRAWITEM:
1429  {
1430  switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1431  {
1432  case IDC_LOOKIN:
1434  return TRUE;
1435  }
1436  }
1437  return FALSE;
1438 
1439  case WM_GETISHELLBROWSER:
1441 
1442  case WM_DESTROY:
1443  {
1445  HWND places_bar = GetDlgItem(hwnd, IDC_TOOLBARPLACES);
1446  HIMAGELIST himl;
1447 
1448  if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1449  MemDialogSize = fodInfos->sizedlg;
1450 
1451  if (places_bar)
1452  {
1456  }
1457  return FALSE;
1458  }
1459 
1460  case WM_NCDESTROY:
1462  return 0;
1463 
1464  case WM_NOTIFY:
1465  {
1466  LPNMHDR lpnmh = (LPNMHDR)lParam;
1467  UINT stringId = -1;
1468 
1469  /* set up the button tooltips strings */
1470  if(TTN_GETDISPINFOA == lpnmh->code )
1471  {
1473  switch(lpnmh->idFrom )
1474  {
1475  /* Up folder button */
1476  case FCIDM_TB_UPFOLDER:
1477  stringId = IDS_UPFOLDER;
1478  break;
1479  /* New folder button */
1480  case FCIDM_TB_NEWFOLDER:
1481  stringId = IDS_NEWFOLDER;
1482  break;
1483  /* List option button */
1484  case FCIDM_TB_SMALLICON:
1485  stringId = IDS_LISTVIEW;
1486  break;
1487  /* Details option button */
1488  case FCIDM_TB_REPORTVIEW:
1489  stringId = IDS_REPORTVIEW;
1490  break;
1491  /* Desktop button */
1492  case FCIDM_TB_DESKTOP:
1493  stringId = IDS_TODESKTOP;
1494  break;
1495  default:
1496  stringId = 0;
1497  }
1498  lpdi->hinst = COMDLG32_hInstance;
1499  lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1500  }
1501  return FALSE;
1502  }
1503  default :
1504  if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1506  return FALSE;
1507  }
1508 }
1509 
1511 {
1512  return (info->ofnInfos->lStructSize == OPENFILENAME_SIZE_VERSION_400W) &&
1514 }
1515 
1516 /***********************************************************************
1517  * FILEDLG95_InitControls
1518  *
1519  * WM_INITDIALOG message handler (before hook notification)
1520  */
1522 {
1523  BOOL win2000plus = FALSE;
1524  BOOL win98plus = FALSE;
1525  BOOL handledPath = FALSE;
1526  OSVERSIONINFOW osVi;
1527  static const WCHAR szwSlash[] = { '\\', 0 };
1528  static const WCHAR szwStar[] = { '*',0 };
1529 
1530  static const TBBUTTON tbb[] =
1531  {
1532  {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1534  {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1536  {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1538  {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1541  };
1542  static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1543 
1544  RECT rectTB;
1545  RECT rectlook;
1546 
1547  HIMAGELIST toolbarImageList;
1548  ITEMIDLIST *desktopPidl;
1550 
1552 
1553  TRACE("%p\n", fodInfos);
1554 
1555  /* Get windows version emulating */
1556  osVi.dwOSVersionInfoSize = sizeof(osVi);
1557  GetVersionExW(&osVi);
1559  win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1560  } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1561  win2000plus = (osVi.dwMajorVersion > 4);
1562  if (win2000plus) win98plus = TRUE;
1563  }
1564  TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1565 
1566 
1567  /* Use either the edit or the comboboxex for the filename control */
1568  if (filename_is_edit( fodInfos ))
1569  {
1571  fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, edt1 );
1572  }
1573  else
1574  {
1576  fodInfos->DlgInfos.hwndFileName = GetDlgItem( hwnd, cmb13 );
1577  }
1578 
1579  /* Get the hwnd of the controls */
1580  fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1581  fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1582 
1583  GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1584  MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1585 
1586  /* construct the toolbar */
1588  MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1589 
1590  rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1591  rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1592  rectTB.left = rectlook.right;
1593  rectTB.top = rectlook.top-1;
1594 
1595  if (fodInfos->unicode)
1596  fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1598  rectTB.left, rectTB.top,
1599  rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1601  else
1602  fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1604  rectTB.left, rectTB.top,
1605  rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1607 
1608  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1609 
1610 /* FIXME: use TB_LOADIMAGES when implemented */
1611 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1612  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1613  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1614 
1615  /* Retrieve and add desktop icon to the toolbar */
1616  toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1618  SHGetFileInfoW((const WCHAR *)desktopPidl, 0, &fileinfo, sizeof(fileinfo),
1620  ImageList_AddIcon(toolbarImageList, fileinfo.hIcon);
1621 
1622  DestroyIcon(fileinfo.hIcon);
1623  CoTaskMemFree(desktopPidl);
1624 
1625  /* Finish Toolbar Construction */
1626  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1627  SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1628 
1629  if (is_places_bar_enabled(fodInfos))
1630  {
1631  TBBUTTON tb = { 0 };
1632  HIMAGELIST himl;
1633  RECT rect;
1634  int i, cx;
1635 
1638  cx = rect.right - rect.left;
1639 
1642 
1643  filedlg_collect_places_pidls(fodInfos);
1644  for (i = 0; i < ARRAY_SIZE(fodInfos->places); i++)
1645  {
1646  int index;
1647 
1648  if (!fodInfos->places[i])
1649  continue;
1650 
1651  memset(&fileinfo, 0, sizeof(fileinfo));
1652  SHGetFileInfoW((const WCHAR *)fodInfos->places[i], 0, &fileinfo, sizeof(fileinfo),
1655 
1656  tb.iBitmap = index;
1657  tb.iString = (INT_PTR)fileinfo.szDisplayName;
1658  tb.fsState = TBSTATE_ENABLED | TBSTATE_WRAP;
1659  tb.idCommand = TBPLACES_CMDID_PLACE0 + i;
1661 
1662  DestroyIcon(fileinfo.hIcon);
1663  }
1664 
1667  }
1668 
1669  /* Set the window text with the text specified in the OPENFILENAME structure */
1670  if(fodInfos->title)
1671  {
1672  SetWindowTextW(hwnd,fodInfos->title);
1673  }
1674  else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1675  {
1676  WCHAR buf[64];
1679  }
1680 
1681  /* Initialise the file name edit control */
1682  handledPath = FALSE;
1683  TRACE("Before manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1684 
1685  if(fodInfos->filename)
1686  {
1687  /* 1. If win2000 or higher and filename contains a path, use it
1688  in preference over the lpstrInitialDir */
1689  if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1690  WCHAR tmpBuf[MAX_PATH];
1691  WCHAR *nameBit;
1692  DWORD result;
1693 
1694  result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1695  if (result) {
1696 
1697  /* nameBit is always shorter than the original filename. It may be NULL
1698  * when the filename contains only a drive name instead of file name */
1699  if (nameBit)
1700  {
1701  lstrcpyW(fodInfos->filename,nameBit);
1702  *nameBit = 0x00;
1703  }
1704  else
1705  *fodInfos->filename = '\0';
1706 
1707  heap_free(fodInfos->initdir);
1708  fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1709  lstrcpyW(fodInfos->initdir, tmpBuf);
1710  handledPath = TRUE;
1711  TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1712  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1713  }
1714  SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1715 
1716  } else {
1717  SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1718  }
1719  }
1720 
1721  /* 2. (All platforms) If initdir is not null, then use it */
1722  if (!handledPath && fodInfos->initdir && *fodInfos->initdir)
1723  {
1724  /* Work out the proper path as supplied one might be relative */
1725  /* (Here because supplying '.' as dir browses to My Computer) */
1726  WCHAR tmpBuf[MAX_PATH];
1727  WCHAR tmpBuf2[MAX_PATH];
1728  WCHAR *nameBit;
1729  DWORD result;
1730 
1731  lstrcpyW(tmpBuf, fodInfos->initdir);
1732  if (PathFileExistsW(tmpBuf)) {
1733  /* initdir does not have to be a directory. If a file is
1734  * specified, the dir part is taken */
1735  if (PathIsDirectoryW(tmpBuf)) {
1736  PathAddBackslashW(tmpBuf);
1737  lstrcatW(tmpBuf, szwStar);
1738  }
1739  result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1740  if (result) {
1741  *nameBit = 0x00;
1742  heap_free(fodInfos->initdir);
1743  fodInfos->initdir = heap_alloc((lstrlenW(tmpBuf2) + 1) * sizeof(WCHAR));
1744  lstrcpyW(fodInfos->initdir, tmpBuf2);
1745  handledPath = TRUE;
1746  TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1747  }
1748  }
1749  else if (fodInfos->initdir)
1750  {
1751  heap_free(fodInfos->initdir);
1752  fodInfos->initdir = NULL;
1753  TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1754  }
1755  }
1756 
1757  if (!handledPath && (!fodInfos->initdir || !*fodInfos->initdir))
1758  {
1759  /* 3. All except w2k+: if filename contains a path use it */
1760  if (!win2000plus && fodInfos->filename &&
1761  *fodInfos->filename &&
1762  strpbrkW(fodInfos->filename, szwSlash)) {
1763  WCHAR tmpBuf[MAX_PATH];
1764  WCHAR *nameBit;
1765  DWORD result;
1766 
1768  tmpBuf, &nameBit);
1769  if (result) {
1770  int len;
1771 
1772  /* nameBit is always shorter than the original filename */
1773  lstrcpyW(fodInfos->filename, nameBit);
1774  *nameBit = 0x00;
1775 
1776  len = lstrlenW(tmpBuf);
1777  heap_free(fodInfos->initdir);
1778  fodInfos->initdir = heap_alloc((len+1)*sizeof(WCHAR));
1779  lstrcpyW(fodInfos->initdir, tmpBuf);
1780 
1781  handledPath = TRUE;
1782  TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1783  debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1784  }
1785  SetWindowTextW( fodInfos->DlgInfos.hwndFileName, fodInfos->filename );
1786  }
1787 
1788  /* 4. Win2000+: Recently used */
1789  if (!handledPath && win2000plus) {
1790  fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1791  fodInfos->initdir[0] = '\0';
1792 
1794 
1795  if (fodInfos->initdir[0] && PathFileExistsW(fodInfos->initdir)){
1796  handledPath = TRUE;
1797  }else{
1798  heap_free(fodInfos->initdir);
1799  fodInfos->initdir = NULL;
1800  }
1801  }
1802 
1803  /* 5. win98+ and win2000+ if any files of specified filter types in
1804  current directory, use it */
1805  if (win98plus && !handledPath && fodInfos->filter && *fodInfos->filter) {
1806 
1807  LPCWSTR lpstrPos = fodInfos->filter;
1808  WIN32_FIND_DATAW FindFileData;
1809  HANDLE hFind;
1810 
1811  while (1)
1812  {
1813  /* filter is a list... title\0ext\0......\0\0 */
1814 
1815  /* Skip the title */
1816  if(! *lpstrPos) break; /* end */
1817  lpstrPos += lstrlenW(lpstrPos) + 1;
1818 
1819  /* See if any files exist in the current dir with this extension */
1820  if(! *lpstrPos) break; /* end */
1821 
1822  hFind = FindFirstFileW(lpstrPos, &FindFileData);
1823 
1824  if (hFind == INVALID_HANDLE_VALUE) {
1825  /* None found - continue search */
1826  lpstrPos += lstrlenW(lpstrPos) + 1;
1827 
1828  } else {
1829 
1830  heap_free(fodInfos->initdir);
1831  fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1833 
1834  handledPath = TRUE;
1835  TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1836  debugstr_w(lpstrPos));
1837  FindClose(hFind);
1838  break;
1839  }
1840  }
1841  }
1842 
1843  /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1844  if (!handledPath && (win2000plus || win98plus)) {
1845  fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1846 
1847  if (SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir) == S_OK)
1848  {
1850  {
1851  /* last fallback */
1853  TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1854  }
1855  else
1856  TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1857  }
1858  else
1859  TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1860 
1861  handledPath = TRUE;
1862  } else if (!handledPath) {
1863  fodInfos->initdir = heap_alloc(MAX_PATH * sizeof(WCHAR));
1865  handledPath = TRUE;
1866  TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1867  }
1868  }
1869  SetFocus( fodInfos->DlgInfos.hwndFileName );
1870  TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1871 
1872  /* Must the open as read only check box be checked ?*/
1873  if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1874  {
1876  }
1877 
1878  /* Must the open as read only check box be hidden? */
1879  if (filedialog_is_readonly_hidden(fodInfos))
1880  {
1883  }
1884 
1885  /* Must the help button be hidden? */
1886  if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1887  {
1890  }
1891 
1892  /* change Open to Save */
1893  if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1894  {
1895  WCHAR buf[16];
1900  }
1901 
1902  /* Initialize the filter combo box */
1904 
1905  return 0;
1906 }
1907 
1908 /***********************************************************************
1909  * FILEDLG95_ResizeControls
1910  *
1911  * WM_INITDIALOG message handler (after hook notification)
1912  */
1914 {
1915  FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1916 
1917  if (fodInfos->DlgInfos.hwndCustomDlg)
1918  {
1919  RECT rc;
1921 
1922  ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1923  filedialog_is_readonly_hidden(fodInfos) && !(fodInfos->ofnInfos->Flags & OFN_SHOWHELP));
1924 
1925  /* resize the custom dialog to the parent size */
1927  GetClientRect(hwnd, &rc);
1928  else
1929  {
1930  /* our own fake template is zero sized and doesn't have children, so
1931  * there is no need to resize it. Picasa depends on it.
1932  */
1933  flags |= SWP_NOSIZE;
1934  SetRectEmpty(&rc);
1935  }
1936  SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1937  0, 0, rc.right, rc.bottom, flags);
1938  }
1939  else
1940  {
1941  /* Resize the height; if opened as read-only, checkbox and help button are
1942  * hidden and we are not using a custom template nor a customDialog
1943  */
1944  if (filedialog_is_readonly_hidden(fodInfos) &&
1945  (!(fodInfos->ofnInfos->Flags &
1947  {
1948  RECT rectDlg, rectHelp, rectCancel;
1949  GetWindowRect(hwnd, &rectDlg);
1950  GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1951  GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1952  /* subtract the height of the help button plus the space between the help
1953  * button and the cancel button to the height of the dialog
1954  */
1955  SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1956  (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1958  }
1959  }
1960  return TRUE;
1961 }
1962 
1963 /***********************************************************************
1964  * FILEDLG95_FillControls
1965  *
1966  * WM_INITDIALOG message handler (after hook notification)
1967  */
1969 {
1970  LPITEMIDLIST pidlItemId = NULL;
1971 
1972  FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1973 
1974  TRACE("dir=%s file=%s\n",
1975  debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1976 
1977  /* Get the initial directory pidl */
1978 
1979  if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1980  {
1981  WCHAR path[MAX_PATH];
1982 
1984  pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1985  }
1986 
1987  /* Initialise shell objects */
1989 
1990  /* Initialize the Look In combo box */
1991  FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1992 
1993  /* Browse to the initial directory */
1994  IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1995 
1996  ILFree(pidlItemId);
1997 
1998  return TRUE;
1999 }
2000 /***********************************************************************
2001  * FILEDLG95_Clean
2002  *
2003  * Regroups all the cleaning functions of the filedlg
2004  */
2006 {
2010 }
2011 
2012 
2013 /***********************************************************************
2014  * Browse to arbitrary pidl
2015  */
2017 {
2018  TRACE("%p, %p\n", info->ShellInfos.hwndOwner, pidl);
2019 
2020  IShellBrowser_BrowseObject(info->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2021  if (info->ofnInfos->Flags & OFN_EXPLORER)
2022  SendCustomDlgNotificationMessage(info->ShellInfos.hwndOwner, CDN_FOLDERCHANGE);
2023 }
2024 
2025 /***********************************************************************
2026  * FILEDLG95_OnWMCommand
2027  *
2028  * WM_COMMAND message handler
2029  */
2031 {
2033  WORD wNotifyCode = HIWORD(wParam); /* notification code */
2034  WORD id = LOWORD(wParam); /* item, control, or accelerator identifier */
2035 
2036  switch (id)
2037  {
2038  /* OK button */
2039  case IDOK:
2041  break;
2042  /* Cancel button */
2043  case IDCANCEL:
2045  EndDialog(hwnd, FALSE);
2046  break;
2047  /* Filetype combo box */
2048  case IDC_FILETYPE:
2049  FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
2050  break;
2051  /* LookIn combo box */
2052  case IDC_LOOKIN:
2053  FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
2054  break;
2055 
2056  /* --- toolbar --- */
2057  /* Up folder button */
2058  case FCIDM_TB_UPFOLDER:
2060  break;
2061  /* New folder button */
2062  case FCIDM_TB_NEWFOLDER:
2063  FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
2064  break;
2065  /* List option button */
2066  case FCIDM_TB_SMALLICON:
2067  FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
2068  break;
2069  /* Details option button */
2070  case FCIDM_TB_REPORTVIEW:
2071  FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
2072  break;
2073 
2074  case FCIDM_TB_DESKTOP:
2075  {
2076  LPITEMIDLIST pidl;
2077 
2079  filedlg_browse_to_pidl(fodInfos, pidl);
2080  ILFree(pidl);
2081  break;
2082  }
2083 
2084  /* Places bar */
2085  case TBPLACES_CMDID_PLACE0:
2086  case TBPLACES_CMDID_PLACE1:
2087  case TBPLACES_CMDID_PLACE2:
2088  case TBPLACES_CMDID_PLACE3:
2089  case TBPLACES_CMDID_PLACE4:
2090  filedlg_browse_to_pidl(fodInfos, fodInfos->places[id - TBPLACES_CMDID_PLACE0]);
2091  break;
2092 
2093  case edt1:
2094  case cmb13:
2095  break;
2096 
2097  }
2098  /* Do not use the listview selection anymore */
2099  fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
2100  return 0;
2101 }
2102 
2103 /***********************************************************************
2104  * FILEDLG95_OnWMGetIShellBrowser
2105  *
2106  * WM_GETISHELLBROWSER message handler
2107  */
2109 {
2111 
2112  TRACE("\n");
2113 
2114  SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
2115 
2116  return TRUE;
2117 }
2118 
2119 
2120 /***********************************************************************
2121  * FILEDLG95_SendFileOK
2122  *
2123  * Sends the CDN_FILEOK notification if required
2124  *
2125  * RETURNS
2126  * TRUE if the dialog should close
2127  * FALSE if the dialog should not be closed
2128  */
2130 {
2131  /* ask the hook if we can close */
2132  if (is_dialog_hooked(fodInfos))
2133  {
2134  LRESULT retval = 0;
2135 
2136  TRACE("---\n");
2137  /* First send CDN_FILEOK as MSDN doc says */
2138  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2140  if( retval)
2141  {
2142  TRACE("canceled\n");
2143  return FALSE;
2144  }
2145 
2146  /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
2147  retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
2148  fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
2149  if( retval)
2150  {
2151  TRACE("canceled\n");
2152  return FALSE;
2153  }
2154  }
2155  return TRUE;
2156 }
2157 
2158 /***********************************************************************
2159  * FILEDLG95_OnOpenMultipleFiles
2160  *
2161  * Handles the opening of multiple files.
2162  *
2163  * FIXME
2164  * check destination buffer size
2165  */
2166 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
2167 {
2169  WCHAR lpstrPathSpec[MAX_PATH] = {0};
2170  UINT nCount, nSizePath;
2171 
2172  TRACE("\n");
2173 
2174  if(fodInfos->unicode)
2175  {
2176  LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2177  ofn->lpstrFile[0] = '\0';
2178  }
2179  else
2180  {
2182  ofn->lpstrFile[0] = '\0';
2183  }
2184 
2185  COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
2186 
2187  if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2188  ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2189  ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2190  {
2191  LPWSTR lpstrTemp = lpstrFileList;
2192 
2193  for ( nCount = 0; nCount < nFileCount; nCount++ )
2194  {
2195  LPITEMIDLIST pidl;
2196 
2197  pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
2198  if (!pidl)
2199  {
2200  WCHAR lpstrNotFound[100];
2201  WCHAR lpstrMsg[100];
2202  WCHAR tmp[400];
2203  static const WCHAR nl[] = {'\n',0};
2204 
2205  LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
2207 
2208  lstrcpyW(tmp, lpstrTemp);
2209  lstrcatW(tmp, nl);
2210  lstrcatW(tmp, lpstrNotFound);
2211  lstrcatW(tmp, nl);
2212  lstrcatW(tmp, lpstrMsg);
2213 
2214  MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
2215  return FALSE;
2216  }
2217 
2218  /* move to the next file in the list of files */
2219  lpstrTemp += lstrlenW(lpstrTemp) + 1;
2220  ILFree(pidl);
2221  }
2222  }
2223 
2224  nSizePath = lstrlenW(lpstrPathSpec) + 1;
2225  if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
2226  {
2227  /* For "oldstyle" dialog the components have to
2228  be separated by blanks (not '\0'!) and short
2229  filenames have to be used! */
2230  FIXME("Components have to be separated by blanks\n");
2231  }
2232  if(fodInfos->unicode)
2233  {
2234  LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2235  lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
2236  memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
2237  }
2238  else
2239  {
2241 
2242  if (ofn->lpstrFile != NULL)
2243  {
2244  nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
2246  if (ofn->nMaxFile > nSizePath)
2247  {
2248  WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
2249  ofn->lpstrFile + nSizePath,
2250  ofn->nMaxFile - nSizePath, NULL, NULL);
2251  }
2252  }
2253  }
2254 
2255  fodInfos->ofnInfos->nFileOffset = nSizePath;
2256  fodInfos->ofnInfos->nFileExtension = 0;
2257 
2258  if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2259  return FALSE;
2260 
2261  /* clean and exit */
2263  return EndDialog(hwnd,TRUE);
2264 }
2265 
2266 /* Returns the 'slot name' of the given module_name in the registry's
2267  * most-recently-used list. This will be an ASCII value in the
2268  * range ['a','z'). Returns zero on error.
2269  *
2270  * The slot's value in the registry has the form:
2271  * module_name\0mru_path\0
2272  *
2273  * If stored_path is given, then stored_path will contain the path name
2274  * stored in the registry's MRU list for the given module_name.
2275  *
2276  * If hkey_ret is given, then hkey_ret will be a handle to the registry's
2277  * MRU list key for the given module_name.
2278  */
2280 {
2281  WCHAR mru_list[32], *cur_mru_slot;
2282  BOOL taken[25] = {0};
2283  DWORD mru_list_size = sizeof(mru_list), key_type = -1, i;
2284  HKEY hkey_tmp, *hkey;
2285  LONG ret;
2286 
2287  if(hkey_ret)
2288  hkey = hkey_ret;
2289  else
2290  hkey = &hkey_tmp;
2291 
2292  if(stored_path)
2293  *stored_path = '\0';
2294 
2296  if(ret){
2297  WARN("Unable to create MRU key: %d\n", ret);
2298  return 0;
2299  }
2300 
2301  ret = RegGetValueW(*hkey, NULL, MRUListW, RRF_RT_REG_SZ, &key_type,
2302  (LPBYTE)mru_list, &mru_list_size);
2303  if(ret || key_type != REG_SZ){
2304  if(ret == ERROR_FILE_NOT_FOUND)
2305  return 'a';
2306 
2307  WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2308  RegCloseKey(*hkey);
2309  return 0;
2310  }
2311 
2312  for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot){
2313  WCHAR value_data[MAX_PATH], value_name[2] = {0};
2314  DWORD value_data_size = sizeof(value_data);
2315 
2316  *value_name = *cur_mru_slot;
2317 
2318  ret = RegGetValueW(*hkey, NULL, value_name, RRF_RT_REG_BINARY,
2319  &key_type, (LPBYTE)value_data, &value_data_size);
2320  if(ret || key_type != REG_BINARY){
2321  WARN("Error getting MRU slot data: type: %d, ret: %d\n", key_type, ret);
2322  continue;
2323  }
2324 
2325  if(!strcmpiW(module_name, value_data)){
2326  if(!hkey_ret)
2327  RegCloseKey(*hkey);
2328  if(stored_path)
2329  lstrcpyW(stored_path, value_data + lstrlenW(value_data) + 1);
2330  return *value_name;
2331  }
2332  }
2333 
2334  if(!hkey_ret)
2335  RegCloseKey(*hkey);
2336 
2337  /* the module name isn't in the registry, so find the next open slot */
2338  for(cur_mru_slot = mru_list; *cur_mru_slot; ++cur_mru_slot)
2339  taken[*cur_mru_slot - 'a'] = TRUE;
2340  for(i = 0; i < 25; ++i){
2341  if(!taken[i])
2342  return i + 'a';
2343  }
2344 
2345  /* all slots are taken, so return the last one in MRUList */
2346  --cur_mru_slot;
2347  return *cur_mru_slot;
2348 }
2349 
2350 /* save the given filename as most-recently-used path for this module */
2352 {
2353  WCHAR module_path[MAX_PATH], *module_name, slot, slot_name[2] = {0};
2354  LONG ret;
2355  HKEY hkey;
2356 
2357  /* get the current executable's name */
2358  if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2359  {
2360  WARN("GotModuleFileName failed: %d\n", GetLastError());
2361  return;
2362  }
2363  module_name = strrchrW(module_path, '\\');
2364  if(!module_name)
2365  module_name = module_path;
2366  else
2367  module_name += 1;
2368 
2370  if(!slot)
2371  return;
2372  *slot_name = slot;
2373 
2374  { /* update the slot's info */
2375  WCHAR *path_ends, *final;
2376  DWORD path_len, final_len;
2377 
2378  /* use only the path segment of `filename' */
2379  path_ends = strrchrW(filename, '\\');
2380  path_len = path_ends - filename;
2381 
2382  final_len = path_len + lstrlenW(module_name) + 2;
2383 
2384  final = heap_alloc(final_len * sizeof(WCHAR));
2385  if(!final)
2386  return;
2387  lstrcpyW(final, module_name);
2388  memcpy(final + lstrlenW(final) + 1, filename, path_len * sizeof(WCHAR));
2389  final[final_len-1] = '\0';
2390 
2391  ret = RegSetValueExW(hkey, slot_name, 0, REG_BINARY, (LPBYTE)final,
2392  final_len * sizeof(WCHAR));
2393  if(ret){
2394  WARN("Error saving MRU data to slot %s: %d\n", wine_dbgstr_w(slot_name), ret);
2395  heap_free(final);
2396  RegCloseKey(hkey);
2397  return;
2398  }
2399 
2400  heap_free(final);
2401  }
2402 
2403  { /* update MRUList value */
2404  WCHAR old_mru_list[32], new_mru_list[32];
2405  WCHAR *old_mru_slot, *new_mru_slot = new_mru_list;
2406  DWORD mru_list_size = sizeof(old_mru_list), key_type;
2407 
2408  ret = RegGetValueW(hkey, NULL, MRUListW, RRF_RT_ANY, &key_type,
2409  (LPBYTE)old_mru_list, &mru_list_size);
2410  if(ret || key_type != REG_SZ){
2411  if(ret == ERROR_FILE_NOT_FOUND){
2412  new_mru_list[0] = slot;
2413  new_mru_list[1] = '\0';
2414  }else{
2415  WARN("Error getting MRUList data: type: %d, ret: %d\n", key_type, ret);
2416  RegCloseKey(hkey);
2417  return;
2418  }
2419  }else{
2420  /* copy old list data over so that the new slot is at the start
2421  * of the list */
2422  *new_mru_slot++ = slot;
2423  for(old_mru_slot = old_mru_list; *old_mru_slot; ++old_mru_slot){
2424  if(*old_mru_slot != slot)
2425  *new_mru_slot++ = *old_mru_slot;
2426  }
2427  *new_mru_slot = '\0';
2428  }
2429 
2430  ret = RegSetValueExW(hkey, MRUListW, 0, REG_SZ, (LPBYTE)new_mru_list,
2431  (lstrlenW(new_mru_list) + 1) * sizeof(WCHAR));
2432  if(ret){
2433  WARN("Error saving MRUList data: %d\n", ret);
2434  RegCloseKey(hkey);
2435  return;
2436  }
2437  }
2438 }
2439 
2440 /* load the most-recently-used path for this module */
2441 static void FILEDLG95_MRU_load_filename(LPWSTR stored_path)
2442 {
2443  WCHAR module_path[MAX_PATH], *module_name;
2444 
2445  /* get the current executable's name */
2446  if (!GetModuleFileNameW(GetModuleHandleW(NULL), module_path, ARRAY_SIZE(module_path)))
2447  {
2448  WARN("GotModuleFileName failed: %d\n", GetLastError());
2449  return;
2450  }
2451  module_name = strrchrW(module_path, '\\');
2452  if(!module_name)
2453  module_name = module_path;
2454  else
2455  module_name += 1;
2456 
2457  FILEDLG95_MRU_get_slot(module_name, stored_path, NULL);
2458  TRACE("got MRU path: %s\n", wine_dbgstr_w(stored_path));
2459 }
2460 
2461 void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
2462 {
2463  WCHAR strMsgTitle[MAX_PATH];
2464  WCHAR strMsgText [MAX_PATH];
2465  if (idCaption)
2466  LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, ARRAY_SIZE(strMsgTitle));
2467  else
2468  strMsgTitle[0] = '\0';
2469  LoadStringW(COMDLG32_hInstance, idText, strMsgText, ARRAY_SIZE(strMsgText));
2470  MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
2471 }
2472 
2473 int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
2474  HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
2475 {
2476  int nOpenAction = defAction;
2477  LPWSTR lpszTemp, lpszTemp1;
2478  LPITEMIDLIST pidl = NULL;
2479  static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2480 
2481  /* check for invalid chars */
2482  if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(flags & OFN_NOVALIDATE))
2483  {
2485  return FALSE;
2486  }
2487 
2488  if (FAILED (SHGetDesktopFolder(ppsf))) return FALSE;
2489 
2490  lpszTemp1 = lpszTemp = lpstrPathAndFile;
2491  while (lpszTemp1)
2492  {
2493  LPSHELLFOLDER lpsfChild;
2494  WCHAR lpwstrTemp[MAX_PATH];
2495  DWORD dwEaten, dwAttributes;
2496  LPWSTR p;
2497 
2498  lstrcpyW(lpwstrTemp, lpszTemp);
2499  p = PathFindNextComponentW(lpwstrTemp);
2500 
2501  if (!p) break; /* end of path */
2502 
2503  *p = 0;
2504  lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2505 
2506  /* There are no wildcards when OFN_NOVALIDATE is set */
2507  if(*lpszTemp==0 && !(flags & OFN_NOVALIDATE))
2508  {
2509  static const WCHAR wszWild[] = { '*', '?', 0 };
2510  /* if the last element is a wildcard do a search */
2511  if(strpbrkW(lpszTemp1, wszWild) != NULL)
2512  {
2513  nOpenAction = ONOPEN_SEARCH;
2514  break;
2515  }
2516  }
2517  lpszTemp1 = lpszTemp;
2518 
2519  TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), *ppsf);
2520 
2521  /* append a backslash to drive letters */
2522  if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2523  ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2524  (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2525  {
2526  PathAddBackslashW(lpwstrTemp);
2527  }
2528 
2529  dwAttributes = SFGAO_FOLDER;
2530  if(SUCCEEDED(IShellFolder_ParseDisplayName(*ppsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2531  {
2532  /* the path component is valid, we have a pidl of the next path component */
2533  TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2534  if(dwAttributes & SFGAO_FOLDER)
2535  {
2536  if(FAILED(IShellFolder_BindToObject(*ppsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2537  {
2538  ERR("bind to failed\n"); /* should not fail */
2539  break;
2540  }
2541  IShellFolder_Release(*ppsf);
2542  *ppsf = lpsfChild;
2543  lpsfChild = NULL;
2544  }
2545  else
2546  {
2547  TRACE("value\n");
2548 
2549  /* end dialog, return value */
2550  nOpenAction = ONOPEN_OPEN;
2551  break;
2552  }
2553  ILFree(pidl);
2554  pidl = NULL;
2555  }
2556  else if (!(flags & OFN_NOVALIDATE))
2557  {
2558  if(*lpszTemp || /* points to trailing null for last path element */
2559  (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2560  {
2561  if(flags & OFN_PATHMUSTEXIST)
2562  {
2564  break;
2565  }
2566  }
2567  else
2568  {
2569  if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
2570  {
2572  break;
2573  }
2574  }
2575  /* change to the current folder */
2576  nOpenAction = ONOPEN_OPEN;
2577  break;
2578  }
2579  else
2580  {
2581  nOpenAction = ONOPEN_OPEN;
2582  break;
2583  }
2584  }
2585  ILFree(pidl);
2586 
2587  return nOpenAction;
2588 }
2589 
2590 /***********************************************************************
2591  * FILEDLG95_OnOpen
2592  *
2593  * Ok button WM_COMMAND message handler
2594  *
2595  * If the function succeeds, the return value is nonzero.
2596  */
2598 {
2600  LPWSTR lpstrFileList;
2601  UINT nFileCount = 0;
2602  UINT sizeUsed = 0;
2603  BOOL ret = TRUE;
2604  WCHAR lpstrPathAndFile[MAX_PATH];
2605  LPSHELLFOLDER lpsf = NULL;
2606  int nOpenAction;
2607 
2608  TRACE("hwnd=%p\n", hwnd);
2609 
2610  /* try to browse the selected item */
2612  return FALSE;
2613 
2614  /* get the files from the edit control */
2615  nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2616 
2617  if(nFileCount == 0)
2618  return FALSE;
2619 
2620  if(nFileCount > 1)
2621  {
2622  ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2623  goto ret;
2624  }
2625 
2626  TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2627 
2628 /*
2629  Step 1: Build a complete path name from the current folder and
2630  the filename or path in the edit box.
2631  Special cases:
2632  - the path in the edit box is a root path
2633  (with or without drive letter)
2634  - the edit box contains ".." (or a path with ".." in it)
2635 */
2636 
2637  COMDLG32_GetCanonicalPath(fodInfos->ShellInfos.pidlAbsCurrent, lpstrFileList, lpstrPathAndFile);
2638  heap_free(lpstrFileList);
2639 
2640 /*
2641  Step 2: here we have a cleaned up path
2642 
2643  We have to parse the path step by step to see if we have to browse
2644  to a folder if the path points to a directory or the last
2645  valid element is a directory.
2646 
2647  valid variables:
2648  lpstrPathAndFile: cleaned up path
2649  */
2650 
2651  if (nFileCount &&
2652  (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2653  !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2654  nOpenAction = ONOPEN_OPEN;
2655  else
2656  nOpenAction = ONOPEN_BROWSE;
2657 
2658  nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
2659  fodInfos->ofnInfos->Flags,
2660  fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
2661  nOpenAction);
2662  if(!nOpenAction)
2663  goto ret;
2664 
2665 /*
2666  Step 3: here we have a cleaned up and validated path
2667 
2668  valid variables:
2669  lpsf: ShellFolder bound to the rightmost valid path component
2670  lpstrPathAndFile: cleaned up path
2671  nOpenAction: action to do
2672 */
2673  TRACE("end validate sf=%p\n", lpsf);
2674 
2675  switch(nOpenAction)
2676  {
2677  case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2678  TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2679  {
2680  int iPos;
2681  LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2682  DWORD len;
2683 
2684  /* replace the current filter */
2685  heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
2686  len = lstrlenW(lpszTemp)+1;
2687  fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc(len * sizeof(WCHAR));
2688  lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2689 
2690  /* set the filter cb to the extension when possible */
2691  if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2692  SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, iPos, 0);
2693  }
2694  /* fall through */
2695  case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2696  TRACE("ONOPEN_BROWSE\n");
2697  {
2698  IPersistFolder2 * ppf2;
2699  if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2700  {
2701  LPITEMIDLIST pidlCurrent;
2702  IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2703  IPersistFolder2_Release(ppf2);
2704  if (!ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2705  {
2706  if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2707  && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2708  {
2710  SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_SETTEXT, 0, (LPARAM)"");
2711  }
2712  }
2713  else if( nOpenAction == ONOPEN_SEARCH )
2714  {
2715  if (fodInfos->Shell.FOIShellView)
2716  IShellView_Refresh(fodInfos->Shell.FOIShellView);
2717  }
2718  ILFree(pidlCurrent);
2719  if (filename_is_edit( fodInfos ))
2720  SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2721  else
2722  {
2723  HWND hwnd;
2724 
2725  hwnd = (HWND)SendMessageA(fodInfos->DlgInfos.hwndFileName, CBEM_GETEDITCONTROL, 0, 0);
2726  SendMessageW(hwnd, EM_SETSEL, 0, -1);
2727  }
2728  }
2729  }
2730  ret = FALSE;
2731  break;
2732  case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2733  TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2734  {
2735  WCHAR *ext = NULL;
2736 
2737  /* update READONLY check box flag */
2739  fodInfos->ofnInfos->Flags |= OFN_READONLY;
2740  else
2741  fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2742 
2743  /* Attach the file extension with file name*/
2744  ext = PathFindExtensionW(lpstrPathAndFile);
2745  if (! *ext && fodInfos->defext)
2746  {
2747  /* if no extension is specified with file name, then */
2748  /* attach the extension from file filter or default one */
2749 
2750  WCHAR *filterExt = NULL;
2751  LPWSTR lpstrFilter = NULL;
2752  static const WCHAR szwDot[] = {'.',0};
2753  int PathLength = lstrlenW(lpstrPathAndFile);
2754 
2755  /*Get the file extension from file type filter*/
2756  lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2757  fodInfos->ofnInfos->nFilterIndex-1);
2758 
2759  if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2760  {
2761  WCHAR* filterSearchIndex;
2762  filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
2763  strcpyW(filterExt, lpstrFilter);
2764 
2765  /* if a semicolon-separated list of file extensions was given, do not include the
2766  semicolon or anything after it in the extension.
2767  example: if filterExt was "*.abc;*.def", it will become "*.abc" */
2768  filterSearchIndex = strchrW(filterExt, ';');
2769  if (filterSearchIndex)
2770  {
2771  filterSearchIndex[0] = '\0';
2772  }
2773 
2774  /* find the file extension by searching for the first dot in filterExt */
2775  /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
2776  /* if the extension is invalid or contains a glob, ignore it */
2777  filterSearchIndex = strchrW(filterExt, '.');
2778  if (filterSearchIndex++ && !strchrW(filterSearchIndex, '*') && !strchrW(filterSearchIndex, '?'))
2779  {
2780  strcpyW(filterExt, filterSearchIndex);
2781  }
2782  else
2783  {
2784  heap_free(filterExt);
2785  filterExt = NULL;
2786  }
2787  }
2788 
2789  if (!filterExt)
2790  {
2791  /* use the default file extension */
2792  filterExt = heap_alloc((lstrlenW(fodInfos->defext) + 1) * sizeof(WCHAR));
2793  strcpyW(filterExt, fodInfos->defext);
2794  }
2795 
2796  if (*filterExt) /* ignore filterExt="" */
2797  {
2798  /* Attach the dot*/
2799  lstrcatW(lpstrPathAndFile, szwDot);
2800  /* Attach the extension */
2801  lstrcatW(lpstrPathAndFile, filterExt);
2802  }
2803 
2804  heap_free(filterExt);
2805 
2806  /* In Open dialog: if file does not exist try without extension */
2807  if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2808  lpstrPathAndFile[PathLength] = '\0';
2809 
2810  /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2811  if (*ext)
2812  ext++;
2813  if (!lstrcmpiW(fodInfos->defext, ext))
2814  fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2815  else
2816  fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2817  }
2818 
2819  /* In Save dialog: check if the file already exists */
2820  if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2821  && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2822  && PathFileExistsW(lpstrPathAndFile))
2823  {
2824  WCHAR lpstrOverwrite[100];
2825  int answer;
2826 
2827  LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2828  answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2830  if (answer == IDNO || answer == IDCANCEL)
2831  {
2832  ret = FALSE;
2833  goto ret;
2834  }
2835  }
2836 
2837  /* In Open dialog: check if it should be created if it doesn't exist */
2838  if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2839  && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2840  && !PathFileExistsW(lpstrPathAndFile))
2841  {
2842  WCHAR lpstrCreate[100];
2843  int answer;
2844 
2845  LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2846  answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2848  if (answer == IDNO || answer == IDCANCEL)
2849  {
2850  ret = FALSE;
2851  goto ret;
2852  }
2853  }
2854 
2855  /* Check that the size of the file does not exceed buffer size.
2856  (Allow for extra \0 if OFN_MULTISELECT is set.) */
2857  if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2858  ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2859  {
2860 
2861  /* fill destination buffer */
2862  if (fodInfos->ofnInfos->lpstrFile)
2863  {
2864  if(fodInfos->unicode)
2865  {
2866  LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2867 
2868  lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2870  ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2871  }
2872  else
2873  {
2875 
2876  WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2879  ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2880  }
2881  }
2882 
2883  if(fodInfos->unicode)
2884  {
2885  LPWSTR lpszTemp;
2886 
2887  /* set filename offset */
2888  lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2889  fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2890 
2891  /* set extension offset */
2892  lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2893  fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2894  }
2895  else
2896  {
2897  LPSTR lpszTemp;
2898  CHAR tempFileA[MAX_PATH];
2899 
2900  /* avoid using fodInfos->ofnInfos->lpstrFile since it can be NULL */
2901  WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2902  tempFileA, sizeof(tempFileA), NULL, NULL);
2903 
2904  /* set filename offset */
2905  lpszTemp = PathFindFileNameA(tempFileA);
2906  fodInfos->ofnInfos->nFileOffset = (lpszTemp - tempFileA);
2907 
2908  /* set extension offset */
2909  lpszTemp = PathFindExtensionA(tempFileA);
2910  fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - tempFileA) + 1 : 0;
2911  }
2912 
2913  /* copy currently selected filter to lpstrCustomFilter */
2914  if (fodInfos->ofnInfos->lpstrCustomFilter)
2915  {
2917  int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2918  NULL, 0, NULL, NULL);
2920  {
2922  s += strlen(ofn->lpstrCustomFilter)+1;
2923  WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2924  s, len, NULL, NULL);
2925  }
2926  }
2927 
2928 
2929  if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2930  goto ret;
2931 
2932  FILEDLG95_MRU_save_filename(lpstrPathAndFile);
2933 
2934  TRACE("close\n");
2936  ret = EndDialog(hwnd, TRUE);
2937  }
2938  else
2939  {
2940  WORD size;
2941 
2942  size = lstrlenW(lpstrPathAndFile) + 1;
2943  if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2944  size += 1;
2945  /* return needed size in first two bytes of lpstrFile */
2946  if(fodInfos->ofnInfos->lpstrFile)
2947  *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2949  ret = EndDialog(hwnd, FALSE);
2951  }
2952  }
2953  break;
2954  }
2955 
2956 ret:
2957  if(lpsf) IShellFolder_Release(lpsf);
2958  return ret;
2959 }
2960 
2961 /***********************************************************************
2962  * FILEDLG95_SHELL_Init
2963  *
2964  * Initialisation of the shell objects
2965  */
2967 {
2969 
2970  TRACE("%p\n", hwnd);
2971 
2972  /*
2973  * Initialisation of the FileOpenDialogInfos structure
2974  */
2975 
2976  /* Shell */
2977 
2978  /*ShellInfos */
2979  fodInfos->ShellInfos.hwndOwner = hwnd;
2980 
2981  /* Disable multi-select if flag not set */
2982  if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2983  {
2984  fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2985  }
2986  fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2987  fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2988 
2989  /* Construct the IShellBrowser interface */
2990  fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2991 
2992  return NOERROR;
2993 }
2994 
2995 /***********************************************************************
2996  * FILEDLG95_SHELL_ExecuteCommand
2997  *
2998  * Change the folder option and refresh the view
2999  * If the function succeeds, the return value is nonzero.
3000  */
3002 {
3004  IContextMenu * pcm;
3005 
3006  TRACE("(%p,%p)\n", hwnd, lpVerb);
3007 
3008  if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
3009  SVGIO_BACKGROUND,
3010  &IID_IContextMenu,
3011  (LPVOID*)&pcm)))
3012  {
3013  CMINVOKECOMMANDINFO ci;
3014  ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
3015  ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
3016  ci.lpVerb = lpVerb;
3017  ci.hwnd = hwnd;
3018 
3019  IContextMenu_InvokeCommand(pcm, &ci);
3020  IContextMenu_Release(pcm);
3021  }
3022 
3023  return FALSE;
3024 }
3025 
3026 /***********************************************************************
3027  * FILEDLG95_SHELL_UpFolder
3028  *
3029  * Browse to the specified object
3030  * If the function succeeds, the return value is nonzero.
3031  */
3033 {
3035 
3036  TRACE("\n");
3037 
3038  if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3039  NULL,
3040  SBSP_PARENT)))
3041  {
3042  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3044  return TRUE;
3045  }
3046  return FALSE;
3047 }
3048 /***********************************************************************
3049  * FILEDLG95_SHELL_Clean
3050  *
3051  * Cleans the memory used by shell objects
3052  */
3054 {
3056 
3057  TRACE("\n");
3058 
3059  ILFree(fodInfos->ShellInfos.pidlAbsCurrent);
3060 
3061  /* clean Shell interfaces */
3062  if (fodInfos->Shell.FOIShellView)
3063  {
3064  IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
3065  IShellView_Release(fodInfos->Shell.FOIShellView);
3066  }
3067  if (fodInfos->Shell.FOIShellFolder)
3068  IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
3069  IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
3070  if (fodInfos->Shell.FOIDataObject)
3071  IDataObject_Release(fodInfos->Shell.FOIDataObject);
3072 }
3073 
3074 /***********************************************************************
3075  * FILEDLG95_FILETYPE_Init
3076  *
3077  * Initialisation of the file type combo box
3078  */
3080 {
3082  int nFilters = 0; /* number of filters */
3083  int nFilterIndexCB;
3084 
3085  TRACE("%p\n", hwnd);
3086 
3087  if(fodInfos->customfilter)
3088  {
3089  /* customfilter has one entry... title\0ext\0
3090  * Set first entry of combo box item with customfilter
3091  */
3092  LPWSTR lpstrExt;
3093  LPCWSTR lpstrPos = fodInfos->customfilter;
3094 
3095  /* Get the title */
3096  lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
3097 
3098  /* Copy the extensions */
3099  if (! *lpstrPos) return E_FAIL; /* malformed filter */
3100  if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3101  lstrcpyW(lpstrExt,lpstrPos);
3102 
3103  /* Add the item at the end of the combo */
3104  SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)fodInfos->customfilter);
3105  SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters, (LPARAM)lpstrExt);
3106 
3107  nFilters++;
3108  }
3109  if(fodInfos->filter)
3110  {
3111  LPCWSTR lpstrPos = fodInfos->filter;
3112 
3113  for(;;)
3114  {
3115  /* filter is a list... title\0ext\0......\0\0
3116  * Set the combo item text to the title and the item data
3117  * to the ext
3118  */
3119  LPCWSTR lpstrDisplay;
3120  LPWSTR lpstrExt;
3121 
3122  /* Get the title */
3123  if(! *lpstrPos) break; /* end */
3124  lpstrDisplay = lpstrPos;
3125  lpstrPos += lstrlenW(lpstrPos) + 1;
3126 
3127  SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_ADDSTRING, 0, (LPARAM)lpstrDisplay);
3128 
3129  nFilters++;
3130 
3131  /* Copy the extensions */
3132  if (!(lpstrExt = heap_alloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
3133  lstrcpyW(lpstrExt,lpstrPos);
3134  lpstrPos += lstrlenW(lpstrPos) + 1;
3135 
3136  /* Add the item at the end of the combo */
3137  SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETITEMDATA, nFilters - 1, (LPARAM)lpstrExt);
3138 
3139  /* malformed filters are added anyway... */
3140  if (!*lpstrExt) break;
3141  }
3142  }
3143 
3144  /*
3145  * Set the current filter to the one specified
3146  * in the initialisation structure
3147  */
3148  if (fodInfos->filter || fodInfos->customfilter)
3149  {
3150  LPWSTR lpstrFilter;
3151 
3152  /* Check to make sure our index isn't out of bounds. */
3153  if ( fodInfos->ofnInfos->nFilterIndex >
3154  nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
3155  fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
3156 
3157  /* set default filter index */
3158  if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
3159  fodInfos->ofnInfos->nFilterIndex = 1;
3160 
3161  /* calculate index of Combo Box item */
3162  nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
3163  if (fodInfos->customfilter == NULL)
3164  nFilterIndexCB--;
3165 
3166  /* Set the current index selection. */
3167  SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_SETCURSEL, nFilterIndexCB, 0);
3168 
3169  /* Get the corresponding text string from the combo box. */
3170  lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3171  nFilterIndexCB);
3172 
3173  if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
3174  lpstrFilter = NULL;
3175 
3176  if(lpstrFilter)
3177  {
3178  DWORD len;
3179  CharLowerW(lpstrFilter); /* lowercase */
3180  len = lstrlenW(lpstrFilter)+1;
3181  fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3182  lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3183  }
3184  } else
3185  fodInfos->ofnInfos->nFilterIndex = 0;
3186  return S_OK;
3187 }
3188 
3189 /***********************************************************************
3190  * FILEDLG95_FILETYPE_OnCommand
3191  *
3192  * WM_COMMAND of the file type combo box
3193  * If the function succeeds, the return value is nonzero.
3194  */
3196 {
3198 
3199  switch(wNotifyCode)
3200  {
3201  case CBN_SELENDOK:
3202  {
3203  LPWSTR lpstrFilter;
3204 
3205  /* Get the current item of the filetype combo box */
3206  int iItem = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCURSEL, 0, 0);
3207 
3208  /* set the current filter index */
3209  fodInfos->ofnInfos->nFilterIndex = iItem +
3210  (fodInfos->customfilter == NULL ? 1 : 0);
3211 
3212  /* Set the current filter with the current selection */
3213  heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3214 
3215  lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
3216  iItem);
3217  if((INT_PTR)lpstrFilter != CB_ERR)
3218  {
3219  DWORD len;
3220  CharLowerW(lpstrFilter); /* lowercase */
3221  len = lstrlenW(lpstrFilter)+1;
3222  fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len * sizeof(WCHAR) );
3223  lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
3224  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3226  }
3227 
3228  /* Refresh the actual view to display the included items*/
3229  if (fodInfos->Shell.FOIShellView)
3230  IShellView_Refresh(fodInfos->Shell.FOIShellView);
3231  }
3232  }
3233  return FALSE;
3234 }
3235 /***********************************************************************
3236  * FILEDLG95_FILETYPE_SearchExt
3237  *
3238  * searches for an extension in the filetype box
3239  */
3241 {
3242  int i, iCount;
3243 
3244  iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3245 
3246  TRACE("%s\n", debugstr_w(lpstrExt));
3247 
3248  if(iCount != CB_ERR)
3249  {
3250  for(i=0;i<iCount;i++)
3251  {
3252  if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
3253  return i;
3254  }
3255  }
3256  return -1;
3257 }
3258 
3259 /***********************************************************************
3260  * FILEDLG95_FILETYPE_Clean
3261  *
3262  * Clean the memory used by the filetype combo box
3263  */
3265 {
3267  int iPos;
3268  int iCount;
3269 
3270  iCount = SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_GETCOUNT, 0, 0);
3271 
3272  TRACE("\n");
3273 
3274  /* Delete each string of the combo and their associated data */
3275  if(iCount != CB_ERR)
3276  {
3277  for(iPos = iCount-1;iPos>=0;iPos--)
3278  {
3279  heap_free((void *)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
3280  SendMessageW(fodInfos->DlgInfos.hwndFileTypeCB, CB_DELETESTRING, iPos, 0);
3281  }
3282  }
3283  /* Current filter */
3284  heap_free(fodInfos->ShellInfos.lpstrCurrentFilter);
3285 }
3286 
3287 /***********************************************************************
3288  * FILEDLG95_LOOKIN_Init
3289  *
3290  * Initialisation of the look in combo box
3291  */
3292 
3293 /* Small helper function, to determine if the unixfs shell extension is rooted
3294  * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
3295  */
3297  HKEY hKey;
3298  static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
3299  'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
3300  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3301  'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
3302  'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
3303  '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
3304  '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
3305 
3306  if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
3307  return FALSE;
3308 
3309  RegCloseKey(hKey);
3310  return TRUE;
3311 }
3312 
3313 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
3314 {
3315  IShellFolder *psfRoot, *psfDrives;
3316  IEnumIDList *lpeRoot, *lpeDrives;
3317  LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
3318  HDC hdc;
3319  TEXTMETRICW tm;
3320  LookInInfos *liInfos = heap_alloc_zero(sizeof(*liInfos));
3321 
3322  TRACE("%p\n", hwndCombo);
3323 
3324  liInfos->iMaxIndentation = 0;
3325 
3326  SetPropA(hwndCombo, LookInInfosStr, liInfos);
3327 
3328  hdc = GetDC( hwndCombo );
3329  SelectObject( hdc, (HFONT)SendMessageW( hwndCombo, WM_GETFONT, 0, 0 ));
3330  GetTextMetricsW( hdc, &tm );
3331  ReleaseDC( hwndCombo, hdc );
3332 
3333  /* set item height for both text field and listbox */
3334  SendMessageW(hwndCombo, CB_SETITEMHEIGHT, -1, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3335  SendMessageW(hwndCombo, CB_SETITEMHEIGHT, 0, max(tm.tmHeight, GetSystemMetrics(SM_CYSMICON)));
3336 
3337  /* Turn on the extended UI for the combo box like Windows does */
3338  SendMessageW(hwndCombo, CB_SETEXTENDEDUI, TRUE, 0);
3339 
3340  /* Initialise data of Desktop folder */
3342  FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3343  ILFree(pidlTmp);
3344 
3346 
3347  SHGetDesktopFolder(&psfRoot);
3348 
3349  if (psfRoot)
3350  {
3351  /* enumerate the contents of the desktop */
3352  if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
3353  {
3354  while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
3355  {
3356  FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
3357 
3358  /* If the unixfs extension is rooted, we don't expand the drives by default */
3360  {
3361  /* special handling for CSIDL_DRIVES */
3362  if (ILIsEqual(pidlTmp, pidlDrives))
3363  {
3364  if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
3365  {
3366  /* enumerate the drives */
3367  if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
3368  {
3369  while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
3370  {
3371  pidlAbsTmp = ILCombine(pidlTmp, pidlTmp1);
3372  FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
3373  ILFree(pidlAbsTmp);
3374  ILFree(pidlTmp1);
3375  }
3376  IEnumIDList_Release(lpeDrives);
3377  }
3378  IShellFolder_Release(psfDrives);
3379  }
3380  }
3381  }
3382 
3383  ILFree(pidlTmp);
3384  }
3385  IEnumIDList_Release(lpeRoot);
3386  }
3387  IShellFolder_Release(psfRoot);
3388  }
3389 
3390  ILFree(pidlDrives);
3391 }
3392 
3393 /***********************************************************************
3394  * FILEDLG95_LOOKIN_DrawItem
3395  *
3396  * WM_DRAWITEM message handler
3397  */
3399 {
3401  COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
3403  RECT rectText;
3404  RECT rectIcon;
3405  SHFILEINFOW sfi;
3406  HIMAGELIST ilItemImage;
3407  int iIndentation;
3408  TEXTMETRICW tm;
3409  LPSFOLDER tmpFolder;
3411  UINT icon_width, icon_height;
3412 
3413  TRACE("\n");
3414 
3415  if(pDIStruct->itemID == -1)
3416  return 0;
3417 
3418  if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
3419  pDIStruct->itemID)))
3420  return 0;
3421 
3422 
3423  icon_width = GetSystemMetrics(SM_CXICON);
3424  icon_height = GetSystemMetrics(SM_CYICON);
3425  if (pDIStruct->rcItem.bottom - pDIStruct->rcItem.top < icon_height)
3426  {
3427  icon_width = GetSystemMetrics(SM_CXSMICON);
3428  icon_height = GetSystemMetrics(SM_CYSMICON);
3429  shgfi_flags |= SHGFI_SMALLICON;
3430  }
3431 
3432  ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
3433  0, &sfi, sizeof (sfi), shgfi_flags );
3434 
3435  /* Is this item selected ? */
3436  if(pDIStruct->itemState & ODS_SELECTED)
3437  {
3438  SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
3439  SetBkColor(pDIStruct->hDC,crHighLight);
3440  FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
3441  }
3442  else
3443  {
3444  SetTextColor(pDIStruct->hDC,crText);
3445  SetBkColor(pDIStruct->hDC,crWin);
3446  FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
3447  }
3448 
3449  /* Do not indent item if drawing in the edit of the combo */
3450  if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
3451  iIndentation = 0;
3452  else
3453  iIndentation = tmpFolder->m_iIndent;
3454 
3455  /* Draw text and icon */
3456 
3457  /* Initialise the icon display area */
3458  rectIcon.left = pDIStruct->rcItem.left + 1 + icon_width/2 * iIndentation;
3459  rectIcon.top = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - icon_height) / 2;
3460  rectIcon.right = rectIcon.left + icon_width + XTEXTOFFSET;
3461  rectIcon.bottom = (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + icon_height) / 2;
3462 
3463  /* Initialise the text display area */
3464  GetTextMetricsW(pDIStruct->hDC, &tm);
3465  rectText.left = rectIcon.right;
3466  rectText.top =
3467  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
3468  rectText.right = pDIStruct->rcItem.right;
3469  rectText.bottom =
3470  (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
3471 
3472  /* Draw the icon from the image list */
3473  ImageList_Draw(ilItemImage,
3474  sfi.iIcon,
3475  pDIStruct->hDC,
3476  rectIcon.left,
3477  rectIcon.top,
3478  ILD_TRANSPARENT );
3479 
3480  /* Draw the associated text */
3481  TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3482  return NOERROR;
3483 }
3484 
3485 /***********************************************************************
3486  * FILEDLG95_LOOKIN_OnCommand
3487  *
3488  * LookIn combo box WM_COMMAND message handler
3489  * If the function succeeds, the return value is nonzero.
3490  */
3492 {
3494 
3495  TRACE("%p\n", fodInfos);
3496 
3497  switch(wNotifyCode)
3498  {
3499  case CBN_SELENDOK:
3500  {
3501  LPSFOLDER tmpFolder;
3502  int iItem;
3503 
3504  iItem = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCURSEL, 0, 0);
3505 
3506  if( iItem == CB_ERR) return FALSE;
3507 
3508  if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3509  iItem)))
3510  return FALSE;
3511 
3512 
3513  if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3514  tmpFolder->pidlItem,
3515  SBSP_ABSOLUTE)))
3516  {
3517  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3519  return TRUE;
3520  }
3521  break;
3522  }
3523 
3524  }
3525  return FALSE;
3526 }
3527 
3528 /***********************************************************************
3529  * FILEDLG95_LOOKIN_AddItem
3530  *
3531  * Adds an absolute pidl item to the lookin combo box
3532  * returns the index of the inserted item
3533  */
3534 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3535 {
3536  LPITEMIDLIST pidlNext;
3537  SHFILEINFOW sfi;
3538  SFOLDER *tmpFolder;
3539  LookInInfos *liInfos;
3540 
3541  TRACE("%p, %p, %d\n", hwnd, pidl, iInsertId);
3542 
3543  if(!pidl)
3544  return -1;
3545 
3546  if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3547  return -1;
3548 
3549  tmpFolder = heap_alloc_zero(sizeof(*tmpFolder));
3550  tmpFolder->m_iIndent = 0;
3551 
3552  /* Calculate the indentation of the item in the lookin*/
3553  pidlNext = pidl;
3554  while ((pidlNext = ILGetNext(pidlNext)))
3555  {
3556  tmpFolder->m_iIndent++;
3557  }
3558 
3559  tmpFolder->pidlItem = ILClone(pidl);
3560 
3561  if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3562  liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3563 
3564  sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3565  SHGetFileInfoW((LPCWSTR)pidl,
3566  0,
3567  &sfi,
3568  sizeof(sfi),
3570 
3571  TRACE("-- Add %s attr=0x%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3572 
3573  if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3574  {
3575  int iItemID;
3576 
3577  TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3578 
3579  /* Add the item at the end of the list */
3580  if(iInsertId < 0)
3581  {
3582  iItemID = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)sfi.szDisplayName);
3583  }
3584  /* Insert the item at the iInsertId position*/
3585  else
3586  {
3587  iItemID = SendMessageW(hwnd, CB_INSERTSTRING, iInsertId, (LPARAM)sfi.szDisplayName);
3588  }
3589 
3590  SendMessageW(hwnd, CB_SETITEMDATA, iItemID, (LPARAM)tmpFolder);
3591  return iItemID;
3592  }
3593 
3594  ILFree( tmpFolder->pidlItem );
3595  heap_free( tmpFolder );
3596  return -1;
3597 
3598 }
3599 
3600 /***********************************************************************
3601  * FILEDLG95_LOOKIN_InsertItemAfterParent
3602  *
3603  * Insert an item below its parent
3604  */
3606 {
3607 
3608  LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3609  int iParentPos;
3610 
3611  TRACE("\n");
3612 
3613  if (pidl == pidlParent)
3614  return -1;
3615 
3616  iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3617 
3618  if(iParentPos < 0)
3619  {
3620  iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3621  }
3622 
3623  ILFree(pidlParent);
3624 
3625  return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3626 }
3627 
3628 /***********************************************************************
3629  * FILEDLG95_LOOKIN_SelectItem
3630  *
3631  * Adds an absolute pidl item to the lookin combo box
3632  * returns the index of the inserted item
3633  */
3635 {
3636  int iItemPos;
3637  LookInInfos *liInfos;
3638 
3639  TRACE("%p, %p\n", hwnd, pidl);
3640 
3642 
3643  liInfos = GetPropA(hwnd,LookInInfosStr);
3644 
3645  if(iItemPos < 0)
3646  {
3649  }
3650 
3651  else
3652  {
3653  SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3654  while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3655  {
3656  int iRemovedItem;
3657 
3658  if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3659  break;
3660  if(iRemovedItem < iItemPos)
3661  iItemPos--;
3662  }
3663  }
3664 
3665  SendMessageW(hwnd, CB_SETCURSEL, iItemPos, 0);
3666  liInfos->uSelectedItem = iItemPos;
3667 
3668  return 0;
3669 
3670 }
3671 
3672 /***********************************************************************
3673  * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3674  *
3675  * Remove the item with an expansion level over iExpansionLevel
3676  */
3678 {
3679  int iItemPos;
3681 
3682  TRACE("\n");
3683 
3684  if(liInfos->iMaxIndentation <= 2)
3685  return -1;
3686 
3687  if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3688  {
3689  SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3690  ILFree(tmpFolder->pidlItem);
3691  heap_free(tmpFolder);
3692  SendMessageW(hwnd, CB_DELETESTRING, iItemPos, 0);
3693  liInfos->iMaxIndentation--;
3694 
3695  return iItemPos;
3696  }
3697 
3698  return -1;
3699 }
3700 
3701 /***********************************************************************
3702  * FILEDLG95_LOOKIN_SearchItem
3703  *
3704  * Search for pidl in the lookin combo box
3705  * returns the index of the found item
3706  */
3707 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3708 {
3709  int i = 0;
3710  int iCount;
3711 
3712  iCount = SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
3713 
3714  TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3715 
3716  if (iCount != CB_ERR)
3717  {
3718  for(;i<iCount;i++)
3719  {
3720  LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3721 
3722  if (iSearchMethod == SEARCH_PIDL && ILIsEqual((LPITEMIDLIST)searchArg, tmpFolder->pidlItem))
3723  return i;
3724  if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3725  return i;
3726  }
3727  }
3728 
3729  return -1;
3730 }
3731 
3732 /***********************************************************************
3733  * FILEDLG95_LOOKIN_Clean
3734  *
3735  * Clean the memory used by the lookin combo box
3736  */
3738 {
3740  LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3741  int iPos, iCount;
3742 
3743  iCount = SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_GETCOUNT, 0, 0);
3744 
3745  TRACE("\n");
3746 
3747  /* Delete each string of the combo and their associated data */
3748  if (iCount != CB_ERR)
3749  {
3750  for(iPos = iCount-1;iPos>=0;iPos--)
3751  {
3752  SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3753  ILFree(tmpFolder->pidlItem);
3754  heap_free(tmpFolder);
3755  SendMessageW(fodInfos->DlgInfos.hwndLookInCB, CB_DELETESTRING, iPos, 0);
3756  }
3757  }
3758 
3759  /* LookInInfos structure */
3760  heap_free(liInfos);
3761  RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3762 }
3763 
3764 /***********************************************************************
3765  * get_def_format
3766  *
3767  * Fill the FORMATETC used in the shell id list
3768  */
3769 static FORMATETC get_def_format(void)
3770 {
3771  static CLIPFORMAT cfFormat;
3772  FORMATETC formatetc;
3773 
3774  if (!cfFormat) cfFormat = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
3775  formatetc.cfFormat = cfFormat;
3776  formatetc.ptd = 0;
3777  formatetc.dwAspect = DVASPECT_CONTENT;
3778  formatetc.lindex = -1;
3779  formatetc.tymed = TYMED_HGLOBAL;
3780  return formatetc;
3781 }
3782 
3783 /***********************************************************************
3784  * FILEDLG95_FILENAME_FillFromSelection
3785  *
3786  * fills the edit box from the cached DataObject
3787  */
3789 {
3791  LPITEMIDLIST pidl;
3792  LPWSTR lpstrAllFiles, lpstrTmp;
3793  UINT nFiles = 0, nFileToOpen, nFileSelected, nAllFilesLength = 0, nThisFileLength, nAllFilesMaxLength;
3794  STGMEDIUM medium;
3795  LPIDA cida;
3796  FORMATETC formatetc = get_def_format();
3797 
3798  TRACE("\n");
3799 
3800  if (FAILED(IDataObject_GetData(fodInfos->Shell.FOIDataObject, &formatetc, &medium)))
3801  return;
3802 
3803  cida = GlobalLock(medium.u.hGlobal);
3804  nFileSelected = cida->cidl;
3805 
3806  /* Allocate a buffer */
3807  nAllFilesMaxLength = MAX_PATH + 3;
3808  lpstrAllFiles = heap_alloc_zero(nAllFilesMaxLength * sizeof(WCHAR));
3809  if (!lpstrAllFiles)
3810  goto ret;
3811 
3812  /* Loop through the selection, handle only files (not folders) */
3813  for (nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++)
3814  {
3815  pidl = (LPITEMIDLIST)((LPBYTE)cida + cida->aoffset[nFileToOpen + 1]);
3816  if (pidl)
3817  {
3818  if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
3819  {
3820  if (nAllFilesLength + MAX_PATH + 3 > nAllFilesMaxLength)
3821  {
3822  nAllFilesMaxLength *= 2;
3823  lpstrTmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpstrAllFiles, nAllFilesMaxLength * sizeof(WCHAR));
3824  if (!lpstrTmp)
3825  goto ret;
3826  lpstrAllFiles = lpstrTmp;
3827  }
3828  nFiles += 1;
3829  lpstrAllFiles[nAllFilesLength++] = '"';
3830  GetName(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, lpstrAllFiles + nAllFilesLength);
3831  nThisFileLength = lstrlenW(lpstrAllFiles + nAllFilesLength);
3832  nAllFilesLength += nThisFileLength;
3833  lpstrAllFiles[nAllFilesLength++] = '"';
3834  lpstrAllFiles[nAllFilesLength++] = ' ';
3835  }
3836  }
3837  }
3838 
3839  if (nFiles != 0)
3840  {
3841  /* If there's only one file, use the name as-is without quotes */
3842  lpstrTmp = lpstrAllFiles;
3843  if (nFiles == 1)
3844  {
3845  lpstrTmp += 1;
3846  lpstrTmp[nThisFileLength] = 0;
3847  }
3848  SetWindowTextW(fodInfos->DlgInfos.hwndFileName, lpstrTmp);
3849  /* Select the file name like Windows does */
3850  if (filename_is_edit(fodInfos))
3851  SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
3852  }
3853 
3854 ret:
3855  heap_free(lpstrAllFiles);
3856  COMCTL32_ReleaseStgMedium(medium);
3857 }
3858 
3859 
3860 /* copied from shell32 to avoid linking to it
3861  * Although shell32 is already linked the behaviour of exported StrRetToStrN
3862  * is dependent on whether emulated OS is unicode or not.
3863  */
3865 {
3866  switch (src->uType)
3867  {
3868  case STRRET_WSTR:
3869  lstrcpynW(dest, src->u.pOleStr, len);
3870  CoTaskMemFree(src->u.pOleStr);
3871  break;
3872 
3873  case STRRET_CSTR:
3874  if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3875  dest[len-1] = 0;
3876  break;
3877 
3878  case STRRET_OFFSET:
3879  if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3880  dest[len-1] = 0;
3881  break;
3882 
3883  default:
3884  FIXME("unknown type %x!\n", src->uType);
3885  if (len) *dest = '\0';
3886  return E_FAIL;
3887  }
3888  return S_OK;
3889 }
3890 
3891 /***********************************************************************
3892  * FILEDLG95_FILENAME_GetFileNames
3893  *
3894  * Copies the filenames to a delimited string list.
3895  */
3896 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3897 {
3899  UINT nFileCount = 0; /* number of files */
3900  UINT nStrLen = 0; /* length of string in edit control */
3901  LPWSTR lpstrEdit; /* buffer for string from edit control */
3902 
3903  TRACE("\n");
3904 
3905  /* get the filenames from the filename control */
3906  nStrLen = GetWindowTextLengthW( fodInfos->DlgInfos.hwndFileName );
3907  lpstrEdit = heap_alloc( (nStrLen+1)*sizeof(WCHAR) );
3908  GetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrEdit, nStrLen+1);
3909 
3910  TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3911 
3912  nFileCount = COMDLG32_SplitFileNames(lpstrEdit, nStrLen, lpstrFileList, sizeUsed);
3913  heap_free(lpstrEdit);
3914  return nFileCount;
3915 }
3916 
3917 /*
3918  * DATAOBJECT Helper functions
3919  */
3920 
3921 /***********************************************************************
3922  * COMCTL32_ReleaseStgMedium
3923  *
3924  * like ReleaseStgMedium from ole32
3925  */
3926 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3927 {
3928  if(medium.pUnkForRelease)
3929  {
3930  IUnknown_Release(medium.pUnkForRelease);
3931  }
3932  else
3933  {
3934  GlobalUnlock(medium.u.hGlobal);
3935  GlobalFree(medium.u.hGlobal);
3936  }
3937 }
3938 
3939 /***********************************************************************
3940  * GetPidlFromDataObject
3941  *
3942  * Return pidl(s) by number from the cached DataObject
3943  *
3944  * nPidlIndex=0 gets the fully qualified root path
3945  */
3947 {
3948 
3949  STGMEDIUM medium;
3950  FORMATETC formatetc = get_def_format();
3951  LPITEMIDLIST pidl = NULL;
3952 
3953  TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3954 
3955  if (!doSelected)
3956  return NULL;
3957 
3958  /* Get the pidls from IDataObject */
3959  if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3960  {
3961  LPIDA cida = GlobalLock(medium.u.hGlobal);
3962  if(nPidlIndex <= cida->cidl)
3963  {
3964  pidl = ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3965  }
3966  COMCTL32_ReleaseStgMedium(medium);
3967  }
3968  return pidl;
3969 }
3970 
3971 /***********************************************************************
3972  * GetNumSelected
3973  *
3974  * Return the number of selected items in the DataObject.
3975  *
3976 */
3977 static UINT GetNumSelected( IDataObject *doSelected )
3978 {
3979  UINT retVal = 0;
3980  STGMEDIUM medium;
3981  FORMATETC formatetc = get_def_format();
3982 
3983  TRACE("sv=%p\n", doSelected);
3984 
3985  if (!doSelected) return 0;
3986 
3987  /* Get the pidls from IDataObject */
3988  if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3989  {
3990  LPIDA cida = GlobalLock(medium.u.hGlobal);
3991  retVal = cida->cidl;
3992  COMCTL32_ReleaseStgMedium(medium);
3993  return retVal;
3994  }
3995  return 0;
3996 }
3997 
3998 /*
3999  * TOOLS
4000  */
4001 
4002 /***********************************************************************
4003  * GetName
4004  *
4005  * Get the pidl's display name (relative to folder) and
4006  * put it in lpstrFileName.
4007  *
4008  * Return NOERROR on success,
4009  * E_FAIL otherwise
4010  */
4011 
4012 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
4013 {
4014  STRRET str;
4015  HRESULT hRes;
4016 
4017  TRACE("sf=%p pidl=%p\n", lpsf, pidl);
4018 
4019  if(!lpsf)
4020  {
4021  SHGetDesktopFolder(&lpsf);
4022  hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
4023  IShellFolder_Release(lpsf);
4024  return hRes;
4025  }
4026 
4027  /* Get the display name of the pidl relative to the folder */
4028  if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
4029  {
4030  return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
4031  }
4032  return E_FAIL;
4033 }
4034 
4035 /***********************************************************************
4036  * GetShellFolderFromPidl
4037  *
4038  * pidlRel is the item pidl relative
4039  * Return the IShellFolder of the absolute pidl
4040  */
4042 {
4043  IShellFolder *psf = NULL,*psfParent;
4044 
4045  TRACE("%p\n", pidlAbs);
4046 
4047  if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
4048  {
4049  psf = psfParent;
4050  if(pidlAbs && pidlAbs->mkid.cb)
4051  {
4052  if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
4053  {
4054  IShellFolder_Release(psfParent);
4055  return psf;
4056  }
4057  }
4058  /* return the desktop */
4059  return psfParent;
4060  }
4061  return NULL;
4062 }
4063 
4064 /***********************************************************************
4065  * GetParentPidl
4066  *
4067  * Return the LPITEMIDLIST to the parent of the pidl in the list
4068  */
4070 {
4071  LPITEMIDLIST pidlParent;
4072 
4073  TRACE("%p\n", pidl);
4074 
4075  pidlParent = ILClone(pidl);
4076  ILRemoveLastID(pidlParent);
4077 
4078  return pidlParent;
4079 }
4080 
4081 /***********************************************************************
4082  * GetPidlFromName
4083  *
4084  * returns the pidl of the file name relative to folder
4085  * NULL if an error occurred
4086  */
4087 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
4088 {
4089  LPITEMIDLIST pidl = NULL;
4090  ULONG ulEaten;
4091 
4092  TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
4093 
4094  if(!lpcstrFileName) return NULL;
4095  if(!*lpcstrFileName) return NULL;
4096 
4097  if(!lpsf)
4098  {
4099  if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
4100  IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4101  IShellFolder_Release(lpsf);
4102  }
4103  }
4104  else
4105  {
4106  IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
4107  }
4108  return pidl;
4109 }
4110 
4111 /*
4112 */
4113 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
4114 {
4115  ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
4116  HRESULT ret;
4117 
4118  TRACE("%p, %p\n", psf, pidl);
4119 
4120  ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
4121 
4122  TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
4123  /* see documentation shell 4.1*/
4124  return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
4125 }
4126 
4127 /***********************************************************************
4128  * BrowseSelectedFolder
4129  */
4131 {
4133  BOOL bBrowseSelFolder = FALSE;
4134 
4135  TRACE("\n");
4136 
4137  if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
4138  {
4139  LPITEMIDLIST pidlSelection;
4140 
4141  /* get the file selected */
4142  pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
4143  if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
4144  {
4145  if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
4146  pidlSelection, SBSP_RELATIVE ) ) )
4147  {
4148  WCHAR buf[64];
4150  MessageBoxW( hwnd, buf, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
4151  }
4152  bBrowseSelFolder = TRUE;
4153  if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
4155  }
4156  ILFree( pidlSelection );
4157  }
4158 
4159  return bBrowseSelFolder;
4160 }
4161 
4163 {
4164  return (size == OPENFILENAME_SIZE_VERSION_400W) ||
4165  (size == sizeof( OPENFILENAMEW ));
4166 }
4167 
4169 {
4171  !(flags & OFN_EXPLORER));
4172 }
4173 
4174 /* ------------------ APIs ---------------------- */
4175 
4176 /***********************************************************************
4177  * GetOpenFileNameA (COMDLG32.@)
4178  *
4179  * Creates a dialog box for the user to select a file to open.
4180  *
4181  * RETURNS
4182  * TRUE on success: user enters a valid file
4183  * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4184  *
4185  */
4187 {
4188  TRACE("flags 0x%08x\n", ofn->Flags);
4189 
4191  {
4193  return FALSE;
4194  }
4195 
4196  /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4197  if (ofn->Flags & OFN_FILEMUSTEXIST)
4199 
4200  if (is_win16_looks(ofn->Flags))
4201  return GetFileName31A(ofn, OPEN_DIALOG);
4202  else
4203  {
4205 
4207  return GetFileDialog95(&info, OPEN_DIALOG);
4208  }
4209 }
4210 
4211 /***********************************************************************
4212  * GetOpenFileNameW (COMDLG32.@)
4213  *
4214  * Creates a dialog box for the user to select a file to open.
4215  *
4216  * RETURNS
4217  * TRUE on success: user enters a valid file
4218  * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4219  *
4220  */
4222 {
4223  TRACE("flags 0x%08x\n", ofn->Flags);
4224 
4226  {
4228  return FALSE;
4229  }
4230 
4231  /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4232  if (ofn->Flags & OFN_FILEMUSTEXIST)
4234 
4235  if (is_win16_looks(ofn->Flags))
4236  return GetFileName31W(ofn, OPEN_DIALOG);
4237  else
4238  {
4240 
4242  return GetFileDialog95(&info, OPEN_DIALOG);
4243  }
4244 }
4245 
4246 
4247 /***********************************************************************
4248  * GetSaveFileNameA (COMDLG32.@)
4249  *
4250  * Creates a dialog box for the user to select a file to save.
4251  *
4252  * RETURNS
4253  * TRUE on success: user enters a valid file
4254  * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4255  *
4256  */
4258 {
4260  {
4262  return FALSE;
4263  }
4264 
4265  if (is_win16_looks(ofn->Flags))
4266  return GetFileName31A(ofn, SAVE_DIALOG);
4267  else
4268  {
4270 
4272  return GetFileDialog95(&info, SAVE_DIALOG);
4273  }
4274 }
4275 
4276 /***********************************************************************
4277  * GetSaveFileNameW (COMDLG32.@)
4278  *
4279  * Creates a dialog box for the user to select a file to save.
4280  *
4281  * RETURNS
4282  * TRUE on success: user enters a valid file
4283  * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4284  *
4285  */
4287  LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4288 {
4290  {
4292  return FALSE;
4293  }
4294 
4295  if (is_win16_looks(ofn->Flags))
4296  return GetFileName31W(ofn, SAVE_DIALOG);
4297  else
4298  {
4300 
4302  return GetFileDialog95(&info, SAVE_DIALOG);
4303  }
4304 }
4305 
4306 /***********************************************************************
4307  * GetFileTitleA (COMDLG32.@)
4308  *
4309  * See GetFileTitleW.
4310  */
4312 {
4313  int ret;
4314  UNICODE_STRING strWFile;
4315  LPWSTR lpWTitle;
4316 
4317  RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4318  lpWTitle = heap_alloc(cbBuf * sizeof(WCHAR));
4319  ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4320  if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4321  RtlFreeUnicodeString( &strWFile );
4322  heap_free( lpWTitle );
4323  return ret;
4324 }
4325 
4326 
4327 /***********************************************************************
4328  * GetFileTitleW (COMDLG32.@)
4329  *
4330  * Get the name of a file.
4331  *
4332  * PARAMS
4333  * lpFile [I] name and location of file
4334  * lpTitle [O] returned file name
4335  * cbBuf [I] buffer size of lpTitle
4336  *
4337  * RETURNS
4338  * Success: zero
4339  * Failure: negative number.
4340  */
4342 {
4343  int i, len;
4344  static const WCHAR brkpoint[] = {'*','[',']',0};
4345  TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4346 
4347  if(lpFile == NULL || lpTitle == NULL)
4348  return -1;
4349 
4350  len = lstrlenW(lpFile);
4351 
4352  if (len == 0)
4353  return -1;
4354 
4355  if(strpbrkW(lpFile, brkpoint))
4356  return -1;
4357 
4358  len--;
4359 
4360  if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4361  return -1;
4362 
4363  for(i = len; i >= 0; i--)
4364  {
4365  if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4366  {
4367  i++;
4368  break;
4369  }
4370  }
4371 
4372  if(i == -1)
4373  i++;
4374 
4375  TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4376 
4377  len = lstrlenW(lpFile+i)+1;
4378  if(cbBuf < len)
4379  return len;
4380 
4381  lstrcpyW(lpTitle, &lpFile[i]);
4382  return 0;
4383 }
LSTATUS WINAPI RegGetValueW(HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData)
Definition: reg.c:1975
static void init_filedlg_infoA(OPENFILENAMEA *ofn, FileOpenDlgInfos *info)
Definition: filedlg.c:493
#define GW_HWNDNEXT
Definition: winuser.h:756
#define WS_GROUP
Definition: pedump.c:633
#define WS_CLIPSIBLINGS
Definition: pedump.c:618
HIMAGELIST hImgList
Definition: filedlg.c:98
#define OFN_FILEMUSTEXIST
Definition: commdlg.h:106
#define MB_ICONHAND
Definition: winuser.h:782
POINT ptMinTrackSize
Definition: winuser.h:3572
#define IDC_TOOLBARPLACES
#define OFN_EXPLORER
Definition: commdlg.h:104
static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
Definition: filedlg.c:3313
#define WM_GETTEXTLENGTH
Definition: winuser.h:1601
HINSTANCE hInstance
Definition: commdlg.h:362
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
LONG WINAPI RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3272
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:607
#define SEARCH_EXP
Definition: filedlg.c:123
#define CB_SETITEMDATA
Definition: winuser.h:1927
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
#define WS_EX_WINDOWEDGE
Definition: winuser.h:407
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
HANDLE WINAPI RemovePropA(_In_ HWND, _In_ LPCSTR)
DWORD Flags
Definition: commdlg.h:373
static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
Definition: filedlg.c:2108
#define TB_SETBUTTONSIZE
Definition: commctrl.h:1107
static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl, DWORD dwFlags, LPWSTR lpstrFileName)
Definition: filedlg.c:4012
#define max(a, b)
Definition: svc.c:63
#define SHGFI_SYSICONINDEX
Definition: shellapi.h:169
#define VER_PLATFORM_WIN32_NT
Definition: rtltypes.h:236
#define IDS_NEWFOLDER
#define OFN_EX_NOPLACESBAR
Definition: commdlg.h:121
HDWP WINAPI BeginDeferWindowPos(_In_ int)
#define TB_BUTTONSTRUCTSIZE
Definition: commctrl.h:1106
#define CDN_FOLDERCHANGE
Definition: commdlg.h:35
#define SM_CYHSCROLL
Definition: winuser.h:952
#define TRUE
Definition: types.h:120
#define FCIDM_TB_REPORTVIEW
Definition: shresdef.h:766
BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
Definition: path.c:1558
#define IDOK
Definition: winuser.h:824
#define IDS_INVALID_FILENAME_TITLE
#define COLOR_HIGHLIGHT
Definition: winuser.h:916
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:925
LPCWSTR lpstrFilter
Definition: commdlg.h:363
LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath)
Definition: path.c:2558
DECLSPEC_HIDDEN HINSTANCE COMDLG32_hInstance
Definition: cdlg32.c:42
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:422
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
#define GW_CHILD
Definition: winuser.h:758
struct FileOpenDlgInfos::@326 ShellInfos
#define IDS_LISTVIEW
long y
Definition: polytest.cpp:48
void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
Definition: filedlg.c:2461
static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam)
Definition: filedlg.c:2030
static const char LookInInfosStr[]
Definition: filedlg.c:144
#define ERROR_SUCCESS
Definition: deptool.c:10
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
#define WideCharToMultiByte
Definition: compat.h:101
#define IDS_SAVE_AS
Definition: cdlg.h:177
HRESULT hr
Definition: shlfolder.c:183
#define CDERR_LOADRESFAILURE
Definition: cderr.h:12
WINE_DEFAULT_DEBUG_CHANNEL(commdlg)
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
LPSTR lpstrFileTitle
Definition: commdlg.h:338
#define NOERROR
Definition: winerror.h:2354
LPCWSTR lpstrInitialDir
Definition: commdlg.h:371
struct _slot slot
Definition: vfat.h:196
long x
Definition: polytest.cpp:48
#define LISTEND
Definition: filedlg.c:119
static LPCWSTR LPCWSTR module_name
Definition: db.cpp:168
DWORD dwAttributes
Definition: shellapi.h:372
struct SFolder SFOLDER
HDC WINAPI GetDC(_In_opt_ HWND)
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define REG_BINARY
Definition: nt_native.h:1496
BOOL WINAPI DestroyIcon(_In_ HICON)
Definition: cursoricon.c:2022
#define KEY_READ
Definition: nt_native.h:1023
BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath)
Definition: