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