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