Get rid of the memory allocation macros, use real functions instead.
[wine.git] / dlls / commdlg / filedlg95.c
blobcb2d676d27fa67b9572552d70582d214a1589c91
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: lpstrCustomFilter not handled
37 * FIXME: if the size of lpstrFile (nMaxFile) is too small the first
38 * two bytes of lpstrFile should contain the needed size
40 * FIXME: algorithm for selecting the initial directory is too simple
42 * FIXME: add to recent docs
44 * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
45 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING, OFN_EXTENSIONDIFFERENT,
46 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
47 * OFN_NOTESTFILECREATE, OFN_OVERWRITEPROMPT, OFN_USEMONIKERS
49 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
54 #include "config.h"
55 #include "wine/port.h"
57 #include <ctype.h>
58 #include <stdlib.h>
59 #include <stdarg.h>
60 #include <stdio.h>
61 #include <string.h>
63 #define NONAMELESSUNION
64 #define NONAMELESSSTRUCT
65 #include "windef.h"
66 #include "winbase.h"
67 #include "winreg.h"
68 #include "winternl.h"
69 #include "winnls.h"
70 #include "wine/unicode.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "commdlg.h"
74 #include "dlgs.h"
75 #include "cdlg.h"
76 #include "wine/debug.h"
77 #include "cderr.h"
78 #include "shellapi.h"
79 #include "shlguid.h"
80 #include "shlobj.h"
81 #include "filedlgbrowser.h"
82 #include "shlwapi.h"
84 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
86 #define UNIMPLEMENTED_FLAGS \
87 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
88 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING | OFN_EXTENSIONDIFFERENT |\
89 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
90 OFN_NOTESTFILECREATE | OFN_OVERWRITEPROMPT /*| OFN_USEMONIKERS*/)
92 #define IsHooked(fodInfos) \
93 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
94 /***********************************************************************
95 * Data structure and global variables
97 typedef struct SFolder
99 int m_iImageIndex; /* Index of picture in image list */
100 HIMAGELIST hImgList;
101 int m_iIndent; /* Indentation index */
102 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
104 } SFOLDER,*LPSFOLDER;
106 typedef struct tagLookInInfo
108 int iMaxIndentation;
109 UINT uSelectedItem;
110 } LookInInfos;
113 /***********************************************************************
114 * Defines and global variables
117 /* Draw item constant */
118 #define ICONWIDTH 18
119 #define XTEXTOFFSET 3
121 /* AddItem flags*/
122 #define LISTEND -1
124 /* SearchItem methods */
125 #define SEARCH_PIDL 1
126 #define SEARCH_EXP 2
127 #define ITEM_NOTFOUND -1
129 /* Undefined windows message sent by CreateViewObject*/
130 #define WM_GETISHELLBROWSER WM_USER+7
132 /* NOTE
133 * Those macros exist in windowsx.h. However, you can't really use them since
134 * they rely on the UNICODE defines and can't be used inside Wine itself.
137 /* Combo box macros */
138 #define CBAddString(hwnd,str) \
139 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
140 #define CBAddStringW(hwnd,str) \
141 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
143 #define CBInsertString(hwnd,str,pos) \
144 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
146 #define CBDeleteString(hwnd,pos) \
147 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
149 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
150 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
152 #define CBGetItemDataPtr(hwnd,iItemId) \
153 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
155 #define CBGetLBText(hwnd,iItemId,str) \
156 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
158 #define CBGetCurSel(hwnd) \
159 SendMessageA(hwnd,CB_GETCURSEL,0,0);
161 #define CBSetCurSel(hwnd,pos) \
162 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
164 #define CBGetCount(hwnd) \
165 SendMessageA(hwnd,CB_GETCOUNT,0,0);
166 #define CBShowDropDown(hwnd,show) \
167 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
168 #define CBSetItemHeight(hwnd,index,height) \
169 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
172 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
173 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
175 /***********************************************************************
176 * Prototypes
179 /* Internal functions used by the dialog */
180 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
181 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
182 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
183 BOOL FILEDLG95_OnOpen(HWND hwnd);
184 static LRESULT FILEDLG95_InitControls(HWND hwnd);
185 static void FILEDLG95_Clean(HWND hwnd);
187 /* Functions used by the shell navigation */
188 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
189 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
190 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
191 static void FILEDLG95_SHELL_Clean(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
194 /* Functions used by the filetype combo box */
195 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
196 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
197 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
198 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
200 /* Functions used by the Look In combo box */
201 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
202 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
203 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
205 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
206 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
207 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
208 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
209 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
211 /* Miscellaneous tool functions */
212 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
213 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
214 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
215 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
216 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
218 /* Shell memory allocation */
219 static void *MemAlloc(UINT size);
220 static void MemFree(void *mem);
222 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
223 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
224 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
225 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
226 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
227 static BOOL BrowseSelectedFolder(HWND hwnd);
229 /***********************************************************************
230 * GetFileName95
232 * Creates an Open common dialog box that lets the user select
233 * the drive, directory, and the name of a file or set of files to open.
235 * IN : The FileOpenDlgInfos structure associated with the dialog
236 * OUT : TRUE on success
237 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
239 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
242 LRESULT lRes;
243 LPCVOID template;
244 HRSRC hRes;
245 HANDLE hDlgTmpl = 0;
247 /* test for missing functionality */
248 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
250 FIXME("Flags 0x%08lx not yet implemented\n",
251 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
254 /* Create the dialog from a template */
256 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG)))
258 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
259 return FALSE;
261 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
262 !(template = LockResource( hDlgTmpl )))
264 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
265 return FALSE;
268 /* old style hook messages */
269 if (IsHooked(fodInfos))
271 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
272 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
273 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
274 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
277 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
278 (LPDLGTEMPLATEA) template,
279 fodInfos->ofnInfos->hwndOwner,
280 FileOpenDlgProc95,
281 (LPARAM) fodInfos);
283 /* Unable to create the dialog */
284 if( lRes == -1)
285 return FALSE;
287 return lRes;
290 /***********************************************************************
291 * GetFileDialog95A
293 * Call GetFileName95 with this structure and clean the memory.
295 * IN : The OPENFILENAMEA initialisation structure passed to
296 * GetOpenFileNameA win api function (see filedlg.c)
298 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
300 BOOL ret;
301 FileOpenDlgInfos fodInfos;
302 LPSTR lpstrSavDir = NULL;
303 LPWSTR title = NULL;
304 LPWSTR defext = NULL;
305 LPWSTR filter = NULL;
306 LPWSTR customfilter = NULL;
308 /* Initialize FileOpenDlgInfos structure */
309 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
311 /* Pass in the original ofn */
312 fodInfos.ofnInfos = ofn;
314 /* save current directory */
315 if (ofn->Flags & OFN_NOCHANGEDIR)
317 lpstrSavDir = MemAlloc(MAX_PATH);
318 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
321 fodInfos.unicode = FALSE;
323 /* convert all the input strings to unicode */
324 if(ofn->lpstrInitialDir)
326 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
327 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
328 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
330 else
331 fodInfos.initdir = NULL;
333 if(ofn->lpstrFile)
335 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
336 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
338 else
339 fodInfos.filename = NULL;
341 if(ofn->lpstrDefExt)
343 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
344 defext = MemAlloc((len+1)*sizeof(WCHAR));
345 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
347 fodInfos.defext = defext;
349 if(ofn->lpstrTitle)
351 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
352 title = MemAlloc((len+1)*sizeof(WCHAR));
353 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
355 fodInfos.title = title;
357 if (ofn->lpstrFilter)
359 LPCSTR s;
360 int n, len;
362 /* filter is a list... title\0ext\0......\0\0 */
363 s = ofn->lpstrFilter;
364 while (*s) s = s+strlen(s)+1;
365 s++;
366 n = s - ofn->lpstrFilter;
367 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
368 filter = MemAlloc(len*sizeof(WCHAR));
369 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
371 fodInfos.filter = filter;
373 /* convert lpstrCustomFilter */
374 if (ofn->lpstrCustomFilter)
376 LPCSTR s;
377 int n, len;
379 /* filter is a list... title\0ext\0......\0\0 */
380 s = ofn->lpstrCustomFilter;
381 while (*s) s = s+strlen(s)+1;
382 s++;
383 n = s - ofn->lpstrCustomFilter;
384 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
385 customfilter = MemAlloc(len*sizeof(WCHAR));
386 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
388 fodInfos.customfilter = customfilter;
390 /* Initialize the dialog property */
391 fodInfos.DlgInfos.dwDlgProp = 0;
392 fodInfos.DlgInfos.hwndCustomDlg = NULL;
394 switch(iDlgType)
396 case OPEN_DIALOG :
397 ret = GetFileName95(&fodInfos);
398 break;
399 case SAVE_DIALOG :
400 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
401 ret = GetFileName95(&fodInfos);
402 break;
403 default :
404 ret = 0;
407 if (lpstrSavDir)
409 SetCurrentDirectoryA(lpstrSavDir);
410 MemFree(lpstrSavDir);
413 if(title)
414 MemFree(title);
415 if(defext)
416 MemFree(defext);
417 if(filter)
418 MemFree(filter);
419 if(customfilter)
420 MemFree(customfilter);
421 if(fodInfos.initdir)
422 MemFree(fodInfos.initdir);
424 if(fodInfos.filename)
425 MemFree(fodInfos.filename);
427 TRACE("selected file: %s\n",ofn->lpstrFile);
429 return ret;
432 /***********************************************************************
433 * GetFileDialog95W
435 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
436 * Call GetFileName95 with this structure and clean the memory.
438 * FIXME: lpstrCustomFilter has to be converted back
441 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
443 BOOL ret;
444 FileOpenDlgInfos fodInfos;
445 LPSTR lpstrSavDir = NULL;
447 /* Initialize FileOpenDlgInfos structure */
448 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
450 /* Pass in the original ofn */
451 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
453 fodInfos.title = ofn->lpstrTitle;
454 fodInfos.defext = ofn->lpstrDefExt;
455 fodInfos.filter = ofn->lpstrFilter;
456 fodInfos.customfilter = ofn->lpstrCustomFilter;
458 /* convert string arguments, save others */
459 if(ofn->lpstrFile)
461 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
462 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
464 else
465 fodInfos.filename = NULL;
467 if(ofn->lpstrInitialDir)
469 DWORD len = strlenW(ofn->lpstrInitialDir);
470 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
471 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
473 else
474 fodInfos.initdir = NULL;
476 /* save current directory */
477 if (ofn->Flags & OFN_NOCHANGEDIR)
479 lpstrSavDir = MemAlloc(MAX_PATH);
480 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
483 fodInfos.unicode = TRUE;
485 switch(iDlgType)
487 case OPEN_DIALOG :
488 ret = GetFileName95(&fodInfos);
489 break;
490 case SAVE_DIALOG :
491 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
492 ret = GetFileName95(&fodInfos);
493 break;
494 default :
495 ret = 0;
498 if (lpstrSavDir)
500 SetCurrentDirectoryA(lpstrSavDir);
501 MemFree(lpstrSavDir);
504 /* restore saved IN arguments and convert OUT arguments back */
505 MemFree(fodInfos.filename);
506 MemFree(fodInfos.initdir);
507 return ret;
510 /***********************************************************************
511 * ArrangeCtrlPositions [internal]
513 * NOTE: Do not change anything here without a lot of testing.
515 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
517 HWND hwndChild, hwndStc32;
518 RECT rectParent, rectChild, rectStc32;
519 INT help_fixup = 0;
521 /* Take into account if open as read only checkbox and help button
522 * are hidden
524 if (hide_help)
526 RECT rectHelp, rectCancel;
527 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
528 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
529 /* subtract the height of the help button plus the space between
530 * the help button and the cancel button to the height of the dialog
532 help_fixup = rectHelp.bottom - rectCancel.bottom;
536 There are two possibilities to add components to the default file dialog box.
538 By default, all the new components are added below the standard dialog box (the else case).
540 However, if there is a static text component with the stc32 id, a special case happens.
541 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
542 in the window and the cx and cy indicate how to size the window.
543 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
544 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
548 GetClientRect(hwndParentDlg, &rectParent);
550 /* when arranging controls we have to use fixed parent size */
551 rectParent.bottom -= help_fixup;
553 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
554 if (hwndStc32)
556 GetWindowRect(hwndStc32, &rectStc32);
557 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
559 /* set the size of the stc32 control according to the size of
560 * client area of the parent dialog
562 SetWindowPos(hwndStc32, 0,
563 0, 0,
564 rectParent.right, rectParent.bottom,
565 SWP_NOMOVE | SWP_NOZORDER);
567 else
568 SetRectEmpty(&rectStc32);
570 /* this part moves controls of the child dialog */
571 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
572 while (hwndChild)
574 if (hwndChild != hwndStc32)
576 GetWindowRect(hwndChild, &rectChild);
577 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
579 /* move only if stc32 exist */
580 if (hwndStc32 && rectChild.left > rectStc32.right)
582 /* move to the right of visible controls of the parent dialog */
583 rectChild.left += rectParent.right;
584 rectChild.left -= rectStc32.right;
586 /* move even if stc32 doesn't exist */
587 if (rectChild.top > rectStc32.bottom)
589 /* move below visible controls of the parent dialog */
590 rectChild.top += rectParent.bottom;
591 rectChild.top -= rectStc32.bottom - rectStc32.top;
594 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
595 0, 0, SWP_NOSIZE | SWP_NOZORDER);
597 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
600 /* this part moves controls of the parent dialog */
601 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
602 while (hwndChild)
604 if (hwndChild != hwndChildDlg)
606 GetWindowRect(hwndChild, &rectChild);
607 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
609 /* left,top of stc32 marks the position of controls
610 * from the parent dialog
612 rectChild.left += rectStc32.left;
613 rectChild.top += rectStc32.top;
615 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
616 0, 0, SWP_NOSIZE | SWP_NOZORDER);
618 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
621 /* calculate the size of the resulting dialog */
623 /* here we have to use original parent size */
624 GetClientRect(hwndParentDlg, &rectParent);
625 GetClientRect(hwndChildDlg, &rectChild);
627 if (hwndStc32)
629 if (rectParent.right > rectChild.right)
631 rectParent.right += rectChild.right;
632 rectParent.right -= rectStc32.right - rectStc32.left;
634 else
636 rectParent.right = rectChild.right;
639 if (rectParent.bottom > rectChild.bottom)
641 rectParent.bottom += rectChild.bottom;
642 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
644 else
646 rectParent.bottom = rectChild.bottom;
649 else
651 rectParent.bottom += rectChild.bottom;
654 /* finally use fixed parent size */
655 rectParent.bottom -= help_fixup;
657 /* save the size of the parent's client area */
658 rectChild.right = rectParent.right;
659 rectChild.bottom = rectParent.bottom;
661 /* set the size of the parent dialog */
662 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
663 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
664 SetWindowPos(hwndParentDlg, 0,
665 0, 0,
666 rectParent.right - rectParent.left,
667 rectParent.bottom - rectParent.top,
668 SWP_NOMOVE | SWP_NOZORDER);
670 /* set the size of the child dialog */
671 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
672 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE);
675 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
677 FileOpenDlgInfos *fodInfos;
679 #if 0
680 TRACE("0x%04x\n", uMsg);
681 #endif
683 switch(uMsg)
685 case WM_INITDIALOG:
687 fodInfos = (FileOpenDlgInfos *)lParam;
688 lParam = (LPARAM) fodInfos->ofnInfos;
690 if(fodInfos && IsHooked(fodInfos))
691 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
692 return 0;
696 fodInfos = (FileOpenDlgInfos *) GetPropA(GetParent(hwnd),FileOpenDlgInfosStr);
697 if(fodInfos && IsHooked(fodInfos))
698 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
700 return 0;
703 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
705 LPCVOID template;
706 HRSRC hRes;
707 HANDLE hDlgTmpl = 0;
708 HWND hChildDlg = 0;
710 TRACE("\n");
713 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
714 * structure's hInstance parameter is not a HINSTANCE, but
715 * instead a pointer to a template resource to use.
717 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
719 HINSTANCE hinst;
720 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
722 hinst = 0;
723 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
725 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
726 return NULL;
729 else
731 hinst = fodInfos->ofnInfos->hInstance;
732 if(fodInfos->unicode)
734 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
735 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
737 else
739 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
740 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
742 if (!hRes)
744 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
745 return NULL;
747 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
748 !(template = LockResource( hDlgTmpl )))
750 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
751 return NULL;
754 hChildDlg= CreateDialogIndirectParamA(COMDLG32_hInstance, template,
755 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
756 if(hChildDlg)
758 ShowWindow(hChildDlg,SW_SHOW);
759 return hChildDlg;
762 else if( IsHooked(fodInfos))
764 RECT rectHwnd;
765 struct {
766 DLGTEMPLATE tmplate;
767 WORD menu,class,title;
768 } temp;
769 GetClientRect(hwnd,&rectHwnd);
770 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
771 temp.tmplate.dwExtendedStyle = 0;
772 temp.tmplate.cdit = 0;
773 temp.tmplate.x = 0;
774 temp.tmplate.y = 0;
775 temp.tmplate.cx = 0;
776 temp.tmplate.cy = 0;
777 temp.menu = temp.class = temp.title = 0;
779 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
780 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
782 return hChildDlg;
784 return NULL;
787 /***********************************************************************
788 * SendCustomDlgNotificationMessage
790 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
793 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
795 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
797 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
799 if(!fodInfos) return 0;
801 if(fodInfos->unicode)
802 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
804 if(fodInfos->DlgInfos.hwndCustomDlg)
806 OFNOTIFYA ofnNotify;
807 HRESULT ret;
808 ofnNotify.hdr.hwndFrom=hwndParentDlg;
809 ofnNotify.hdr.idFrom=0;
810 ofnNotify.hdr.code = uCode;
811 ofnNotify.lpOFN = fodInfos->ofnInfos;
812 ofnNotify.pszFile = NULL;
813 TRACE("CALL NOTIFY for %x\n", uCode);
814 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
815 TRACE("RET NOTIFY\n");
816 return ret;
818 return TRUE;
821 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
823 UINT sizeUsed = 0, n, total;
824 LPWSTR lpstrFileList = NULL;
825 WCHAR lpstrCurrentDir[MAX_PATH];
826 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
828 TRACE("CDM_GETFILEPATH:\n");
830 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
831 return -1;
833 /* get path and filenames */
834 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
835 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
837 TRACE("path >%s< filespec >%s< %d files\n",
838 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
840 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
841 NULL, 0, NULL, NULL);
842 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
843 NULL, 0, NULL, NULL);
845 /* Prepend the current path */
846 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
847 buffer, size, NULL, NULL);
849 if(n<size)
851 /* 'n' includes trailing \0 */
852 buffer[n-1] = '\\';
853 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
854 &buffer[n], size-n, NULL, NULL);
856 MemFree(lpstrFileList);
858 TRACE("returned -> %s\n",debugstr_a(buffer));
860 return total;
863 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
865 UINT sizeUsed = 0;
866 LPWSTR lpstrFileList = NULL;
868 TRACE("CDM_GETSPEC:\n");
870 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
871 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
872 MemFree(lpstrFileList);
874 return sizeUsed;
877 /***********************************************************************
878 * FILEDLG95_HandleCustomDialogMessages
880 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
882 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
884 char lpstrPath[MAX_PATH];
885 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
886 if(!fodInfos) return -1;
888 switch(uMsg)
890 case CDM_GETFILEPATH:
891 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
893 case CDM_GETFOLDERPATH:
894 TRACE("CDM_GETFOLDERPATH:\n");
895 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
896 if ((LPSTR)lParam!=NULL)
897 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
898 return strlen(lpstrPath);
900 case CDM_GETSPEC:
901 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
903 case CDM_SETCONTROLTEXT:
904 TRACE("CDM_SETCONTROLTEXT:\n");
905 if ( 0 != lParam )
906 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
907 return TRUE;
909 case CDM_HIDECONTROL:
910 case CDM_SETDEFEXT:
911 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
912 return -1;
914 return TRUE;
917 /***********************************************************************
918 * FileOpenDlgProc95
920 * File open dialog procedure
922 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
924 #if 0
925 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
926 #endif
928 switch(uMsg)
930 case WM_INITDIALOG:
932 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
934 /* Adds the FileOpenDlgInfos in the property list of the dialog
935 so it will be easily accessible through a GetPropA(...) */
936 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
938 fodInfos->DlgInfos.hwndCustomDlg =
939 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
941 FILEDLG95_InitControls(hwnd);
943 if (fodInfos->DlgInfos.hwndCustomDlg)
944 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
945 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
947 FILEDLG95_FillControls(hwnd, wParam, lParam);
949 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
950 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
951 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
952 return 0;
954 case WM_COMMAND:
955 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
956 case WM_DRAWITEM:
958 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
960 case IDC_LOOKIN:
961 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
962 return TRUE;
965 return FALSE;
967 case WM_GETISHELLBROWSER:
968 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
970 case WM_DESTROY:
971 RemovePropA(hwnd, FileOpenDlgInfosStr);
972 return FALSE;
974 case WM_NOTIFY:
976 LPNMHDR lpnmh = (LPNMHDR)lParam;
977 UINT stringId = -1;
979 /* set up the button tooltips strings */
980 if(TTN_GETDISPINFOA == lpnmh->code )
982 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
983 switch(lpnmh->idFrom )
985 /* Up folder button */
986 case FCIDM_TB_UPFOLDER:
987 stringId = IDS_UPFOLDER;
988 break;
989 /* New folder button */
990 case FCIDM_TB_NEWFOLDER:
991 stringId = IDS_NEWFOLDER;
992 break;
993 /* List option button */
994 case FCIDM_TB_SMALLICON:
995 stringId = IDS_LISTVIEW;
996 break;
997 /* Details option button */
998 case FCIDM_TB_REPORTVIEW:
999 stringId = IDS_REPORTVIEW;
1000 break;
1001 /* Desktop button */
1002 case FCIDM_TB_DESKTOP:
1003 stringId = IDS_TODESKTOP;
1004 break;
1005 default:
1006 stringId = 0;
1008 lpdi->hinst = COMDLG32_hInstance;
1009 lpdi->lpszText = (LPSTR) stringId;
1011 return FALSE;
1013 default :
1014 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1015 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1016 return FALSE;
1020 /***********************************************************************
1021 * FILEDLG95_InitControls
1023 * WM_INITDIALOG message handler (before hook notification)
1025 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1027 int win2000plus = 0;
1028 int win98plus = 0;
1029 int handledPath = FALSE;
1030 OSVERSIONINFOA osVi;
1031 const WCHAR szwSlash[] = { '\\', 0 };
1032 const WCHAR szwStar[] = { '*',0 };
1034 TBBUTTON tbb[] =
1036 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1037 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1038 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1039 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1040 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1041 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1042 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1043 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1044 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1046 TBADDBITMAP tba[2];
1047 RECT rectTB;
1048 RECT rectlook;
1049 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1051 tba[0].hInst = HINST_COMMCTRL;
1052 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1053 tba[1].hInst = COMDLG32_hInstance;
1054 tba[1].nID = 800;
1056 TRACE("%p\n", fodInfos);
1058 /* Get windows version emulating */
1059 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1060 GetVersionExA(&osVi);
1061 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1062 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1063 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1064 win2000plus = (osVi.dwMajorVersion > 4);
1065 if (win2000plus) win98plus = TRUE;
1067 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1069 /* Get the hwnd of the controls */
1070 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1071 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1072 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1074 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1075 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1077 /* construct the toolbar */
1078 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1079 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1081 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1082 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1083 rectTB.left = rectlook.right;
1084 rectTB.top = rectlook.top-1;
1086 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1087 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1088 rectTB.left, rectTB.top,
1089 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1090 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1092 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1094 /* FIXME: use TB_LOADIMAGES when implemented */
1095 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1096 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1097 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1099 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1100 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1102 /* Set the window text with the text specified in the OPENFILENAME structure */
1103 if(fodInfos->title)
1105 SetWindowTextW(hwnd,fodInfos->title);
1107 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1109 SetWindowTextA(hwnd,"Save");
1112 /* Initialise the file name edit control */
1113 handledPath = FALSE;
1114 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1116 if(fodInfos->filename)
1118 /* 1. If win2000 or higher and filename contains a path, use it
1119 in preference over the lpstrInitialDir */
1120 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1121 WCHAR tmpBuf[MAX_PATH];
1122 WCHAR *nameBit;
1123 DWORD result;
1125 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1126 if (result) {
1128 /* nameBit is always shorter than the original filename */
1129 strcpyW(fodInfos->filename,nameBit);
1131 *nameBit = 0x00;
1132 if (fodInfos->initdir == NULL)
1133 MemFree(fodInfos->initdir);
1134 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1135 strcpyW(fodInfos->initdir, tmpBuf);
1136 handledPath = TRUE;
1137 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1138 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1140 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1142 } else {
1143 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1147 /* 2. (All platforms) If initdir is not null, then use it */
1148 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1149 (*fodInfos->initdir!=0x00))
1151 /* Work out the proper path as supplied one might be relative */
1152 /* (Here because supplying '.' as dir browses to My Computer) */
1153 if (handledPath==FALSE) {
1154 WCHAR tmpBuf[MAX_PATH];
1155 WCHAR tmpBuf2[MAX_PATH];
1156 WCHAR *nameBit;
1157 DWORD result;
1159 strcpyW(tmpBuf, fodInfos->initdir);
1160 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1161 strcatW(tmpBuf, szwSlash);
1163 strcatW(tmpBuf, szwStar);
1164 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1165 if (result) {
1166 *nameBit = 0x00;
1167 if (fodInfos->initdir)
1168 MemFree(fodInfos->initdir);
1169 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1170 strcpyW(fodInfos->initdir, tmpBuf2);
1171 handledPath = TRUE;
1172 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1177 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1178 (*fodInfos->initdir==0x00)))
1180 /* 3. All except w2k+: if filename contains a path use it */
1181 if (!win2000plus && fodInfos->filename &&
1182 *fodInfos->filename &&
1183 strpbrkW(fodInfos->filename, szwSlash)) {
1184 WCHAR tmpBuf[MAX_PATH];
1185 WCHAR *nameBit;
1186 DWORD result;
1188 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1189 tmpBuf, &nameBit);
1190 if (result) {
1191 int len;
1193 /* nameBit is always shorter than the original filename */
1194 strcpyW(fodInfos->filename, nameBit);
1195 *nameBit = 0x00;
1197 len = strlenW(tmpBuf);
1198 if(fodInfos->initdir)
1199 MemFree(fodInfos->initdir);
1200 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1201 strcpyW(fodInfos->initdir, tmpBuf);
1203 handledPath = TRUE;
1204 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1205 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1207 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1210 /* 4. win98+ and win2000+ if any files of specified filter types in
1211 current directory, use it */
1212 if ( win98plus && handledPath == FALSE &&
1213 fodInfos->filter && *fodInfos->filter) {
1215 BOOL searchMore = TRUE;
1216 LPCWSTR lpstrPos = fodInfos->filter;
1217 WIN32_FIND_DATAW FindFileData;
1218 HANDLE hFind;
1220 while (searchMore)
1222 /* filter is a list... title\0ext\0......\0\0 */
1224 /* Skip the title */
1225 if(! *lpstrPos) break; /* end */
1226 lpstrPos += strlenW(lpstrPos) + 1;
1228 /* See if any files exist in the current dir with this extension */
1229 if(! *lpstrPos) break; /* end */
1231 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1233 if (hFind == INVALID_HANDLE_VALUE) {
1234 /* None found - continue search */
1235 lpstrPos += strlenW(lpstrPos) + 1;
1237 } else {
1238 searchMore = FALSE;
1240 if(fodInfos->initdir)
1241 MemFree(fodInfos->initdir);
1242 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1243 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1245 handledPath = TRUE;
1246 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1247 debugstr_w(lpstrPos));
1248 break;
1253 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1255 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1256 if (handledPath == FALSE && (win2000plus || win98plus)) {
1257 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1259 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1261 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1263 /* last fallback */
1264 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1265 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1266 } else {
1267 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1269 } else {
1270 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1272 handledPath = TRUE;
1273 } else if (handledPath==FALSE) {
1274 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1275 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1276 handledPath = TRUE;
1277 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1280 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1281 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1283 /* Must the open as read only check box be checked ?*/
1284 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1286 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1289 /* Must the open as read only check box be hidden? */
1290 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1292 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1293 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1296 /* Must the help button be hidden? */
1297 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1299 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1300 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1303 /* Resize the height, if open as read only checkbox ad help button
1304 are hidden and we are not using a custom template nor a customDialog
1306 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1307 (!(fodInfos->ofnInfos->Flags &
1308 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1309 (!fodInfos->DlgInfos.hwndCustomDlg ))
1311 RECT rectDlg, rectHelp, rectCancel;
1312 GetWindowRect(hwnd, &rectDlg);
1313 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1314 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1315 /* subtract the height of the help button plus the space between
1316 the help button and the cancel button to the height of the dialog */
1317 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1318 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1319 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1321 /* change Open to Save FIXME: use resources */
1322 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1324 SetDlgItemTextA(hwnd,IDOK,"&Save");
1325 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1327 return 0;
1330 /***********************************************************************
1331 * FILEDLG95_FillControls
1333 * WM_INITDIALOG message handler (after hook notification)
1335 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1337 LPITEMIDLIST pidlItemId = NULL;
1339 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1341 TRACE("dir=%s file=%s\n",
1342 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1344 /* Get the initial directory pidl */
1346 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1348 WCHAR path[MAX_PATH];
1350 GetCurrentDirectoryW(MAX_PATH,path);
1351 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1354 /* Initialise shell objects */
1355 FILEDLG95_SHELL_Init(hwnd);
1357 /* Initialize the Look In combo box */
1358 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1360 /* Initialize the filter combo box */
1361 FILEDLG95_FILETYPE_Init(hwnd);
1363 /* Browse to the initial directory */
1364 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1366 /* Free pidlItem memory */
1367 COMDLG32_SHFree(pidlItemId);
1369 return TRUE;
1371 /***********************************************************************
1372 * FILEDLG95_Clean
1374 * Regroups all the cleaning functions of the filedlg
1376 void FILEDLG95_Clean(HWND hwnd)
1378 FILEDLG95_FILETYPE_Clean(hwnd);
1379 FILEDLG95_LOOKIN_Clean(hwnd);
1380 FILEDLG95_SHELL_Clean(hwnd);
1382 /***********************************************************************
1383 * FILEDLG95_OnWMCommand
1385 * WM_COMMAND message handler
1387 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1389 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1390 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1391 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1393 switch(wID)
1395 /* OK button */
1396 case IDOK:
1397 FILEDLG95_OnOpen(hwnd);
1398 break;
1399 /* Cancel button */
1400 case IDCANCEL:
1401 FILEDLG95_Clean(hwnd);
1402 EndDialog(hwnd, FALSE);
1403 break;
1404 /* Filetype combo box */
1405 case IDC_FILETYPE:
1406 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1407 break;
1408 /* LookIn combo box */
1409 case IDC_LOOKIN:
1410 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1411 break;
1413 /* --- toolbar --- */
1414 /* Up folder button */
1415 case FCIDM_TB_UPFOLDER:
1416 FILEDLG95_SHELL_UpFolder(hwnd);
1417 break;
1418 /* New folder button */
1419 case FCIDM_TB_NEWFOLDER:
1420 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1421 break;
1422 /* List option button */
1423 case FCIDM_TB_SMALLICON:
1424 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1425 break;
1426 /* Details option button */
1427 case FCIDM_TB_REPORTVIEW:
1428 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1429 break;
1430 /* Details option button */
1431 case FCIDM_TB_DESKTOP:
1432 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1433 break;
1435 case IDC_FILENAME:
1436 break;
1439 /* Do not use the listview selection anymore */
1440 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1441 return 0;
1444 /***********************************************************************
1445 * FILEDLG95_OnWMGetIShellBrowser
1447 * WM_GETISHELLBROWSER message handler
1449 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1452 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1454 TRACE("\n");
1456 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1458 return TRUE;
1462 /***********************************************************************
1463 * FILEDLG95_SendFileOK
1465 * Sends the CDN_FILEOK notification if required
1467 * RETURNS
1468 * TRUE if the dialog should close
1469 * FALSE if the dialog should not be closed
1471 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1473 /* ask the hook if we can close */
1474 if(IsHooked(fodInfos))
1476 TRACE("---\n");
1477 /* First send CDN_FILEOK as MSDN doc says */
1478 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1480 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1481 CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,
1482 fodInfos->DlgInfos.hwndCustomDlg,
1483 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1484 if (GetWindowLongA(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1486 TRACE("canceled\n");
1487 return FALSE;
1490 return TRUE;
1493 /***********************************************************************
1494 * FILEDLG95_OnOpenMultipleFiles
1496 * Handles the opening of multiple files.
1498 * FIXME
1499 * check destination buffer size
1501 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1503 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1504 UINT nCount, nSizePath;
1505 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1507 TRACE("\n");
1509 if(fodInfos->unicode)
1511 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1512 ofn->lpstrFile[0] = '\0';
1514 else
1516 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1517 ofn->lpstrFile[0] = '\0';
1520 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1522 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1523 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1524 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1526 LPWSTR lpstrTemp = lpstrFileList;
1528 for ( nCount = 0; nCount < nFileCount; nCount++ )
1530 LPITEMIDLIST pidl;
1532 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1533 if (!pidl)
1535 WCHAR lpstrNotFound[100];
1536 WCHAR lpstrMsg[100];
1537 WCHAR tmp[400];
1538 WCHAR nl[] = {'\n',0};
1540 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1541 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1543 strcpyW(tmp, lpstrTemp);
1544 strcatW(tmp, nl);
1545 strcatW(tmp, lpstrNotFound);
1546 strcatW(tmp, nl);
1547 strcatW(tmp, lpstrMsg);
1549 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1550 return FALSE;
1553 /* move to the next file in the list of files */
1554 lpstrTemp += strlenW(lpstrTemp) + 1;
1555 COMDLG32_SHFree(pidl);
1559 nSizePath = strlenW(lpstrPathSpec) + 1;
1560 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1562 /* For "oldstyle" dialog the components have to
1563 be spearated by blanks (not '\0'!) and short
1564 filenames have to be used! */
1565 FIXME("Components have to be separated by blanks");
1567 if(fodInfos->unicode)
1569 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1570 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1571 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1573 else
1575 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1577 if (ofn->lpstrFile != NULL)
1579 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1580 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1581 if (ofn->nMaxFile > nSizePath)
1583 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1584 ofn->lpstrFile + nSizePath,
1585 ofn->nMaxFile - nSizePath, NULL, NULL);
1590 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1591 fodInfos->ofnInfos->nFileExtension = 0;
1593 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1594 return FALSE;
1596 /* clean and exit */
1597 FILEDLG95_Clean(hwnd);
1598 return EndDialog(hwnd,TRUE);
1601 /***********************************************************************
1602 * FILEDLG95_OnOpen
1604 * Ok button WM_COMMAND message handler
1606 * If the function succeeds, the return value is nonzero.
1608 #define ONOPEN_BROWSE 1
1609 #define ONOPEN_OPEN 2
1610 #define ONOPEN_SEARCH 3
1611 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1613 char strMsgTitle[MAX_PATH];
1614 char strMsgText [MAX_PATH];
1615 if (idCaption)
1616 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1617 else
1618 strMsgTitle[0] = '\0';
1619 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1620 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1623 BOOL FILEDLG95_OnOpen(HWND hwnd)
1625 LPWSTR lpstrFileList;
1626 UINT nFileCount = 0;
1627 UINT sizeUsed = 0;
1628 BOOL ret = TRUE;
1629 WCHAR lpstrPathAndFile[MAX_PATH];
1630 WCHAR lpstrTemp[MAX_PATH];
1631 LPSHELLFOLDER lpsf = NULL;
1632 int nOpenAction;
1633 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1635 TRACE("hwnd=%p\n", hwnd);
1637 /* get the files from the edit control */
1638 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1640 /* try if the user selected a folder in the shellview */
1641 if(nFileCount == 0)
1643 BrowseSelectedFolder(hwnd);
1644 return FALSE;
1647 if(nFileCount > 1)
1649 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1650 goto ret;
1653 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1656 Step 1: Build a complete path name from the current folder and
1657 the filename or path in the edit box.
1658 Special cases:
1659 - the path in the edit box is a root path
1660 (with or without drive letter)
1661 - the edit box contains ".." (or a path with ".." in it)
1664 /* Get the current directory name */
1665 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1667 /* we are in a special folder, default to desktop */
1668 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1670 /* last fallback */
1671 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1674 PathAddBackslashW(lpstrPathAndFile);
1676 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1678 /* if the user specifyed a fully qualified path use it */
1679 if(PathIsRelativeW(lpstrFileList))
1681 strcatW(lpstrPathAndFile, lpstrFileList);
1683 else
1685 /* does the path have a drive letter? */
1686 if (PathGetDriveNumberW(lpstrFileList) == -1)
1687 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1688 else
1689 strcpyW(lpstrPathAndFile, lpstrFileList);
1692 /* resolve "." and ".." */
1693 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1694 strcpyW(lpstrPathAndFile, lpstrTemp);
1695 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1697 MemFree(lpstrFileList);
1700 Step 2: here we have a cleaned up path
1702 We have to parse the path step by step to see if we have to browse
1703 to a folder if the path points to a directory or the last
1704 valid element is a directory.
1706 valid variables:
1707 lpstrPathAndFile: cleaned up path
1710 nOpenAction = ONOPEN_BROWSE;
1712 /* dont apply any checks with OFN_NOVALIDATE */
1714 LPWSTR lpszTemp, lpszTemp1;
1715 LPITEMIDLIST pidl = NULL;
1716 WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1718 /* check for invalid chars */
1719 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1721 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1722 ret = FALSE;
1723 goto ret;
1726 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1728 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1729 while (lpszTemp1)
1731 LPSHELLFOLDER lpsfChild;
1732 WCHAR lpwstrTemp[MAX_PATH];
1733 DWORD dwEaten, dwAttributes;
1734 LPWSTR p;
1736 strcpyW(lpwstrTemp, lpszTemp);
1737 p = PathFindNextComponentW(lpwstrTemp);
1739 if (!p) break; /* end of path */
1741 *p = 0;
1742 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1744 if(*lpszTemp==0)
1746 WCHAR wszWild[] = { '*', '?', 0 };
1747 /* if the last element is a wildcard do a search */
1748 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1750 nOpenAction = ONOPEN_SEARCH;
1751 break;
1754 lpszTemp1 = lpszTemp;
1756 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1758 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1760 dwAttributes = SFGAO_FOLDER;
1761 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1763 /* the path component is valid, we have a pidl of the next path component */
1764 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1765 if(dwAttributes & SFGAO_FOLDER)
1767 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1769 ERR("bind to failed\n"); /* should not fail */
1770 break;
1772 IShellFolder_Release(lpsf);
1773 lpsf = lpsfChild;
1774 lpsfChild = NULL;
1776 else
1778 TRACE("value\n");
1780 /* end dialog, return value */
1781 nOpenAction = ONOPEN_OPEN;
1782 break;
1784 COMDLG32_SHFree(pidl);
1785 pidl = NULL;
1787 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1789 if(*lpszTemp) /* points to trailing null for last path element */
1791 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1793 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1794 break;
1797 else
1799 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1800 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1802 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1803 break;
1806 /* change to the current folder */
1807 nOpenAction = ONOPEN_OPEN;
1808 break;
1810 else
1812 nOpenAction = ONOPEN_OPEN;
1813 break;
1816 if(pidl) COMDLG32_SHFree(pidl);
1820 Step 3: here we have a cleaned up and validated path
1822 valid variables:
1823 lpsf: ShellFolder bound to the rightmost valid path component
1824 lpstrPathAndFile: cleaned up path
1825 nOpenAction: action to do
1827 TRACE("end validate sf=%p\n", lpsf);
1829 switch(nOpenAction)
1831 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1832 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1834 int iPos;
1835 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1836 DWORD len;
1838 /* replace the current filter */
1839 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1840 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1841 len = strlenW(lpszTemp)+1;
1842 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1843 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1845 /* set the filter cb to the extension when possible */
1846 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1847 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1849 /* fall through */
1850 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1851 TRACE("ONOPEN_BROWSE\n");
1853 IPersistFolder2 * ppf2;
1854 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1856 LPITEMIDLIST pidlCurrent;
1857 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1858 IPersistFolder2_Release(ppf2);
1859 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1861 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1863 else if( nOpenAction == ONOPEN_SEARCH )
1865 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1867 COMDLG32_SHFree(pidlCurrent);
1870 ret = FALSE;
1871 break;
1872 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1873 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1875 /* add default extension */
1876 if (fodInfos->defext)
1878 if (! *PathFindExtensionW(lpstrPathAndFile))
1880 /* only add "." in case a default extension does exist */
1881 if (*fodInfos->defext != '\0')
1883 const WCHAR szwDot[] = {'.',0};
1884 int PathLength = strlenW(lpstrPathAndFile);
1886 strcatW(lpstrPathAndFile, szwDot);
1887 strcatW(lpstrPathAndFile, fodInfos->defext);
1889 /* if file does not exist try without extension */
1890 if (!PathFileExistsW(lpstrPathAndFile))
1891 lpstrPathAndFile[PathLength] = '\0';
1896 /* Check that the size of the file does not exceed buffer size.
1897 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1898 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1899 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1901 LPWSTR lpszTemp;
1903 /* fill destination buffer */
1904 if (fodInfos->ofnInfos->lpstrFile)
1906 if(fodInfos->unicode)
1908 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1910 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1911 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1912 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1914 else
1916 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1918 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1919 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1920 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1921 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1925 /* set filename offset */
1926 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1927 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1929 /* set extension offset */
1930 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1931 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1933 /* set the lpstrFileTitle */
1934 if(fodInfos->ofnInfos->lpstrFileTitle)
1936 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1937 if(fodInfos->unicode)
1939 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1940 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1942 else
1944 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1945 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1946 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1950 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1951 goto ret;
1953 TRACE("close\n");
1954 FILEDLG95_Clean(hwnd);
1955 ret = EndDialog(hwnd, TRUE);
1957 else
1959 /* FIXME set error FNERR_BUFFERTOSMALL */
1960 FILEDLG95_Clean(hwnd);
1961 ret = EndDialog(hwnd, FALSE);
1963 goto ret;
1965 break;
1968 ret:
1969 if(lpsf) IShellFolder_Release(lpsf);
1970 return ret;
1973 /***********************************************************************
1974 * FILEDLG95_SHELL_Init
1976 * Initialisation of the shell objects
1978 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
1980 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1982 TRACE("\n");
1985 * Initialisation of the FileOpenDialogInfos structure
1988 /* Shell */
1990 /*ShellInfos */
1991 fodInfos->ShellInfos.hwndOwner = hwnd;
1993 /* Disable multi-select if flag not set */
1994 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
1996 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
1998 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
1999 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2001 /* Construct the IShellBrowser interface */
2002 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2004 return NOERROR;
2007 /***********************************************************************
2008 * FILEDLG95_SHELL_ExecuteCommand
2010 * Change the folder option and refresh the view
2011 * If the function succeeds, the return value is nonzero.
2013 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2015 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2017 IContextMenu * pcm;
2018 TRACE("(%p,%p)\n", hwnd, lpVerb);
2020 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2021 SVGIO_BACKGROUND,
2022 &IID_IContextMenu,
2023 (LPVOID*)&pcm)))
2025 CMINVOKECOMMANDINFO ci;
2026 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2027 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2028 ci.lpVerb = lpVerb;
2029 ci.hwnd = hwnd;
2031 IContextMenu_InvokeCommand(pcm, &ci);
2032 IContextMenu_Release(pcm);
2035 return FALSE;
2038 /***********************************************************************
2039 * FILEDLG95_SHELL_UpFolder
2041 * Browse to the specified object
2042 * If the function succeeds, the return value is nonzero.
2044 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2046 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2048 TRACE("\n");
2050 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2051 NULL,
2052 SBSP_PARENT)))
2054 return TRUE;
2056 return FALSE;
2059 /***********************************************************************
2060 * FILEDLG95_SHELL_BrowseToDesktop
2062 * Browse to the Desktop
2063 * If the function succeeds, the return value is nonzero.
2065 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2067 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2068 LPITEMIDLIST pidl;
2069 HRESULT hres;
2071 TRACE("\n");
2073 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2074 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2075 COMDLG32_SHFree(pidl);
2076 return SUCCEEDED(hres);
2078 /***********************************************************************
2079 * FILEDLG95_SHELL_Clean
2081 * Cleans the memory used by shell objects
2083 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2085 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2087 TRACE("\n");
2089 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2091 /* clean Shell interfaces */
2092 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2093 IShellView_Release(fodInfos->Shell.FOIShellView);
2094 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2095 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2096 if (fodInfos->Shell.FOIDataObject)
2097 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2100 /***********************************************************************
2101 * FILEDLG95_FILETYPE_Init
2103 * Initialisation of the file type combo box
2105 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2107 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2109 TRACE("\n");
2111 if(fodInfos->filter)
2113 int nFilters = 0; /* number of filters */
2114 LPWSTR lpstrFilter;
2115 LPCWSTR lpstrPos = fodInfos->filter;
2117 for(;;)
2119 /* filter is a list... title\0ext\0......\0\0
2120 * Set the combo item text to the title and the item data
2121 * to the ext
2123 LPCWSTR lpstrDisplay;
2124 LPWSTR lpstrExt;
2126 /* Get the title */
2127 if(! *lpstrPos) break; /* end */
2128 lpstrDisplay = lpstrPos;
2129 lpstrPos += strlenW(lpstrPos) + 1;
2131 /* Copy the extensions */
2132 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2133 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2134 strcpyW(lpstrExt,lpstrPos);
2135 lpstrPos += strlenW(lpstrPos) + 1;
2137 /* Add the item at the end of the combo */
2138 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2139 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2140 nFilters++;
2143 * Set the current filter to the one specified
2144 * in the initialisation structure
2145 * FIXME: lpstrCustomFilter not handled at all
2148 /* set default filter index */
2149 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2150 fodInfos->ofnInfos->nFilterIndex = 1;
2152 /* First, check to make sure our index isn't out of bounds. */
2153 if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
2154 fodInfos->ofnInfos->nFilterIndex = nFilters;
2156 /* Set the current index selection. */
2157 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
2159 /* Get the corresponding text string from the combo box. */
2160 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2161 fodInfos->ofnInfos->nFilterIndex-1);
2163 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2164 lpstrFilter = NULL;
2166 if(lpstrFilter)
2168 DWORD len;
2169 CharLowerW(lpstrFilter); /* lowercase */
2170 len = strlenW(lpstrFilter)+1;
2171 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2172 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2175 return NOERROR;
2178 /***********************************************************************
2179 * FILEDLG95_FILETYPE_OnCommand
2181 * WM_COMMAND of the file type combo box
2182 * If the function succeeds, the return value is nonzero.
2184 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2186 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2188 switch(wNotifyCode)
2190 case CBN_SELENDOK:
2192 LPWSTR lpstrFilter;
2194 /* Get the current item of the filetype combo box */
2195 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2197 /* set the current filter index - indexed from 1 */
2198 fodInfos->ofnInfos->nFilterIndex = iItem + 1;
2200 /* Set the current filter with the current selection */
2201 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2202 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2204 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2205 iItem);
2206 if((int)lpstrFilter != CB_ERR)
2208 DWORD len;
2209 CharLowerW(lpstrFilter); /* lowercase */
2210 len = strlenW(lpstrFilter)+1;
2211 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2212 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2213 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2216 /* Refresh the actual view to display the included items*/
2217 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2220 return FALSE;
2222 /***********************************************************************
2223 * FILEDLG95_FILETYPE_SearchExt
2225 * searches for a extension in the filetype box
2227 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2229 int i, iCount = CBGetCount(hwnd);
2231 TRACE("%s\n", debugstr_w(lpstrExt));
2233 if(iCount != CB_ERR)
2235 for(i=0;i<iCount;i++)
2237 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2238 return i;
2241 return -1;
2244 /***********************************************************************
2245 * FILEDLG95_FILETYPE_Clean
2247 * Clean the memory used by the filetype combo box
2249 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2251 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2252 int iPos;
2253 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2255 TRACE("\n");
2257 /* Delete each string of the combo and their associated data */
2258 if(iCount != CB_ERR)
2260 for(iPos = iCount-1;iPos>=0;iPos--)
2262 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2263 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2266 /* Current filter */
2267 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2268 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2272 /***********************************************************************
2273 * FILEDLG95_LOOKIN_Init
2275 * Initialisation of the look in combo box
2277 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2279 IShellFolder *psfRoot, *psfDrives;
2280 IEnumIDList *lpeRoot, *lpeDrives;
2281 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2283 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2285 TRACE("\n");
2287 liInfos->iMaxIndentation = 0;
2289 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2291 /* set item height for both text field and listbox */
2292 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2293 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2295 /* Initialise data of Desktop folder */
2296 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2297 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2298 COMDLG32_SHFree(pidlTmp);
2300 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2302 SHGetDesktopFolder(&psfRoot);
2304 if (psfRoot)
2306 /* enumerate the contents of the desktop */
2307 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2309 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2311 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2313 /* special handling for CSIDL_DRIVES */
2314 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2316 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2318 /* enumerate the drives */
2319 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2321 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2323 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2324 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2325 COMDLG32_SHFree(pidlAbsTmp);
2326 COMDLG32_SHFree(pidlTmp1);
2328 IEnumIDList_Release(lpeDrives);
2330 IShellFolder_Release(psfDrives);
2333 COMDLG32_SHFree(pidlTmp);
2335 IEnumIDList_Release(lpeRoot);
2339 IShellFolder_Release(psfRoot);
2340 COMDLG32_SHFree(pidlDrives);
2341 return NOERROR;
2344 /***********************************************************************
2345 * FILEDLG95_LOOKIN_DrawItem
2347 * WM_DRAWITEM message handler
2349 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2351 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2352 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2353 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2354 RECT rectText;
2355 RECT rectIcon;
2356 SHFILEINFOA sfi;
2357 HIMAGELIST ilItemImage;
2358 int iIndentation;
2359 TEXTMETRICA tm;
2360 LPSFOLDER tmpFolder;
2363 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2365 TRACE("\n");
2367 if(pDIStruct->itemID == -1)
2368 return 0;
2370 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2371 pDIStruct->itemID)))
2372 return 0;
2375 if(pDIStruct->itemID == liInfos->uSelectedItem)
2377 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2379 &sfi,
2380 sizeof (SHFILEINFOA),
2381 SHGFI_PIDL | SHGFI_SMALLICON |
2382 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2383 SHGFI_DISPLAYNAME );
2385 else
2387 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2389 &sfi,
2390 sizeof (SHFILEINFOA),
2391 SHGFI_PIDL | SHGFI_SMALLICON |
2392 SHGFI_SYSICONINDEX |
2393 SHGFI_DISPLAYNAME);
2396 /* Is this item selected ? */
2397 if(pDIStruct->itemState & ODS_SELECTED)
2399 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2400 SetBkColor(pDIStruct->hDC,crHighLight);
2401 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2403 else
2405 SetTextColor(pDIStruct->hDC,crText);
2406 SetBkColor(pDIStruct->hDC,crWin);
2407 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2410 /* Do not indent item if drawing in the edit of the combo */
2411 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2413 iIndentation = 0;
2414 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2416 &sfi,
2417 sizeof (SHFILEINFOA),
2418 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2419 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2422 else
2424 iIndentation = tmpFolder->m_iIndent;
2426 /* Draw text and icon */
2428 /* Initialise the icon display area */
2429 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2430 rectIcon.top = pDIStruct->rcItem.top;
2431 rectIcon.right = rectIcon.left + ICONWIDTH;
2432 rectIcon.bottom = pDIStruct->rcItem.bottom;
2434 /* Initialise the text display area */
2435 GetTextMetricsA(pDIStruct->hDC, &tm);
2436 rectText.left = rectIcon.right;
2437 rectText.top =
2438 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2439 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2440 rectText.bottom =
2441 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2443 /* Draw the icon from the image list */
2444 ImageList_Draw(ilItemImage,
2445 sfi.iIcon,
2446 pDIStruct->hDC,
2447 rectIcon.left,
2448 rectIcon.top,
2449 ILD_TRANSPARENT );
2451 /* Draw the associated text */
2452 if(sfi.szDisplayName)
2453 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2456 return NOERROR;
2459 /***********************************************************************
2460 * FILEDLG95_LOOKIN_OnCommand
2462 * LookIn combo box WM_COMMAND message handler
2463 * If the function succeeds, the return value is nonzero.
2465 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2467 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2469 TRACE("%p\n", fodInfos);
2471 switch(wNotifyCode)
2473 case CBN_SELENDOK:
2475 LPSFOLDER tmpFolder;
2476 int iItem;
2478 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2480 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2481 iItem)))
2482 return FALSE;
2485 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2486 tmpFolder->pidlItem,
2487 SBSP_ABSOLUTE)))
2489 return TRUE;
2491 break;
2495 return FALSE;
2498 /***********************************************************************
2499 * FILEDLG95_LOOKIN_AddItem
2501 * Adds an absolute pidl item to the lookin combo box
2502 * returns the index of the inserted item
2504 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2506 LPITEMIDLIST pidlNext;
2507 SHFILEINFOA sfi;
2508 SFOLDER *tmpFolder;
2509 LookInInfos *liInfos;
2511 TRACE("%08x\n", iInsertId);
2513 if(!pidl)
2514 return -1;
2516 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2517 return -1;
2519 tmpFolder = MemAlloc(sizeof(SFOLDER));
2520 tmpFolder->m_iIndent = 0;
2522 /* Calculate the indentation of the item in the lookin*/
2523 pidlNext = pidl;
2524 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2526 tmpFolder->m_iIndent++;
2529 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2531 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2532 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2534 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2535 SHGetFileInfoA((LPSTR)pidl,
2537 &sfi,
2538 sizeof(sfi),
2539 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2540 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2542 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2544 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2546 int iItemID;
2548 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2550 /* Add the item at the end of the list */
2551 if(iInsertId < 0)
2553 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2555 /* Insert the item at the iInsertId position*/
2556 else
2558 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2561 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2562 return iItemID;
2565 COMDLG32_SHFree( tmpFolder->pidlItem );
2566 MemFree( tmpFolder );
2567 return -1;
2571 /***********************************************************************
2572 * FILEDLG95_LOOKIN_InsertItemAfterParent
2574 * Insert an item below its parent
2576 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2579 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2580 int iParentPos;
2582 TRACE("\n");
2584 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2586 if(iParentPos < 0)
2588 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2591 /* Free pidlParent memory */
2592 COMDLG32_SHFree((LPVOID)pidlParent);
2594 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2597 /***********************************************************************
2598 * FILEDLG95_LOOKIN_SelectItem
2600 * Adds an absolute pidl item to the lookin combo box
2601 * returns the index of the inserted item
2603 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2605 int iItemPos;
2606 LookInInfos *liInfos;
2608 TRACE("\n");
2610 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2612 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2614 if(iItemPos < 0)
2616 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2617 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2620 else
2622 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2623 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2625 int iRemovedItem;
2627 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2628 break;
2629 if(iRemovedItem < iItemPos)
2630 iItemPos--;
2634 CBSetCurSel(hwnd,iItemPos);
2635 liInfos->uSelectedItem = iItemPos;
2637 return 0;
2641 /***********************************************************************
2642 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2644 * Remove the item with an expansion level over iExpansionLevel
2646 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2648 int iItemPos;
2650 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2652 TRACE("\n");
2654 if(liInfos->iMaxIndentation <= 2)
2655 return -1;
2657 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2659 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2660 COMDLG32_SHFree(tmpFolder->pidlItem);
2661 MemFree(tmpFolder);
2662 CBDeleteString(hwnd,iItemPos);
2663 liInfos->iMaxIndentation--;
2665 return iItemPos;
2668 return -1;
2671 /***********************************************************************
2672 * FILEDLG95_LOOKIN_SearchItem
2674 * Search for pidl in the lookin combo box
2675 * returns the index of the found item
2677 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2679 int i = 0;
2680 int iCount = CBGetCount(hwnd);
2682 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2684 if (iCount != CB_ERR)
2686 for(;i<iCount;i++)
2688 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2690 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2691 return i;
2692 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2693 return i;
2697 return -1;
2700 /***********************************************************************
2701 * FILEDLG95_LOOKIN_Clean
2703 * Clean the memory used by the lookin combo box
2705 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2707 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2708 int iPos;
2709 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2711 TRACE("\n");
2713 /* Delete each string of the combo and their associated data */
2714 if (iCount != CB_ERR)
2716 for(iPos = iCount-1;iPos>=0;iPos--)
2718 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2719 COMDLG32_SHFree(tmpFolder->pidlItem);
2720 MemFree(tmpFolder);
2721 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2725 /* LookInInfos structure */
2726 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2729 /***********************************************************************
2730 * FILEDLG95_FILENAME_FillFromSelection
2732 * fills the edit box from the cached DataObject
2734 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2736 FileOpenDlgInfos *fodInfos;
2737 LPITEMIDLIST pidl;
2738 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2739 char lpstrTemp[MAX_PATH];
2740 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2742 TRACE("\n");
2743 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2745 /* Count how many files we have */
2746 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2748 /* calculate the string length, count files */
2749 if (nFileSelected >= 1)
2751 nLength += 3; /* first and last quotes, trailing \0 */
2752 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2754 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2756 if (pidl)
2758 /* get the total length of the selected file names */
2759 lpstrTemp[0] = '\0';
2760 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2762 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2764 nLength += strlen( lpstrTemp ) + 3;
2765 nFiles++;
2767 COMDLG32_SHFree( pidl );
2772 /* allocate the buffer */
2773 if (nFiles <= 1) nLength = MAX_PATH;
2774 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2775 lpstrAllFile[0] = '\0';
2777 /* Generate the string for the edit control */
2778 if(nFiles >= 1)
2780 lpstrCurrFile = lpstrAllFile;
2781 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2783 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2785 if (pidl)
2787 /* get the file name */
2788 lpstrTemp[0] = '\0';
2789 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2791 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2793 if ( nFiles > 1)
2795 *lpstrCurrFile++ = '\"';
2796 strcpy( lpstrCurrFile, lpstrTemp );
2797 lpstrCurrFile += strlen( lpstrTemp );
2798 strcpy( lpstrCurrFile, "\" " );
2799 lpstrCurrFile += 2;
2801 else
2803 strcpy( lpstrAllFile, lpstrTemp );
2806 COMDLG32_SHFree( (LPVOID) pidl );
2809 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2811 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2815 /* copied from shell32 to avoid linking to it */
2816 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2818 switch (src->uType)
2820 case STRRET_WSTR:
2821 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2822 COMDLG32_SHFree(src->u.pOleStr);
2823 break;
2825 case STRRET_CSTR:
2826 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2827 break;
2829 case STRRET_OFFSET:
2830 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2831 break;
2833 default:
2834 FIXME("unknown type!\n");
2835 if (len)
2837 *(LPSTR)dest = '\0';
2839 return(FALSE);
2841 return S_OK;
2844 /***********************************************************************
2845 * FILEDLG95_FILENAME_GetFileNames
2847 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2849 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2851 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2852 UINT nStrCharCount = 0; /* index in src buffer */
2853 UINT nFileIndex = 0; /* index in dest buffer */
2854 UINT nFileCount = 0; /* number of files */
2855 UINT nStrLen = 0; /* length of string in edit control */
2856 LPWSTR lpstrEdit; /* buffer for string from edit control */
2858 TRACE("\n");
2860 /* get the filenames from the edit control */
2861 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2862 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2863 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2865 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2867 /* we might get single filename without any '"',
2868 * so we need nStrLen + terminating \0 + end-of-list \0 */
2869 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2870 *sizeUsed = 0;
2872 /* build 0-delimited file list from filenames */
2873 while ( nStrCharCount <= nStrLen )
2875 if ( lpstrEdit[nStrCharCount]=='"' )
2877 nStrCharCount++;
2878 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2880 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2881 (*sizeUsed)++;
2882 nStrCharCount++;
2884 (*lpstrFileList)[nFileIndex++] = '\0';
2885 (*sizeUsed)++;
2886 nFileCount++;
2888 nStrCharCount++;
2891 /* single, unquoted string */
2892 if ((nStrLen > 0) && (*sizeUsed == 0) )
2894 strcpyW(*lpstrFileList, lpstrEdit);
2895 nFileIndex = strlenW(lpstrEdit) + 1;
2896 (*sizeUsed) = nFileIndex;
2897 nFileCount = 1;
2900 /* trailing \0 */
2901 (*lpstrFileList)[nFileIndex] = '\0';
2902 (*sizeUsed)++;
2904 MemFree(lpstrEdit);
2905 return nFileCount;
2908 #define SETDefFormatEtc(fe,cf,med) \
2910 (fe).cfFormat = cf;\
2911 (fe).dwAspect = DVASPECT_CONTENT; \
2912 (fe).ptd =NULL;\
2913 (fe).tymed = med;\
2914 (fe).lindex = -1;\
2918 * DATAOBJECT Helper functions
2921 /***********************************************************************
2922 * COMCTL32_ReleaseStgMedium
2924 * like ReleaseStgMedium from ole32
2926 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2928 if(medium.pUnkForRelease)
2930 IUnknown_Release(medium.pUnkForRelease);
2932 else
2934 GlobalUnlock(medium.u.hGlobal);
2935 GlobalFree(medium.u.hGlobal);
2939 /***********************************************************************
2940 * GetPidlFromDataObject
2942 * Return pidl(s) by number from the cached DataObject
2944 * nPidlIndex=0 gets the fully qualified root path
2946 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2949 STGMEDIUM medium;
2950 FORMATETC formatetc;
2951 LPITEMIDLIST pidl = NULL;
2953 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
2955 /* Set the FORMATETC structure*/
2956 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2958 /* Get the pidls from IDataObject */
2959 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2961 LPIDA cida = GlobalLock(medium.u.hGlobal);
2962 if(nPidlIndex <= cida->cidl)
2964 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
2966 COMCTL32_ReleaseStgMedium(medium);
2968 return pidl;
2971 /***********************************************************************
2972 * GetNumSelected
2974 * Return the number of selected items in the DataObject.
2977 UINT GetNumSelected( IDataObject *doSelected )
2979 UINT retVal = 0;
2980 STGMEDIUM medium;
2981 FORMATETC formatetc;
2983 TRACE("sv=%p\n", doSelected);
2985 if (!doSelected) return 0;
2987 /* Set the FORMATETC structure*/
2988 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2990 /* Get the pidls from IDataObject */
2991 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2993 LPIDA cida = GlobalLock(medium.u.hGlobal);
2994 retVal = cida->cidl;
2995 COMCTL32_ReleaseStgMedium(medium);
2996 return retVal;
2998 return 0;
3002 * TOOLS
3005 /***********************************************************************
3006 * GetName
3008 * Get the pidl's display name (relative to folder) and
3009 * put it in lpstrFileName.
3011 * Return NOERROR on success,
3012 * E_FAIL otherwise
3015 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3017 STRRET str;
3018 HRESULT hRes;
3020 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3022 if(!lpsf)
3024 HRESULT hRes;
3025 SHGetDesktopFolder(&lpsf);
3026 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3027 IShellFolder_Release(lpsf);
3028 return hRes;
3031 /* Get the display name of the pidl relative to the folder */
3032 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3034 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3036 return E_FAIL;
3039 /***********************************************************************
3040 * GetShellFolderFromPidl
3042 * pidlRel is the item pidl relative
3043 * Return the IShellFolder of the absolute pidl
3045 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3047 IShellFolder *psf = NULL,*psfParent;
3049 TRACE("%p\n", pidlAbs);
3051 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3053 psf = psfParent;
3054 if(pidlAbs && pidlAbs->mkid.cb)
3056 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3058 IShellFolder_Release(psfParent);
3059 return psf;
3062 /* return the desktop */
3063 return psfParent;
3065 return NULL;
3068 /***********************************************************************
3069 * GetParentPidl
3071 * Return the LPITEMIDLIST to the parent of the pidl in the list
3073 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3075 LPITEMIDLIST pidlParent;
3077 TRACE("%p\n", pidl);
3079 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3080 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3082 return pidlParent;
3085 /***********************************************************************
3086 * GetPidlFromName
3088 * returns the pidl of the file name relative to folder
3089 * NULL if an error occurred
3091 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3093 LPITEMIDLIST pidl = NULL;
3094 ULONG ulEaten;
3096 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3098 if(!lpcstrFileName) return NULL;
3099 if(!*lpcstrFileName) return NULL;
3101 if(!lpsf)
3103 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3104 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3105 IShellFolder_Release(lpsf);
3108 else
3110 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3112 return pidl;
3117 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3119 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3120 HRESULT ret;
3122 TRACE("%p, %p\n", psf, pidl);
3124 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3126 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3127 /* see documentation shell 4.1*/
3128 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3131 /***********************************************************************
3132 * BrowseSelectedFolder
3134 static BOOL BrowseSelectedFolder(HWND hwnd)
3136 BOOL bBrowseSelFolder = FALSE;
3137 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3139 TRACE("\n");
3141 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3143 LPITEMIDLIST pidlSelection;
3145 /* get the file selected */
3146 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3147 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3149 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3150 pidlSelection, SBSP_RELATIVE ) ) )
3152 WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3153 ' ','n','o','t',' ','e','x','i','s','t',0};
3154 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3157 bBrowseSelFolder = TRUE;
3159 COMDLG32_SHFree( pidlSelection );
3162 return bBrowseSelFolder;
3166 * Memory allocation methods */
3167 static void *MemAlloc(UINT size)
3169 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3172 static void MemFree(void *mem)
3174 if(mem)
3176 HeapFree(GetProcessHeap(),0,mem);