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