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