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