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