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