Fix 16/32 bit separation.
[wine/multimedia.git] / dlls / commdlg / filedlg.c
blobaef7f7747295dae09e3ef3a4415b3207b9dc7057
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "windef.h"
61 #include "winbase.h"
62 #include "winreg.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wine/unicode.h"
66 #include "wingdi.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "filedlg31.h"
72 #include "wine/debug.h"
73 #include "cderr.h"
74 #include "shellapi.h"
75 #include "shlguid.h"
76 #include "shlobj.h"
77 #include "filedlgbrowser.h"
78 #include "shlwapi.h"
80 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
82 #define UNIMPLEMENTED_FLAGS \
83 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
84 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
96 HIMAGELIST hImgList;
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
104 int iMaxIndentation;
105 UINT uSelectedItem;
106 } LookInInfos;
108 typedef struct tagFD32_PRIVATE
110 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
111 } FD32_PRIVATE, *PFD32_PRIVATE;
114 /***********************************************************************
115 * Defines and global variables
118 /* Draw item constant */
119 #define ICONWIDTH 18
120 #define XTEXTOFFSET 3
122 /* AddItem flags*/
123 #define LISTEND -1
125 /* SearchItem methods */
126 #define SEARCH_PIDL 1
127 #define SEARCH_EXP 2
128 #define ITEM_NOTFOUND -1
130 /* Undefined windows message sent by CreateViewObject*/
131 #define WM_GETISHELLBROWSER WM_USER+7
133 /* NOTE
134 * Those macros exist in windowsx.h. However, you can't really use them since
135 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 /* Combo box macros */
139 #define CBAddString(hwnd,str) \
140 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
141 #define CBAddStringW(hwnd,str) \
142 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
159 #define CBGetCurSel(hwnd) \
160 SendMessageA(hwnd,CB_GETCURSEL,0,0);
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
165 #define CBGetCount(hwnd) \
166 SendMessageA(hwnd,CB_GETCOUNT,0,0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0)
175 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
176 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
178 /***********************************************************************
179 * Prototypes
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186 BOOL FILEDLG95_OnOpen(HWND hwnd);
187 static LRESULT FILEDLG95_InitControls(HWND hwnd);
188 static void FILEDLG95_Clean(HWND hwnd);
190 /* Functions used by the shell navigation */
191 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197 /* Functions used by the filetype combo box */
198 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
199 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
200 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
201 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
203 /* Functions used by the Look In combo box */
204 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
205 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
206 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
207 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
208 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
209 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
210 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
211 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
212 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
214 /* Miscellaneous tool functions */
215 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
216 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
217 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
218 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
219 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
221 /* Shell memory allocation */
222 static void *MemAlloc(UINT size);
223 static void MemFree(void *mem);
225 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
226 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
227 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
228 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
230 static BOOL BrowseSelectedFolder(HWND hwnd);
232 /***********************************************************************
233 * GetFileName95
235 * Creates an Open common dialog box that lets the user select
236 * the drive, directory, and the name of a file or set of files to open.
238 * IN : The FileOpenDlgInfos structure associated with the dialog
239 * OUT : TRUE on success
240 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
242 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
245 LRESULT lRes;
246 LPCVOID template;
247 HRSRC hRes;
248 HANDLE hDlgTmpl = 0;
250 /* test for missing functionality */
251 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
253 FIXME("Flags 0x%08lx not yet implemented\n",
254 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
257 /* Create the dialog from a template */
259 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
261 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
262 return FALSE;
264 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
265 !(template = LockResource( hDlgTmpl )))
267 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
268 return FALSE;
271 /* old style hook messages */
272 if (IsHooked(fodInfos))
274 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
275 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
276 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
277 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
280 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
281 (LPDLGTEMPLATEA) template,
282 fodInfos->ofnInfos->hwndOwner,
283 FileOpenDlgProc95,
284 (LPARAM) fodInfos);
286 /* Unable to create the dialog */
287 if( lRes == -1)
288 return FALSE;
290 return lRes;
293 /***********************************************************************
294 * GetFileDialog95A
296 * Call GetFileName95 with this structure and clean the memory.
298 * IN : The OPENFILENAMEA initialisation structure passed to
299 * GetOpenFileNameA win api function (see filedlg.c)
301 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
303 BOOL ret;
304 FileOpenDlgInfos fodInfos;
305 LPSTR lpstrSavDir = NULL;
306 LPWSTR title = NULL;
307 LPWSTR defext = NULL;
308 LPWSTR filter = NULL;
309 LPWSTR customfilter = NULL;
311 /* Initialize FileOpenDlgInfos structure */
312 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
314 /* Pass in the original ofn */
315 fodInfos.ofnInfos = ofn;
317 /* save current directory */
318 if (ofn->Flags & OFN_NOCHANGEDIR)
320 lpstrSavDir = MemAlloc(MAX_PATH);
321 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
324 fodInfos.unicode = FALSE;
326 /* convert all the input strings to unicode */
327 if(ofn->lpstrInitialDir)
329 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
330 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
331 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
333 else
334 fodInfos.initdir = NULL;
336 if(ofn->lpstrFile)
338 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
339 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
341 else
342 fodInfos.filename = NULL;
344 if(ofn->lpstrDefExt)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
347 defext = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
350 fodInfos.defext = defext;
352 if(ofn->lpstrTitle)
354 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
355 title = MemAlloc((len+1)*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
358 fodInfos.title = title;
360 if (ofn->lpstrFilter)
362 LPCSTR s;
363 int n, len;
365 /* filter is a list... title\0ext\0......\0\0 */
366 s = ofn->lpstrFilter;
367 while (*s) s = s+strlen(s)+1;
368 s++;
369 n = s - ofn->lpstrFilter;
370 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
371 filter = MemAlloc(len*sizeof(WCHAR));
372 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
374 fodInfos.filter = filter;
376 /* convert lpstrCustomFilter */
377 if (ofn->lpstrCustomFilter)
379 LPCSTR s;
380 int n, len;
382 /* customfilter contains a pair of strings... title\0ext\0 */
383 s = ofn->lpstrCustomFilter;
384 if (*s) s = s+strlen(s)+1;
385 if (*s) s = s+strlen(s)+1;
386 n = s - ofn->lpstrCustomFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
388 customfilter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
391 fodInfos.customfilter = customfilter;
393 /* Initialize the dialog property */
394 fodInfos.DlgInfos.dwDlgProp = 0;
395 fodInfos.DlgInfos.hwndCustomDlg = NULL;
397 switch(iDlgType)
399 case OPEN_DIALOG :
400 ret = GetFileName95(&fodInfos);
401 break;
402 case SAVE_DIALOG :
403 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
404 ret = GetFileName95(&fodInfos);
405 break;
406 default :
407 ret = 0;
410 if (lpstrSavDir)
412 SetCurrentDirectoryA(lpstrSavDir);
413 MemFree(lpstrSavDir);
416 if(title)
417 MemFree(title);
418 if(defext)
419 MemFree(defext);
420 if(filter)
421 MemFree(filter);
422 if(customfilter)
423 MemFree(customfilter);
424 if(fodInfos.initdir)
425 MemFree(fodInfos.initdir);
427 if(fodInfos.filename)
428 MemFree(fodInfos.filename);
430 TRACE("selected file: %s\n",ofn->lpstrFile);
432 return ret;
435 /***********************************************************************
436 * GetFileDialog95W
438 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
439 * Call GetFileName95 with this structure and clean the memory.
442 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
444 BOOL ret;
445 FileOpenDlgInfos fodInfos;
446 LPSTR lpstrSavDir = NULL;
448 /* Initialize FileOpenDlgInfos structure */
449 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
451 /* Pass in the original ofn */
452 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
454 fodInfos.title = ofn->lpstrTitle;
455 fodInfos.defext = ofn->lpstrDefExt;
456 fodInfos.filter = ofn->lpstrFilter;
457 fodInfos.customfilter = ofn->lpstrCustomFilter;
459 /* convert string arguments, save others */
460 if(ofn->lpstrFile)
462 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
463 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
465 else
466 fodInfos.filename = NULL;
468 if(ofn->lpstrInitialDir)
470 DWORD len = strlenW(ofn->lpstrInitialDir);
471 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
472 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
474 else
475 fodInfos.initdir = NULL;
477 /* save current directory */
478 if (ofn->Flags & OFN_NOCHANGEDIR)
480 lpstrSavDir = MemAlloc(MAX_PATH);
481 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
484 fodInfos.unicode = TRUE;
486 switch(iDlgType)
488 case OPEN_DIALOG :
489 ret = GetFileName95(&fodInfos);
490 break;
491 case SAVE_DIALOG :
492 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
493 ret = GetFileName95(&fodInfos);
494 break;
495 default :
496 ret = 0;
499 if (lpstrSavDir)
501 SetCurrentDirectoryA(lpstrSavDir);
502 MemFree(lpstrSavDir);
505 /* restore saved IN arguments and convert OUT arguments back */
506 MemFree(fodInfos.filename);
507 MemFree(fodInfos.initdir);
508 return ret;
511 /***********************************************************************
512 * ArrangeCtrlPositions [internal]
514 * NOTE: Do not change anything here without a lot of testing.
516 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
518 HWND hwndChild, hwndStc32;
519 RECT rectParent, rectChild, rectStc32;
520 INT help_fixup = 0;
522 /* Take into account if open as read only checkbox and help button
523 * are hidden
525 if (hide_help)
527 RECT rectHelp, rectCancel;
528 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
529 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
530 /* subtract the height of the help button plus the space between
531 * the help button and the cancel button to the height of the dialog
533 help_fixup = rectHelp.bottom - rectCancel.bottom;
537 There are two possibilities to add components to the default file dialog box.
539 By default, all the new components are added below the standard dialog box (the else case).
541 However, if there is a static text component with the stc32 id, a special case happens.
542 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
543 in the window and the cx and cy indicate how to size the window.
544 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
545 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
549 GetClientRect(hwndParentDlg, &rectParent);
551 /* when arranging controls we have to use fixed parent size */
552 rectParent.bottom -= help_fixup;
554 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
555 if (hwndStc32)
557 GetWindowRect(hwndStc32, &rectStc32);
558 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
560 /* set the size of the stc32 control according to the size of
561 * client area of the parent dialog
563 SetWindowPos(hwndStc32, 0,
564 0, 0,
565 rectParent.right, rectParent.bottom,
566 SWP_NOMOVE | SWP_NOZORDER);
568 else
569 SetRectEmpty(&rectStc32);
571 /* this part moves controls of the child dialog */
572 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
573 while (hwndChild)
575 if (hwndChild != hwndStc32)
577 GetWindowRect(hwndChild, &rectChild);
578 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
580 /* move only if stc32 exist */
581 if (hwndStc32 && rectChild.left > rectStc32.right)
583 /* move to the right of visible controls of the parent dialog */
584 rectChild.left += rectParent.right;
585 rectChild.left -= rectStc32.right;
587 /* move even if stc32 doesn't exist */
588 if (rectChild.top > rectStc32.bottom)
590 /* move below visible controls of the parent dialog */
591 rectChild.top += rectParent.bottom;
592 rectChild.top -= rectStc32.bottom - rectStc32.top;
595 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
596 0, 0, SWP_NOSIZE | SWP_NOZORDER);
598 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
601 /* this part moves controls of the parent dialog */
602 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
603 while (hwndChild)
605 if (hwndChild != hwndChildDlg)
607 GetWindowRect(hwndChild, &rectChild);
608 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
610 /* left,top of stc32 marks the position of controls
611 * from the parent dialog
613 rectChild.left += rectStc32.left;
614 rectChild.top += rectStc32.top;
616 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
617 0, 0, SWP_NOSIZE | SWP_NOZORDER);
619 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
622 /* calculate the size of the resulting dialog */
624 /* here we have to use original parent size */
625 GetClientRect(hwndParentDlg, &rectParent);
626 GetClientRect(hwndChildDlg, &rectChild);
628 if (hwndStc32)
630 if (rectParent.right > rectChild.right)
632 rectParent.right += rectChild.right;
633 rectParent.right -= rectStc32.right - rectStc32.left;
635 else
637 rectParent.right = rectChild.right;
640 if (rectParent.bottom > rectChild.bottom)
642 rectParent.bottom += rectChild.bottom;
643 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
645 else
647 rectParent.bottom = rectChild.bottom;
650 else
652 rectParent.bottom += rectChild.bottom;
655 /* finally use fixed parent size */
656 rectParent.bottom -= help_fixup;
658 /* save the size of the parent's client area */
659 rectChild.right = rectParent.right;
660 rectChild.bottom = rectParent.bottom;
662 /* set the size of the parent dialog */
663 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
664 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
665 SetWindowPos(hwndParentDlg, 0,
666 0, 0,
667 rectParent.right - rectParent.left,
668 rectParent.bottom - rectParent.top,
669 SWP_NOMOVE | SWP_NOZORDER);
671 /* set the size of the child dialog */
672 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
673 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
676 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
678 switch(uMsg) {
679 case WM_INITDIALOG:
680 return TRUE;
682 return FALSE;
685 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
687 LPCVOID template;
688 HRSRC hRes;
689 HANDLE hDlgTmpl = 0;
690 HWND hChildDlg = 0;
692 TRACE("\n");
695 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
696 * structure's hInstance parameter is not a HINSTANCE, but
697 * instead a pointer to a template resource to use.
699 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
701 HINSTANCE hinst;
702 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
704 hinst = 0;
705 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
707 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
708 return NULL;
711 else
713 hinst = fodInfos->ofnInfos->hInstance;
714 if(fodInfos->unicode)
716 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
717 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
719 else
721 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
722 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
724 if (!hRes)
726 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
727 return NULL;
729 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
730 !(template = LockResource( hDlgTmpl )))
732 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
733 return NULL;
736 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd,
737 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
738 (LPARAM)fodInfos->ofnInfos);
739 if(hChildDlg)
741 ShowWindow(hChildDlg,SW_SHOW);
742 return hChildDlg;
745 else if( IsHooked(fodInfos))
747 RECT rectHwnd;
748 struct {
749 DLGTEMPLATE tmplate;
750 WORD menu,class,title;
751 } temp;
752 GetClientRect(hwnd,&rectHwnd);
753 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
754 temp.tmplate.dwExtendedStyle = 0;
755 temp.tmplate.cdit = 0;
756 temp.tmplate.x = 0;
757 temp.tmplate.y = 0;
758 temp.tmplate.cx = 0;
759 temp.tmplate.cy = 0;
760 temp.menu = temp.class = temp.title = 0;
762 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
763 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
765 return hChildDlg;
767 return NULL;
770 /***********************************************************************
771 * SendCustomDlgNotificationMessage
773 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
776 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
778 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
780 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
782 if(!fodInfos) return 0;
784 if(fodInfos->unicode)
785 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
787 if(fodInfos->DlgInfos.hwndCustomDlg)
789 OFNOTIFYA ofnNotify;
790 HRESULT ret;
791 ofnNotify.hdr.hwndFrom=hwndParentDlg;
792 ofnNotify.hdr.idFrom=0;
793 ofnNotify.hdr.code = uCode;
794 ofnNotify.lpOFN = fodInfos->ofnInfos;
795 ofnNotify.pszFile = NULL;
796 TRACE("CALL NOTIFY for %x\n", uCode);
797 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
798 TRACE("RET NOTIFY\n");
799 return ret;
801 return TRUE;
804 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
806 UINT sizeUsed = 0, n, total;
807 LPWSTR lpstrFileList = NULL;
808 WCHAR lpstrCurrentDir[MAX_PATH];
809 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
811 TRACE("CDM_GETFILEPATH:\n");
813 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
814 return -1;
816 /* get path and filenames */
817 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
818 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
820 TRACE("path >%s< filespec >%s< %d files\n",
821 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
823 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
824 NULL, 0, NULL, NULL);
825 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
826 NULL, 0, NULL, NULL);
828 /* Prepend the current path */
829 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
830 buffer, size, NULL, NULL);
832 if(n<size)
834 /* 'n' includes trailing \0 */
835 buffer[n-1] = '\\';
836 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
837 &buffer[n], size-n, NULL, NULL);
839 MemFree(lpstrFileList);
841 TRACE("returned -> %s\n",debugstr_a(buffer));
843 return total;
846 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
848 UINT sizeUsed = 0;
849 LPWSTR lpstrFileList = NULL;
851 TRACE("CDM_GETSPEC:\n");
853 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
854 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
855 MemFree(lpstrFileList);
857 return sizeUsed;
860 /***********************************************************************
861 * FILEDLG95_HandleCustomDialogMessages
863 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
865 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
867 char lpstrPath[MAX_PATH];
868 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
869 if(!fodInfos) return -1;
871 switch(uMsg)
873 case CDM_GETFILEPATH:
874 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
876 case CDM_GETFOLDERPATH:
877 TRACE("CDM_GETFOLDERPATH:\n");
878 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
879 if ((LPSTR)lParam!=NULL)
880 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
881 return strlen(lpstrPath);
883 case CDM_GETSPEC:
884 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
886 case CDM_SETCONTROLTEXT:
887 TRACE("CDM_SETCONTROLTEXT:\n");
888 if ( 0 != lParam )
889 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
890 return TRUE;
892 case CDM_HIDECONTROL:
893 case CDM_SETDEFEXT:
894 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
895 return -1;
897 return TRUE;
900 /***********************************************************************
901 * FileOpenDlgProc95
903 * File open dialog procedure
905 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
907 #if 0
908 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
909 #endif
911 switch(uMsg)
913 case WM_INITDIALOG:
915 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
917 /* Adds the FileOpenDlgInfos in the property list of the dialog
918 so it will be easily accessible through a GetPropA(...) */
919 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
921 fodInfos->DlgInfos.hwndCustomDlg =
922 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
924 FILEDLG95_InitControls(hwnd);
926 if (fodInfos->DlgInfos.hwndCustomDlg)
927 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
928 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
930 FILEDLG95_FillControls(hwnd, wParam, lParam);
932 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
933 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
934 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
935 return 0;
937 case WM_COMMAND:
938 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
939 case WM_DRAWITEM:
941 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
943 case IDC_LOOKIN:
944 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
945 return TRUE;
948 return FALSE;
950 case WM_GETISHELLBROWSER:
951 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
953 case WM_DESTROY:
954 RemovePropA(hwnd, FileOpenDlgInfosStr);
955 return FALSE;
957 case WM_NOTIFY:
959 LPNMHDR lpnmh = (LPNMHDR)lParam;
960 UINT stringId = -1;
962 /* set up the button tooltips strings */
963 if(TTN_GETDISPINFOA == lpnmh->code )
965 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
966 switch(lpnmh->idFrom )
968 /* Up folder button */
969 case FCIDM_TB_UPFOLDER:
970 stringId = IDS_UPFOLDER;
971 break;
972 /* New folder button */
973 case FCIDM_TB_NEWFOLDER:
974 stringId = IDS_NEWFOLDER;
975 break;
976 /* List option button */
977 case FCIDM_TB_SMALLICON:
978 stringId = IDS_LISTVIEW;
979 break;
980 /* Details option button */
981 case FCIDM_TB_REPORTVIEW:
982 stringId = IDS_REPORTVIEW;
983 break;
984 /* Desktop button */
985 case FCIDM_TB_DESKTOP:
986 stringId = IDS_TODESKTOP;
987 break;
988 default:
989 stringId = 0;
991 lpdi->hinst = COMDLG32_hInstance;
992 lpdi->lpszText = (LPSTR) stringId;
994 return FALSE;
996 default :
997 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
998 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
999 return FALSE;
1003 /***********************************************************************
1004 * FILEDLG95_InitControls
1006 * WM_INITDIALOG message handler (before hook notification)
1008 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1010 int win2000plus = 0;
1011 int win98plus = 0;
1012 int handledPath = FALSE;
1013 OSVERSIONINFOA osVi;
1014 static const WCHAR szwSlash[] = { '\\', 0 };
1015 static const WCHAR szwStar[] = { '*',0 };
1017 TBBUTTON tbb[] =
1019 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1020 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1021 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1022 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1023 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1024 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1025 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1026 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1027 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1029 TBADDBITMAP tba[2];
1030 RECT rectTB;
1031 RECT rectlook;
1032 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1034 tba[0].hInst = HINST_COMMCTRL;
1035 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1036 tba[1].hInst = COMDLG32_hInstance;
1037 tba[1].nID = 800;
1039 TRACE("%p\n", fodInfos);
1041 /* Get windows version emulating */
1042 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1043 GetVersionExA(&osVi);
1044 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1045 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1046 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1047 win2000plus = (osVi.dwMajorVersion > 4);
1048 if (win2000plus) win98plus = TRUE;
1050 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1052 /* Get the hwnd of the controls */
1053 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1054 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1055 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1057 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1058 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1060 /* construct the toolbar */
1061 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1062 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1064 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1065 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1066 rectTB.left = rectlook.right;
1067 rectTB.top = rectlook.top-1;
1069 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1070 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1071 rectTB.left, rectTB.top,
1072 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1073 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1075 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1077 /* FIXME: use TB_LOADIMAGES when implemented */
1078 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1079 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1080 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1082 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1083 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1085 /* Set the window text with the text specified in the OPENFILENAME structure */
1086 if(fodInfos->title)
1088 SetWindowTextW(hwnd,fodInfos->title);
1090 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1092 SetWindowTextA(hwnd,"Save");
1095 /* Initialise the file name edit control */
1096 handledPath = FALSE;
1097 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1099 if(fodInfos->filename)
1101 /* 1. If win2000 or higher and filename contains a path, use it
1102 in preference over the lpstrInitialDir */
1103 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1104 WCHAR tmpBuf[MAX_PATH];
1105 WCHAR *nameBit;
1106 DWORD result;
1108 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1109 if (result) {
1111 /* nameBit is always shorter than the original filename */
1112 strcpyW(fodInfos->filename,nameBit);
1114 *nameBit = 0x00;
1115 if (fodInfos->initdir == NULL)
1116 MemFree(fodInfos->initdir);
1117 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1118 strcpyW(fodInfos->initdir, tmpBuf);
1119 handledPath = TRUE;
1120 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1121 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1123 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1125 } else {
1126 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1130 /* 2. (All platforms) If initdir is not null, then use it */
1131 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1132 (*fodInfos->initdir!=0x00))
1134 /* Work out the proper path as supplied one might be relative */
1135 /* (Here because supplying '.' as dir browses to My Computer) */
1136 if (handledPath==FALSE) {
1137 WCHAR tmpBuf[MAX_PATH];
1138 WCHAR tmpBuf2[MAX_PATH];
1139 WCHAR *nameBit;
1140 DWORD result;
1142 strcpyW(tmpBuf, fodInfos->initdir);
1143 if( PathFileExistsW(tmpBuf) ) {
1144 /* initdir does not have to be a directory. If a file is
1145 * specified, the dir part is taken */
1146 if( PathIsDirectoryW(tmpBuf)) {
1147 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1148 strcatW(tmpBuf, szwSlash);
1150 strcatW(tmpBuf, szwStar);
1152 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1153 if (result) {
1154 *nameBit = 0x00;
1155 if (fodInfos->initdir)
1156 MemFree(fodInfos->initdir);
1157 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1158 strcpyW(fodInfos->initdir, tmpBuf2);
1159 handledPath = TRUE;
1160 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1163 else if (fodInfos->initdir)
1165 MemFree(fodInfos->initdir);
1166 fodInfos->initdir = NULL;
1167 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1172 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1173 (*fodInfos->initdir==0x00)))
1175 /* 3. All except w2k+: if filename contains a path use it */
1176 if (!win2000plus && fodInfos->filename &&
1177 *fodInfos->filename &&
1178 strpbrkW(fodInfos->filename, szwSlash)) {
1179 WCHAR tmpBuf[MAX_PATH];
1180 WCHAR *nameBit;
1181 DWORD result;
1183 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1184 tmpBuf, &nameBit);
1185 if (result) {
1186 int len;
1188 /* nameBit is always shorter than the original filename */
1189 strcpyW(fodInfos->filename, nameBit);
1190 *nameBit = 0x00;
1192 len = strlenW(tmpBuf);
1193 if(fodInfos->initdir)
1194 MemFree(fodInfos->initdir);
1195 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1196 strcpyW(fodInfos->initdir, tmpBuf);
1198 handledPath = TRUE;
1199 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1200 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1202 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1205 /* 4. win98+ and win2000+ if any files of specified filter types in
1206 current directory, use it */
1207 if ( win98plus && handledPath == FALSE &&
1208 fodInfos->filter && *fodInfos->filter) {
1210 BOOL searchMore = TRUE;
1211 LPCWSTR lpstrPos = fodInfos->filter;
1212 WIN32_FIND_DATAW FindFileData;
1213 HANDLE hFind;
1215 while (searchMore)
1217 /* filter is a list... title\0ext\0......\0\0 */
1219 /* Skip the title */
1220 if(! *lpstrPos) break; /* end */
1221 lpstrPos += strlenW(lpstrPos) + 1;
1223 /* See if any files exist in the current dir with this extension */
1224 if(! *lpstrPos) break; /* end */
1226 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1228 if (hFind == INVALID_HANDLE_VALUE) {
1229 /* None found - continue search */
1230 lpstrPos += strlenW(lpstrPos) + 1;
1232 } else {
1233 searchMore = FALSE;
1235 if(fodInfos->initdir)
1236 MemFree(fodInfos->initdir);
1237 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1238 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1240 handledPath = TRUE;
1241 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1242 debugstr_w(lpstrPos));
1243 break;
1248 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1250 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1251 if (handledPath == FALSE && (win2000plus || win98plus)) {
1252 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1254 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1256 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1258 /* last fallback */
1259 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1260 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1261 } else {
1262 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1264 } else {
1265 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1267 handledPath = TRUE;
1268 } else if (handledPath==FALSE) {
1269 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1270 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1271 handledPath = TRUE;
1272 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1275 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1276 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1278 /* Must the open as read only check box be checked ?*/
1279 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1281 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1284 /* Must the open as read only check box be hidden? */
1285 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1287 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1288 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1291 /* Must the help button be hidden? */
1292 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1294 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1295 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1298 /* Resize the height, if open as read only checkbox ad help button
1299 are hidden and we are not using a custom template nor a customDialog
1301 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1302 (!(fodInfos->ofnInfos->Flags &
1303 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1304 (!fodInfos->DlgInfos.hwndCustomDlg ))
1306 RECT rectDlg, rectHelp, rectCancel;
1307 GetWindowRect(hwnd, &rectDlg);
1308 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1309 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1310 /* subtract the height of the help button plus the space between
1311 the help button and the cancel button to the height of the dialog */
1312 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1313 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1314 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1316 /* change Open to Save FIXME: use resources */
1317 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1319 SetDlgItemTextA(hwnd,IDOK,"&Save");
1320 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1322 return 0;
1325 /***********************************************************************
1326 * FILEDLG95_FillControls
1328 * WM_INITDIALOG message handler (after hook notification)
1330 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1332 LPITEMIDLIST pidlItemId = NULL;
1334 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1336 TRACE("dir=%s file=%s\n",
1337 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1339 /* Get the initial directory pidl */
1341 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1343 WCHAR path[MAX_PATH];
1345 GetCurrentDirectoryW(MAX_PATH,path);
1346 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1349 /* Initialise shell objects */
1350 FILEDLG95_SHELL_Init(hwnd);
1352 /* Initialize the Look In combo box */
1353 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1355 /* Initialize the filter combo box */
1356 FILEDLG95_FILETYPE_Init(hwnd);
1358 /* Browse to the initial directory */
1359 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1361 /* Free pidlItem memory */
1362 COMDLG32_SHFree(pidlItemId);
1364 return TRUE;
1366 /***********************************************************************
1367 * FILEDLG95_Clean
1369 * Regroups all the cleaning functions of the filedlg
1371 void FILEDLG95_Clean(HWND hwnd)
1373 FILEDLG95_FILETYPE_Clean(hwnd);
1374 FILEDLG95_LOOKIN_Clean(hwnd);
1375 FILEDLG95_SHELL_Clean(hwnd);
1377 /***********************************************************************
1378 * FILEDLG95_OnWMCommand
1380 * WM_COMMAND message handler
1382 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1384 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1385 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1386 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1388 switch(wID)
1390 /* OK button */
1391 case IDOK:
1392 FILEDLG95_OnOpen(hwnd);
1393 break;
1394 /* Cancel button */
1395 case IDCANCEL:
1396 FILEDLG95_Clean(hwnd);
1397 EndDialog(hwnd, FALSE);
1398 break;
1399 /* Filetype combo box */
1400 case IDC_FILETYPE:
1401 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1402 break;
1403 /* LookIn combo box */
1404 case IDC_LOOKIN:
1405 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1406 break;
1408 /* --- toolbar --- */
1409 /* Up folder button */
1410 case FCIDM_TB_UPFOLDER:
1411 FILEDLG95_SHELL_UpFolder(hwnd);
1412 break;
1413 /* New folder button */
1414 case FCIDM_TB_NEWFOLDER:
1415 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1416 break;
1417 /* List option button */
1418 case FCIDM_TB_SMALLICON:
1419 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1420 break;
1421 /* Details option button */
1422 case FCIDM_TB_REPORTVIEW:
1423 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1424 break;
1425 /* Details option button */
1426 case FCIDM_TB_DESKTOP:
1427 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1428 break;
1430 case IDC_FILENAME:
1431 break;
1434 /* Do not use the listview selection anymore */
1435 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1436 return 0;
1439 /***********************************************************************
1440 * FILEDLG95_OnWMGetIShellBrowser
1442 * WM_GETISHELLBROWSER message handler
1444 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1447 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1449 TRACE("\n");
1451 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1453 return TRUE;
1457 /***********************************************************************
1458 * FILEDLG95_SendFileOK
1460 * Sends the CDN_FILEOK notification if required
1462 * RETURNS
1463 * TRUE if the dialog should close
1464 * FALSE if the dialog should not be closed
1466 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1468 /* ask the hook if we can close */
1469 if(IsHooked(fodInfos))
1471 TRACE("---\n");
1472 /* First send CDN_FILEOK as MSDN doc says */
1473 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1474 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1476 TRACE("canceled\n");
1477 return FALSE;
1480 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1481 SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1482 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1483 if (GetWindowLongW(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1485 TRACE("canceled\n");
1486 return FALSE;
1489 return TRUE;
1492 /***********************************************************************
1493 * FILEDLG95_OnOpenMultipleFiles
1495 * Handles the opening of multiple files.
1497 * FIXME
1498 * check destination buffer size
1500 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1502 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1503 UINT nCount, nSizePath;
1504 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1506 TRACE("\n");
1508 if(fodInfos->unicode)
1510 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1511 ofn->lpstrFile[0] = '\0';
1513 else
1515 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1516 ofn->lpstrFile[0] = '\0';
1519 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1521 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1522 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1523 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1525 LPWSTR lpstrTemp = lpstrFileList;
1527 for ( nCount = 0; nCount < nFileCount; nCount++ )
1529 LPITEMIDLIST pidl;
1531 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1532 if (!pidl)
1534 WCHAR lpstrNotFound[100];
1535 WCHAR lpstrMsg[100];
1536 WCHAR tmp[400];
1537 static const WCHAR nl[] = {'\n',0};
1539 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1540 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1542 strcpyW(tmp, lpstrTemp);
1543 strcatW(tmp, nl);
1544 strcatW(tmp, lpstrNotFound);
1545 strcatW(tmp, nl);
1546 strcatW(tmp, lpstrMsg);
1548 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1549 return FALSE;
1552 /* move to the next file in the list of files */
1553 lpstrTemp += strlenW(lpstrTemp) + 1;
1554 COMDLG32_SHFree(pidl);
1558 nSizePath = strlenW(lpstrPathSpec) + 1;
1559 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1561 /* For "oldstyle" dialog the components have to
1562 be separated by blanks (not '\0'!) and short
1563 filenames have to be used! */
1564 FIXME("Components have to be separated by blanks\n");
1566 if(fodInfos->unicode)
1568 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1569 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1570 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1572 else
1574 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1576 if (ofn->lpstrFile != NULL)
1578 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1579 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1580 if (ofn->nMaxFile > nSizePath)
1582 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1583 ofn->lpstrFile + nSizePath,
1584 ofn->nMaxFile - nSizePath, NULL, NULL);
1589 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1590 fodInfos->ofnInfos->nFileExtension = 0;
1592 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1593 return FALSE;
1595 /* clean and exit */
1596 FILEDLG95_Clean(hwnd);
1597 return EndDialog(hwnd,TRUE);
1600 /***********************************************************************
1601 * FILEDLG95_OnOpen
1603 * Ok button WM_COMMAND message handler
1605 * If the function succeeds, the return value is nonzero.
1607 #define ONOPEN_BROWSE 1
1608 #define ONOPEN_OPEN 2
1609 #define ONOPEN_SEARCH 3
1610 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1612 char strMsgTitle[MAX_PATH];
1613 char strMsgText [MAX_PATH];
1614 if (idCaption)
1615 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1616 else
1617 strMsgTitle[0] = '\0';
1618 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1619 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1622 BOOL FILEDLG95_OnOpen(HWND hwnd)
1624 LPWSTR lpstrFileList;
1625 UINT nFileCount = 0;
1626 UINT sizeUsed = 0;
1627 BOOL ret = TRUE;
1628 WCHAR lpstrPathAndFile[MAX_PATH];
1629 WCHAR lpstrTemp[MAX_PATH];
1630 LPSHELLFOLDER lpsf = NULL;
1631 int nOpenAction;
1632 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1634 TRACE("hwnd=%p\n", hwnd);
1636 /* get the files from the edit control */
1637 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1639 /* try if the user selected a folder in the shellview */
1640 if(nFileCount == 0)
1642 BrowseSelectedFolder(hwnd);
1643 return FALSE;
1646 if(nFileCount > 1)
1648 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1649 goto ret;
1652 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1655 Step 1: Build a complete path name from the current folder and
1656 the filename or path in the edit box.
1657 Special cases:
1658 - the path in the edit box is a root path
1659 (with or without drive letter)
1660 - the edit box contains ".." (or a path with ".." in it)
1663 /* Get the current directory name */
1664 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1666 /* we are in a special folder, default to desktop */
1667 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1669 /* last fallback */
1670 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1673 PathAddBackslashW(lpstrPathAndFile);
1675 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1677 /* if the user specifyed a fully qualified path use it */
1678 if(PathIsRelativeW(lpstrFileList))
1680 strcatW(lpstrPathAndFile, lpstrFileList);
1682 else
1684 /* does the path have a drive letter? */
1685 if (PathGetDriveNumberW(lpstrFileList) == -1)
1686 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1687 else
1688 strcpyW(lpstrPathAndFile, lpstrFileList);
1691 /* resolve "." and ".." */
1692 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1693 strcpyW(lpstrPathAndFile, lpstrTemp);
1694 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1696 MemFree(lpstrFileList);
1699 Step 2: here we have a cleaned up path
1701 We have to parse the path step by step to see if we have to browse
1702 to a folder if the path points to a directory or the last
1703 valid element is a directory.
1705 valid variables:
1706 lpstrPathAndFile: cleaned up path
1709 nOpenAction = ONOPEN_BROWSE;
1711 /* don't apply any checks with OFN_NOVALIDATE */
1713 LPWSTR lpszTemp, lpszTemp1;
1714 LPITEMIDLIST pidl = NULL;
1715 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1717 /* check for invalid chars */
1718 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1720 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1721 ret = FALSE;
1722 goto ret;
1725 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1727 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1728 while (lpszTemp1)
1730 LPSHELLFOLDER lpsfChild;
1731 WCHAR lpwstrTemp[MAX_PATH];
1732 DWORD dwEaten, dwAttributes;
1733 LPWSTR p;
1735 strcpyW(lpwstrTemp, lpszTemp);
1736 p = PathFindNextComponentW(lpwstrTemp);
1738 if (!p) break; /* end of path */
1740 *p = 0;
1741 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1743 if(*lpszTemp==0)
1745 static const WCHAR wszWild[] = { '*', '?', 0 };
1746 /* if the last element is a wildcard do a search */
1747 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1749 nOpenAction = ONOPEN_SEARCH;
1750 break;
1753 lpszTemp1 = lpszTemp;
1755 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1757 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1759 dwAttributes = SFGAO_FOLDER;
1760 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1762 /* the path component is valid, we have a pidl of the next path component */
1763 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1764 if(dwAttributes & SFGAO_FOLDER)
1766 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1768 ERR("bind to failed\n"); /* should not fail */
1769 break;
1771 IShellFolder_Release(lpsf);
1772 lpsf = lpsfChild;
1773 lpsfChild = NULL;
1775 else
1777 TRACE("value\n");
1779 /* end dialog, return value */
1780 nOpenAction = ONOPEN_OPEN;
1781 break;
1783 COMDLG32_SHFree(pidl);
1784 pidl = NULL;
1786 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1788 if(*lpszTemp) /* points to trailing null for last path element */
1790 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1792 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1793 break;
1796 else
1798 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1799 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1801 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1802 break;
1805 /* change to the current folder */
1806 nOpenAction = ONOPEN_OPEN;
1807 break;
1809 else
1811 nOpenAction = ONOPEN_OPEN;
1812 break;
1815 if(pidl) COMDLG32_SHFree(pidl);
1819 Step 3: here we have a cleaned up and validated path
1821 valid variables:
1822 lpsf: ShellFolder bound to the rightmost valid path component
1823 lpstrPathAndFile: cleaned up path
1824 nOpenAction: action to do
1826 TRACE("end validate sf=%p\n", lpsf);
1828 switch(nOpenAction)
1830 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1831 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1833 int iPos;
1834 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1835 DWORD len;
1837 /* replace the current filter */
1838 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1839 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1840 len = strlenW(lpszTemp)+1;
1841 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1842 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1844 /* set the filter cb to the extension when possible */
1845 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1846 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1848 /* fall through */
1849 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1850 TRACE("ONOPEN_BROWSE\n");
1852 IPersistFolder2 * ppf2;
1853 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1855 LPITEMIDLIST pidlCurrent;
1856 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1857 IPersistFolder2_Release(ppf2);
1858 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1860 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1862 else if( nOpenAction == ONOPEN_SEARCH )
1864 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1866 COMDLG32_SHFree(pidlCurrent);
1869 ret = FALSE;
1870 break;
1871 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1872 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1874 /* update READONLY check box flag */
1875 if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
1876 fodInfos->ofnInfos->Flags |= OFN_READONLY;
1877 else
1878 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
1880 /* add default extension */
1881 if (fodInfos->defext)
1883 WCHAR *ext = PathFindExtensionW(lpstrPathAndFile);
1885 if (! *ext)
1887 /* only add "." in case a default extension does exist */
1888 if (*fodInfos->defext != '\0')
1890 static const WCHAR szwDot[] = {'.',0};
1891 int PathLength = strlenW(lpstrPathAndFile);
1893 strcatW(lpstrPathAndFile, szwDot);
1894 strcatW(lpstrPathAndFile, fodInfos->defext);
1896 /* In Open dialog: if file does not exist try without extension */
1897 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1898 && !PathFileExistsW(lpstrPathAndFile))
1899 lpstrPathAndFile[PathLength] = '\0';
1903 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
1904 if (*ext)
1905 ext++;
1906 if (!lstrcmpiW(fodInfos->defext, ext))
1907 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
1908 else
1909 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
1912 /* In Save dialog: check if the file already exists */
1913 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
1914 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
1915 && PathFileExistsW(lpstrPathAndFile))
1917 WCHAR lpstrOverwrite[100];
1918 int answer;
1920 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
1921 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
1922 MB_YESNO | MB_ICONEXCLAMATION);
1923 if (answer == IDNO)
1925 ret = FALSE;
1926 goto ret;
1930 /* Check that the size of the file does not exceed buffer size.
1931 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1932 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1933 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1935 LPWSTR lpszTemp;
1937 /* fill destination buffer */
1938 if (fodInfos->ofnInfos->lpstrFile)
1940 if(fodInfos->unicode)
1942 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1944 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1945 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1946 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1948 else
1950 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1952 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1953 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1954 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1955 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1959 /* set filename offset */
1960 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1961 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1963 /* set extension offset */
1964 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1965 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1967 /* set the lpstrFileTitle */
1968 if(fodInfos->ofnInfos->lpstrFileTitle)
1970 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1971 if(fodInfos->unicode)
1973 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1974 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1976 else
1978 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1979 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1980 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1984 /* copy currently selected filter to lpstrCustomFilter */
1985 if (fodInfos->ofnInfos->lpstrCustomFilter)
1987 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1988 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
1989 NULL, 0, NULL, NULL);
1990 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
1992 LPSTR s = ofn->lpstrCustomFilter;
1993 s += strlen(ofn->lpstrCustomFilter)+1;
1994 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
1995 s, len, NULL, NULL);
2000 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2001 goto ret;
2003 TRACE("close\n");
2004 FILEDLG95_Clean(hwnd);
2005 ret = EndDialog(hwnd, TRUE);
2007 else
2009 WORD size;
2011 size = strlenW(lpstrPathAndFile) + 1;
2012 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2013 size += 1;
2014 /* return needed size in first two bytes of lpstrFile */
2015 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2016 FILEDLG95_Clean(hwnd);
2017 ret = EndDialog(hwnd, FALSE);
2018 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2020 goto ret;
2022 break;
2025 ret:
2026 if(lpsf) IShellFolder_Release(lpsf);
2027 return ret;
2030 /***********************************************************************
2031 * FILEDLG95_SHELL_Init
2033 * Initialisation of the shell objects
2035 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2037 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2039 TRACE("\n");
2042 * Initialisation of the FileOpenDialogInfos structure
2045 /* Shell */
2047 /*ShellInfos */
2048 fodInfos->ShellInfos.hwndOwner = hwnd;
2050 /* Disable multi-select if flag not set */
2051 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2053 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2055 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2056 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2058 /* Construct the IShellBrowser interface */
2059 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2061 return NOERROR;
2064 /***********************************************************************
2065 * FILEDLG95_SHELL_ExecuteCommand
2067 * Change the folder option and refresh the view
2068 * If the function succeeds, the return value is nonzero.
2070 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2072 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2074 IContextMenu * pcm;
2075 TRACE("(%p,%p)\n", hwnd, lpVerb);
2077 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2078 SVGIO_BACKGROUND,
2079 &IID_IContextMenu,
2080 (LPVOID*)&pcm)))
2082 CMINVOKECOMMANDINFO ci;
2083 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2084 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2085 ci.lpVerb = lpVerb;
2086 ci.hwnd = hwnd;
2088 IContextMenu_InvokeCommand(pcm, &ci);
2089 IContextMenu_Release(pcm);
2092 return FALSE;
2095 /***********************************************************************
2096 * FILEDLG95_SHELL_UpFolder
2098 * Browse to the specified object
2099 * If the function succeeds, the return value is nonzero.
2101 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2103 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2105 TRACE("\n");
2107 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2108 NULL,
2109 SBSP_PARENT)))
2111 return TRUE;
2113 return FALSE;
2116 /***********************************************************************
2117 * FILEDLG95_SHELL_BrowseToDesktop
2119 * Browse to the Desktop
2120 * If the function succeeds, the return value is nonzero.
2122 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2124 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2125 LPITEMIDLIST pidl;
2126 HRESULT hres;
2128 TRACE("\n");
2130 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2131 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2132 COMDLG32_SHFree(pidl);
2133 return SUCCEEDED(hres);
2135 /***********************************************************************
2136 * FILEDLG95_SHELL_Clean
2138 * Cleans the memory used by shell objects
2140 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2142 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2144 TRACE("\n");
2146 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2148 /* clean Shell interfaces */
2149 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2150 IShellView_Release(fodInfos->Shell.FOIShellView);
2151 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2152 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2153 if (fodInfos->Shell.FOIDataObject)
2154 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2157 /***********************************************************************
2158 * FILEDLG95_FILETYPE_Init
2160 * Initialisation of the file type combo box
2162 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2164 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2165 int nFilters = 0; /* number of filters */
2166 int nFilterIndexCB;
2168 TRACE("\n");
2170 if(fodInfos->customfilter)
2172 /* customfilter has one entry... title\0ext\0
2173 * Set first entry of combo box item with customfilter
2175 LPWSTR lpstrExt;
2176 LPCWSTR lpstrPos = fodInfos->customfilter;
2178 /* Get the title */
2179 lpstrPos += strlenW(fodInfos->customfilter) + 1;
2181 /* Copy the extensions */
2182 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2183 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2184 strcpyW(lpstrExt,lpstrPos);
2186 /* Add the item at the end of the combo */
2187 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2188 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2189 nFilters++;
2191 if(fodInfos->filter)
2193 LPCWSTR lpstrPos = fodInfos->filter;
2195 for(;;)
2197 /* filter is a list... title\0ext\0......\0\0
2198 * Set the combo item text to the title and the item data
2199 * to the ext
2201 LPCWSTR lpstrDisplay;
2202 LPWSTR lpstrExt;
2204 /* Get the title */
2205 if(! *lpstrPos) break; /* end */
2206 lpstrDisplay = lpstrPos;
2207 lpstrPos += strlenW(lpstrPos) + 1;
2209 /* Copy the extensions */
2210 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2211 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2212 strcpyW(lpstrExt,lpstrPos);
2213 lpstrPos += strlenW(lpstrPos) + 1;
2215 /* Add the item at the end of the combo */
2216 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2217 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2218 nFilters++;
2223 * Set the current filter to the one specified
2224 * in the initialisation structure
2226 if (fodInfos->filter || fodInfos->customfilter)
2228 LPWSTR lpstrFilter;
2230 /* Check to make sure our index isn't out of bounds. */
2231 if ( fodInfos->ofnInfos->nFilterIndex >
2232 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2233 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2235 /* set default filter index */
2236 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2237 fodInfos->ofnInfos->nFilterIndex = 1;
2239 /* calculate index of Combo Box item */
2240 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2241 if (fodInfos->customfilter == NULL)
2242 nFilterIndexCB--;
2244 /* Set the current index selection. */
2245 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2247 /* Get the corresponding text string from the combo box. */
2248 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2249 nFilterIndexCB);
2251 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2252 lpstrFilter = NULL;
2254 if(lpstrFilter)
2256 DWORD len;
2257 CharLowerW(lpstrFilter); /* lowercase */
2258 len = strlenW(lpstrFilter)+1;
2259 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2260 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2262 } else
2263 fodInfos->ofnInfos->nFilterIndex = 0;
2265 return NOERROR;
2268 /***********************************************************************
2269 * FILEDLG95_FILETYPE_OnCommand
2271 * WM_COMMAND of the file type combo box
2272 * If the function succeeds, the return value is nonzero.
2274 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2276 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2278 switch(wNotifyCode)
2280 case CBN_SELENDOK:
2282 LPWSTR lpstrFilter;
2284 /* Get the current item of the filetype combo box */
2285 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2287 /* set the current filter index */
2288 fodInfos->ofnInfos->nFilterIndex = iItem +
2289 (fodInfos->customfilter == NULL ? 1 : 0);
2291 /* Set the current filter with the current selection */
2292 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2293 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2295 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2296 iItem);
2297 if((int)lpstrFilter != CB_ERR)
2299 DWORD len;
2300 CharLowerW(lpstrFilter); /* lowercase */
2301 len = strlenW(lpstrFilter)+1;
2302 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2303 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2304 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2307 /* Refresh the actual view to display the included items*/
2308 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2311 return FALSE;
2313 /***********************************************************************
2314 * FILEDLG95_FILETYPE_SearchExt
2316 * searches for a extension in the filetype box
2318 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2320 int i, iCount = CBGetCount(hwnd);
2322 TRACE("%s\n", debugstr_w(lpstrExt));
2324 if(iCount != CB_ERR)
2326 for(i=0;i<iCount;i++)
2328 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2329 return i;
2332 return -1;
2335 /***********************************************************************
2336 * FILEDLG95_FILETYPE_Clean
2338 * Clean the memory used by the filetype combo box
2340 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2342 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2343 int iPos;
2344 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2346 TRACE("\n");
2348 /* Delete each string of the combo and their associated data */
2349 if(iCount != CB_ERR)
2351 for(iPos = iCount-1;iPos>=0;iPos--)
2353 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2354 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2357 /* Current filter */
2358 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2359 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2363 /***********************************************************************
2364 * FILEDLG95_LOOKIN_Init
2366 * Initialisation of the look in combo box
2368 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2370 IShellFolder *psfRoot, *psfDrives;
2371 IEnumIDList *lpeRoot, *lpeDrives;
2372 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2374 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2376 TRACE("\n");
2378 liInfos->iMaxIndentation = 0;
2380 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2382 /* set item height for both text field and listbox */
2383 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2384 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2386 /* Turn on the extended UI for the combo box like Windows does */
2387 CBSetExtendedUI(hwndCombo, TRUE);
2389 /* Initialise data of Desktop folder */
2390 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2391 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2392 COMDLG32_SHFree(pidlTmp);
2394 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2396 SHGetDesktopFolder(&psfRoot);
2398 if (psfRoot)
2400 /* enumerate the contents of the desktop */
2401 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2403 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2405 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2407 /* special handling for CSIDL_DRIVES */
2408 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2410 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2412 /* enumerate the drives */
2413 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2415 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2417 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2418 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2419 COMDLG32_SHFree(pidlAbsTmp);
2420 COMDLG32_SHFree(pidlTmp1);
2422 IEnumIDList_Release(lpeDrives);
2424 IShellFolder_Release(psfDrives);
2427 COMDLG32_SHFree(pidlTmp);
2429 IEnumIDList_Release(lpeRoot);
2431 IShellFolder_Release(psfRoot);
2434 COMDLG32_SHFree(pidlDrives);
2435 return NOERROR;
2438 /***********************************************************************
2439 * FILEDLG95_LOOKIN_DrawItem
2441 * WM_DRAWITEM message handler
2443 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2445 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2446 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2447 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2448 RECT rectText;
2449 RECT rectIcon;
2450 SHFILEINFOA sfi;
2451 HIMAGELIST ilItemImage;
2452 int iIndentation;
2453 TEXTMETRICA tm;
2454 LPSFOLDER tmpFolder;
2457 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2459 TRACE("\n");
2461 if(pDIStruct->itemID == -1)
2462 return 0;
2464 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2465 pDIStruct->itemID)))
2466 return 0;
2469 if(pDIStruct->itemID == liInfos->uSelectedItem)
2471 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2473 &sfi,
2474 sizeof (SHFILEINFOA),
2475 SHGFI_PIDL | SHGFI_SMALLICON |
2476 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2477 SHGFI_DISPLAYNAME );
2479 else
2481 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2483 &sfi,
2484 sizeof (SHFILEINFOA),
2485 SHGFI_PIDL | SHGFI_SMALLICON |
2486 SHGFI_SYSICONINDEX |
2487 SHGFI_DISPLAYNAME);
2490 /* Is this item selected ? */
2491 if(pDIStruct->itemState & ODS_SELECTED)
2493 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2494 SetBkColor(pDIStruct->hDC,crHighLight);
2495 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2497 else
2499 SetTextColor(pDIStruct->hDC,crText);
2500 SetBkColor(pDIStruct->hDC,crWin);
2501 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2504 /* Do not indent item if drawing in the edit of the combo */
2505 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2507 iIndentation = 0;
2508 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2510 &sfi,
2511 sizeof (SHFILEINFOA),
2512 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2513 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2516 else
2518 iIndentation = tmpFolder->m_iIndent;
2520 /* Draw text and icon */
2522 /* Initialise the icon display area */
2523 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2524 rectIcon.top = pDIStruct->rcItem.top;
2525 rectIcon.right = rectIcon.left + ICONWIDTH;
2526 rectIcon.bottom = pDIStruct->rcItem.bottom;
2528 /* Initialise the text display area */
2529 GetTextMetricsA(pDIStruct->hDC, &tm);
2530 rectText.left = rectIcon.right;
2531 rectText.top =
2532 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2533 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2534 rectText.bottom =
2535 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2537 /* Draw the icon from the image list */
2538 ImageList_Draw(ilItemImage,
2539 sfi.iIcon,
2540 pDIStruct->hDC,
2541 rectIcon.left,
2542 rectIcon.top,
2543 ILD_TRANSPARENT );
2545 /* Draw the associated text */
2546 if(sfi.szDisplayName)
2547 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2550 return NOERROR;
2553 /***********************************************************************
2554 * FILEDLG95_LOOKIN_OnCommand
2556 * LookIn combo box WM_COMMAND message handler
2557 * If the function succeeds, the return value is nonzero.
2559 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2561 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2563 TRACE("%p\n", fodInfos);
2565 switch(wNotifyCode)
2567 case CBN_SELENDOK:
2569 LPSFOLDER tmpFolder;
2570 int iItem;
2572 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2574 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2575 iItem)))
2576 return FALSE;
2579 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2580 tmpFolder->pidlItem,
2581 SBSP_ABSOLUTE)))
2583 return TRUE;
2585 break;
2589 return FALSE;
2592 /***********************************************************************
2593 * FILEDLG95_LOOKIN_AddItem
2595 * Adds an absolute pidl item to the lookin combo box
2596 * returns the index of the inserted item
2598 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2600 LPITEMIDLIST pidlNext;
2601 SHFILEINFOA sfi;
2602 SFOLDER *tmpFolder;
2603 LookInInfos *liInfos;
2605 TRACE("%08x\n", iInsertId);
2607 if(!pidl)
2608 return -1;
2610 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2611 return -1;
2613 tmpFolder = MemAlloc(sizeof(SFOLDER));
2614 tmpFolder->m_iIndent = 0;
2616 /* Calculate the indentation of the item in the lookin*/
2617 pidlNext = pidl;
2618 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2620 tmpFolder->m_iIndent++;
2623 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2625 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2626 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2628 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2629 SHGetFileInfoA((LPSTR)pidl,
2631 &sfi,
2632 sizeof(sfi),
2633 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2634 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2636 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2638 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2640 int iItemID;
2642 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2644 /* Add the item at the end of the list */
2645 if(iInsertId < 0)
2647 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2649 /* Insert the item at the iInsertId position*/
2650 else
2652 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2655 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2656 return iItemID;
2659 COMDLG32_SHFree( tmpFolder->pidlItem );
2660 MemFree( tmpFolder );
2661 return -1;
2665 /***********************************************************************
2666 * FILEDLG95_LOOKIN_InsertItemAfterParent
2668 * Insert an item below its parent
2670 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2673 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2674 int iParentPos;
2676 TRACE("\n");
2678 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2680 if(iParentPos < 0)
2682 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2685 /* Free pidlParent memory */
2686 COMDLG32_SHFree((LPVOID)pidlParent);
2688 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2691 /***********************************************************************
2692 * FILEDLG95_LOOKIN_SelectItem
2694 * Adds an absolute pidl item to the lookin combo box
2695 * returns the index of the inserted item
2697 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2699 int iItemPos;
2700 LookInInfos *liInfos;
2702 TRACE("\n");
2704 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2706 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2708 if(iItemPos < 0)
2710 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2711 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2714 else
2716 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2717 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2719 int iRemovedItem;
2721 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2722 break;
2723 if(iRemovedItem < iItemPos)
2724 iItemPos--;
2728 CBSetCurSel(hwnd,iItemPos);
2729 liInfos->uSelectedItem = iItemPos;
2731 return 0;
2735 /***********************************************************************
2736 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2738 * Remove the item with an expansion level over iExpansionLevel
2740 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2742 int iItemPos;
2744 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2746 TRACE("\n");
2748 if(liInfos->iMaxIndentation <= 2)
2749 return -1;
2751 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2753 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2754 COMDLG32_SHFree(tmpFolder->pidlItem);
2755 MemFree(tmpFolder);
2756 CBDeleteString(hwnd,iItemPos);
2757 liInfos->iMaxIndentation--;
2759 return iItemPos;
2762 return -1;
2765 /***********************************************************************
2766 * FILEDLG95_LOOKIN_SearchItem
2768 * Search for pidl in the lookin combo box
2769 * returns the index of the found item
2771 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2773 int i = 0;
2774 int iCount = CBGetCount(hwnd);
2776 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2778 if (iCount != CB_ERR)
2780 for(;i<iCount;i++)
2782 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2784 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2785 return i;
2786 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2787 return i;
2791 return -1;
2794 /***********************************************************************
2795 * FILEDLG95_LOOKIN_Clean
2797 * Clean the memory used by the lookin combo box
2799 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2801 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2802 int iPos;
2803 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2805 TRACE("\n");
2807 /* Delete each string of the combo and their associated data */
2808 if (iCount != CB_ERR)
2810 for(iPos = iCount-1;iPos>=0;iPos--)
2812 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2813 COMDLG32_SHFree(tmpFolder->pidlItem);
2814 MemFree(tmpFolder);
2815 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2819 /* LookInInfos structure */
2820 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2823 /***********************************************************************
2824 * FILEDLG95_FILENAME_FillFromSelection
2826 * fills the edit box from the cached DataObject
2828 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2830 FileOpenDlgInfos *fodInfos;
2831 LPITEMIDLIST pidl;
2832 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2833 char lpstrTemp[MAX_PATH];
2834 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2836 TRACE("\n");
2837 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2839 /* Count how many files we have */
2840 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2842 /* calculate the string length, count files */
2843 if (nFileSelected >= 1)
2845 nLength += 3; /* first and last quotes, trailing \0 */
2846 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2848 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2850 if (pidl)
2852 /* get the total length of the selected file names */
2853 lpstrTemp[0] = '\0';
2854 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2856 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2858 nLength += strlen( lpstrTemp ) + 3;
2859 nFiles++;
2861 COMDLG32_SHFree( pidl );
2866 /* allocate the buffer */
2867 if (nFiles <= 1) nLength = MAX_PATH;
2868 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2869 lpstrAllFile[0] = '\0';
2871 /* Generate the string for the edit control */
2872 if(nFiles >= 1)
2874 lpstrCurrFile = lpstrAllFile;
2875 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2877 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2879 if (pidl)
2881 /* get the file name */
2882 lpstrTemp[0] = '\0';
2883 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2885 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2887 if ( nFiles > 1)
2889 *lpstrCurrFile++ = '\"';
2890 strcpy( lpstrCurrFile, lpstrTemp );
2891 lpstrCurrFile += strlen( lpstrTemp );
2892 strcpy( lpstrCurrFile, "\" " );
2893 lpstrCurrFile += 2;
2895 else
2897 strcpy( lpstrAllFile, lpstrTemp );
2900 COMDLG32_SHFree( (LPVOID) pidl );
2903 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2905 /* Select the file name like Windows does */
2906 SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
2908 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2912 /* copied from shell32 to avoid linking to it */
2913 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2915 switch (src->uType)
2917 case STRRET_WSTR:
2918 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2919 COMDLG32_SHFree(src->u.pOleStr);
2920 break;
2922 case STRRET_CSTR:
2923 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2924 break;
2926 case STRRET_OFFSET:
2927 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2928 break;
2930 default:
2931 FIXME("unknown type!\n");
2932 if (len)
2934 *(LPSTR)dest = '\0';
2936 return(FALSE);
2938 return S_OK;
2941 /***********************************************************************
2942 * FILEDLG95_FILENAME_GetFileNames
2944 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2946 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2948 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2949 UINT nStrCharCount = 0; /* index in src buffer */
2950 UINT nFileIndex = 0; /* index in dest buffer */
2951 UINT nFileCount = 0; /* number of files */
2952 UINT nStrLen = 0; /* length of string in edit control */
2953 LPWSTR lpstrEdit; /* buffer for string from edit control */
2955 TRACE("\n");
2957 /* get the filenames from the edit control */
2958 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2959 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2960 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2962 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2964 /* we might get single filename without any '"',
2965 * so we need nStrLen + terminating \0 + end-of-list \0 */
2966 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2967 *sizeUsed = 0;
2969 /* build 0-delimited file list from filenames */
2970 while ( nStrCharCount <= nStrLen )
2972 if ( lpstrEdit[nStrCharCount]=='"' )
2974 nStrCharCount++;
2975 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2977 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2978 (*sizeUsed)++;
2979 nStrCharCount++;
2981 (*lpstrFileList)[nFileIndex++] = '\0';
2982 (*sizeUsed)++;
2983 nFileCount++;
2985 nStrCharCount++;
2988 /* single, unquoted string */
2989 if ((nStrLen > 0) && (*sizeUsed == 0) )
2991 strcpyW(*lpstrFileList, lpstrEdit);
2992 nFileIndex = strlenW(lpstrEdit) + 1;
2993 (*sizeUsed) = nFileIndex;
2994 nFileCount = 1;
2997 /* trailing \0 */
2998 (*lpstrFileList)[nFileIndex] = '\0';
2999 (*sizeUsed)++;
3001 MemFree(lpstrEdit);
3002 return nFileCount;
3005 #define SETDefFormatEtc(fe,cf,med) \
3007 (fe).cfFormat = cf;\
3008 (fe).dwAspect = DVASPECT_CONTENT; \
3009 (fe).ptd =NULL;\
3010 (fe).tymed = med;\
3011 (fe).lindex = -1;\
3015 * DATAOBJECT Helper functions
3018 /***********************************************************************
3019 * COMCTL32_ReleaseStgMedium
3021 * like ReleaseStgMedium from ole32
3023 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3025 if(medium.pUnkForRelease)
3027 IUnknown_Release(medium.pUnkForRelease);
3029 else
3031 GlobalUnlock(medium.u.hGlobal);
3032 GlobalFree(medium.u.hGlobal);
3036 /***********************************************************************
3037 * GetPidlFromDataObject
3039 * Return pidl(s) by number from the cached DataObject
3041 * nPidlIndex=0 gets the fully qualified root path
3043 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3046 STGMEDIUM medium;
3047 FORMATETC formatetc;
3048 LPITEMIDLIST pidl = NULL;
3050 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3052 /* Set the FORMATETC structure*/
3053 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3055 /* Get the pidls from IDataObject */
3056 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3058 LPIDA cida = GlobalLock(medium.u.hGlobal);
3059 if(nPidlIndex <= cida->cidl)
3061 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3063 COMCTL32_ReleaseStgMedium(medium);
3065 return pidl;
3068 /***********************************************************************
3069 * GetNumSelected
3071 * Return the number of selected items in the DataObject.
3074 UINT GetNumSelected( IDataObject *doSelected )
3076 UINT retVal = 0;
3077 STGMEDIUM medium;
3078 FORMATETC formatetc;
3080 TRACE("sv=%p\n", doSelected);
3082 if (!doSelected) return 0;
3084 /* Set the FORMATETC structure*/
3085 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3087 /* Get the pidls from IDataObject */
3088 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3090 LPIDA cida = GlobalLock(medium.u.hGlobal);
3091 retVal = cida->cidl;
3092 COMCTL32_ReleaseStgMedium(medium);
3093 return retVal;
3095 return 0;
3099 * TOOLS
3102 /***********************************************************************
3103 * GetName
3105 * Get the pidl's display name (relative to folder) and
3106 * put it in lpstrFileName.
3108 * Return NOERROR on success,
3109 * E_FAIL otherwise
3112 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3114 STRRET str;
3115 HRESULT hRes;
3117 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3119 if(!lpsf)
3121 HRESULT hRes;
3122 SHGetDesktopFolder(&lpsf);
3123 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3124 IShellFolder_Release(lpsf);
3125 return hRes;
3128 /* Get the display name of the pidl relative to the folder */
3129 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3131 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3133 return E_FAIL;
3136 /***********************************************************************
3137 * GetShellFolderFromPidl
3139 * pidlRel is the item pidl relative
3140 * Return the IShellFolder of the absolute pidl
3142 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3144 IShellFolder *psf = NULL,*psfParent;
3146 TRACE("%p\n", pidlAbs);
3148 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3150 psf = psfParent;
3151 if(pidlAbs && pidlAbs->mkid.cb)
3153 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3155 IShellFolder_Release(psfParent);
3156 return psf;
3159 /* return the desktop */
3160 return psfParent;
3162 return NULL;
3165 /***********************************************************************
3166 * GetParentPidl
3168 * Return the LPITEMIDLIST to the parent of the pidl in the list
3170 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3172 LPITEMIDLIST pidlParent;
3174 TRACE("%p\n", pidl);
3176 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3177 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3179 return pidlParent;
3182 /***********************************************************************
3183 * GetPidlFromName
3185 * returns the pidl of the file name relative to folder
3186 * NULL if an error occurred
3188 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3190 LPITEMIDLIST pidl = NULL;
3191 ULONG ulEaten;
3193 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3195 if(!lpcstrFileName) return NULL;
3196 if(!*lpcstrFileName) return NULL;
3198 if(!lpsf)
3200 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3201 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3202 IShellFolder_Release(lpsf);
3205 else
3207 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3209 return pidl;
3214 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3216 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3217 HRESULT ret;
3219 TRACE("%p, %p\n", psf, pidl);
3221 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3223 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3224 /* see documentation shell 4.1*/
3225 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3228 /***********************************************************************
3229 * BrowseSelectedFolder
3231 static BOOL BrowseSelectedFolder(HWND hwnd)
3233 BOOL bBrowseSelFolder = FALSE;
3234 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3236 TRACE("\n");
3238 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3240 LPITEMIDLIST pidlSelection;
3242 /* get the file selected */
3243 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3244 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3246 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3247 pidlSelection, SBSP_RELATIVE ) ) )
3249 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3250 ' ','n','o','t',' ','e','x','i','s','t',0};
3251 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3254 bBrowseSelFolder = TRUE;
3256 COMDLG32_SHFree( pidlSelection );
3259 return bBrowseSelFolder;
3263 * Memory allocation methods */
3264 static void *MemAlloc(UINT size)
3266 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3269 static void MemFree(void *mem)
3271 if(mem)
3273 HeapFree(GetProcessHeap(),0,mem);
3278 * Old-style (win3.1) dialogs */
3280 /***********************************************************************
3281 * FD32_GetTemplate [internal]
3283 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3284 * by a 32 bits application
3287 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3289 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3290 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3291 HANDLE hDlgTmpl;
3293 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3295 if (!(lfs->template = LockResource( ofnW->hInstance )))
3297 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3298 return FALSE;
3301 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3303 HRSRC hResInfo;
3304 if (priv->ofnA)
3305 hResInfo = FindResourceA(priv->ofnA->hInstance,
3306 priv->ofnA->lpTemplateName,
3307 (LPSTR)RT_DIALOG);
3308 else
3309 hResInfo = FindResourceW(ofnW->hInstance,
3310 ofnW->lpTemplateName,
3311 (LPWSTR)RT_DIALOG);
3312 if (!hResInfo)
3314 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3315 return FALSE;
3317 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3318 hResInfo)) ||
3319 !(lfs->template = LockResource(hDlgTmpl)))
3321 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3322 return FALSE;
3324 } else { /* get it from internal Wine resource */
3325 HRSRC hResInfo;
3326 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3327 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3329 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3330 return FALSE;
3332 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3333 !(lfs->template = LockResource( hDlgTmpl )))
3335 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3336 return FALSE;
3339 return TRUE;
3343 /************************************************************************
3344 * FD32_Init [internal]
3345 * called from the common 16/32 code to initialize 32 bit data
3347 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3349 BOOL IsUnicode = (BOOL) data;
3350 PFD32_PRIVATE priv;
3352 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3353 lfs->private1632 = priv;
3354 if (NULL == lfs->private1632) return FALSE;
3355 if (IsUnicode)
3357 lfs->ofnW = *((LPOPENFILENAMEW) lParam);
3358 if (lfs->ofnW.Flags & OFN_ENABLEHOOK)
3359 if (lfs->ofnW.lpfnHook)
3360 lfs->hook = TRUE;
3362 else
3364 priv->ofnA = (LPOPENFILENAMEA) lParam;
3365 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3366 if (priv->ofnA->lpfnHook)
3367 lfs->hook = TRUE;
3368 FD31_MapOfnStructA(priv->ofnA, &lfs->ofnW, lfs->open);
3371 if (! FD32_GetTemplate(lfs)) return FALSE;
3373 return TRUE;
3376 /***********************************************************************
3377 * FD32_CallWindowProc [internal]
3379 * called from the common 16/32 code to call the appropriate hook
3381 BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam,
3382 LPARAM lParam)
3384 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3386 if (priv->ofnA)
3388 return (BOOL) CallWindowProcA(
3389 (WNDPROC)priv->ofnA->lpfnHook, lfs->hwnd,
3390 wMsg, wParam, lParam);
3393 return (BOOL) CallWindowProcW(
3394 (WNDPROC)lfs->ofnW.lpfnHook, lfs->hwnd,
3395 wMsg, wParam, lParam);
3398 /***********************************************************************
3399 * FD32_UpdateResult [internal]
3400 * update the real client structures if any
3402 static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs)
3404 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3405 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3407 if (priv->ofnA)
3409 if (ofnW->nMaxFile &&
3410 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3411 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3412 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3413 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3414 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3418 /***********************************************************************
3419 * FD32_UpdateFileTitle [internal]
3420 * update the real client structures if any
3422 static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs)
3424 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3425 LPOPENFILENAMEW ofnW = &lfs->ofnW;
3427 if (priv->ofnA)
3429 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3430 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3431 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3436 /***********************************************************************
3437 * FD32_SendLbGetCurSel [internal]
3438 * retrieve selected listbox item
3440 static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs)
3442 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3446 /************************************************************************
3447 * FD32_Destroy [internal]
3448 * called from the common 16/32 code to cleanup 32 bit data
3450 static void CALLBACK FD32_Destroy(PFD31_DATA lfs)
3452 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3454 /* if ofnW has been allocated, have to free everything in it */
3455 if (NULL != priv && NULL != priv->ofnA)
3456 FD31_FreeOfnW(&lfs->ofnW);
3459 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3461 callbacks->Init = FD32_Init;
3462 callbacks->CWP = FD32_CallWindowProc;
3463 callbacks->UpdateResult = FD32_UpdateResult;
3464 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3465 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3466 callbacks->Destroy = FD32_Destroy;
3469 /***********************************************************************
3470 * FD32_WMMeasureItem [internal]
3472 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3474 LPMEASUREITEMSTRUCT lpmeasure;
3476 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3477 lpmeasure->itemHeight = FD31_GetFldrHeight();
3478 return TRUE;
3482 /***********************************************************************
3483 * FileOpenDlgProc [internal]
3484 * Used for open and save, in fact.
3486 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3487 WPARAM wParam, LPARAM lParam)
3489 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3491 TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam);
3492 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3494 INT_PTR lRet;
3495 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3496 if (lRet)
3497 return lRet; /* else continue message processing */
3499 switch (wMsg)
3501 case WM_INITDIALOG:
3502 return FD31_WMInitDialog(hWnd, wParam, lParam);
3504 case WM_MEASUREITEM:
3505 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3507 case WM_DRAWITEM:
3508 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3510 case WM_COMMAND:
3511 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3512 #if 0
3513 case WM_CTLCOLOR:
3514 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3515 switch (HIWORD(lParam))
3517 case CTLCOLOR_BTN:
3518 SetTextColor((HDC16)wParam, 0x00000000);
3519 return hGRAYBrush;
3520 case CTLCOLOR_STATIC:
3521 SetTextColor((HDC16)wParam, 0x00000000);
3522 return hGRAYBrush;
3524 break;
3525 #endif
3527 return FALSE;
3531 /***********************************************************************
3532 * GetFileName31A [internal]
3534 * Creates a win31 style dialog box for the user to select a file to open/save.
3536 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3537 UINT dlgType /* type dialogue : open/save */
3540 HINSTANCE hInst;
3541 BOOL bRet = FALSE;
3542 PFD31_DATA lfs;
3543 FD31_CALLBACKS callbacks;
3545 if (!lpofn || !FD31_Init()) return FALSE;
3547 TRACE("ofn flags %08lx\n", lpofn->Flags);
3548 FD32_SetupCallbacks(&callbacks);
3549 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3550 if (lfs)
3552 hInst = (HINSTANCE)GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
3553 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3554 FD32_FileOpenDlgProc, (LPARAM)lfs);
3555 FD31_DestroyPrivate(lfs);
3558 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3559 return bRet;
3562 /***********************************************************************
3563 * GetFileName31W [internal]
3565 * Creates a win31 style dialog box for the user to select a file to open/save
3567 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3568 UINT dlgType /* type dialogue : open/save */
3571 HINSTANCE hInst;
3572 BOOL bRet = FALSE;
3573 PFD31_DATA lfs;
3574 FD31_CALLBACKS callbacks;
3576 if (!lpofn || !FD31_Init()) return FALSE;
3578 FD32_SetupCallbacks(&callbacks);
3579 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3580 if (lfs)
3582 hInst = (HINSTANCE)GetWindowLongA( lpofn->hwndOwner, GWL_HINSTANCE );
3583 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3584 FD32_FileOpenDlgProc, (LPARAM)lfs);
3585 FD31_DestroyPrivate(lfs);
3588 TRACE("return lpstrFile=%s !\n", debugstr_w(lpofn->lpstrFile));
3589 return bRet;
3592 /* ------------------ APIs ---------------------- */
3594 /***********************************************************************
3595 * GetOpenFileNameA (COMDLG32.@)
3597 * Creates a dialog box for the user to select a file to open.
3599 * RETURNS
3600 * TRUE on success: user enters a valid file
3601 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3604 BOOL WINAPI GetOpenFileNameA(
3605 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3607 BOOL win16look = FALSE;
3609 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3610 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3612 if (win16look)
3613 return GetFileName31A(ofn, OPEN_DIALOG);
3614 else
3615 return GetFileDialog95A(ofn, OPEN_DIALOG);
3618 /***********************************************************************
3619 * GetOpenFileNameW (COMDLG32.@)
3621 * Creates a dialog box for the user to select a file to open.
3623 * RETURNS
3624 * TRUE on success: user enters a valid file
3625 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3628 BOOL WINAPI GetOpenFileNameW(
3629 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3631 BOOL win16look = FALSE;
3633 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3634 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3636 if (win16look)
3637 return GetFileName31W(ofn, OPEN_DIALOG);
3638 else
3639 return GetFileDialog95W(ofn, OPEN_DIALOG);
3643 /***********************************************************************
3644 * GetSaveFileNameA (COMDLG32.@)
3646 * Creates a dialog box for the user to select a file to save.
3648 * RETURNS
3649 * TRUE on success: user enters a valid file
3650 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3653 BOOL WINAPI GetSaveFileNameA(
3654 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3656 BOOL win16look = FALSE;
3658 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3659 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3661 if (win16look)
3662 return GetFileName31A(ofn, SAVE_DIALOG);
3663 else
3664 return GetFileDialog95A(ofn, SAVE_DIALOG);
3667 /***********************************************************************
3668 * GetSaveFileNameW (COMDLG32.@)
3670 * Creates a dialog box for the user to select a file to save.
3672 * RETURNS
3673 * TRUE on success: user enters a valid file
3674 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3677 BOOL WINAPI GetSaveFileNameW(
3678 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3680 BOOL win16look = FALSE;
3682 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3683 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3685 if (win16look)
3686 return GetFileName31W(ofn, SAVE_DIALOG);
3687 else
3688 return GetFileDialog95W(ofn, SAVE_DIALOG);