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