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