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