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_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 *
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
45 *
46 *
47 */
48
49 #include "config.h"
50 #include "wine/port.h"
51
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
57
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winternl.h"
65 #include "winnls.h"
66 #include "wingdi.h"
67 #include "winreg.h"
68 #include "winuser.h"
69 #include "commdlg.h"
70 #include "dlgs.h"
71 #include "cdlg.h"
72 #include "filedlg31.h"
73 #include "cderr.h"
74 #include "shellapi.h"
75 #include "shlobj.h"
76 #include "filedlgbrowser.h"
77 #include "shlwapi.h"
78
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
81
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
89
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
94 */
95 typedef struct SFolder
96 {
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
101
102 } SFOLDER,*LPSFOLDER;
103
104 typedef struct tagLookInInfo
105 {
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
109
110 typedef struct tagFD32_PRIVATE
111 {
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
114
115
116 /***********************************************************************
117 * Defines and global variables
118 */
119
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
123
124 /* AddItem flags*/
125 #define LISTEND -1
126
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
131
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
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 CBAddString(hwnd,str) \
142 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
143
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
146
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
149
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
152
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
155
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
158
159 #define CBGetCurSel(hwnd) \
160 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
161
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
164
165 #define CBGetCount(hwnd) \
166 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
171
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
174
175 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
176 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
177
178 /***********************************************************************
179 * Prototypes
180 */
181
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
190
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
200
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
206
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
217
218 /* Miscellaneous tool functions */
219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
223 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
224 static UINT GetNumSelected( IDataObject *doSelected );
225
226 /* Shell memory allocation */
227 static void *MemAlloc(UINT size);
228 static void MemFree(void *mem);
229
230 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
232 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
233 static BOOL BrowseSelectedFolder(HWND hwnd);
234
235 /***********************************************************************
236 * GetFileName95
237 *
238 * Creates an Open common dialog box that lets the user select
239 * the drive, directory, and the name of a file or set of files to open.
240 *
241 * IN : The FileOpenDlgInfos structure associated with the dialog
242 * OUT : TRUE on success
243 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 */
245 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
246 {
247
248 LRESULT lRes;
249 LPCVOID template;
250 HRSRC hRes;
251 HANDLE hDlgTmpl = 0;
252 HRESULT hr;
253
254 /* test for missing functionality */
255 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 {
257 FIXME("Flags 0x%08x not yet implemented\n",
258 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 }
260
261 /* Create the dialog from a template */
262
263 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
264 {
265 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
266 return FALSE;
267 }
268 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
269 !(template = LockResource( hDlgTmpl )))
270 {
271 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
272 return FALSE;
273 }
274
275 /* old style hook messages */
276 if (IsHooked(fodInfos))
277 {
278 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
279 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
280 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
281 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
282 }
283
284 /* Some shell namespace extensions depend on COM being initialized. */
285 hr = OleInitialize(NULL);
286
287 if (fodInfos->unicode)
288 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
289 template,
290 fodInfos->ofnInfos->hwndOwner,
291 FileOpenDlgProc95,
292 (LPARAM) fodInfos);
293 else
294 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
295 (LPCDLGTEMPLATEA) template,
296 fodInfos->ofnInfos->hwndOwner,
297 FileOpenDlgProc95,
298 (LPARAM) fodInfos);
299 if (SUCCEEDED(hr))
300 OleUninitialize();
301
302 /* Unable to create the dialog */
303 if( lRes == -1)
304 return FALSE;
305
306 return lRes;
307 }
308
309 /***********************************************************************
310 * GetFileDialog95A
311 *
312 * Call GetFileName95 with this structure and clean the memory.
313 *
314 * IN : The OPENFILENAMEA initialisation structure passed to
315 * GetOpenFileNameA win api function (see filedlg.c)
316 */
317 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
318 {
319 BOOL ret;
320 FileOpenDlgInfos fodInfos;
321 LPSTR lpstrSavDir = NULL;
322 LPWSTR title = NULL;
323 LPWSTR defext = NULL;
324 LPWSTR filter = NULL;
325 LPWSTR customfilter = NULL;
326
327 /* Initialize CommDlgExtendedError() */
328 COMDLG32_SetCommDlgExtendedError(0);
329
330 /* Initialize FileOpenDlgInfos structure */
331 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
332
333 /* Pass in the original ofn */
334 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
335
336 /* save current directory */
337 if (ofn->Flags & OFN_NOCHANGEDIR)
338 {
339 lpstrSavDir = MemAlloc(MAX_PATH);
340 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 }
342
343 fodInfos.unicode = FALSE;
344
345 /* convert all the input strings to unicode */
346 if(ofn->lpstrInitialDir)
347 {
348 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
349 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
350 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
351 }
352 else
353 fodInfos.initdir = NULL;
354
355 if(ofn->lpstrFile)
356 {
357 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
358 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
359 }
360 else
361 fodInfos.filename = NULL;
362
363 if(ofn->lpstrDefExt)
364 {
365 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
366 defext = MemAlloc((len+1)*sizeof(WCHAR));
367 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
368 }
369 fodInfos.defext = defext;
370
371 if(ofn->lpstrTitle)
372 {
373 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
374 title = MemAlloc((len+1)*sizeof(WCHAR));
375 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
376 }
377 fodInfos.title = title;
378
379 if (ofn->lpstrFilter)
380 {
381 LPCSTR s;
382 int n, len;
383
384 /* filter is a list... title\0ext\0......\0\0 */
385 s = ofn->lpstrFilter;
386 while (*s) s = s+strlen(s)+1;
387 s++;
388 n = s - ofn->lpstrFilter;
389 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
390 filter = MemAlloc(len*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
392 }
393 fodInfos.filter = filter;
394
395 /* convert lpstrCustomFilter */
396 if (ofn->lpstrCustomFilter)
397 {
398 LPCSTR s;
399 int n, len;
400
401 /* customfilter contains a pair of strings... title\0ext\0 */
402 s = ofn->lpstrCustomFilter;
403 if (*s) s = s+strlen(s)+1;
404 if (*s) s = s+strlen(s)+1;
405 n = s - ofn->lpstrCustomFilter;
406 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
407 customfilter = MemAlloc(len*sizeof(WCHAR));
408 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
409 }
410 fodInfos.customfilter = customfilter;
411
412 /* Initialize the dialog property */
413 fodInfos.DlgInfos.dwDlgProp = 0;
414 fodInfos.DlgInfos.hwndCustomDlg = NULL;
415
416 switch(iDlgType)
417 {
418 case OPEN_DIALOG :
419 ret = GetFileName95(&fodInfos);
420 break;
421 case SAVE_DIALOG :
422 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
423 ret = GetFileName95(&fodInfos);
424 break;
425 default :
426 ret = 0;
427 }
428
429 if (lpstrSavDir)
430 {
431 SetCurrentDirectoryA(lpstrSavDir);
432 MemFree(lpstrSavDir);
433 }
434
435 MemFree(title);
436 MemFree(defext);
437 MemFree(filter);
438 MemFree(customfilter);
439 MemFree(fodInfos.initdir);
440 MemFree(fodInfos.filename);
441
442 TRACE("selected file: %s\n",ofn->lpstrFile);
443
444 return ret;
445 }
446
447 /***********************************************************************
448 * GetFileDialog95W
449 *
450 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
451 * Call GetFileName95 with this structure and clean the memory.
452 *
453 */
454 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
455 {
456 BOOL ret;
457 FileOpenDlgInfos fodInfos;
458 LPWSTR lpstrSavDir = NULL;
459
460 /* Initialize CommDlgExtendedError() */
461 COMDLG32_SetCommDlgExtendedError(0);
462
463 /* Initialize FileOpenDlgInfos structure */
464 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
465
466 /* Pass in the original ofn */
467 fodInfos.ofnInfos = ofn;
468
469 fodInfos.title = ofn->lpstrTitle;
470 fodInfos.defext = ofn->lpstrDefExt;
471 fodInfos.filter = ofn->lpstrFilter;
472 fodInfos.customfilter = ofn->lpstrCustomFilter;
473
474 /* convert string arguments, save others */
475 if(ofn->lpstrFile)
476 {
477 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
478 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
479 }
480 else
481 fodInfos.filename = NULL;
482
483 if(ofn->lpstrInitialDir)
484 {
485 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
486 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
487 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
488 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
489 }
490 else
491 fodInfos.initdir = NULL;
492
493 /* save current directory */
494 if (ofn->Flags & OFN_NOCHANGEDIR)
495 {
496 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
497 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
498 }
499
500 fodInfos.unicode = TRUE;
501
502 switch(iDlgType)
503 {
504 case OPEN_DIALOG :
505 ret = GetFileName95(&fodInfos);
506 break;
507 case SAVE_DIALOG :
508 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
509 ret = GetFileName95(&fodInfos);
510 break;
511 default :
512 ret = 0;
513 }
514
515 if (lpstrSavDir)
516 {
517 SetCurrentDirectoryW(lpstrSavDir);
518 MemFree(lpstrSavDir);
519 }
520
521 /* restore saved IN arguments and convert OUT arguments back */
522 MemFree(fodInfos.filename);
523 MemFree(fodInfos.initdir);
524 return ret;
525 }
526
527 /******************************************************************************
528 * COMDLG32_GetDisplayNameOf [internal]
529 *
530 * Helper function to get the display name for a pidl.
531 */
532 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
533 LPSHELLFOLDER psfDesktop;
534 STRRET strret;
535
536 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
537 return FALSE;
538
539 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
540 IShellFolder_Release(psfDesktop);
541 return FALSE;
542 }
543
544 IShellFolder_Release(psfDesktop);
545 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
546 }
547
548 /***********************************************************************
549 * ArrangeCtrlPositions [internal]
550 *
551 * NOTE: Do not change anything here without a lot of testing.
552 */
553 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
554 {
555 HWND hwndChild, hwndStc32;
556 RECT rectParent, rectChild, rectStc32;
557 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
558
559 /* Take into account if open as read only checkbox and help button
560 * are hidden
561 */
562 if (hide_help)
563 {
564 RECT rectHelp, rectCancel;
565 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
566 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
567 /* subtract the height of the help button plus the space between
568 * the help button and the cancel button to the height of the dialog
569 */
570 help_fixup = rectHelp.bottom - rectCancel.bottom;
571 }
572
573 /*
574 There are two possibilities to add components to the default file dialog box.
575
576 By default, all the new components are added below the standard dialog box (the else case).
577
578 However, if there is a static text component with the stc32 id, a special case happens.
579 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
580 in the window and the cx and cy indicate how to size the window.
581 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
582 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
583
584 */
585
586 GetClientRect(hwndParentDlg, &rectParent);
587
588 /* when arranging controls we have to use fixed parent size */
589 rectParent.bottom -= help_fixup;
590
591 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
592 if (hwndStc32)
593 {
594 GetWindowRect(hwndStc32, &rectStc32);
595 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
596
597 /* set the size of the stc32 control according to the size of
598 * client area of the parent dialog
599 */
600 SetWindowPos(hwndStc32, 0,
601 0, 0,
602 rectParent.right, rectParent.bottom,
603 SWP_NOMOVE | SWP_NOZORDER);
604 }
605 else
606 SetRectEmpty(&rectStc32);
607
608 /* this part moves controls of the child dialog */
609 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
610 while (hwndChild)
611 {
612 if (hwndChild != hwndStc32)
613 {
614 GetWindowRect(hwndChild, &rectChild);
615 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
616
617 /* move only if stc32 exist */
618 if (hwndStc32 && rectChild.left > rectStc32.right)
619 {
620 LONG old_left = rectChild.left;
621
622 /* move to the right of visible controls of the parent dialog */
623 rectChild.left += rectParent.right;
624 rectChild.left -= rectStc32.right;
625
626 child_width_fixup = rectChild.left - old_left;
627 }
628 /* move even if stc32 doesn't exist */
629 if (rectChild.top >= rectStc32.bottom)
630 {
631 LONG old_top = rectChild.top;
632
633 /* move below visible controls of the parent dialog */
634 rectChild.top += rectParent.bottom;
635 rectChild.top -= rectStc32.bottom - rectStc32.top;
636
637 child_height_fixup = rectChild.top - old_top;
638 }
639
640 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
641 0, 0, SWP_NOSIZE | SWP_NOZORDER);
642 }
643 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
644 }
645
646 /* this part moves controls of the parent dialog */
647 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
648 while (hwndChild)
649 {
650 if (hwndChild != hwndChildDlg)
651 {
652 GetWindowRect(hwndChild, &rectChild);
653 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
654
655 /* left,top of stc32 marks the position of controls
656 * from the parent dialog
657 */
658 rectChild.left += rectStc32.left;
659 rectChild.top += rectStc32.top;
660
661 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
662 0, 0, SWP_NOSIZE | SWP_NOZORDER);
663 }
664 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
665 }
666
667 /* calculate the size of the resulting dialog */
668
669 /* here we have to use original parent size */
670 GetClientRect(hwndParentDlg, &rectParent);
671 GetClientRect(hwndChildDlg, &rectChild);
672
673 if (hwndStc32)
674 {
675 rectChild.right += child_width_fixup;
676 rectChild.bottom += child_height_fixup;
677
678 if (rectParent.right > rectChild.right)
679 {
680 rectParent.right += rectChild.right;
681 rectParent.right -= rectStc32.right - rectStc32.left;
682 }
683 else
684 {
685 rectParent.right = rectChild.right;
686 }
687
688 if (rectParent.bottom > rectChild.bottom)
689 {
690 rectParent.bottom += rectChild.bottom;
691 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
692 }
693 else
694 {
695 /* child dialog is higher, unconditionally set new dialog
696 * height to its size (help_fixup will be subtracted below)
697 */
698 rectParent.bottom = rectChild.bottom + help_fixup;
699 }
700 }
701 else
702 {
703 rectParent.bottom += rectChild.bottom;
704 }
705
706 /* finally use fixed parent size */
707 rectParent.bottom -= help_fixup;
708
709 /* set the size of the parent dialog */
710 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
711 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
712 SetWindowPos(hwndParentDlg, 0,
713 0, 0,
714 rectParent.right - rectParent.left,
715 rectParent.bottom - rectParent.top,
716 SWP_NOMOVE | SWP_NOZORDER);
717 }
718
719 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
720 {
721 switch(uMsg) {
722 case WM_INITDIALOG:
723 return TRUE;
724 }
725 return FALSE;
726 }
727
728 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
729 {
730 LPCVOID template;
731 HRSRC hRes;
732 HANDLE hDlgTmpl = 0;
733 HWND hChildDlg = 0;
734
735 TRACE("\n");
736
737 /*
738 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
739 * structure's hInstance parameter is not a HINSTANCE, but
740 * instead a pointer to a template resource to use.
741 */
742 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
743 {
744 HINSTANCE hinst;
745 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
746 {
747 hinst = COMDLG32_hInstance;
748 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
749 {
750 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
751 return NULL;
752 }
753 }
754 else
755 {
756 hinst = fodInfos->ofnInfos->hInstance;
757 if(fodInfos->unicode)
758 {
759 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
760 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
761 }
762 else
763 {
764 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
765 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
766 }
767 if (!hRes)
768 {
769 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
770 return NULL;
771 }
772 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
773 !(template = LockResource( hDlgTmpl )))
774 {
775 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
776 return NULL;
777 }
778 }
779 if (fodInfos->unicode)
780 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
781 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
782 (LPARAM)fodInfos->ofnInfos);
783 else
784 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
785 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
786 (LPARAM)fodInfos->ofnInfos);
787 if(hChildDlg)
788 {
789 ShowWindow(hChildDlg,SW_SHOW);
790 return hChildDlg;
791 }
792 }
793 else if( IsHooked(fodInfos))
794 {
795 RECT rectHwnd;
796 struct {
797 DLGTEMPLATE tmplate;
798 WORD menu,class,title;
799 } temp;
800 GetClientRect(hwnd,&rectHwnd);
801 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
802 temp.tmplate.dwExtendedStyle = 0;
803 temp.tmplate.cdit = 0;
804 temp.tmplate.x = 0;
805 temp.tmplate.y = 0;
806 temp.tmplate.cx = 0;
807 temp.tmplate.cy = 0;
808 temp.menu = temp.class = temp.title = 0;
809
810 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
811 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
812
813 return hChildDlg;
814 }
815 return NULL;
816 }
817
818 /***********************************************************************
819 * SendCustomDlgNotificationMessage
820 *
821 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
822 */
823
824 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
825 {
826 LRESULT hook_result = 0;
827 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
828
829 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
830
831 if(!fodInfos) return 0;
832
833 if(fodInfos->DlgInfos.hwndCustomDlg)
834 {
835 TRACE("CALL NOTIFY for %x\n", uCode);
836 if(fodInfos->unicode)
837 {
838 OFNOTIFYW ofnNotify;
839 ofnNotify.hdr.hwndFrom=hwndParentDlg;
840 ofnNotify.hdr.idFrom=0;
841 ofnNotify.hdr.code = uCode;
842 ofnNotify.lpOFN = fodInfos->ofnInfos;
843 ofnNotify.pszFile = NULL;
844 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
845 }
846 else
847 {
848 OFNOTIFYA ofnNotify;
849 ofnNotify.hdr.hwndFrom=hwndParentDlg;
850 ofnNotify.hdr.idFrom=0;
851 ofnNotify.hdr.code = uCode;
852 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
853 ofnNotify.pszFile = NULL;
854 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
855 }
856 TRACE("RET NOTIFY\n");
857 }
858 TRACE("Retval: 0x%08lx\n", hook_result);
859 return hook_result;
860 }
861
862 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
863 {
864 UINT len, total;
865 WCHAR *p, *buffer;
866 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
867
868 TRACE("CDM_GETFILEPATH:\n");
869
870 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
871 return -1;
872
873 /* get path and filenames */
874 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
875 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
876 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
877 if (len)
878 {
879 p = buffer + strlenW(buffer);
880 *p++ = '\\';
881 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
882 }
883 if (fodInfos->unicode)
884 {
885 total = strlenW( buffer) + 1;
886 if (result) lstrcpynW( result, buffer, size );
887 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
888 }
889 else
890 {
891 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
892 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
893 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
894 }
895 HeapFree( GetProcessHeap(), 0, buffer );
896 return total;
897 }
898
899 /***********************************************************************
900 * FILEDLG95_HandleCustomDialogMessages
901 *
902 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
903 */
904 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
905 {
906 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
907 WCHAR lpstrPath[MAX_PATH];
908 INT_PTR retval;
909
910 if(!fodInfos) return FALSE;
911
912 switch(uMsg)
913 {
914 case CDM_GETFILEPATH:
915 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
916 break;
917
918 case CDM_GETFOLDERPATH:
919 TRACE("CDM_GETFOLDERPATH:\n");
920 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
921 if (lParam)
922 {
923 if (fodInfos->unicode)
924 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
925 else
926 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
927 (LPSTR)lParam, (int)wParam, NULL, NULL);
928 }
929 retval = lstrlenW(lpstrPath);
930 break;
931
932 case CDM_GETFOLDERIDLIST:
933 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
934 if (retval <= wParam)
935 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
936 break;
937
938 case CDM_GETSPEC:
939 TRACE("CDM_GETSPEC:\n");
940 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
941 if (lParam)
942 {
943 if (fodInfos->unicode)
944 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
945 else
946 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
947 }
948 break;
949
950 case CDM_SETCONTROLTEXT:
951 TRACE("CDM_SETCONTROLTEXT:\n");
952 if ( lParam )
953 {
954 if( fodInfos->unicode )
955 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
956 else
957 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
958 }
959 retval = TRUE;
960 break;
961
962 case CDM_HIDECONTROL:
963 /* MSDN states that it should fail for not OFN_EXPLORER case */
964 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
965 {
966 HWND control = GetDlgItem( hwnd, wParam );
967 if (control) ShowWindow( control, SW_HIDE );
968 retval = TRUE;
969 }
970 else retval = FALSE;
971 break;
972
973 default:
974 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
975 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
976 return FALSE;
977 }
978 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
979 return TRUE;
980 }
981
982 /***********************************************************************
983 * FileOpenDlgProc95
984 *
985 * File open dialog procedure
986 */
987 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
988 {
989 #if 0
990 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
991 #endif
992
993 switch(uMsg)
994 {
995 case WM_INITDIALOG:
996 {
997 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
998
999 /* Adds the FileOpenDlgInfos in the property list of the dialog
1000 so it will be easily accessible through a GetPropA(...) */
1001 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1002
1003 FILEDLG95_InitControls(hwnd);
1004
1005 fodInfos->DlgInfos.hwndCustomDlg =
1006 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1007
1008 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1009 FILEDLG95_FillControls(hwnd, wParam, lParam);
1010
1011 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1012 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1013 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1014 return 0;
1015 }
1016 case WM_COMMAND:
1017 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1018 case WM_DRAWITEM:
1019 {
1020 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1021 {
1022 case IDC_LOOKIN:
1023 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1024 return TRUE;
1025 }
1026 }
1027 return FALSE;
1028
1029 case WM_GETISHELLBROWSER:
1030 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1031
1032 case WM_DESTROY:
1033 RemovePropA(hwnd, FileOpenDlgInfosStr);
1034 return FALSE;
1035
1036 case WM_NOTIFY:
1037 {
1038 LPNMHDR lpnmh = (LPNMHDR)lParam;
1039 UINT stringId = -1;
1040
1041 /* set up the button tooltips strings */
1042 if(TTN_GETDISPINFOA == lpnmh->code )
1043 {
1044 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1045 switch(lpnmh->idFrom )
1046 {
1047 /* Up folder button */
1048 case FCIDM_TB_UPFOLDER:
1049 stringId = IDS_UPFOLDER;
1050 break;
1051 /* New folder button */
1052 case FCIDM_TB_NEWFOLDER:
1053 stringId = IDS_NEWFOLDER;
1054 break;
1055 /* List option button */
1056 case FCIDM_TB_SMALLICON:
1057 stringId = IDS_LISTVIEW;
1058 break;
1059 /* Details option button */
1060 case FCIDM_TB_REPORTVIEW:
1061 stringId = IDS_REPORTVIEW;
1062 break;
1063 /* Desktop button */
1064 case FCIDM_TB_DESKTOP:
1065 stringId = IDS_TODESKTOP;
1066 break;
1067 default:
1068 stringId = 0;
1069 }
1070 lpdi->hinst = COMDLG32_hInstance;
1071 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1072 }
1073 return FALSE;
1074 }
1075 default :
1076 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1077 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1078 return FALSE;
1079 }
1080 }
1081
1082 /***********************************************************************
1083 * FILEDLG95_InitControls
1084 *
1085 * WM_INITDIALOG message handler (before hook notification)
1086 */
1087 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1088 {
1089 int win2000plus = 0;
1090 int win98plus = 0;
1091 int handledPath = FALSE;
1092 OSVERSIONINFOW osVi;
1093 static const WCHAR szwSlash[] = { '\\', 0 };
1094 static const WCHAR szwStar[] = { '*',0 };
1095
1096 static const TBBUTTON tbb[] =
1097 {
1098 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1099 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1100 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1101 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1102 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1103 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1104 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1105 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1106 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1107 };
1108 TBADDBITMAP tba[2];
1109 RECT rectTB;
1110 RECT rectlook;
1111 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1112
1113 tba[0].hInst = HINST_COMMCTRL;
1114 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1115 tba[1].hInst = COMDLG32_hInstance;
1116 tba[1].nID = 800;
1117
1118 TRACE("%p\n", fodInfos);
1119
1120 /* Get windows version emulating */
1121 osVi.dwOSVersionInfoSize = sizeof(osVi);
1122 GetVersionExW(&osVi);
1123 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1124 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1125 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1126 win2000plus = (osVi.dwMajorVersion > 4);
1127 if (win2000plus) win98plus = TRUE;
1128 }
1129 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1130
1131 /* Get the hwnd of the controls */
1132 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1133 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1134 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1135
1136 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1137 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1138
1139 /* construct the toolbar */
1140 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1141 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1142
1143 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1144 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1145 rectTB.left = rectlook.right;
1146 rectTB.top = rectlook.top-1;
1147
1148 if (fodInfos->unicode)
1149 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1150 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1151 rectTB.left, rectTB.top,
1152 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1153 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1154 else
1155 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1156 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1157 rectTB.left, rectTB.top,
1158 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1159 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1160
1161 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1162
1163 /* FIXME: use TB_LOADIMAGES when implemented */
1164 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1165 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1166 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1167
1168 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1169 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1170
1171 /* Set the window text with the text specified in the OPENFILENAME structure */
1172 if(fodInfos->title)
1173 {
1174 SetWindowTextW(hwnd,fodInfos->title);
1175 }
1176 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1177 {
1178 WCHAR buf[16];
1179 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1180 SetWindowTextW(hwnd, buf);
1181 }
1182
1183 /* Initialise the file name edit control */
1184 handledPath = FALSE;
1185 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1186
1187 if(fodInfos->filename)
1188 {
1189 /* 1. If win2000 or higher and filename contains a path, use it
1190 in preference over the lpstrInitialDir */
1191 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1192 WCHAR tmpBuf[MAX_PATH];
1193 WCHAR *nameBit;
1194 DWORD result;
1195
1196 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1197 if (result) {
1198
1199 /* nameBit is always shorter than the original filename */
1200 lstrcpyW(fodInfos->filename,nameBit);
1201
1202 *nameBit = 0x00;
1203 if (fodInfos->initdir == NULL)
1204 MemFree(fodInfos->initdir);
1205 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1206 lstrcpyW(fodInfos->initdir, tmpBuf);
1207 handledPath = TRUE;
1208 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1209 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1210 }
1211 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1212
1213 } else {
1214 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1215 }
1216 }
1217
1218 /* 2. (All platforms) If initdir is not null, then use it */
1219 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1220 (*fodInfos->initdir!=0x00))
1221 {
1222 /* Work out the proper path as supplied one might be relative */
1223 /* (Here because supplying '.' as dir browses to My Computer) */
1224 if (handledPath==FALSE) {
1225 WCHAR tmpBuf[MAX_PATH];
1226 WCHAR tmpBuf2[MAX_PATH];
1227 WCHAR *nameBit;
1228 DWORD result;
1229
1230 lstrcpyW(tmpBuf, fodInfos->initdir);
1231 if( PathFileExistsW(tmpBuf) ) {
1232 /* initdir does not have to be a directory. If a file is
1233 * specified, the dir part is taken */
1234 if( PathIsDirectoryW(tmpBuf)) {
1235 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1236 lstrcatW(tmpBuf, szwSlash);
1237 }
1238 lstrcatW(tmpBuf, szwStar);
1239 }
1240 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1241 if (result) {
1242 *nameBit = 0x00;
1243 MemFree(fodInfos->initdir);
1244 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1245 lstrcpyW(fodInfos->initdir, tmpBuf2);
1246 handledPath = TRUE;
1247 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1248 }
1249 }
1250 else if (fodInfos->initdir)
1251 {
1252 MemFree(fodInfos->initdir);
1253 fodInfos->initdir = NULL;
1254 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1255 }
1256 }
1257 }
1258
1259 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1260 (*fodInfos->initdir==0x00)))
1261 {
1262 /* 3. All except w2k+: if filename contains a path use it */
1263 if (!win2000plus && fodInfos->filename &&
1264 *fodInfos->filename &&
1265 strpbrkW(fodInfos->filename, szwSlash)) {
1266 WCHAR tmpBuf[MAX_PATH];
1267 WCHAR *nameBit;
1268 DWORD result;
1269
1270 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1271 tmpBuf, &nameBit);
1272 if (result) {
1273 int len;
1274
1275 /* nameBit is always shorter than the original filename */
1276 lstrcpyW(fodInfos->filename, nameBit);
1277 *nameBit = 0x00;
1278
1279 len = lstrlenW(tmpBuf);
1280 MemFree(fodInfos->initdir);
1281 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1282 lstrcpyW(fodInfos->initdir, tmpBuf);
1283
1284 handledPath = TRUE;
1285 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1286 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1287 }
1288 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1289 }
1290
1291 /* 4. win98+ and win2000+ if any files of specified filter types in
1292 current directory, use it */
1293 if ( win98plus && handledPath == FALSE &&
1294 fodInfos->filter && *fodInfos->filter) {
1295
1296 BOOL searchMore = TRUE;
1297 LPCWSTR lpstrPos = fodInfos->filter;
1298 WIN32_FIND_DATAW FindFileData;
1299 HANDLE hFind;
1300
1301 while (searchMore)
1302 {
1303 /* filter is a list... title\0ext\0......\0\0 */
1304
1305 /* Skip the title */
1306 if(! *lpstrPos) break; /* end */
1307 lpstrPos += lstrlenW(lpstrPos) + 1;
1308
1309 /* See if any files exist in the current dir with this extension */
1310 if(! *lpstrPos) break; /* end */
1311
1312 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1313
1314 if (hFind == INVALID_HANDLE_VALUE) {
1315 /* None found - continue search */
1316 lpstrPos += lstrlenW(lpstrPos) + 1;
1317
1318 } else {
1319 searchMore = FALSE;
1320
1321 MemFree(fodInfos->initdir);
1322 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1323 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1324
1325 handledPath = TRUE;
1326 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1327 debugstr_w(lpstrPos));
1328 break;
1329 }
1330 }
1331 }
1332
1333 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1334
1335 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1336 if (handledPath == FALSE && (win2000plus || win98plus)) {
1337 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1338
1339 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1340 {
1341 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1342 {
1343 /* last fallback */
1344 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1345 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1346 } else {
1347 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1348 }
1349 } else {
1350 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1351 }
1352 handledPath = TRUE;
1353 } else if (handledPath==FALSE) {
1354 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1355 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1356 handledPath = TRUE;
1357 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1358 }
1359 }
1360 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1361 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1362
1363 /* Must the open as read only check box be checked ?*/
1364 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1365 {
1366 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1367 }
1368
1369 /* Must the open as read only check box be hidden? */
1370 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1371 {
1372 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1373 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1374 }
1375
1376 /* Must the help button be hidden? */
1377 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1378 {
1379 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1380 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1381 }
1382
1383 /* change Open to Save */
1384 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1385 {
1386 WCHAR buf[16];
1387 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1388 SetDlgItemTextW(hwnd, IDOK, buf);
1389 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1390 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1391 }
1392
1393 /* Initialize the filter combo box */
1394 FILEDLG95_FILETYPE_Init(hwnd);
1395
1396 return 0;
1397 }
1398
1399 /***********************************************************************
1400 * FILEDLG95_ResizeControls
1401 *
1402 * WM_INITDIALOG message handler (after hook notification)
1403 */
1404 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1405 {
1406 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1407
1408 if (fodInfos->DlgInfos.hwndCustomDlg)
1409 {
1410 RECT rc;
1411 UINT flags = SWP_NOACTIVATE;
1412
1413 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1414 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1415
1416 /* resize the custom dialog to the parent size */
1417 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1418 GetClientRect(hwnd, &rc);
1419 else
1420 {
1421 /* our own fake template is zero sized and doesn't have children, so
1422 * there is no need to resize it. Picasa depends on it.
1423 */
1424 flags |= SWP_NOSIZE;
1425 SetRectEmpty(&rc);
1426 }
1427 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1428 0, 0, rc.right, rc.bottom, flags);
1429 }
1430 else
1431 {
1432 /* Resize the height, if open as read only checkbox ad help button are
1433 * hidden and we are not using a custom template nor a customDialog
1434 */
1435 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1436 (!(fodInfos->ofnInfos->Flags &
1437 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1438 {
1439 RECT rectDlg, rectHelp, rectCancel;
1440 GetWindowRect(hwnd, &rectDlg);
1441 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1442 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1443 /* subtract the height of the help button plus the space between the help
1444 * button and the cancel button to the height of the dialog
1445 */
1446 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1447 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1448 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1449 }
1450 }
1451 return TRUE;
1452 }
1453
1454 /***********************************************************************
1455 * FILEDLG95_FillControls
1456 *
1457 * WM_INITDIALOG message handler (after hook notification)
1458 */
1459 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1460 {
1461 LPITEMIDLIST pidlItemId = NULL;
1462
1463 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1464
1465 TRACE("dir=%s file=%s\n",
1466 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1467
1468 /* Get the initial directory pidl */
1469
1470 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1471 {
1472 WCHAR path[MAX_PATH];
1473
1474 GetCurrentDirectoryW(MAX_PATH,path);
1475 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1476 }
1477
1478 /* Initialise shell objects */
1479 FILEDLG95_SHELL_Init(hwnd);
1480
1481 /* Initialize the Look In combo box */
1482 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1483
1484 /* Browse to the initial directory */
1485 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1486
1487 /* Free pidlItem memory */
1488 COMDLG32_SHFree(pidlItemId);
1489
1490 return TRUE;
1491 }
1492 /***********************************************************************
1493 * FILEDLG95_Clean
1494 *
1495 * Regroups all the cleaning functions of the filedlg
1496 */
1497 void FILEDLG95_Clean(HWND hwnd)
1498 {
1499 FILEDLG95_FILETYPE_Clean(hwnd);
1500 FILEDLG95_LOOKIN_Clean(hwnd);
1501 FILEDLG95_SHELL_Clean(hwnd);
1502 }
1503 /***********************************************************************
1504 * FILEDLG95_OnWMCommand
1505 *
1506 * WM_COMMAND message handler
1507 */
1508 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1509 {
1510 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1511 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1512 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1513
1514 switch(wID)
1515 {
1516 /* OK button */
1517 case IDOK:
1518 FILEDLG95_OnOpen(hwnd);
1519 break;
1520 /* Cancel button */
1521 case IDCANCEL:
1522 FILEDLG95_Clean(hwnd);
1523 EndDialog(hwnd, FALSE);
1524 break;
1525 /* Filetype combo box */
1526 case IDC_FILETYPE:
1527 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1528 break;
1529 /* LookIn combo box */
1530 case IDC_LOOKIN:
1531 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1532 break;
1533
1534 /* --- toolbar --- */
1535 /* Up folder button */
1536 case FCIDM_TB_UPFOLDER:
1537 FILEDLG95_SHELL_UpFolder(hwnd);
1538 break;
1539 /* New folder button */
1540 case FCIDM_TB_NEWFOLDER:
1541 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1542 break;
1543 /* List option button */
1544 case FCIDM_TB_SMALLICON:
1545 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1546 break;
1547 /* Details option button */
1548 case FCIDM_TB_REPORTVIEW:
1549 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1550 break;
1551 /* Details option button */
1552 case FCIDM_TB_DESKTOP:
1553 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1554 break;
1555
1556 case IDC_FILENAME:
1557 break;
1558
1559 }
1560 /* Do not use the listview selection anymore */
1561 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1562 return 0;
1563 }
1564
1565 /***********************************************************************
1566 * FILEDLG95_OnWMGetIShellBrowser
1567 *
1568 * WM_GETISHELLBROWSER message handler
1569 */
1570 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1571 {
1572 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1573
1574 TRACE("\n");
1575
1576 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1577
1578 return TRUE;
1579 }
1580
1581
1582 /***********************************************************************
1583 * FILEDLG95_SendFileOK
1584 *
1585 * Sends the CDN_FILEOK notification if required
1586 *
1587 * RETURNS
1588 * TRUE if the dialog should close
1589 * FALSE if the dialog should not be closed
1590 */
1591 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1592 {
1593 /* ask the hook if we can close */
1594 if(IsHooked(fodInfos))
1595 {
1596 LRESULT retval;
1597
1598 TRACE("---\n");
1599 /* First send CDN_FILEOK as MSDN doc says */
1600 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1601 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1602 {
1603 TRACE("canceled\n");
1604 return (retval == 0);
1605 }
1606
1607 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1608 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1609 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1610 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1611 {
1612 TRACE("canceled\n");
1613 return (retval == 0);
1614 }
1615 }
1616 return TRUE;
1617 }
1618
1619 /***********************************************************************
1620 * FILEDLG95_OnOpenMultipleFiles
1621 *
1622 * Handles the opening of multiple files.
1623 *
1624 * FIXME
1625 * check destination buffer size
1626 */
1627 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1628 {
1629 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1630 UINT nCount, nSizePath;
1631 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1632
1633 TRACE("\n");
1634
1635 if(fodInfos->unicode)
1636 {
1637 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1638 ofn->lpstrFile[0] = '\0';
1639 }
1640 else
1641 {
1642 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1643 ofn->lpstrFile[0] = '\0';
1644 }
1645
1646 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1647
1648 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1649 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1650 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1651 {
1652 LPWSTR lpstrTemp = lpstrFileList;
1653
1654 for ( nCount = 0; nCount < nFileCount; nCount++ )
1655 {
1656 LPITEMIDLIST pidl;
1657
1658 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1659 if (!pidl)
1660 {
1661 WCHAR lpstrNotFound[100];
1662 WCHAR lpstrMsg[100];
1663 WCHAR tmp[400];
1664 static const WCHAR nl[] = {'\n',0};
1665
1666 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1667 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1668
1669 lstrcpyW(tmp, lpstrTemp);
1670 lstrcatW(tmp, nl);
1671 lstrcatW(tmp, lpstrNotFound);
1672 lstrcatW(tmp, nl);
1673 lstrcatW(tmp, lpstrMsg);
1674
1675 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1676 return FALSE;
1677 }
1678
1679 /* move to the next file in the list of files */
1680 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1681 COMDLG32_SHFree(pidl);
1682 }
1683 }
1684
1685 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1686 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1687 {
1688 /* For "oldstyle" dialog the components have to
1689 be separated by blanks (not '\0'!) and short
1690 filenames have to be used! */
1691 FIXME("Components have to be separated by blanks\n");
1692 }
1693 if(fodInfos->unicode)
1694 {
1695 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1696 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1697 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1698 }
1699 else
1700 {
1701 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1702
1703 if (ofn->lpstrFile != NULL)
1704 {
1705 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1706 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1707 if (ofn->nMaxFile > nSizePath)
1708 {
1709 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1710 ofn->lpstrFile + nSizePath,
1711 ofn->nMaxFile - nSizePath, NULL, NULL);
1712 }
1713 }
1714 }
1715
1716 fodInfos->ofnInfos->nFileOffset = nSizePath;
1717 fodInfos->ofnInfos->nFileExtension = 0;
1718
1719 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1720 return FALSE;
1721
1722 /* clean and exit */
1723 FILEDLG95_Clean(hwnd);
1724 return EndDialog(hwnd,TRUE);
1725 }
1726
1727 /***********************************************************************
1728 * FILEDLG95_OnOpen
1729 *
1730 * Ok button WM_COMMAND message handler
1731 *
1732 * If the function succeeds, the return value is nonzero.
1733 */
1734 #define ONOPEN_BROWSE 1
1735 #define ONOPEN_OPEN 2
1736 #define ONOPEN_SEARCH 3
1737 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1738 {
1739 WCHAR strMsgTitle[MAX_PATH];
1740 WCHAR strMsgText [MAX_PATH];
1741 if (idCaption)
1742 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1743 else
1744 strMsgTitle[0] = '\0';
1745 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1746 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1747 }
1748
1749 BOOL FILEDLG95_OnOpen(HWND hwnd)
1750 {
1751 LPWSTR lpstrFileList;
1752 UINT nFileCount = 0;
1753 UINT sizeUsed = 0;
1754 BOOL ret = TRUE;
1755 WCHAR lpstrPathAndFile[MAX_PATH];
1756 WCHAR lpstrTemp[MAX_PATH];
1757 LPSHELLFOLDER lpsf = NULL;
1758 int nOpenAction;
1759 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1760
1761 TRACE("hwnd=%p\n", hwnd);
1762
1763 /* get the files from the edit control */
1764 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1765
1766 /* try if the user selected a folder in the shellview */
1767 if(nFileCount == 0)
1768 {
1769 BrowseSelectedFolder(hwnd);
1770 return FALSE;
1771 }
1772
1773 if(nFileCount > 1)
1774 {
1775 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1776 goto ret;
1777 }
1778
1779 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1780
1781 /*
1782 Step 1: Build a complete path name from the current folder and
1783 the filename or path in the edit box.
1784 Special cases:
1785 - the path in the edit box is a root path
1786 (with or without drive letter)
1787 - the edit box contains ".." (or a path with ".." in it)
1788 */
1789
1790 /* Get the current directory name */
1791 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1792 {
1793 /* last fallback */
1794 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1795 }
1796 PathAddBackslashW(lpstrPathAndFile);
1797
1798 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1799
1800 /* if the user specified a fully qualified path use it */
1801 if(PathIsRelativeW(lpstrFileList))
1802 {
1803 lstrcatW(lpstrPathAndFile, lpstrFileList);
1804 }
1805 else
1806 {
1807 /* does the path have a drive letter? */
1808 if (PathGetDriveNumberW(lpstrFileList) == -1)
1809 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1810 else
1811 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1812 }
1813
1814 /* resolve "." and ".." */
1815 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1816 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1817 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1818
1819 MemFree(lpstrFileList);
1820
1821 /*
1822 Step 2: here we have a cleaned up path
1823
1824 We have to parse the path step by step to see if we have to browse
1825 to a folder if the path points to a directory or the last
1826 valid element is a directory.
1827
1828 valid variables:
1829 lpstrPathAndFile: cleaned up path
1830 */
1831
1832 if (nFileCount &&
1833 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1834 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1835 nOpenAction = ONOPEN_OPEN;
1836 else
1837 nOpenAction = ONOPEN_BROWSE;
1838
1839 /* don't apply any checks with OFN_NOVALIDATE */
1840 {
1841 LPWSTR lpszTemp, lpszTemp1;
1842 LPITEMIDLIST pidl = NULL;
1843 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1844
1845 /* check for invalid chars */
1846 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1847 {
1848 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1849 ret = FALSE;
1850 goto ret;
1851 }
1852
1853 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1854
1855 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1856 while (lpszTemp1)
1857 {
1858 LPSHELLFOLDER lpsfChild;
1859 WCHAR lpwstrTemp[MAX_PATH];
1860 DWORD dwEaten, dwAttributes;
1861 LPWSTR p;
1862
1863 lstrcpyW(lpwstrTemp, lpszTemp);
1864 p = PathFindNextComponentW(lpwstrTemp);
1865
1866 if (!p) break; /* end of path */
1867
1868 *p = 0;
1869 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1870
1871 /* There are no wildcards when OFN_NOVALIDATE is set */
1872 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1873 {
1874 static const WCHAR wszWild[] = { '*', '?', 0 };
1875 /* if the last element is a wildcard do a search */
1876 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1877 {
1878 nOpenAction = ONOPEN_SEARCH;
1879 break;
1880 }
1881 }
1882 lpszTemp1 = lpszTemp;
1883
1884 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1885
1886 /* append a backslash to drive letters */
1887 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1888 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1889 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1890 {
1891 PathAddBackslashW(lpwstrTemp);
1892 }
1893
1894 dwAttributes = SFGAO_FOLDER;
1895 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1896 {
1897 /* the path component is valid, we have a pidl of the next path component */
1898 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1899 if(dwAttributes & SFGAO_FOLDER)
1900 {
1901 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1902 {
1903 ERR("bind to failed\n"); /* should not fail */
1904 break;
1905 }
1906 IShellFolder_Release(lpsf);
1907 lpsf = lpsfChild;
1908 lpsfChild = NULL;
1909 }
1910 else
1911 {
1912 TRACE("value\n");
1913
1914 /* end dialog, return value */
1915 nOpenAction = ONOPEN_OPEN;
1916 break;
1917 }
1918 COMDLG32_SHFree(pidl);
1919 pidl = NULL;
1920 }
1921 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1922 {
1923 if(*lpszTemp || /* points to trailing null for last path element */
1924 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1925 {
1926 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1927 {
1928 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1929 break;
1930 }
1931 }
1932 else
1933 {
1934 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1935 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1936 {
1937 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1938 break;
1939 }
1940 }
1941 /* change to the current folder */
1942 nOpenAction = ONOPEN_OPEN;
1943 break;
1944 }
1945 else
1946 {
1947 nOpenAction = ONOPEN_OPEN;
1948 break;
1949 }
1950 }
1951 if(pidl) COMDLG32_SHFree(pidl);
1952 }
1953
1954 /*
1955 Step 3: here we have a cleaned up and validated path
1956
1957 valid variables:
1958 lpsf: ShellFolder bound to the rightmost valid path component
1959 lpstrPathAndFile: cleaned up path
1960 nOpenAction: action to do
1961 */
1962 TRACE("end validate sf=%p\n", lpsf);
1963
1964 switch(nOpenAction)
1965 {
1966 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1967 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1968 {
1969 int iPos;
1970 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1971 DWORD len;
1972
1973 /* replace the current filter */
1974 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1975 len = lstrlenW(lpszTemp)+1;
1976 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1977 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1978
1979 /* set the filter cb to the extension when possible */
1980 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1981 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1982 }
1983 /* fall through */
1984 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1985 TRACE("ONOPEN_BROWSE\n");
1986 {
1987 IPersistFolder2 * ppf2;
1988 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1989 {
1990 LPITEMIDLIST pidlCurrent;
1991 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1992 IPersistFolder2_Release(ppf2);
1993 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1994 {
1995 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
1996 {
1997 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1998 }
1999 }
2000 else if( nOpenAction == ONOPEN_SEARCH )
2001 {
2002 if (fodInfos->Shell.FOIShellView)
2003 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2004 }
2005 COMDLG32_SHFree(pidlCurrent);
2006 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2007 }
2008 }
2009 ret = FALSE;
2010 break;
2011 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2012 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2013 {
2014 WCHAR *ext = NULL;
2015
2016 /* update READONLY check box flag */
2017 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2018 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2019 else
2020 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2021
2022 /* Attach the file extension with file name*/
2023 ext = PathFindExtensionW(lpstrPathAndFile);
2024 if (! *ext)
2025 {
2026 /* if no extension is specified with file name, then */
2027 /* attach the extension from file filter or default one */
2028
2029 WCHAR *filterExt = NULL;
2030 LPWSTR lpstrFilter = NULL;
2031 static const WCHAR szwDot[] = {'.',0};
2032 int PathLength = lstrlenW(lpstrPathAndFile);
2033
2034 /* Attach the dot*/
2035 lstrcatW(lpstrPathAndFile, szwDot);
2036
2037 /*Get the file extension from file type filter*/
2038 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2039 fodInfos->ofnInfos->nFilterIndex-1);
2040
2041 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2042 filterExt = PathFindExtensionW(lpstrFilter);
2043
2044 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2045 lstrcatW(lpstrPathAndFile, filterExt + 1);
2046 else if ( fodInfos->defext ) /* attach the default file extension*/
2047 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2048
2049 /* In Open dialog: if file does not exist try without extension */
2050 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2051 lpstrPathAndFile[PathLength] = '\0';
2052 }
2053
2054 if (fodInfos->defext) /* add default extension */
2055 {
2056 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2057 if (*ext)
2058 ext++;
2059 if (!lstrcmpiW(fodInfos->defext, ext))
2060 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2061 else
2062 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2063 }
2064
2065 /* In Save dialog: check if the file already exists */
2066 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2067 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2068 && PathFileExistsW(lpstrPathAndFile))
2069 {
2070 WCHAR lpstrOverwrite[100];
2071 int answer;
2072
2073 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2074 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2075 MB_YESNO | MB_ICONEXCLAMATION);
2076 if (answer == IDNO)
2077 {
2078 ret = FALSE;
2079 goto ret;
2080 }
2081 }
2082
2083 /* In Open dialog: check if it should be created if it doesn't exist */
2084 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2085 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2086 && !PathFileExistsW(lpstrPathAndFile))
2087 {
2088 WCHAR lpstrCreate[100];
2089 int answer;
2090
2091 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2092 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2093 MB_YESNO | MB_ICONEXCLAMATION);
2094 if (answer == IDNO)
2095 {
2096 ret = FALSE;
2097 goto ret;
2098 }
2099 }
2100
2101 /* Check that the size of the file does not exceed buffer size.
2102 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2103 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2104 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2105 {
2106
2107 /* fill destination buffer */
2108 if (fodInfos->ofnInfos->lpstrFile)
2109 {
2110 if(fodInfos->unicode)
2111 {
2112 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2113
2114 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2115 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2116 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2117 }
2118 else
2119 {
2120 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2121
2122 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2123 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2124 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2125 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2126 }
2127 }
2128
2129 if(fodInfos->unicode)
2130 {
2131 LPWSTR lpszTemp;
2132
2133 /* set filename offset */
2134 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2135 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2136
2137 /* set extension offset */
2138 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2139 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2140 }
2141 else
2142 {
2143 LPSTR lpszTemp;
2144 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2145
2146 /* set filename offset */
2147 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2148 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2149
2150 /* set extension offset */
2151 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2152 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2153 }
2154
2155 /* set the lpstrFileTitle */
2156 if(fodInfos->ofnInfos->lpstrFileTitle)
2157 {
2158 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2159 if(fodInfos->unicode)
2160 {
2161 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2162 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2163 }
2164 else
2165 {
2166 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2167 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2168 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2169 }
2170 }
2171
2172 /* copy currently selected filter to lpstrCustomFilter */
2173 if (fodInfos->ofnInfos->lpstrCustomFilter)
2174 {
2175 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2176 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2177 NULL, 0, NULL, NULL);
2178 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2179 {
2180 LPSTR s = ofn->lpstrCustomFilter;
2181 s += strlen(ofn->lpstrCustomFilter)+1;
2182 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2183 s, len, NULL, NULL);
2184 }
2185 }
2186
2187
2188 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2189 goto ret;
2190
2191 TRACE("close\n");
2192 FILEDLG95_Clean(hwnd);
2193 ret = EndDialog(hwnd, TRUE);
2194 }
2195 else
2196 {
2197 WORD size;
2198
2199 size = lstrlenW(lpstrPathAndFile) + 1;
2200 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2201 size += 1;
2202 /* return needed size in first two bytes of lpstrFile */
2203 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2204 FILEDLG95_Clean(hwnd);
2205 ret = EndDialog(hwnd, FALSE);
2206 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2207 }
2208 goto ret;
2209 }
2210 break;
2211 }
2212
2213 ret:
2214 if(lpsf) IShellFolder_Release(lpsf);
2215 return ret;
2216 }
2217
2218 /***********************************************************************
2219 * FILEDLG95_SHELL_Init
2220 *
2221 * Initialisation of the shell objects
2222 */
2223 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2224 {
2225 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2226
2227 TRACE("\n");
2228
2229 /*
2230 * Initialisation of the FileOpenDialogInfos structure
2231 */
2232
2233 /* Shell */
2234
2235 /*ShellInfos */
2236 fodInfos->ShellInfos.hwndOwner = hwnd;
2237
2238 /* Disable multi-select if flag not set */
2239 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2240 {
2241 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2242 }
2243 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2244 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2245
2246 /* Construct the IShellBrowser interface */
2247 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2248
2249 return NOERROR;
2250 }
2251
2252 /***********************************************************************
2253 * FILEDLG95_SHELL_ExecuteCommand
2254 *
2255 * Change the folder option and refresh the view
2256 * If the function succeeds, the return value is nonzero.
2257 */
2258 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2259 {
2260 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2261 IContextMenu * pcm;
2262
2263 TRACE("(%p,%p)\n", hwnd, lpVerb);
2264
2265 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2266 SVGIO_BACKGROUND,
2267 &IID_IContextMenu,
2268 (LPVOID*)&pcm)))
2269 {
2270 CMINVOKECOMMANDINFO ci;
2271 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2272 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2273 ci.lpVerb = lpVerb;
2274 ci.hwnd = hwnd;
2275
2276 IContextMenu_InvokeCommand(pcm, &ci);
2277 IContextMenu_Release(pcm);
2278 }
2279
2280 return FALSE;
2281 }
2282
2283 /***********************************************************************
2284 * FILEDLG95_SHELL_UpFolder
2285 *
2286 * Browse to the specified object
2287 * If the function succeeds, the return value is nonzero.
2288 */
2289 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2290 {
2291 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2292
2293 TRACE("\n");
2294
2295 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2296 NULL,
2297 SBSP_PARENT)))
2298 {
2299 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2300 return TRUE;
2301 }
2302 return FALSE;
2303 }
2304
2305 /***********************************************************************
2306 * FILEDLG95_SHELL_BrowseToDesktop
2307 *
2308 * Browse to the Desktop
2309 * If the function succeeds, the return value is nonzero.
2310 */
2311 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2312 {
2313 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2314 LPITEMIDLIST pidl;
2315 HRESULT hres;
2316
2317 TRACE("\n");
2318
2319 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2320 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2321 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2322 COMDLG32_SHFree(pidl);
2323 return SUCCEEDED(hres);
2324 }
2325 /***********************************************************************
2326 * FILEDLG95_SHELL_Clean
2327 *
2328 * Cleans the memory used by shell objects
2329 */
2330 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2331 {
2332 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2333
2334 TRACE("\n");
2335
2336 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2337
2338 /* clean Shell interfaces */
2339 if (fodInfos->Shell.FOIShellView)
2340 {
2341 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2342 IShellView_Release(fodInfos->Shell.FOIShellView);
2343 }
2344 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2345 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2346 if (fodInfos->Shell.FOIDataObject)
2347 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2348 }
2349
2350 /***********************************************************************
2351 * FILEDLG95_FILETYPE_Init
2352 *
2353 * Initialisation of the file type combo box
2354 */
2355 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2356 {
2357 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2358 int nFilters = 0; /* number of filters */
2359 int nFilterIndexCB;
2360
2361 TRACE("\n");
2362
2363 if(fodInfos->customfilter)
2364 {
2365 /* customfilter has one entry... title\0ext\0
2366 * Set first entry of combo box item with customfilter
2367 */
2368 LPWSTR lpstrExt;
2369 LPCWSTR lpstrPos = fodInfos->customfilter;
2370
2371 /* Get the title */
2372 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2373
2374 /* Copy the extensions */
2375 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2376 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2377 lstrcpyW(lpstrExt,lpstrPos);
2378
2379 /* Add the item at the end of the combo */
2380 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2381 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2382 nFilters++;
2383 }
2384 if(fodInfos->filter)
2385 {
2386 LPCWSTR lpstrPos = fodInfos->filter;
2387
2388 for(;;)
2389 {
2390 /* filter is a list... title\0ext\0......\0\0
2391 * Set the combo item text to the title and the item data
2392 * to the ext
2393 */
2394 LPCWSTR lpstrDisplay;
2395 LPWSTR lpstrExt;
2396
2397 /* Get the title */
2398 if(! *lpstrPos) break; /* end */
2399 lpstrDisplay = lpstrPos;
2400 lpstrPos += lstrlenW(lpstrPos) + 1;
2401
2402 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2403
2404 nFilters++;
2405
2406 /* Copy the extensions */
2407 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2408 lstrcpyW(lpstrExt,lpstrPos);
2409 lpstrPos += lstrlenW(lpstrPos) + 1;
2410
2411 /* Add the item at the end of the combo */
2412 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2413
2414 /* malformed filters are added anyway... */
2415 if (!*lpstrExt) break;
2416 }
2417 }
2418
2419 /*
2420 * Set the current filter to the one specified
2421 * in the initialisation structure
2422 */
2423 if (fodInfos->filter || fodInfos->customfilter)
2424 {
2425 LPWSTR lpstrFilter;
2426
2427 /* Check to make sure our index isn't out of bounds. */
2428 if ( fodInfos->ofnInfos->nFilterIndex >
2429 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2430 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2431
2432 /* set default filter index */
2433 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2434 fodInfos->ofnInfos->nFilterIndex = 1;
2435
2436 /* calculate index of Combo Box item */
2437 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2438 if (fodInfos->customfilter == NULL)
2439 nFilterIndexCB--;
2440
2441 /* Set the current index selection. */
2442 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2443
2444 /* Get the corresponding text string from the combo box. */
2445 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2446 nFilterIndexCB);
2447
2448 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2449 lpstrFilter = NULL;
2450
2451 if(lpstrFilter)
2452 {
2453 DWORD len;
2454 CharLowerW(lpstrFilter); /* lowercase */
2455 len = lstrlenW(lpstrFilter)+1;
2456 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2457 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2458 }
2459 } else
2460 fodInfos->ofnInfos->nFilterIndex = 0;
2461 return S_OK;
2462 }
2463
2464 /***********************************************************************
2465 * FILEDLG95_FILETYPE_OnCommand
2466 *
2467 * WM_COMMAND of the file type combo box
2468 * If the function succeeds, the return value is nonzero.
2469 */
2470 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2471 {
2472 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2473
2474 switch(wNotifyCode)
2475 {
2476 case CBN_SELENDOK:
2477 {
2478 LPWSTR lpstrFilter;
2479
2480 /* Get the current item of the filetype combo box */
2481 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2482
2483 /* set the current filter index */
2484 fodInfos->ofnInfos->nFilterIndex = iItem +
2485 (fodInfos->customfilter == NULL ? 1 : 0);
2486
2487 /* Set the current filter with the current selection */
2488 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2489
2490 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2491 iItem);
2492 if((INT_PTR)lpstrFilter != CB_ERR)
2493 {
2494 DWORD len;
2495 CharLowerW(lpstrFilter); /* lowercase */
2496 len = lstrlenW(lpstrFilter)+1;
2497 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2498 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2499 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2500 }
2501
2502 /* Refresh the actual view to display the included items*/
2503 if (fodInfos->Shell.FOIShellView)
2504 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2505 }
2506 }
2507 return FALSE;
2508 }
2509 /***********************************************************************
2510 * FILEDLG95_FILETYPE_SearchExt
2511 *
2512 * searches for an extension in the filetype box
2513 */
2514 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2515 {
2516 int i, iCount = CBGetCount(hwnd);
2517
2518 TRACE("%s\n", debugstr_w(lpstrExt));
2519
2520 if(iCount != CB_ERR)
2521 {
2522 for(i=0;i<iCount;i++)
2523 {
2524 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2525 return i;
2526 }
2527 }
2528 return -1;
2529 }
2530
2531 /***********************************************************************
2532 * FILEDLG95_FILETYPE_Clean
2533 *
2534 * Clean the memory used by the filetype combo box
2535 */
2536 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2537 {
2538 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2539 int iPos;
2540 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2541
2542 TRACE("\n");
2543
2544 /* Delete each string of the combo and their associated data */
2545 if(iCount != CB_ERR)
2546 {
2547 for(iPos = iCount-1;iPos>=0;iPos--)
2548 {
2549 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2550 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2551 }
2552 }
2553 /* Current filter */
2554 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2555
2556 }
2557
2558 /***********************************************************************
2559 * FILEDLG95_LOOKIN_Init
2560 *
2561 * Initialisation of the look in combo box
2562 */
2563
2564 /* Small helper function, to determine if the unixfs shell extension is rooted
2565 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2566 */
2567 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2568 HKEY hKey;
2569 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2570 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2571 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2572 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2573 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','','A','A','E','8',
2574 '-','','6','2','5','-','4','4','B','','-','9','C','A','7','-',
2575 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2576
2577 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2578 return FALSE;
2579
2580 RegCloseKey(hKey);
2581 return TRUE;
2582 }
2583
2584 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2585 {
2586 IShellFolder *psfRoot, *psfDrives;
2587 IEnumIDList *lpeRoot, *lpeDrives;
2588 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2589
2590 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2591
2592 TRACE("\n");
2593
2594 liInfos->iMaxIndentation = 0;
2595
2596 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2597
2598 /* set item height for both text field and listbox */
2599 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2600 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2601
2602 /* Turn on the extended UI for the combo box like Windows does */
2603 CBSetExtendedUI(hwndCombo, TRUE);
2604
2605 /* Initialise data of Desktop folder */
2606 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2607 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2608 COMDLG32_SHFree(pidlTmp);
2609
2610 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2611
2612 SHGetDesktopFolder(&psfRoot);
2613
2614 if (psfRoot)
2615 {
2616 /* enumerate the contents of the desktop */
2617 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2618 {
2619 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2620 {
2621 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2622
2623 /* If the unixfs extension is rooted, we don't expand the drives by default */
2624 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2625 {
2626 /* special handling for CSIDL_DRIVES */
2627 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2628 {
2629 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2630 {
2631 /* enumerate the drives */
2632 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2633 {
2634 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2635 {
2636 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2637 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2638 COMDLG32_SHFree(pidlAbsTmp);
2639 COMDLG32_SHFree(pidlTmp1);
2640 }
2641 IEnumIDList_Release(lpeDrives);
2642 }
2643 IShellFolder_Release(psfDrives);
2644 }
2645 }
2646 }
2647
2648 COMDLG32_SHFree(pidlTmp);
2649 }
2650 IEnumIDList_Release(lpeRoot);
2651 }
2652 IShellFolder_Release(psfRoot);
2653 }
2654
2655 COMDLG32_SHFree(pidlDrives);
2656 }
2657
2658 /***********************************************************************
2659 * FILEDLG95_LOOKIN_DrawItem
2660 *
2661 * WM_DRAWITEM message handler
2662 */
2663 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2664 {
2665 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2666 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2667 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2668 RECT rectText;
2669 RECT rectIcon;
2670 SHFILEINFOW sfi;
2671 HIMAGELIST ilItemImage;
2672 int iIndentation;
2673 TEXTMETRICW tm;
2674 LPSFOLDER tmpFolder;
2675 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2676
2677 TRACE("\n");
2678
2679 if(pDIStruct->itemID == -1)
2680 return 0;
2681
2682 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2683 pDIStruct->itemID)))
2684 return 0;
2685
2686
2687 if(pDIStruct->itemID == liInfos->uSelectedItem)
2688 {
2689 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2690 0,
2691 &sfi,
2692 sizeof (sfi),
2693 SHGFI_PIDL | SHGFI_SMALLICON |
2694 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2695 SHGFI_DISPLAYNAME );
2696 }
2697 else
2698 {
2699 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2700 0,
2701 &sfi,
2702 sizeof (sfi),
2703 SHGFI_PIDL | SHGFI_SMALLICON |
2704 SHGFI_SYSICONINDEX |
2705 SHGFI_DISPLAYNAME);
2706 }
2707
2708 /* Is this item selected ? */
2709 if(pDIStruct->itemState & ODS_SELECTED)
2710 {
2711 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2712 SetBkColor(pDIStruct->hDC,crHighLight);
2713 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2714 }
2715 else
2716 {
2717 SetTextColor(pDIStruct->hDC,crText);
2718 SetBkColor(pDIStruct->hDC,crWin);
2719 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2720 }
2721
2722 /* Do not indent item if drawing in the edit of the combo */
2723 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2724 {
2725 iIndentation = 0;
2726 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2727 0,
2728 &sfi,
2729 sizeof (sfi),
2730 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2731 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2732
2733 }
2734 else
2735 {
2736 iIndentation = tmpFolder->m_iIndent;
2737 }
2738 /* Draw text and icon */
2739
2740 /* Initialise the icon display area */
2741 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2742 rectIcon.top = pDIStruct->rcItem.top;
2743 rectIcon.right = rectIcon.left + ICONWIDTH;
2744 rectIcon.bottom = pDIStruct->rcItem.bottom;
2745
2746 /* Initialise the text display area */
2747 GetTextMetricsW(pDIStruct->hDC, &tm);
2748 rectText.left = rectIcon.right;
2749 rectText.top =
2750 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2751 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2752 rectText.bottom =
2753 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2754
2755 /* Draw the icon from the image list */
2756 ImageList_Draw(ilItemImage,
2757 sfi.iIcon,
2758 pDIStruct->hDC,
2759 rectIcon.left,
2760 rectIcon.top,
2761 ILD_TRANSPARENT );
2762
2763 /* Draw the associated text */
2764 if(sfi.szDisplayName)
2765 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2766
2767
2768 return NOERROR;
2769 }
2770
2771 /***********************************************************************
2772 * FILEDLG95_LOOKIN_OnCommand
2773 *
2774 * LookIn combo box WM_COMMAND message handler
2775 * If the function succeeds, the return value is nonzero.
2776 */
2777 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2778 {
2779 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2780
2781 TRACE("%p\n", fodInfos);
2782
2783 switch(wNotifyCode)
2784 {
2785 case CBN_SELENDOK:
2786 {
2787 LPSFOLDER tmpFolder;
2788 int iItem;
2789
2790 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2791
2792 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2793 iItem)))
2794 return FALSE;
2795
2796
2797 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2798 tmpFolder->pidlItem,
2799 SBSP_ABSOLUTE)))
2800 {
2801 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2802 return TRUE;
2803 }
2804 break;
2805 }
2806
2807 }
2808 return FALSE;
2809 }
2810
2811 /***********************************************************************
2812 * FILEDLG95_LOOKIN_AddItem
2813 *
2814 * Adds an absolute pidl item to the lookin combo box
2815 * returns the index of the inserted item
2816 */
2817 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2818 {
2819 LPITEMIDLIST pidlNext;
2820 SHFILEINFOW sfi;
2821 SFOLDER *tmpFolder;
2822 LookInInfos *liInfos;
2823
2824 TRACE("%08x\n", iInsertId);
2825
2826 if(!pidl)
2827 return -1;
2828
2829 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
2830 return -1;
2831
2832 tmpFolder = MemAlloc(sizeof(SFOLDER));
2833 tmpFolder->m_iIndent = 0;
2834
2835 /* Calculate the indentation of the item in the lookin*/
2836 pidlNext = pidl;
2837 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2838 {
2839 tmpFolder->m_iIndent++;
2840 }
2841
2842 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2843
2844 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2845 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2846
2847 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2848 SHGetFileInfoW((LPCWSTR)pidl,
2849 0,
2850 &sfi,
2851 sizeof(sfi),
2852 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2853 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2854
2855 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2856
2857 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2858 {
2859 int iItemID;
2860
2861 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2862
2863 /* Add the item at the end of the list */
2864 if(iInsertId < 0)
2865 {
2866 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2867 }
2868 /* Insert the item at the iInsertId position*/
2869 else
2870 {
2871 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2872 }
2873
2874 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2875 return iItemID;
2876 }
2877
2878 COMDLG32_SHFree( tmpFolder->pidlItem );
2879 MemFree( tmpFolder );
2880 return -1;
2881
2882 }
2883
2884 /***********************************************************************
2885 * FILEDLG95_LOOKIN_InsertItemAfterParent
2886 *
2887 * Insert an item below its parent
2888 */
2889 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2890 {
2891
2892 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2893 int iParentPos;
2894
2895 TRACE("\n");
2896
2897 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2898
2899 if(iParentPos < 0)
2900 {
2901 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2902 }
2903
2904 /* Free pidlParent memory */
2905 COMDLG32_SHFree((LPVOID)pidlParent);
2906
2907 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2908 }
2909
2910 /***********************************************************************
2911 * FILEDLG95_LOOKIN_SelectItem
2912 *
2913 * Adds an absolute pidl item to the lookin combo box
2914 * returns the index of the inserted item
2915 */
2916 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2917 {
2918 int iItemPos;
2919 LookInInfos *liInfos;
2920
2921 TRACE("\n");
2922
2923 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2924
2925 liInfos = GetPropA(hwnd,LookInInfosStr);
2926
2927 if(iItemPos < 0)
2928 {
2929 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2930 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2931 }
2932
2933 else
2934 {
2935 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2936 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2937 {
2938 int iRemovedItem;
2939
2940 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2941 break;
2942 if(iRemovedItem < iItemPos)
2943 iItemPos--;
2944 }
2945 }
2946
2947 CBSetCurSel(hwnd,iItemPos);
2948 liInfos->uSelectedItem = iItemPos;
2949
2950 return 0;
2951
2952 }
2953
2954 /***********************************************************************
2955 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2956 *
2957 * Remove the item with an expansion level over iExpansionLevel
2958 */
2959 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2960 {
2961 int iItemPos;
2962 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
2963
2964 TRACE("\n");
2965
2966 if(liInfos->iMaxIndentation <= 2)
2967 return -1;
2968
2969 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2970 {
2971 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2972 COMDLG32_SHFree(tmpFolder->pidlItem);
2973 MemFree(tmpFolder);
2974 CBDeleteString(hwnd,iItemPos);
2975 liInfos->iMaxIndentation--;
2976
2977 return iItemPos;
2978 }
2979
2980 return -1;
2981 }
2982
2983 /***********************************************************************
2984 * FILEDLG95_LOOKIN_SearchItem
2985 *
2986 * Search for pidl in the lookin combo box
2987 * returns the index of the found item
2988 */
2989 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2990 {
2991 int i = 0;
2992 int iCount = CBGetCount(hwnd);
2993
2994 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
2995
2996 if (iCount != CB_ERR)
2997 {
2998 for(;i<iCount;i++)
2999 {
3000 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3001
3002 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3003 return i;
3004 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3005 return i;
3006 }
3007 }
3008
3009 return -1;
3010 }
3011
3012 /***********************************************************************
3013 * FILEDLG95_LOOKIN_Clean
3014 *
3015 * Clean the memory used by the lookin combo box
3016 */
3017 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3018 {
3019 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3020 int iPos;
3021 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3022
3023 TRACE("\n");
3024
3025 /* Delete each string of the combo and their associated data */
3026 if (iCount != CB_ERR)
3027 {
3028 for(iPos = iCount-1;iPos>=0;iPos--)
3029 {
3030 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3031 COMDLG32_SHFree(tmpFolder->pidlItem);
3032 MemFree(tmpFolder);
3033 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3034 }
3035 }
3036
3037 /* LookInInfos structure */
3038 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3039
3040 }
3041 /***********************************************************************
3042 * FILEDLG95_FILENAME_FillFromSelection
3043 *
3044 * fills the edit box from the cached DataObject
3045 */
3046 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3047 {
3048 FileOpenDlgInfos *fodInfos;
3049 LPITEMIDLIST pidl;
3050 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3051 WCHAR lpstrTemp[MAX_PATH];
3052 LPWSTR lpstrAllFile, lpstrCurrFile;
3053
3054 TRACE("\n");
3055 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3056
3057 /* Count how many files we have */
3058 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3059
3060 /* calculate the string length, count files */
3061 if (nFileSelected >= 1)
3062 {
3063 nLength += 3; /* first and last quotes, trailing \0 */
3064 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3065 {
3066 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3067
3068 if (pidl)
3069 {
3070 /* get the total length of the selected file names */
3071 lpstrTemp[0] = '\0';
3072 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3073
3074 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3075 {
3076 nLength += lstrlenW( lpstrTemp ) + 3;
3077 nFiles++;
3078 }
3079 COMDLG32_SHFree( pidl );
3080 }
3081 }
3082 }
3083
3084 /* allocate the buffer */
3085 if (nFiles <= 1) nLength = MAX_PATH;
3086 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3087
3088 /* Generate the string for the edit control */
3089 if(nFiles >= 1)
3090 {
3091 lpstrCurrFile = lpstrAllFile;
3092 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3093 {
3094 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3095
3096 if (pidl)
3097 {
3098 /* get the file name */
3099 lpstrTemp[0] = '\0';
3100 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3101
3102 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3103 {
3104 if ( nFiles > 1)
3105 {
3106 *lpstrCurrFile++ = '\"';
3107 lstrcpyW( lpstrCurrFile, lpstrTemp );
3108 lpstrCurrFile += lstrlenW( lpstrTemp );
3109 *lpstrCurrFile++ = '\"';
3110 *lpstrCurrFile++ = ' ';
3111 *lpstrCurrFile = 0;
3112 }
3113 else
3114 {
3115 lstrcpyW( lpstrAllFile, lpstrTemp );
3116 }
3117 }
3118 COMDLG32_SHFree( (LPVOID) pidl );
3119 }
3120 }
3121 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3122
3123 /* Select the file name like Windows does */
3124 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3125 }
3126 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3127 }
3128
3129
3130 /* copied from shell32 to avoid linking to it
3131 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3132 * is dependent on whether emulated OS is unicode or not.
3133 */
3134 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3135 {
3136 switch (src->uType)
3137 {
3138 case STRRET_WSTR:
3139 lstrcpynW(dest, src->u.pOleStr, len);
3140 COMDLG32_SHFree(src->u.pOleStr);
3141 break;
3142
3143 case STRRET_CSTR:
3144 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3145 dest[len-1] = 0;
3146 break;
3147
3148 case STRRET_OFFSET:
3149 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3150 dest[len-1] = 0;
3151 break;
3152
3153 default:
3154 FIXME("unknown type %x!\n", src->uType);
3155 if (len) *dest = '\0';
3156 return E_FAIL;
3157 }
3158 return S_OK;
3159 }
3160
3161 /***********************************************************************
3162 * FILEDLG95_FILENAME_GetFileNames
3163 *
3164 * Copies the filenames to a delimited string list.
3165 * The delimiter is specified by the parameter 'separator',
3166 * usually either a space or a nul
3167 */
3168 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3169 {
3170 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3171 UINT nStrCharCount = 0; /* index in src buffer */
3172 UINT nFileIndex = 0; /* index in dest buffer */
3173 UINT nFileCount = 0; /* number of files */
3174 UINT nStrLen = 0; /* length of string in edit control */
3175 LPWSTR lpstrEdit; /* buffer for string from edit control */
3176
3177 TRACE("\n");
3178
3179 /* get the filenames from the edit control */
3180 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3181 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3182 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3183
3184 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3185
3186 /* we might get single filename without any '"',
3187 * so we need nStrLen + terminating \0 + end-of-list \0 */
3188 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3189 *sizeUsed = 0;
3190
3191 /* build delimited file list from filenames */
3192 while ( nStrCharCount <= nStrLen )
3193 {
3194 if ( lpstrEdit[nStrCharCount]=='"' )
3195 {
3196 nStrCharCount++;
3197 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3198 {
3199 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3200 nStrCharCount++;
3201 }
3202 (*lpstrFileList)[nFileIndex++] = 0;
3203 nFileCount++;
3204 }
3205 nStrCharCount++;
3206 }
3207
3208 /* single, unquoted string */
3209 if ((nStrLen > 0) && (nFileIndex == 0) )
3210 {
3211 lstrcpyW(*lpstrFileList, lpstrEdit);
3212 nFileIndex = lstrlenW(lpstrEdit) + 1;
3213 nFileCount = 1;
3214 }
3215
3216 /* trailing \0 */
3217 (*lpstrFileList)[nFileIndex++] = '\0';
3218
3219 *sizeUsed = nFileIndex;
3220 MemFree(lpstrEdit);
3221 return nFileCount;
3222 }
3223
3224 #define SETDefFormatEtc(fe,cf,med) \
3225 { \
3226 (fe).cfFormat = cf;\
3227 (fe).dwAspect = DVASPECT_CONTENT; \
3228 (fe).ptd =NULL;\
3229 (fe).tymed = med;\
3230 (fe).lindex = -1;\
3231 };
3232
3233 /*
3234 * DATAOBJECT Helper functions
3235 */
3236
3237 /***********************************************************************
3238 * COMCTL32_ReleaseStgMedium
3239 *
3240 * like ReleaseStgMedium from ole32
3241 */
3242 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3243 {
3244 if(medium.pUnkForRelease)
3245 {
3246 IUnknown_Release(medium.pUnkForRelease);
3247 }
3248 else
3249 {
3250 GlobalUnlock(medium.u.hGlobal);
3251 GlobalFree(medium.u.hGlobal);
3252 }
3253 }
3254
3255 /***********************************************************************
3256 * GetPidlFromDataObject
3257 *
3258 * Return pidl(s) by number from the cached DataObject
3259 *
3260 * nPidlIndex=0 gets the fully qualified root path
3261 */
3262 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3263 {
3264
3265 STGMEDIUM medium;
3266 FORMATETC formatetc;
3267 LPITEMIDLIST pidl = NULL;
3268
3269 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3270
3271 if (!doSelected)
3272 return NULL;
3273
3274 /* Set the FORMATETC structure*/
3275 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3276
3277 /* Get the pidls from IDataObject */
3278 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3279 {
3280 LPIDA cida = GlobalLock(medium.u.hGlobal);
3281 if(nPidlIndex <= cida->cidl)
3282 {
3283 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3284 }
3285 COMCTL32_ReleaseStgMedium(medium);
3286 }
3287 return pidl;
3288 }
3289
3290 /***********************************************************************
3291 * GetNumSelected
3292 *
3293 * Return the number of selected items in the DataObject.
3294 *
3295 */
3296 static UINT GetNumSelected( IDataObject *doSelected )
3297 {
3298 UINT retVal = 0;
3299 STGMEDIUM medium;
3300 FORMATETC formatetc;
3301
3302 TRACE("sv=%p\n", doSelected);
3303
3304 if (!doSelected) return 0;
3305
3306 /* Set the FORMATETC structure*/
3307 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3308
3309 /* Get the pidls from IDataObject */
3310 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3311 {
3312 LPIDA cida = GlobalLock(medium.u.hGlobal);
3313 retVal = cida->cidl;
3314 COMCTL32_ReleaseStgMedium(medium);
3315 return retVal;
3316 }
3317 return 0;
3318 }
3319
3320 /*
3321 * TOOLS
3322 */
3323
3324 /***********************************************************************
3325 * GetName
3326 *
3327 * Get the pidl's display name (relative to folder) and
3328 * put it in lpstrFileName.
3329 *
3330 * Return NOERROR on success,
3331 * E_FAIL otherwise
3332 */
3333
3334 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3335 {
3336 STRRET str;
3337 HRESULT hRes;
3338
3339 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3340
3341 if(!lpsf)
3342 {
3343 SHGetDesktopFolder(&lpsf);
3344 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3345 IShellFolder_Release(lpsf);
3346 return hRes;
3347 }
3348
3349 /* Get the display name of the pidl relative to the folder */
3350 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3351 {
3352 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3353 }
3354 return E_FAIL;
3355 }
3356
3357 /***********************************************************************
3358 * GetShellFolderFromPidl
3359 *
3360 * pidlRel is the item pidl relative
3361 * Return the IShellFolder of the absolute pidl
3362 */
3363 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3364 {
3365 IShellFolder *psf = NULL,*psfParent;
3366
3367 TRACE("%p\n", pidlAbs);
3368
3369 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3370 {
3371 psf = psfParent;
3372 if(pidlAbs && pidlAbs->mkid.cb)
3373 {
3374 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3375 {
3376 IShellFolder_Release(psfParent);
3377 return psf;
3378 }
3379 }
3380 /* return the desktop */
3381 return psfParent;
3382 }
3383 return NULL;
3384 }
3385
3386 /***********************************************************************
3387 * GetParentPidl
3388 *
3389 * Return the LPITEMIDLIST to the parent of the pidl in the list
3390 */
3391 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3392 {
3393 LPITEMIDLIST pidlParent;
3394
3395 TRACE("%p\n", pidl);
3396
3397 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3398 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3399
3400 return pidlParent;
3401 }
3402
3403 /***********************************************************************
3404 * GetPidlFromName
3405 *
3406 * returns the pidl of the file name relative to folder
3407 * NULL if an error occurred
3408 */
3409 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3410 {
3411 LPITEMIDLIST pidl = NULL;
3412 ULONG ulEaten;
3413
3414 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3415
3416 if(!lpcstrFileName) return NULL;
3417 if(!*lpcstrFileName) return NULL;
3418
3419 if(!lpsf)
3420 {
3421 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3422 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3423 IShellFolder_Release(lpsf);
3424 }
3425 }
3426 else
3427 {
3428 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3429 }
3430 return pidl;
3431 }
3432
3433 /*
3434 */
3435 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3436 {
3437 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3438 HRESULT ret;
3439
3440 TRACE("%p, %p\n", psf, pidl);
3441
3442 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3443
3444 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3445 /* see documentation shell 4.1*/
3446 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3447 }
3448
3449 /***********************************************************************
3450 * BrowseSelectedFolder
3451 */
3452 static BOOL BrowseSelectedFolder(HWND hwnd)
3453 {
3454 BOOL bBrowseSelFolder = FALSE;
3455 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3456
3457 TRACE("\n");
3458
3459 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3460 {
3461 LPITEMIDLIST pidlSelection;
3462
3463 /* get the file selected */
3464 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3465 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3466 {
3467 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3468 pidlSelection, SBSP_RELATIVE ) ) )
3469 {
3470 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3471 ' ','n','o','t',' ','e','x','i','s','t',0};
3472 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3473 }
3474 bBrowseSelFolder = TRUE;
3475 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3476 }
3477 COMDLG32_SHFree( pidlSelection );
3478 }
3479
3480 return bBrowseSelFolder;
3481 }
3482
3483 /*
3484 * Memory allocation methods */
3485 static void *MemAlloc(UINT size)
3486 {
3487 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3488 }
3489
3490 static void MemFree(void *mem)
3491 {
3492 HeapFree(GetProcessHeap(),0,mem);
3493 }
3494
3495 /*
3496 * Old-style (win3.1) dialogs */
3497
3498 /***********************************************************************
3499 * FD32_GetTemplate [internal]
3500 *
3501 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3502 * by a 32 bits application
3503 *
3504 */
3505 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3506 {
3507 LPOPENFILENAMEW ofnW = lfs->ofnW;
3508 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3509 HANDLE hDlgTmpl;
3510
3511 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3512 {
3513 if (!(lfs->template = LockResource( ofnW->hInstance )))
3514 {
3515 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3516 return FALSE;
3517 }
3518 }
3519 else if (ofnW->Flags &