Improve handling of custom dialog templates passed to
[wine/multimedia.git] / dlls / commdlg / filedlg95.c
blobf8f74700425855afb4aa09b6d709e05effb96e53
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 <stdio.h>
60 #include <string.h>
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
64 #include "winbase.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wine/unicode.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "wine/debug.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlguid.h"
75 #include "filedlgbrowser.h"
76 #include "shlwapi.h"
77 #include "wine/obj_contextmenu.h"
79 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
81 #define UNIMPLEMENTED_FLAGS \
82 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
83 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING | OFN_EXTENSIONDIFFERENT |\
84 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
85 OFN_NOTESTFILECREATE | OFN_OVERWRITEPROMPT /*| OFN_USEMONIKERS*/)
87 #define IsHooked(fodInfos) \
88 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
89 /***********************************************************************
90 * Data structure and global variables
92 typedef struct SFolder
94 int m_iImageIndex; /* Index of picture in image list */
95 HIMAGELIST hImgList;
96 int m_iIndent; /* Indentation index */
97 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
99 } SFOLDER,*LPSFOLDER;
101 typedef struct tagLookInInfo
103 int iMaxIndentation;
104 UINT uSelectedItem;
105 } LookInInfos;
108 /***********************************************************************
109 * Defines and global variables
112 /* Draw item constant */
113 #define ICONWIDTH 18
114 #define XTEXTOFFSET 3
116 /* AddItem flags*/
117 #define LISTEND -1
119 /* SearchItem methods */
120 #define SEARCH_PIDL 1
121 #define SEARCH_EXP 2
122 #define ITEM_NOTFOUND -1
124 /* Undefined windows message sent by CreateViewObject*/
125 #define WM_GETISHELLBROWSER WM_USER+7
127 /* NOTE
128 * Those macros exist in windowsx.h. However, you can't really use them since
129 * they rely on the UNICODE defines and can't be used inside Wine itself.
132 /* Combo box macros */
133 #define CBAddString(hwnd,str) \
134 SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
135 #define CBAddStringW(hwnd,str) \
136 SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str);
138 #define CBInsertString(hwnd,str,pos) \
139 SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
141 #define CBDeleteString(hwnd,pos) \
142 SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
144 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
145 SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
147 #define CBGetItemDataPtr(hwnd,iItemId) \
148 SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
150 #define CBGetLBText(hwnd,iItemId,str) \
151 SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
153 #define CBGetCurSel(hwnd) \
154 SendMessageA(hwnd,CB_GETCURSEL,0,0);
156 #define CBSetCurSel(hwnd,pos) \
157 SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
159 #define CBGetCount(hwnd) \
160 SendMessageA(hwnd,CB_GETCOUNT,0,0);
161 #define CBShowDropDown(hwnd,show) \
162 SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
163 #define CBSetItemHeight(hwnd,index,height) \
164 SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
167 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
168 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
170 /***********************************************************************
171 * Prototypes
174 /* Internal functions used by the dialog */
175 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
176 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
177 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
178 BOOL FILEDLG95_OnOpen(HWND hwnd);
179 static LRESULT FILEDLG95_InitControls(HWND hwnd);
180 static void FILEDLG95_Clean(HWND hwnd);
182 /* Functions used by the shell navigation */
183 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
184 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
185 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
186 static void FILEDLG95_SHELL_Clean(HWND hwnd);
187 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
189 /* Functions used by the filetype combo box */
190 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
191 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
192 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
193 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
195 /* Functions used by the Look In combo box */
196 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
197 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
198 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
199 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
200 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
201 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
202 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
203 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
204 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
206 /* Miscellaneous tool functions */
207 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
208 HRESULT GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
209 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
210 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
211 LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
213 /* Shell memory allocation */
214 static void *MemAlloc(UINT size);
215 static void MemFree(void *mem);
217 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
218 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
219 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
220 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
221 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
222 static BOOL BrowseSelectedFolder(HWND hwnd);
224 /***********************************************************************
225 * GetFileName95
227 * Creates an Open common dialog box that lets the user select
228 * the drive, directory, and the name of a file or set of files to open.
230 * IN : The FileOpenDlgInfos structure associated with the dialog
231 * OUT : TRUE on success
232 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
234 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
237 LRESULT lRes;
238 LPCVOID template;
239 HRSRC hRes;
240 HANDLE hDlgTmpl = 0;
242 /* test for missing functionality */
243 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
245 FIXME("Flags 0x%08lx not yet implemented\n",
246 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
249 /* Create the dialog from a template */
251 if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),RT_DIALOGA)))
253 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
254 return FALSE;
256 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
257 !(template = LockResource( hDlgTmpl )))
259 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
260 return FALSE;
263 /* old style hook messages */
264 if (IsHooked(fodInfos))
266 fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
267 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
268 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
269 fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
272 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
273 (LPDLGTEMPLATEA) template,
274 fodInfos->ofnInfos->hwndOwner,
275 FileOpenDlgProc95,
276 (LPARAM) fodInfos);
278 /* Unable to create the dialog */
279 if( lRes == -1)
280 return FALSE;
282 return lRes;
285 /***********************************************************************
286 * GetFileDialog95A
288 * Call GetFileName95 with this structure and clean the memory.
290 * IN : The OPENFILENAMEA initialisation structure passed to
291 * GetOpenFileNameA win api function (see filedlg.c)
293 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
295 BOOL ret;
296 FileOpenDlgInfos fodInfos;
297 LPSTR lpstrSavDir = NULL;
298 LPWSTR title = NULL;
299 LPWSTR defext = NULL;
300 LPWSTR filter = NULL;
301 LPWSTR customfilter = NULL;
303 /* Initialize FileOpenDlgInfos structure */
304 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
306 /* Pass in the original ofn */
307 fodInfos.ofnInfos = ofn;
309 /* save current directory */
310 if (ofn->Flags & OFN_NOCHANGEDIR)
312 lpstrSavDir = MemAlloc(MAX_PATH);
313 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
316 fodInfos.unicode = FALSE;
318 /* convert all the input strings to unicode */
319 if(ofn->lpstrInitialDir)
321 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
322 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
323 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
325 else
326 fodInfos.initdir = NULL;
328 if(ofn->lpstrFile)
330 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
331 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
333 else
334 fodInfos.filename = NULL;
336 if(ofn->lpstrDefExt)
338 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
339 defext = MemAlloc((len+1)*sizeof(WCHAR));
340 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
342 fodInfos.defext = defext;
344 if(ofn->lpstrTitle)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
347 title = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
350 fodInfos.title = title;
352 if (ofn->lpstrFilter)
354 LPCSTR s;
355 int n, len;
357 /* filter is a list... title\0ext\0......\0\0 */
358 s = ofn->lpstrFilter;
359 while (*s) s = s+strlen(s)+1;
360 s++;
361 n = s - ofn->lpstrFilter;
362 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
363 filter = MemAlloc(len*sizeof(WCHAR));
364 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
366 fodInfos.filter = filter;
368 /* convert lpstrCustomFilter */
369 if (ofn->lpstrCustomFilter)
371 LPCSTR s;
372 int n, len;
374 /* filter is a list... title\0ext\0......\0\0 */
375 s = ofn->lpstrCustomFilter;
376 while (*s) s = s+strlen(s)+1;
377 s++;
378 n = s - ofn->lpstrCustomFilter;
379 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
380 customfilter = MemAlloc(len*sizeof(WCHAR));
381 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
383 fodInfos.customfilter = customfilter;
385 /* Initialize the dialog property */
386 fodInfos.DlgInfos.dwDlgProp = 0;
387 fodInfos.DlgInfos.hwndCustomDlg = NULL;
389 switch(iDlgType)
391 case OPEN_DIALOG :
392 ret = GetFileName95(&fodInfos);
393 break;
394 case SAVE_DIALOG :
395 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
396 ret = GetFileName95(&fodInfos);
397 break;
398 default :
399 ret = 0;
402 if (lpstrSavDir)
404 SetCurrentDirectoryA(lpstrSavDir);
405 MemFree(lpstrSavDir);
408 if(title)
409 MemFree(title);
410 if(defext)
411 MemFree(defext);
412 if(filter)
413 MemFree(filter);
414 if(customfilter)
415 MemFree(customfilter);
416 if(fodInfos.initdir)
417 MemFree(fodInfos.initdir);
419 if(fodInfos.filename)
420 MemFree(fodInfos.filename);
422 TRACE("selected file: %s\n",ofn->lpstrFile);
424 return ret;
427 /***********************************************************************
428 * GetFileDialog95W
430 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
431 * Call GetFileName95 with this structure and clean the memory.
433 * FIXME: lpstrCustomFilter has to be converted back
436 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
438 BOOL ret;
439 FileOpenDlgInfos fodInfos;
440 LPSTR lpstrSavDir = NULL;
442 /* Initialize FileOpenDlgInfos structure */
443 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
445 /* Pass in the original ofn */
446 fodInfos.ofnInfos = (LPOPENFILENAMEA) ofn;
448 fodInfos.title = ofn->lpstrTitle;
449 fodInfos.defext = ofn->lpstrDefExt;
450 fodInfos.filter = ofn->lpstrFilter;
451 fodInfos.customfilter = ofn->lpstrCustomFilter;
453 /* convert string arguments, save others */
454 if(ofn->lpstrFile)
456 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
457 strncpyW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
459 else
460 fodInfos.filename = NULL;
462 if(ofn->lpstrInitialDir)
464 DWORD len = strlenW(ofn->lpstrInitialDir);
465 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
466 strcpyW(fodInfos.initdir,ofn->lpstrInitialDir);
468 else
469 fodInfos.initdir = NULL;
471 /* save current directory */
472 if (ofn->Flags & OFN_NOCHANGEDIR)
474 lpstrSavDir = MemAlloc(MAX_PATH);
475 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
478 fodInfos.unicode = TRUE;
480 switch(iDlgType)
482 case OPEN_DIALOG :
483 ret = GetFileName95(&fodInfos);
484 break;
485 case SAVE_DIALOG :
486 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
487 ret = GetFileName95(&fodInfos);
488 break;
489 default :
490 ret = 0;
493 if (lpstrSavDir)
495 SetCurrentDirectoryA(lpstrSavDir);
496 MemFree(lpstrSavDir);
499 /* restore saved IN arguments and convert OUT arguments back */
500 MemFree(fodInfos.filename);
501 MemFree(fodInfos.initdir);
502 return ret;
505 /***********************************************************************
506 * ArrangeCtrlPositions [internal]
508 * NOTE: Do not change anything here without a lot of testing.
510 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
512 HWND hwndChild, hwndStc32;
513 RECT rectParent, rectChild, rectStc32;
514 INT help_fixup = 0;
516 /* Take into account if open as read only checkbox and help button
517 * are hidden
519 if (hide_help)
521 RECT rectHelp, rectCancel;
522 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
523 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
524 /* subtract the height of the help button plus the space between
525 * the help button and the cancel button to the height of the dialog
527 help_fixup = rectHelp.bottom - rectCancel.bottom;
531 There are two possibilities to add components to the default file dialog box.
533 By default, all the new components are added below the standard dialog box (the else case).
535 However, if there is a static text component with the stc32 id, a special case happens.
536 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
537 in the window and the cx and cy indicate how to size the window.
538 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
539 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
543 GetClientRect(hwndParentDlg, &rectParent);
545 /* when arranging controls we have to use fixed parent size */
546 rectParent.bottom -= help_fixup;
548 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
549 if (hwndStc32)
551 GetWindowRect(hwndStc32, &rectStc32);
552 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
554 /* set the size of the stc32 control according to the size of
555 * client area of the parent dialog
557 SetWindowPos(hwndStc32, 0,
558 0, 0,
559 rectParent.right, rectParent.bottom,
560 SWP_NOMOVE | SWP_NOZORDER);
562 else
563 SetRectEmpty(&rectStc32);
565 /* this part moves controls of the child dialog */
566 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
567 while (hwndChild)
569 if (hwndChild != hwndStc32)
571 GetWindowRect(hwndChild, &rectChild);
572 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
574 /* move only if stc32 exist */
575 if (hwndStc32 && rectChild.left > rectStc32.right)
577 /* move to the right of visible controls of the parent dialog */
578 rectChild.left += rectParent.right;
579 rectChild.left -= rectStc32.right;
581 /* move even if stc32 doesn't exist */
582 if (rectChild.top > rectStc32.bottom)
584 /* move below visible controls of the parent dialog */
585 rectChild.top += rectParent.bottom;
586 rectChild.top -= rectStc32.bottom - rectStc32.top;
589 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
590 0, 0, SWP_NOSIZE | SWP_NOZORDER);
592 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
595 /* this part moves controls of the parent dialog */
596 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
597 while (hwndChild)
599 if (hwndChild != hwndChildDlg)
601 GetWindowRect(hwndChild, &rectChild);
602 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
604 /* left,top of stc32 marks the position of controls
605 * from the parent dialog
607 rectChild.left += rectStc32.left;
608 rectChild.top += rectStc32.top;
610 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
611 0, 0, SWP_NOSIZE | SWP_NOZORDER);
613 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
616 /* calculate the size of the resulting dialog */
618 /* here we have to use original parent size */
619 GetClientRect(hwndParentDlg, &rectParent);
620 GetClientRect(hwndChildDlg, &rectChild);
622 if (hwndStc32)
624 if (rectParent.right > rectChild.right)
626 rectParent.right += rectChild.right;
627 rectParent.right -= rectStc32.right - rectStc32.left;
629 else
631 rectParent.right = rectChild.right;
634 if (rectParent.bottom > rectChild.bottom)
636 rectParent.bottom += rectChild.bottom;
637 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
639 else
641 rectParent.bottom = rectChild.bottom;
644 else
646 rectParent.bottom += rectChild.bottom;
649 /* finally use fixed parent size */
650 rectParent.bottom -= help_fixup;
652 /* set the size of the child dialog */
653 SetWindowPos(hwndChildDlg, HWND_BOTTOM,
654 0, 0, rectParent.right, rectParent.bottom, SWP_NOACTIVATE);
656 /* set the size of the parent dialog */
657 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
658 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
659 SetWindowPos(hwndParentDlg, 0,
660 0, 0,
661 rectParent.right - rectParent.left,
662 rectParent.bottom - rectParent.top,
663 SWP_NOMOVE | SWP_NOZORDER);
666 INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
668 FileOpenDlgInfos *fodInfos;
670 #if 0
671 TRACE("0x%04x\n", uMsg);
672 #endif
674 switch(uMsg)
676 case WM_INITDIALOG:
678 fodInfos = (FileOpenDlgInfos *)lParam;
679 lParam = (LPARAM) fodInfos->ofnInfos;
681 if(fodInfos && IsHooked(fodInfos))
682 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
683 return 0;
687 fodInfos = (FileOpenDlgInfos *) GetPropA(GetParent(hwnd),FileOpenDlgInfosStr);
688 if(fodInfos && IsHooked(fodInfos))
689 return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
691 return 0;
694 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
696 LPCVOID template;
697 HRSRC hRes;
698 HANDLE hDlgTmpl = 0;
699 HWND hChildDlg = 0;
701 TRACE("\n");
704 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
705 * structure's hInstance parameter is not a HINSTANCE, but
706 * instead a pointer to a template resource to use.
708 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
710 HINSTANCE hinst;
711 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
713 hinst = 0;
714 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
716 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
717 return NULL;
720 else
722 hinst = fodInfos->ofnInfos->hInstance;
723 if(fodInfos->unicode)
725 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
726 hRes = FindResourceW( hinst, ofn->lpTemplateName, RT_DIALOGW);
728 else
730 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
731 hRes = FindResourceA( hinst, ofn->lpTemplateName, RT_DIALOGA);
733 if (!hRes)
735 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
736 return NULL;
738 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
739 !(template = LockResource( hDlgTmpl )))
741 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
742 return NULL;
745 hChildDlg= CreateDialogIndirectParamA(COMDLG32_hInstance, template,
746 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
747 if(hChildDlg)
749 ShowWindow(hChildDlg,SW_SHOW);
750 return hChildDlg;
753 else if( IsHooked(fodInfos))
755 RECT rectHwnd;
756 struct {
757 DLGTEMPLATE tmplate;
758 WORD menu,class,title;
759 } temp;
760 GetClientRect(hwnd,&rectHwnd);
761 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
762 temp.tmplate.dwExtendedStyle = 0;
763 temp.tmplate.cdit = 0;
764 temp.tmplate.x = 0;
765 temp.tmplate.y = 0;
766 temp.tmplate.cx = 0;
767 temp.tmplate.cy = 0;
768 temp.menu = temp.class = temp.title = 0;
770 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
771 hwnd, FileOpenDlgProcUserTemplate, (LPARAM)fodInfos);
773 return hChildDlg;
775 return NULL;
778 /***********************************************************************
779 * SendCustomDlgNotificationMessage
781 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
784 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
786 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
788 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
790 if(!fodInfos) return 0;
792 if(fodInfos->unicode)
793 FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
795 if(fodInfos->DlgInfos.hwndCustomDlg)
797 OFNOTIFYA ofnNotify;
798 HRESULT ret;
799 ofnNotify.hdr.hwndFrom=hwndParentDlg;
800 ofnNotify.hdr.idFrom=0;
801 ofnNotify.hdr.code = uCode;
802 ofnNotify.lpOFN = fodInfos->ofnInfos;
803 ofnNotify.pszFile = NULL;
804 TRACE("CALL NOTIFY for %x\n", uCode);
805 ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
806 TRACE("RET NOTIFY\n");
807 return ret;
809 return TRUE;
812 HRESULT FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPSTR buffer)
814 UINT sizeUsed = 0, n, total;
815 LPWSTR lpstrFileList = NULL;
816 WCHAR lpstrCurrentDir[MAX_PATH];
817 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
819 TRACE("CDM_GETFILEPATH:\n");
821 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
822 return -1;
824 /* get path and filenames */
825 SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
826 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
828 TRACE("path >%s< filespec >%s< %d files\n",
829 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
831 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
832 NULL, 0, NULL, NULL);
833 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
834 NULL, 0, NULL, NULL);
836 /* Prepend the current path */
837 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
838 buffer, size, NULL, NULL);
840 if(n<size)
842 /* 'n' includes trailing \0 */
843 buffer[n-1] = '\\';
844 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
845 &buffer[n], size-n, NULL, NULL);
847 MemFree(lpstrFileList);
849 TRACE("returned -> %s\n",debugstr_a(buffer));
851 return total;
854 HRESULT FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPSTR buffer)
856 UINT sizeUsed = 0;
857 LPWSTR lpstrFileList = NULL;
859 TRACE("CDM_GETSPEC:\n");
861 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
862 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, buffer, size, NULL, NULL);
863 MemFree(lpstrFileList);
865 return sizeUsed;
868 /***********************************************************************
869 * FILEDLG95_HandleCustomDialogMessages
871 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
873 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
875 char lpstrPath[MAX_PATH];
876 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
877 if(!fodInfos) return -1;
879 switch(uMsg)
881 case CDM_GETFILEPATH:
882 return FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPSTR)lParam);
884 case CDM_GETFOLDERPATH:
885 TRACE("CDM_GETFOLDERPATH:\n");
886 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
887 if ((LPSTR)lParam!=NULL)
888 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
889 return strlen(lpstrPath);
891 case CDM_GETSPEC:
892 return FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
894 case CDM_SETCONTROLTEXT:
895 TRACE("CDM_SETCONTROLTEXT:\n");
896 if ( 0 != lParam )
897 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
898 return TRUE;
900 case CDM_HIDECONTROL:
901 case CDM_SETDEFEXT:
902 FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
903 return -1;
905 return TRUE;
908 /***********************************************************************
909 * FileOpenDlgProc95
911 * File open dialog procedure
913 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
915 #if 0
916 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
917 #endif
919 switch(uMsg)
921 case WM_INITDIALOG:
923 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
925 /* Adds the FileOpenDlgInfos in the property list of the dialog
926 so it will be easily accessible through a GetPropA(...) */
927 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
929 fodInfos->DlgInfos.hwndCustomDlg =
930 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
932 FILEDLG95_InitControls(hwnd);
933 FILEDLG95_FillControls(hwnd, wParam, lParam);
934 if (fodInfos->DlgInfos.hwndCustomDlg)
935 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
936 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
938 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
939 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
940 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
941 return 0;
943 case WM_COMMAND:
944 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
945 case WM_DRAWITEM:
947 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
949 case IDC_LOOKIN:
950 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
951 return TRUE;
954 return FALSE;
956 case WM_GETISHELLBROWSER:
957 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
959 case WM_DESTROY:
960 RemovePropA(hwnd, FileOpenDlgInfosStr);
961 return FALSE;
963 case WM_NOTIFY:
965 LPNMHDR lpnmh = (LPNMHDR)lParam;
966 UINT stringId = -1;
968 /* set up the button tooltips strings */
969 if(TTN_GETDISPINFOA == lpnmh->code )
971 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
972 switch(lpnmh->idFrom )
974 /* Up folder button */
975 case FCIDM_TB_UPFOLDER:
976 stringId = IDS_UPFOLDER;
977 break;
978 /* New folder button */
979 case FCIDM_TB_NEWFOLDER:
980 stringId = IDS_NEWFOLDER;
981 break;
982 /* List option button */
983 case FCIDM_TB_SMALLICON:
984 stringId = IDS_LISTVIEW;
985 break;
986 /* Details option button */
987 case FCIDM_TB_REPORTVIEW:
988 stringId = IDS_REPORTVIEW;
989 break;
990 /* Desktop button */
991 case FCIDM_TB_DESKTOP:
992 stringId = IDS_TODESKTOP;
993 break;
994 default:
995 stringId = 0;
997 lpdi->hinst = COMDLG32_hInstance;
998 lpdi->lpszText = (LPSTR) stringId;
1000 return FALSE;
1002 default :
1003 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1004 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1005 return FALSE;
1009 /***********************************************************************
1010 * FILEDLG95_InitControls
1012 * WM_INITDIALOG message handler (before hook notification)
1014 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1016 int win2000plus = 0;
1017 int win98plus = 0;
1018 int handledPath = FALSE;
1019 OSVERSIONINFOA osVi;
1020 const WCHAR szwSlash[] = { '\\', 0 };
1021 const WCHAR szwStar[] = { '*',0 };
1023 TBBUTTON tbb[] =
1025 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1026 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1027 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1028 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1029 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1030 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1031 {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
1032 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1033 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
1035 TBADDBITMAP tba[2];
1036 RECT rectTB;
1037 RECT rectlook;
1038 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1040 tba[0].hInst = HINST_COMMCTRL;
1041 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1042 tba[1].hInst = COMDLG32_hInstance;
1043 tba[1].nID = 800;
1045 TRACE("%p\n", fodInfos);
1047 /* Get windows version emulating */
1048 osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1049 GetVersionExA(&osVi);
1050 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1051 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1052 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1053 win2000plus = (osVi.dwMajorVersion > 4);
1054 if (win2000plus) win98plus = TRUE;
1056 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1058 /* Get the hwnd of the controls */
1059 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1060 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1061 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1063 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1064 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1066 /* construct the toolbar */
1067 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1068 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1070 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1071 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1072 rectTB.left = rectlook.right;
1073 rectTB.top = rectlook.top-1;
1075 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1076 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1077 rectTB.left, rectTB.top,
1078 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1079 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1081 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1083 /* FIXME: use TB_LOADIMAGES when implemented */
1084 /* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1085 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
1086 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
1088 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
1089 SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1091 /* Set the window text with the text specified in the OPENFILENAME structure */
1092 if(fodInfos->title)
1094 SetWindowTextW(hwnd,fodInfos->title);
1096 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1098 SetWindowTextA(hwnd,"Save");
1101 /* Initialise the file name edit control */
1102 handledPath = FALSE;
1103 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1105 if(fodInfos->filename)
1107 /* 1. If win2000 or higher and filename contains a path, use it
1108 in preference over the lpstrInitialDir */
1109 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1110 WCHAR tmpBuf[MAX_PATH];
1111 WCHAR *nameBit;
1112 DWORD result;
1114 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1115 if (result) {
1117 /* nameBit is always shorter than the original filename */
1118 strcpyW(fodInfos->filename,nameBit);
1120 *nameBit = 0x00;
1121 if (fodInfos->initdir == NULL)
1122 MemFree(fodInfos->initdir);
1123 fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR));
1124 strcpyW(fodInfos->initdir, tmpBuf);
1125 handledPath = TRUE;
1126 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1127 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1129 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1131 } else {
1132 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1136 /* 2. (All platforms) If initdir is not null, then use it */
1137 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1138 (*fodInfos->initdir!=0x00))
1140 /* Work out the proper path as supplied one might be relative */
1141 /* (Here because supplying '.' as dir browses to My Computer) */
1142 if (handledPath==FALSE) {
1143 WCHAR tmpBuf[MAX_PATH];
1144 WCHAR tmpBuf2[MAX_PATH];
1145 WCHAR *nameBit;
1146 DWORD result;
1148 strcpyW(tmpBuf, fodInfos->initdir);
1149 if (tmpBuf[strlenW(tmpBuf)-1] != '\\') {
1150 strcatW(tmpBuf, szwSlash);
1152 strcatW(tmpBuf, szwStar);
1153 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1154 if (result) {
1155 *nameBit = 0x00;
1156 if (fodInfos->initdir)
1157 MemFree(fodInfos->initdir);
1158 fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1159 strcpyW(fodInfos->initdir, tmpBuf2);
1160 handledPath = TRUE;
1161 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1166 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1167 (*fodInfos->initdir==0x00)))
1169 /* 3. All except w2k+: if filename contains a path use it */
1170 if (!win2000plus && fodInfos->filename &&
1171 *fodInfos->filename &&
1172 strpbrkW(fodInfos->filename, szwSlash)) {
1173 WCHAR tmpBuf[MAX_PATH];
1174 WCHAR *nameBit;
1175 DWORD result;
1177 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1178 tmpBuf, &nameBit);
1179 if (result) {
1180 int len;
1182 /* nameBit is always shorter than the original filename */
1183 strcpyW(fodInfos->filename, nameBit);
1184 *nameBit = 0x00;
1186 len = strlenW(tmpBuf);
1187 if(fodInfos->initdir)
1188 MemFree(fodInfos->initdir);
1189 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1190 strcpyW(fodInfos->initdir, tmpBuf);
1192 handledPath = TRUE;
1193 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1194 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1196 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1199 /* 4. win98+ and win2000+ if any files of specified filter types in
1200 current directory, use it */
1201 if ( win98plus && handledPath == FALSE &&
1202 fodInfos->filter && *fodInfos->filter) {
1204 BOOL searchMore = TRUE;
1205 LPCWSTR lpstrPos = fodInfos->filter;
1206 WIN32_FIND_DATAW FindFileData;
1207 HANDLE hFind;
1209 while (searchMore)
1211 /* filter is a list... title\0ext\0......\0\0 */
1213 /* Skip the title */
1214 if(! *lpstrPos) break; /* end */
1215 lpstrPos += strlenW(lpstrPos) + 1;
1217 /* See if any files exist in the current dir with this extension */
1218 if(! *lpstrPos) break; /* end */
1220 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1222 if (hFind == INVALID_HANDLE_VALUE) {
1223 /* None found - continue search */
1224 lpstrPos += strlenW(lpstrPos) + 1;
1226 } else {
1227 searchMore = FALSE;
1229 if(fodInfos->initdir)
1230 MemFree(fodInfos->initdir);
1231 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1232 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1234 handledPath = TRUE;
1235 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1236 debugstr_w(lpstrPos));
1237 break;
1242 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1244 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1245 if (handledPath == FALSE && (win2000plus || win98plus)) {
1246 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1248 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1250 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1252 /* last fallback */
1253 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1254 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1255 } else {
1256 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1258 } else {
1259 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1261 handledPath = TRUE;
1262 } else if (handledPath==FALSE) {
1263 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1264 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1265 handledPath = TRUE;
1266 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1269 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1270 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1272 /* Must the open as read only check box be checked ?*/
1273 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1275 SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
1278 /* Must the open as read only check box be hidden? */
1279 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1281 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1282 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1285 /* Must the help button be hidden? */
1286 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1288 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1289 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1292 /* Resize the height, if open as read only checkbox ad help button
1293 are hidden and we are not using a custom template nor a customDialog
1295 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1296 (!(fodInfos->ofnInfos->Flags &
1297 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) &&
1298 (!fodInfos->DlgInfos.hwndCustomDlg ))
1300 RECT rectDlg, rectHelp, rectCancel;
1301 GetWindowRect(hwnd, &rectDlg);
1302 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1303 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1304 /* subtract the height of the help button plus the space between
1305 the help button and the cancel button to the height of the dialog */
1306 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1307 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1308 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1310 /* change Open to Save FIXME: use resources */
1311 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1313 SetDlgItemTextA(hwnd,IDOK,"&Save");
1314 SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1316 return 0;
1319 /***********************************************************************
1320 * FILEDLG95_FillControls
1322 * WM_INITDIALOG message handler (after hook notification)
1324 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1326 LPITEMIDLIST pidlItemId = NULL;
1328 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1330 TRACE("dir=%s file=%s\n",
1331 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1333 /* Get the initial directory pidl */
1335 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1337 WCHAR path[MAX_PATH];
1339 GetCurrentDirectoryW(MAX_PATH,path);
1340 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1343 /* Initialise shell objects */
1344 FILEDLG95_SHELL_Init(hwnd);
1346 /* Initialize the Look In combo box */
1347 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1349 /* Initialize the filter combo box */
1350 FILEDLG95_FILETYPE_Init(hwnd);
1352 /* Browse to the initial directory */
1353 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1355 /* Free pidlItem memory */
1356 COMDLG32_SHFree(pidlItemId);
1358 return TRUE;
1360 /***********************************************************************
1361 * FILEDLG95_Clean
1363 * Regroups all the cleaning functions of the filedlg
1365 void FILEDLG95_Clean(HWND hwnd)
1367 FILEDLG95_FILETYPE_Clean(hwnd);
1368 FILEDLG95_LOOKIN_Clean(hwnd);
1369 FILEDLG95_SHELL_Clean(hwnd);
1371 /***********************************************************************
1372 * FILEDLG95_OnWMCommand
1374 * WM_COMMAND message handler
1376 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1378 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1379 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1380 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1382 switch(wID)
1384 /* OK button */
1385 case IDOK:
1386 FILEDLG95_OnOpen(hwnd);
1387 break;
1388 /* Cancel button */
1389 case IDCANCEL:
1390 FILEDLG95_Clean(hwnd);
1391 EndDialog(hwnd, FALSE);
1392 break;
1393 /* Filetype combo box */
1394 case IDC_FILETYPE:
1395 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1396 break;
1397 /* LookIn combo box */
1398 case IDC_LOOKIN:
1399 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1400 break;
1402 /* --- toolbar --- */
1403 /* Up folder button */
1404 case FCIDM_TB_UPFOLDER:
1405 FILEDLG95_SHELL_UpFolder(hwnd);
1406 break;
1407 /* New folder button */
1408 case FCIDM_TB_NEWFOLDER:
1409 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDER);
1410 break;
1411 /* List option button */
1412 case FCIDM_TB_SMALLICON:
1413 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLIST);
1414 break;
1415 /* Details option button */
1416 case FCIDM_TB_REPORTVIEW:
1417 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILS);
1418 break;
1419 /* Details option button */
1420 case FCIDM_TB_DESKTOP:
1421 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1422 break;
1424 case IDC_FILENAME:
1425 break;
1428 /* Do not use the listview selection anymore */
1429 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1430 return 0;
1433 /***********************************************************************
1434 * FILEDLG95_OnWMGetIShellBrowser
1436 * WM_GETISHELLBROWSER message handler
1438 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1441 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1443 TRACE("\n");
1445 SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1447 return TRUE;
1451 /***********************************************************************
1452 * FILEDLG95_SendFileOK
1454 * Sends the CDN_FILEOK notification if required
1456 * RETURNS
1457 * TRUE if the dialog should close
1458 * FALSE if the dialog should not be closed
1460 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1462 /* ask the hook if we can close */
1463 if(IsHooked(fodInfos))
1465 TRACE("---\n");
1466 /* First send CDN_FILEOK as MSDN doc says */
1467 SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1469 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1470 CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,
1471 fodInfos->DlgInfos.hwndCustomDlg,
1472 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1473 if (GetWindowLongA(fodInfos->DlgInfos.hwndCustomDlg, DWL_MSGRESULT))
1475 TRACE("canceled\n");
1476 return FALSE;
1479 return TRUE;
1482 /***********************************************************************
1483 * FILEDLG95_OnOpenMultipleFiles
1485 * Handles the opening of multiple files.
1487 * FIXME
1488 * check destination buffer size
1490 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1492 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1493 UINT nCount, nSizePath;
1494 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1496 TRACE("\n");
1498 if(fodInfos->unicode)
1500 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1501 ofn->lpstrFile[0] = '\0';
1503 else
1505 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1506 ofn->lpstrFile[0] = '\0';
1509 SHGetPathFromIDListW( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1511 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1512 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1513 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1515 LPWSTR lpstrTemp = lpstrFileList;
1517 for ( nCount = 0; nCount < nFileCount; nCount++ )
1519 LPITEMIDLIST pidl;
1521 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1522 if (!pidl)
1524 WCHAR lpstrNotFound[100];
1525 WCHAR lpstrMsg[100];
1526 WCHAR tmp[400];
1527 WCHAR nl[] = {'\n',0};
1529 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1530 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1532 strcpyW(tmp, lpstrTemp);
1533 strcatW(tmp, nl);
1534 strcatW(tmp, lpstrNotFound);
1535 strcatW(tmp, nl);
1536 strcatW(tmp, lpstrMsg);
1538 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1539 return FALSE;
1542 /* move to the next file in the list of files */
1543 lpstrTemp += strlenW(lpstrTemp) + 1;
1544 COMDLG32_SHFree(pidl);
1548 nSizePath = strlenW(lpstrPathSpec) + 1;
1549 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1551 /* For "oldstyle" dialog the components have to
1552 be spearated by blanks (not '\0'!) and short
1553 filenames have to be used! */
1554 FIXME("Components have to be separated by blanks");
1556 if(fodInfos->unicode)
1558 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1559 strcpyW( ofn->lpstrFile, lpstrPathSpec);
1560 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1562 else
1564 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1566 if (ofn->lpstrFile != NULL)
1568 WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1569 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1570 if (ofn->nMaxFile > nSizePath)
1572 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1573 ofn->lpstrFile + nSizePath,
1574 ofn->nMaxFile - nSizePath, NULL, NULL);
1579 fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1580 fodInfos->ofnInfos->nFileExtension = 0;
1582 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1583 return FALSE;
1585 /* clean and exit */
1586 FILEDLG95_Clean(hwnd);
1587 return EndDialog(hwnd,TRUE);
1590 /***********************************************************************
1591 * FILEDLG95_OnOpen
1593 * Ok button WM_COMMAND message handler
1595 * If the function succeeds, the return value is nonzero.
1597 #define ONOPEN_BROWSE 1
1598 #define ONOPEN_OPEN 2
1599 #define ONOPEN_SEARCH 3
1600 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1602 char strMsgTitle[MAX_PATH];
1603 char strMsgText [MAX_PATH];
1604 if (idCaption)
1605 LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1606 else
1607 strMsgTitle[0] = '\0';
1608 LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1609 MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1612 BOOL FILEDLG95_OnOpen(HWND hwnd)
1614 LPWSTR lpstrFileList;
1615 UINT nFileCount = 0;
1616 UINT sizeUsed = 0;
1617 BOOL ret = TRUE;
1618 WCHAR lpstrPathAndFile[MAX_PATH];
1619 WCHAR lpstrTemp[MAX_PATH];
1620 LPSHELLFOLDER lpsf = NULL;
1621 int nOpenAction;
1622 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1624 TRACE("hwnd=%p\n", hwnd);
1626 /* get the files from the edit control */
1627 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1629 /* try if the user selected a folder in the shellview */
1630 if(nFileCount == 0)
1632 BrowseSelectedFolder(hwnd);
1633 return FALSE;
1636 if(nFileCount > 1)
1638 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1639 goto ret;
1642 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1645 Step 1: Build a complete path name from the current folder and
1646 the filename or path in the edit box.
1647 Special cases:
1648 - the path in the edit box is a root path
1649 (with or without drive letter)
1650 - the edit box contains ".." (or a path with ".." in it)
1653 /* Get the current directory name */
1654 if (!SHGetPathFromIDListW(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1656 /* we are in a special folder, default to desktop */
1657 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1659 /* last fallback */
1660 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1663 PathAddBackslashW(lpstrPathAndFile);
1665 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1667 /* if the user specifyed a fully qualified path use it */
1668 if(PathIsRelativeW(lpstrFileList))
1670 strcatW(lpstrPathAndFile, lpstrFileList);
1672 else
1674 /* does the path have a drive letter? */
1675 if (PathGetDriveNumberW(lpstrFileList) == -1)
1676 strcpyW(lpstrPathAndFile+2, lpstrFileList);
1677 else
1678 strcpyW(lpstrPathAndFile, lpstrFileList);
1681 /* resolve "." and ".." */
1682 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1683 strcpyW(lpstrPathAndFile, lpstrTemp);
1684 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1686 MemFree(lpstrFileList);
1689 Step 2: here we have a cleaned up path
1691 We have to parse the path step by step to see if we have to browse
1692 to a folder if the path points to a directory or the last
1693 valid element is a directory.
1695 valid variables:
1696 lpstrPathAndFile: cleaned up path
1699 nOpenAction = ONOPEN_BROWSE;
1701 /* dont apply any checks with OFN_NOVALIDATE */
1703 LPWSTR lpszTemp, lpszTemp1;
1704 LPITEMIDLIST pidl = NULL;
1705 WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1707 /* check for invalid chars */
1708 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1710 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1711 ret = FALSE;
1712 goto ret;
1715 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1717 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1718 while (lpszTemp1)
1720 LPSHELLFOLDER lpsfChild;
1721 WCHAR lpwstrTemp[MAX_PATH];
1722 DWORD dwEaten, dwAttributes;
1723 LPWSTR p;
1725 strcpyW(lpwstrTemp, lpszTemp);
1726 p = PathFindNextComponentW(lpwstrTemp);
1728 if (!p) break; /* end of path */
1730 *p = 0;
1731 lpszTemp = lpszTemp + strlenW(lpwstrTemp);
1733 if(*lpszTemp==0)
1735 WCHAR wszWild[] = { '*', '?', 0 };
1736 /* if the last element is a wildcard do a search */
1737 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1739 nOpenAction = ONOPEN_SEARCH;
1740 break;
1743 lpszTemp1 = lpszTemp;
1745 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1747 if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1749 dwAttributes = SFGAO_FOLDER;
1750 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1752 /* the path component is valid, we have a pidl of the next path component */
1753 TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1754 if(dwAttributes & SFGAO_FOLDER)
1756 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1758 ERR("bind to failed\n"); /* should not fail */
1759 break;
1761 IShellFolder_Release(lpsf);
1762 lpsf = lpsfChild;
1763 lpsfChild = NULL;
1765 else
1767 TRACE("value\n");
1769 /* end dialog, return value */
1770 nOpenAction = ONOPEN_OPEN;
1771 break;
1773 COMDLG32_SHFree(pidl);
1774 pidl = NULL;
1776 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1778 if(*lpszTemp) /* points to trailing null for last path element */
1780 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1782 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1783 break;
1786 else
1788 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1789 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1791 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1792 break;
1795 /* change to the current folder */
1796 nOpenAction = ONOPEN_OPEN;
1797 break;
1799 else
1801 nOpenAction = ONOPEN_OPEN;
1802 break;
1805 if(pidl) COMDLG32_SHFree(pidl);
1809 Step 3: here we have a cleaned up and validated path
1811 valid variables:
1812 lpsf: ShellFolder bound to the rightmost valid path component
1813 lpstrPathAndFile: cleaned up path
1814 nOpenAction: action to do
1816 TRACE("end validate sf=%p\n", lpsf);
1818 switch(nOpenAction)
1820 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1821 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1823 int iPos;
1824 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1825 DWORD len;
1827 /* replace the current filter */
1828 if(fodInfos->ShellInfos.lpstrCurrentFilter)
1829 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1830 len = strlenW(lpszTemp)+1;
1831 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1832 strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1834 /* set the filter cb to the extension when possible */
1835 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1836 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1838 /* fall through */
1839 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1840 TRACE("ONOPEN_BROWSE\n");
1842 IPersistFolder2 * ppf2;
1843 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1845 LPITEMIDLIST pidlCurrent;
1846 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1847 IPersistFolder2_Release(ppf2);
1848 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1850 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1852 else if( nOpenAction == ONOPEN_SEARCH )
1854 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1856 COMDLG32_SHFree(pidlCurrent);
1859 ret = FALSE;
1860 break;
1861 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
1862 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
1864 /* add default extension */
1865 if (fodInfos->defext)
1867 if (! *PathFindExtensionW(lpstrPathAndFile))
1869 /* only add "." in case a default extension does exist */
1870 if (*fodInfos->defext != '\0')
1872 const WCHAR szwDot[] = {'.',0};
1873 int PathLength = strlenW(lpstrPathAndFile);
1875 strcatW(lpstrPathAndFile, szwDot);
1876 strcatW(lpstrPathAndFile, fodInfos->defext);
1878 /* if file does not exist try without extension */
1879 if (!PathFileExistsW(lpstrPathAndFile))
1880 lpstrPathAndFile[PathLength] = '\0';
1885 /* Check that the size of the file does not exceed buffer size.
1886 (Allow for extra \0 if OFN_MULTISELECT is set.) */
1887 if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1888 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1890 LPWSTR lpszTemp;
1892 /* fill destination buffer */
1893 if (fodInfos->ofnInfos->lpstrFile)
1895 if(fodInfos->unicode)
1897 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1899 strncpyW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
1900 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1901 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
1903 else
1905 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1907 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
1908 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1909 if (ofn->Flags & OFN_ALLOWMULTISELECT)
1910 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
1914 /* set filename offset */
1915 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1916 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
1918 /* set extension offset */
1919 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
1920 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
1922 /* set the lpstrFileTitle */
1923 if(fodInfos->ofnInfos->lpstrFileTitle)
1925 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
1926 if(fodInfos->unicode)
1928 LPOPENFILENAMEW ofn = (LPOPENFILENAMEW) fodInfos->ofnInfos;
1929 strncpyW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
1931 else
1933 LPOPENFILENAMEA ofn = fodInfos->ofnInfos;
1934 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
1935 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
1939 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1940 goto ret;
1942 TRACE("close\n");
1943 FILEDLG95_Clean(hwnd);
1944 ret = EndDialog(hwnd, TRUE);
1946 else
1948 /* FIXME set error FNERR_BUFFERTOSMALL */
1949 FILEDLG95_Clean(hwnd);
1950 ret = EndDialog(hwnd, FALSE);
1952 goto ret;
1954 break;
1957 ret:
1958 if(lpsf) IShellFolder_Release(lpsf);
1959 return ret;
1962 /***********************************************************************
1963 * FILEDLG95_SHELL_Init
1965 * Initialisation of the shell objects
1967 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
1969 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1971 TRACE("\n");
1974 * Initialisation of the FileOpenDialogInfos structure
1977 /* Shell */
1979 /*ShellInfos */
1980 fodInfos->ShellInfos.hwndOwner = hwnd;
1982 /* Disable multi-select if flag not set */
1983 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
1985 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
1987 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
1988 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
1990 GetWindowRect(GetDlgItem(hwnd,IDC_SHELLSTATIC),&fodInfos->ShellInfos.rectView);
1991 ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.left);
1992 ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.right);
1994 /* Construct the IShellBrowser interface */
1995 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
1997 return NOERROR;
2000 /***********************************************************************
2001 * FILEDLG95_SHELL_ExecuteCommand
2003 * Change the folder option and refresh the view
2004 * If the function succeeds, the return value is nonzero.
2006 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2008 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2010 IContextMenu * pcm;
2011 TRACE("(%p,%p)\n", hwnd, lpVerb);
2013 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2014 SVGIO_BACKGROUND,
2015 &IID_IContextMenu,
2016 (LPVOID*)&pcm)))
2018 CMINVOKECOMMANDINFO ci;
2019 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2020 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2021 ci.lpVerb = lpVerb;
2022 ci.hwnd = hwnd;
2024 IContextMenu_InvokeCommand(pcm, &ci);
2025 IContextMenu_Release(pcm);
2028 return FALSE;
2031 /***********************************************************************
2032 * FILEDLG95_SHELL_UpFolder
2034 * Browse to the specified object
2035 * If the function succeeds, the return value is nonzero.
2037 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2039 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2041 TRACE("\n");
2043 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2044 NULL,
2045 SBSP_PARENT)))
2047 return TRUE;
2049 return FALSE;
2052 /***********************************************************************
2053 * FILEDLG95_SHELL_BrowseToDesktop
2055 * Browse to the Desktop
2056 * If the function succeeds, the return value is nonzero.
2058 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2060 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2061 LPITEMIDLIST pidl;
2062 HRESULT hres;
2064 TRACE("\n");
2066 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2067 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2068 COMDLG32_SHFree(pidl);
2069 return SUCCEEDED(hres);
2071 /***********************************************************************
2072 * FILEDLG95_SHELL_Clean
2074 * Cleans the memory used by shell objects
2076 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2078 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2080 TRACE("\n");
2082 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2084 /* clean Shell interfaces */
2085 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2086 IShellView_Release(fodInfos->Shell.FOIShellView);
2087 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2088 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2089 if (fodInfos->Shell.FOIDataObject)
2090 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2093 /***********************************************************************
2094 * FILEDLG95_FILETYPE_Init
2096 * Initialisation of the file type combo box
2098 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2100 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2102 TRACE("\n");
2104 if(fodInfos->filter)
2106 int nFilters = 0; /* number of filters */
2107 LPWSTR lpstrFilter;
2108 LPCWSTR lpstrPos = fodInfos->filter;
2110 for(;;)
2112 /* filter is a list... title\0ext\0......\0\0
2113 * Set the combo item text to the title and the item data
2114 * to the ext
2116 LPCWSTR lpstrDisplay;
2117 LPWSTR lpstrExt;
2119 /* Get the title */
2120 if(! *lpstrPos) break; /* end */
2121 lpstrDisplay = lpstrPos;
2122 lpstrPos += strlenW(lpstrPos) + 1;
2124 /* Copy the extensions */
2125 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2126 if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2127 strcpyW(lpstrExt,lpstrPos);
2128 lpstrPos += strlenW(lpstrPos) + 1;
2130 /* Add the item at the end of the combo */
2131 CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2132 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2133 nFilters++;
2136 * Set the current filter to the one specified
2137 * in the initialisation structure
2138 * FIXME: lpstrCustomFilter not handled at all
2141 /* set default filter index */
2142 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2143 fodInfos->ofnInfos->nFilterIndex = 1;
2145 /* First, check to make sure our index isn't out of bounds. */
2146 if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
2147 fodInfos->ofnInfos->nFilterIndex = nFilters;
2149 /* Set the current index selection. */
2150 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
2152 /* Get the corresponding text string from the combo box. */
2153 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2154 fodInfos->ofnInfos->nFilterIndex-1);
2156 if ((INT)lpstrFilter == CB_ERR) /* control is empty */
2157 lpstrFilter = NULL;
2159 if(lpstrFilter)
2161 DWORD len;
2162 CharLowerW(lpstrFilter); /* lowercase */
2163 len = strlenW(lpstrFilter)+1;
2164 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2165 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2168 return NOERROR;
2171 /***********************************************************************
2172 * FILEDLG95_FILETYPE_OnCommand
2174 * WM_COMMAND of the file type combo box
2175 * If the function succeeds, the return value is nonzero.
2177 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2179 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2181 switch(wNotifyCode)
2183 case CBN_SELENDOK:
2185 LPWSTR lpstrFilter;
2187 /* Get the current item of the filetype combo box */
2188 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2190 /* set the current filter index - indexed from 1 */
2191 fodInfos->ofnInfos->nFilterIndex = iItem + 1;
2193 /* Set the current filter with the current selection */
2194 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2195 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2197 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2198 iItem);
2199 if((int)lpstrFilter != CB_ERR)
2201 DWORD len;
2202 CharLowerW(lpstrFilter); /* lowercase */
2203 len = strlenW(lpstrFilter)+1;
2204 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2205 strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2206 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2209 /* Refresh the actual view to display the included items*/
2210 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2213 return FALSE;
2215 /***********************************************************************
2216 * FILEDLG95_FILETYPE_SearchExt
2218 * searches for a extension in the filetype box
2220 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2222 int i, iCount = CBGetCount(hwnd);
2224 TRACE("%s\n", debugstr_w(lpstrExt));
2226 if(iCount != CB_ERR)
2228 for(i=0;i<iCount;i++)
2230 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2231 return i;
2234 return -1;
2237 /***********************************************************************
2238 * FILEDLG95_FILETYPE_Clean
2240 * Clean the memory used by the filetype combo box
2242 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2244 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2245 int iPos;
2246 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2248 TRACE("\n");
2250 /* Delete each string of the combo and their associated data */
2251 if(iCount != CB_ERR)
2253 for(iPos = iCount-1;iPos>=0;iPos--)
2255 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2256 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2259 /* Current filter */
2260 if(fodInfos->ShellInfos.lpstrCurrentFilter)
2261 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2265 /***********************************************************************
2266 * FILEDLG95_LOOKIN_Init
2268 * Initialisation of the look in combo box
2270 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2272 IShellFolder *psfRoot, *psfDrives;
2273 IEnumIDList *lpeRoot, *lpeDrives;
2274 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2276 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2278 TRACE("\n");
2280 liInfos->iMaxIndentation = 0;
2282 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2284 /* set item height for both text field and listbox */
2285 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2286 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2288 /* Initialise data of Desktop folder */
2289 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2290 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2291 COMDLG32_SHFree(pidlTmp);
2293 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2295 SHGetDesktopFolder(&psfRoot);
2297 if (psfRoot)
2299 /* enumerate the contents of the desktop */
2300 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2302 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2304 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2306 /* special handling for CSIDL_DRIVES */
2307 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2309 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2311 /* enumerate the drives */
2312 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2314 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2316 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2317 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2318 COMDLG32_SHFree(pidlAbsTmp);
2319 COMDLG32_SHFree(pidlTmp1);
2321 IEnumIDList_Release(lpeDrives);
2323 IShellFolder_Release(psfDrives);
2326 COMDLG32_SHFree(pidlTmp);
2328 IEnumIDList_Release(lpeRoot);
2332 IShellFolder_Release(psfRoot);
2333 COMDLG32_SHFree(pidlDrives);
2334 return NOERROR;
2337 /***********************************************************************
2338 * FILEDLG95_LOOKIN_DrawItem
2340 * WM_DRAWITEM message handler
2342 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2344 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2345 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2346 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2347 RECT rectText;
2348 RECT rectIcon;
2349 SHFILEINFOA sfi;
2350 HIMAGELIST ilItemImage;
2351 int iIndentation;
2352 TEXTMETRICA tm;
2353 LPSFOLDER tmpFolder;
2356 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2358 TRACE("\n");
2360 if(pDIStruct->itemID == -1)
2361 return 0;
2363 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2364 pDIStruct->itemID)))
2365 return 0;
2368 if(pDIStruct->itemID == liInfos->uSelectedItem)
2370 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2372 &sfi,
2373 sizeof (SHFILEINFOA),
2374 SHGFI_PIDL | SHGFI_SMALLICON |
2375 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2376 SHGFI_DISPLAYNAME );
2378 else
2380 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2382 &sfi,
2383 sizeof (SHFILEINFOA),
2384 SHGFI_PIDL | SHGFI_SMALLICON |
2385 SHGFI_SYSICONINDEX |
2386 SHGFI_DISPLAYNAME);
2389 /* Is this item selected ? */
2390 if(pDIStruct->itemState & ODS_SELECTED)
2392 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2393 SetBkColor(pDIStruct->hDC,crHighLight);
2394 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2396 else
2398 SetTextColor(pDIStruct->hDC,crText);
2399 SetBkColor(pDIStruct->hDC,crWin);
2400 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2403 /* Do not indent item if drawing in the edit of the combo */
2404 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2406 iIndentation = 0;
2407 ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2409 &sfi,
2410 sizeof (SHFILEINFOA),
2411 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2412 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2415 else
2417 iIndentation = tmpFolder->m_iIndent;
2419 /* Draw text and icon */
2421 /* Initialise the icon display area */
2422 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2423 rectIcon.top = pDIStruct->rcItem.top;
2424 rectIcon.right = rectIcon.left + ICONWIDTH;
2425 rectIcon.bottom = pDIStruct->rcItem.bottom;
2427 /* Initialise the text display area */
2428 GetTextMetricsA(pDIStruct->hDC, &tm);
2429 rectText.left = rectIcon.right;
2430 rectText.top =
2431 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2432 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2433 rectText.bottom =
2434 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2436 /* Draw the icon from the image list */
2437 ImageList_Draw(ilItemImage,
2438 sfi.iIcon,
2439 pDIStruct->hDC,
2440 rectIcon.left,
2441 rectIcon.top,
2442 ILD_TRANSPARENT );
2444 /* Draw the associated text */
2445 if(sfi.szDisplayName)
2446 TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2449 return NOERROR;
2452 /***********************************************************************
2453 * FILEDLG95_LOOKIN_OnCommand
2455 * LookIn combo box WM_COMMAND message handler
2456 * If the function succeeds, the return value is nonzero.
2458 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2460 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2462 TRACE("%p\n", fodInfos);
2464 switch(wNotifyCode)
2466 case CBN_SELENDOK:
2468 LPSFOLDER tmpFolder;
2469 int iItem;
2471 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2473 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2474 iItem)))
2475 return FALSE;
2478 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2479 tmpFolder->pidlItem,
2480 SBSP_ABSOLUTE)))
2482 return TRUE;
2484 break;
2488 return FALSE;
2491 /***********************************************************************
2492 * FILEDLG95_LOOKIN_AddItem
2494 * Adds an absolute pidl item to the lookin combo box
2495 * returns the index of the inserted item
2497 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2499 LPITEMIDLIST pidlNext;
2500 SHFILEINFOA sfi;
2501 SFOLDER *tmpFolder;
2502 LookInInfos *liInfos;
2504 TRACE("%08x\n", iInsertId);
2506 if(!pidl)
2507 return -1;
2509 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2510 return -1;
2512 tmpFolder = MemAlloc(sizeof(SFOLDER));
2513 tmpFolder->m_iIndent = 0;
2515 /* Calculate the indentation of the item in the lookin*/
2516 pidlNext = pidl;
2517 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2519 tmpFolder->m_iIndent++;
2522 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2524 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2525 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2527 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2528 SHGetFileInfoA((LPSTR)pidl,
2530 &sfi,
2531 sizeof(sfi),
2532 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2533 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2535 TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2537 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2539 int iItemID;
2541 TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2543 /* Add the item at the end of the list */
2544 if(iInsertId < 0)
2546 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2548 /* Insert the item at the iInsertId position*/
2549 else
2551 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2554 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2555 return iItemID;
2558 COMDLG32_SHFree( tmpFolder->pidlItem );
2559 MemFree( tmpFolder );
2560 return -1;
2564 /***********************************************************************
2565 * FILEDLG95_LOOKIN_InsertItemAfterParent
2567 * Insert an item below its parent
2569 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2572 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2573 int iParentPos;
2575 TRACE("\n");
2577 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2579 if(iParentPos < 0)
2581 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2584 /* Free pidlParent memory */
2585 COMDLG32_SHFree((LPVOID)pidlParent);
2587 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2590 /***********************************************************************
2591 * FILEDLG95_LOOKIN_SelectItem
2593 * Adds an absolute pidl item to the lookin combo box
2594 * returns the index of the inserted item
2596 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2598 int iItemPos;
2599 LookInInfos *liInfos;
2601 TRACE("\n");
2603 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2605 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2607 if(iItemPos < 0)
2609 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2610 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2613 else
2615 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2616 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2618 int iRemovedItem;
2620 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2621 break;
2622 if(iRemovedItem < iItemPos)
2623 iItemPos--;
2627 CBSetCurSel(hwnd,iItemPos);
2628 liInfos->uSelectedItem = iItemPos;
2630 return 0;
2634 /***********************************************************************
2635 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2637 * Remove the item with an expansion level over iExpansionLevel
2639 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2641 int iItemPos;
2643 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2645 TRACE("\n");
2647 if(liInfos->iMaxIndentation <= 2)
2648 return -1;
2650 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2652 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2653 COMDLG32_SHFree(tmpFolder->pidlItem);
2654 MemFree(tmpFolder);
2655 CBDeleteString(hwnd,iItemPos);
2656 liInfos->iMaxIndentation--;
2658 return iItemPos;
2661 return -1;
2664 /***********************************************************************
2665 * FILEDLG95_LOOKIN_SearchItem
2667 * Search for pidl in the lookin combo box
2668 * returns the index of the found item
2670 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2672 int i = 0;
2673 int iCount = CBGetCount(hwnd);
2675 TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2677 if (iCount != CB_ERR)
2679 for(;i<iCount;i++)
2681 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2683 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2684 return i;
2685 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2686 return i;
2690 return -1;
2693 /***********************************************************************
2694 * FILEDLG95_LOOKIN_Clean
2696 * Clean the memory used by the lookin combo box
2698 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2700 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2701 int iPos;
2702 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2704 TRACE("\n");
2706 /* Delete each string of the combo and their associated data */
2707 if (iCount != CB_ERR)
2709 for(iPos = iCount-1;iPos>=0;iPos--)
2711 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2712 COMDLG32_SHFree(tmpFolder->pidlItem);
2713 MemFree(tmpFolder);
2714 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2718 /* LookInInfos structure */
2719 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2722 /***********************************************************************
2723 * FILEDLG95_FILENAME_FillFromSelection
2725 * fills the edit box from the cached DataObject
2727 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2729 FileOpenDlgInfos *fodInfos;
2730 LPITEMIDLIST pidl;
2731 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2732 char lpstrTemp[MAX_PATH];
2733 LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL;
2735 TRACE("\n");
2736 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2738 /* Count how many files we have */
2739 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2741 /* calculate the string length, count files */
2742 if (nFileSelected >= 1)
2744 nLength += 3; /* first and last quotes, trailing \0 */
2745 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2747 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2749 if (pidl)
2751 /* get the total length of the selected file names */
2752 lpstrTemp[0] = '\0';
2753 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2755 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2757 nLength += strlen( lpstrTemp ) + 3;
2758 nFiles++;
2760 COMDLG32_SHFree( pidl );
2765 /* allocate the buffer */
2766 if (nFiles <= 1) nLength = MAX_PATH;
2767 lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2768 lpstrAllFile[0] = '\0';
2770 /* Generate the string for the edit control */
2771 if(nFiles >= 1)
2773 lpstrCurrFile = lpstrAllFile;
2774 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2776 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2778 if (pidl)
2780 /* get the file name */
2781 lpstrTemp[0] = '\0';
2782 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
2784 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2786 if ( nFiles > 1)
2788 *lpstrCurrFile++ = '\"';
2789 strcpy( lpstrCurrFile, lpstrTemp );
2790 lpstrCurrFile += strlen( lpstrTemp );
2791 strcpy( lpstrCurrFile, "\" " );
2792 lpstrCurrFile += 2;
2794 else
2796 strcpy( lpstrAllFile, lpstrTemp );
2799 COMDLG32_SHFree( (LPVOID) pidl );
2802 SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2804 HeapFree(GetProcessHeap(),0, lpstrAllFile );
2808 /* copied from shell32 to avoid linking to it */
2809 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2811 switch (src->uType)
2813 case STRRET_WSTR:
2814 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2815 COMDLG32_SHFree(src->u.pOleStr);
2816 break;
2818 case STRRET_CSTR:
2819 lstrcpynA((LPSTR)dest, src->u.cStr, len);
2820 break;
2822 case STRRET_OFFSET:
2823 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2824 break;
2826 default:
2827 FIXME("unknown type!\n");
2828 if (len)
2830 *(LPSTR)dest = '\0';
2832 return(FALSE);
2834 return S_OK;
2837 /***********************************************************************
2838 * FILEDLG95_FILENAME_GetFileNames
2840 * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2842 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
2844 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2845 UINT nStrCharCount = 0; /* index in src buffer */
2846 UINT nFileIndex = 0; /* index in dest buffer */
2847 UINT nFileCount = 0; /* number of files */
2848 UINT nStrLen = 0; /* length of string in edit control */
2849 LPWSTR lpstrEdit; /* buffer for string from edit control */
2851 TRACE("\n");
2853 /* get the filenames from the edit control */
2854 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2855 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
2856 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2858 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
2860 /* we might get single filename without any '"',
2861 * so we need nStrLen + terminating \0 + end-of-list \0 */
2862 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
2863 *sizeUsed = 0;
2865 /* build 0-delimited file list from filenames */
2866 while ( nStrCharCount <= nStrLen )
2868 if ( lpstrEdit[nStrCharCount]=='"' )
2870 nStrCharCount++;
2871 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2873 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2874 (*sizeUsed)++;
2875 nStrCharCount++;
2877 (*lpstrFileList)[nFileIndex++] = '\0';
2878 (*sizeUsed)++;
2879 nFileCount++;
2881 nStrCharCount++;
2884 /* single, unquoted string */
2885 if ((nStrLen > 0) && (*sizeUsed == 0) )
2887 strcpyW(*lpstrFileList, lpstrEdit);
2888 nFileIndex = strlenW(lpstrEdit) + 1;
2889 (*sizeUsed) = nFileIndex;
2890 nFileCount = 1;
2893 /* trailing \0 */
2894 (*lpstrFileList)[nFileIndex] = '\0';
2895 (*sizeUsed)++;
2897 MemFree(lpstrEdit);
2898 return nFileCount;
2901 #define SETDefFormatEtc(fe,cf,med) \
2903 (fe).cfFormat = cf;\
2904 (fe).dwAspect = DVASPECT_CONTENT; \
2905 (fe).ptd =NULL;\
2906 (fe).tymed = med;\
2907 (fe).lindex = -1;\
2911 * DATAOBJECT Helper functions
2914 /***********************************************************************
2915 * COMCTL32_ReleaseStgMedium
2917 * like ReleaseStgMedium from ole32
2919 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2921 if(medium.pUnkForRelease)
2923 IUnknown_Release(medium.pUnkForRelease);
2925 else
2927 GlobalUnlock(medium.u.hGlobal);
2928 GlobalFree(medium.u.hGlobal);
2932 /***********************************************************************
2933 * GetPidlFromDataObject
2935 * Return pidl(s) by number from the cached DataObject
2937 * nPidlIndex=0 gets the fully qualified root path
2939 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2942 STGMEDIUM medium;
2943 FORMATETC formatetc;
2944 LPITEMIDLIST pidl = NULL;
2946 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
2948 /* Set the FORMATETC structure*/
2949 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2951 /* Get the pidls from IDataObject */
2952 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2954 LPIDA cida = GlobalLock(medium.u.hGlobal);
2955 if(nPidlIndex <= cida->cidl)
2957 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
2959 COMCTL32_ReleaseStgMedium(medium);
2961 return pidl;
2964 /***********************************************************************
2965 * GetNumSelected
2967 * Return the number of selected items in the DataObject.
2970 UINT GetNumSelected( IDataObject *doSelected )
2972 UINT retVal = 0;
2973 STGMEDIUM medium;
2974 FORMATETC formatetc;
2976 TRACE("sv=%p\n", doSelected);
2978 if (!doSelected) return 0;
2980 /* Set the FORMATETC structure*/
2981 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2983 /* Get the pidls from IDataObject */
2984 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2986 LPIDA cida = GlobalLock(medium.u.hGlobal);
2987 retVal = cida->cidl;
2988 COMCTL32_ReleaseStgMedium(medium);
2989 return retVal;
2991 return 0;
2995 * TOOLS
2998 /***********************************************************************
2999 * GetName
3001 * Get the pidl's display name (relative to folder) and
3002 * put it in lpstrFileName.
3004 * Return NOERROR on success,
3005 * E_FAIL otherwise
3008 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
3010 STRRET str;
3011 HRESULT hRes;
3013 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3015 if(!lpsf)
3017 HRESULT hRes;
3018 SHGetDesktopFolder(&lpsf);
3019 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3020 IShellFolder_Release(lpsf);
3021 return hRes;
3024 /* Get the display name of the pidl relative to the folder */
3025 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3027 return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
3029 return E_FAIL;
3032 /***********************************************************************
3033 * GetShellFolderFromPidl
3035 * pidlRel is the item pidl relative
3036 * Return the IShellFolder of the absolute pidl
3038 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3040 IShellFolder *psf = NULL,*psfParent;
3042 TRACE("%p\n", pidlAbs);
3044 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3046 psf = psfParent;
3047 if(pidlAbs && pidlAbs->mkid.cb)
3049 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3051 IShellFolder_Release(psfParent);
3052 return psf;
3055 /* return the desktop */
3056 return psfParent;
3058 return NULL;
3061 /***********************************************************************
3062 * GetParentPidl
3064 * Return the LPITEMIDLIST to the parent of the pidl in the list
3066 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3068 LPITEMIDLIST pidlParent;
3070 TRACE("%p\n", pidl);
3072 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3073 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3075 return pidlParent;
3078 /***********************************************************************
3079 * GetPidlFromName
3081 * returns the pidl of the file name relative to folder
3082 * NULL if an error occurred
3084 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3086 LPITEMIDLIST pidl = NULL;
3087 ULONG ulEaten;
3089 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3091 if(!lpcstrFileName) return NULL;
3092 if(!*lpcstrFileName) return NULL;
3094 if(!lpsf)
3096 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3097 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3098 IShellFolder_Release(lpsf);
3101 else
3103 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3105 return pidl;
3110 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPITEMIDLIST pidl)
3112 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3113 HRESULT ret;
3115 TRACE("%p, %p\n", psf, pidl);
3117 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3119 TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
3120 /* see documentation shell 4.1*/
3121 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3124 /***********************************************************************
3125 * BrowseSelectedFolder
3127 static BOOL BrowseSelectedFolder(HWND hwnd)
3129 BOOL bBrowseSelFolder = FALSE;
3130 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3132 TRACE("\n");
3134 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3136 LPITEMIDLIST pidlSelection;
3138 /* get the file selected */
3139 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3140 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3142 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3143 pidlSelection, SBSP_RELATIVE ) ) )
3145 WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3146 ' ','n','o','t',' ','e','x','i','s','t',0};
3147 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3150 bBrowseSelFolder = TRUE;
3152 COMDLG32_SHFree( pidlSelection );
3155 return bBrowseSelFolder;
3159 * Memory allocation methods */
3160 static void *MemAlloc(UINT size)
3162 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3165 static void MemFree(void *mem)
3167 if(mem)
3169 HeapFree(GetProcessHeap(),0,mem);