dpwsockx: Implementation of SPInit
[wine/gsoc_dplay.git] / dlls / comdlg32 / filedlg.c
blob4986122a8e454744ee3b7ffa2b079b5484951b4c
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
41 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
43 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
48 #include "config.h"
49 #include "wine/port.h"
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <string.h>
57 #define COBJMACROS
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winternl.h"
64 #include "winnls.h"
65 #include "wingdi.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "commdlg.h"
69 #include "dlgs.h"
70 #include "cdlg.h"
71 #include "filedlg31.h"
72 #include "cderr.h"
73 #include "shellapi.h"
74 #include "shlobj.h"
75 #include "filedlgbrowser.h"
76 #include "shlwapi.h"
78 #include "wine/unicode.h"
79 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
83 #define UNIMPLEMENTED_FLAGS \
84 (OFN_DONTADDTORECENT |\
85 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
86 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
88 #define IsHooked(fodInfos) \
89 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
90 /***********************************************************************
91 * Data structure and global variables
93 typedef struct SFolder
95 int m_iImageIndex; /* Index of picture in image list */
96 HIMAGELIST hImgList;
97 int m_iIndent; /* Indentation index */
98 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
100 } SFOLDER,*LPSFOLDER;
102 typedef struct tagLookInInfo
104 int iMaxIndentation;
105 UINT uSelectedItem;
106 } LookInInfos;
108 typedef struct tagFD32_PRIVATE
110 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
111 } FD32_PRIVATE, *PFD32_PRIVATE;
114 /***********************************************************************
115 * Defines and global variables
118 /* Draw item constant */
119 #define ICONWIDTH 18
120 #define XTEXTOFFSET 3
122 /* AddItem flags*/
123 #define LISTEND -1
125 /* SearchItem methods */
126 #define SEARCH_PIDL 1
127 #define SEARCH_EXP 2
128 #define ITEM_NOTFOUND -1
130 /* Undefined windows message sent by CreateViewObject*/
131 #define WM_GETISHELLBROWSER WM_USER+7
133 /* NOTE
134 * Those macros exist in windowsx.h. However, you can't really use them since
135 * they rely on the UNICODE defines and can't be used inside Wine itself.
138 /* Combo box macros */
139 #define CBAddString(hwnd,str) \
140 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
142 #define CBInsertString(hwnd,str,pos) \
143 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
145 #define CBDeleteString(hwnd,pos) \
146 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
148 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
149 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
151 #define CBGetItemDataPtr(hwnd,iItemId) \
152 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
154 #define CBGetLBText(hwnd,iItemId,str) \
155 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
157 #define CBGetCurSel(hwnd) \
158 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
160 #define CBSetCurSel(hwnd,pos) \
161 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
163 #define CBGetCount(hwnd) \
164 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
165 #define CBShowDropDown(hwnd,show) \
166 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
167 #define CBSetItemHeight(hwnd,index,height) \
168 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
170 #define CBSetExtendedUI(hwnd,flag) \
171 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
173 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
174 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
175 static SIZE MemDialogSize = { 0, 0}; /* keep size of the (resizable) dialog */
177 /***********************************************************************
178 * Prototypes
181 /* Internal functions used by the dialog */
182 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
183 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
186 static BOOL FILEDLG95_OnOpen(HWND hwnd);
187 static LRESULT FILEDLG95_InitControls(HWND hwnd);
188 static void FILEDLG95_Clean(HWND hwnd);
190 /* Functions used by the shell navigation */
191 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
192 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
194 static void FILEDLG95_SHELL_Clean(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
197 /* Functions used by the EDIT box */
198 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed);
200 /* Functions used by the filetype combo box */
201 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
202 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
203 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
204 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
206 /* Functions used by the Look In combo box */
207 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
208 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
209 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
210 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
211 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
212 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
213 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
214 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
215 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
217 /* Miscellaneous tool functions */
218 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
219 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
220 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
221 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
222 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl);
223 static UINT GetNumSelected( IDataObject *doSelected );
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size);
227 static void MemFree(void *mem);
229 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
235 * GetFileName95
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 static BOOL GetFileName95(FileOpenDlgInfos *fodInfos)
247 LRESULT lRes;
248 LPCVOID template;
249 HRSRC hRes;
250 HANDLE hDlgTmpl = 0;
251 HRESULT hr;
253 /* test for missing functionality */
254 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 FIXME("Flags 0x%08x not yet implemented\n",
257 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
260 /* Create the dialog from a template */
262 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
265 return FALSE;
267 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268 !(template = LockResource( hDlgTmpl )))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
271 return FALSE;
274 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
276 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
277 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
278 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
280 else
281 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
284 /* old style hook messages */
285 if (IsHooked(fodInfos))
287 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
288 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
289 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
290 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
293 /* Some shell namespace extensions depend on COM being initialized. */
294 hr = OleInitialize(NULL);
296 if (fodInfos->unicode)
297 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
298 template,
299 fodInfos->ofnInfos->hwndOwner,
300 FileOpenDlgProc95,
301 (LPARAM) fodInfos);
302 else
303 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
304 template,
305 fodInfos->ofnInfos->hwndOwner,
306 FileOpenDlgProc95,
307 (LPARAM) fodInfos);
308 if (SUCCEEDED(hr))
309 OleUninitialize();
311 /* Unable to create the dialog */
312 if( lRes == -1)
313 return FALSE;
315 return lRes;
318 /***********************************************************************
319 * GetFileDialog95A
321 * Call GetFileName95 with this structure and clean the memory.
323 * IN : The OPENFILENAMEA initialisation structure passed to
324 * GetOpenFileNameA win api function (see filedlg.c)
326 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
328 BOOL ret;
329 FileOpenDlgInfos fodInfos;
330 LPSTR lpstrSavDir = NULL;
331 LPWSTR title = NULL;
332 LPWSTR defext = NULL;
333 LPWSTR filter = NULL;
334 LPWSTR customfilter = NULL;
336 /* Initialize CommDlgExtendedError() */
337 COMDLG32_SetCommDlgExtendedError(0);
339 /* Initialize FileOpenDlgInfos structure */
340 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
342 /* Pass in the original ofn */
343 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
345 /* save current directory */
346 if (ofn->Flags & OFN_NOCHANGEDIR)
348 lpstrSavDir = MemAlloc(MAX_PATH);
349 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
352 fodInfos.unicode = FALSE;
354 /* convert all the input strings to unicode */
355 if(ofn->lpstrInitialDir)
357 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
358 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
359 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
361 else
362 fodInfos.initdir = NULL;
364 if(ofn->lpstrFile)
366 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
367 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
369 else
370 fodInfos.filename = NULL;
372 if(ofn->lpstrDefExt)
374 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
375 defext = MemAlloc((len+1)*sizeof(WCHAR));
376 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
378 fodInfos.defext = defext;
380 if(ofn->lpstrTitle)
382 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
383 title = MemAlloc((len+1)*sizeof(WCHAR));
384 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
386 fodInfos.title = title;
388 if (ofn->lpstrFilter)
390 LPCSTR s;
391 int n, len;
393 /* filter is a list... title\0ext\0......\0\0 */
394 s = ofn->lpstrFilter;
395 while (*s) s = s+strlen(s)+1;
396 s++;
397 n = s - ofn->lpstrFilter;
398 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
399 filter = MemAlloc(len*sizeof(WCHAR));
400 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
402 fodInfos.filter = filter;
404 /* convert lpstrCustomFilter */
405 if (ofn->lpstrCustomFilter)
407 LPCSTR s;
408 int n, len;
410 /* customfilter contains a pair of strings... title\0ext\0 */
411 s = ofn->lpstrCustomFilter;
412 if (*s) s = s+strlen(s)+1;
413 if (*s) s = s+strlen(s)+1;
414 n = s - ofn->lpstrCustomFilter;
415 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
416 customfilter = MemAlloc(len*sizeof(WCHAR));
417 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
419 fodInfos.customfilter = customfilter;
421 /* Initialize the dialog property */
422 fodInfos.DlgInfos.dwDlgProp = 0;
423 fodInfos.DlgInfos.hwndCustomDlg = NULL;
425 switch(iDlgType)
427 case OPEN_DIALOG :
428 ret = GetFileName95(&fodInfos);
429 break;
430 case SAVE_DIALOG :
431 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
432 ret = GetFileName95(&fodInfos);
433 break;
434 default :
435 ret = 0;
438 if (lpstrSavDir)
440 SetCurrentDirectoryA(lpstrSavDir);
441 MemFree(lpstrSavDir);
444 MemFree(title);
445 MemFree(defext);
446 MemFree(filter);
447 MemFree(customfilter);
448 MemFree(fodInfos.initdir);
449 MemFree(fodInfos.filename);
451 TRACE("selected file: %s\n",ofn->lpstrFile);
453 return ret;
456 /***********************************************************************
457 * GetFileDialog95W
459 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
460 * Call GetFileName95 with this structure and clean the memory.
463 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
465 BOOL ret;
466 FileOpenDlgInfos fodInfos;
467 LPWSTR lpstrSavDir = NULL;
469 /* Initialize CommDlgExtendedError() */
470 COMDLG32_SetCommDlgExtendedError(0);
472 /* Initialize FileOpenDlgInfos structure */
473 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
475 /* Pass in the original ofn */
476 fodInfos.ofnInfos = ofn;
478 fodInfos.title = ofn->lpstrTitle;
479 fodInfos.defext = ofn->lpstrDefExt;
480 fodInfos.filter = ofn->lpstrFilter;
481 fodInfos.customfilter = ofn->lpstrCustomFilter;
483 /* convert string arguments, save others */
484 if(ofn->lpstrFile)
486 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
487 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
489 else
490 fodInfos.filename = NULL;
492 if(ofn->lpstrInitialDir)
494 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
495 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
496 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
497 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
499 else
500 fodInfos.initdir = NULL;
502 /* save current directory */
503 if (ofn->Flags & OFN_NOCHANGEDIR)
505 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
506 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
509 fodInfos.unicode = TRUE;
511 switch(iDlgType)
513 case OPEN_DIALOG :
514 ret = GetFileName95(&fodInfos);
515 break;
516 case SAVE_DIALOG :
517 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
518 ret = GetFileName95(&fodInfos);
519 break;
520 default :
521 ret = 0;
524 if (lpstrSavDir)
526 SetCurrentDirectoryW(lpstrSavDir);
527 MemFree(lpstrSavDir);
530 /* restore saved IN arguments and convert OUT arguments back */
531 MemFree(fodInfos.filename);
532 MemFree(fodInfos.initdir);
533 return ret;
536 /******************************************************************************
537 * COMDLG32_GetDisplayNameOf [internal]
539 * Helper function to get the display name for a pidl.
541 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
542 LPSHELLFOLDER psfDesktop;
543 STRRET strret;
545 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
546 return FALSE;
548 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
549 IShellFolder_Release(psfDesktop);
550 return FALSE;
553 IShellFolder_Release(psfDesktop);
554 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
557 /***********************************************************************
558 * ArrangeCtrlPositions [internal]
560 * NOTE: Make sure to add testcases for any changes made here.
562 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
564 HWND hwndChild, hwndStc32;
565 RECT rectParent, rectChild, rectStc32;
566 INT help_fixup = 0;
567 int chgx, chgy;
569 /* Take into account if open as read only checkbox and help button
570 * are hidden
572 if (hide_help)
574 RECT rectHelp, rectCancel;
575 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
576 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
577 /* subtract the height of the help button plus the space between
578 * the help button and the cancel button to the height of the dialog
580 help_fixup = rectHelp.bottom - rectCancel.bottom;
584 There are two possibilities to add components to the default file dialog box.
586 By default, all the new components are added below the standard dialog box (the else case).
588 However, if there is a static text component with the stc32 id, a special case happens.
589 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
590 in the window and the cx and cy indicate how to size the window.
591 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
592 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
596 GetClientRect(hwndParentDlg, &rectParent);
598 /* when arranging controls we have to use fixed parent size */
599 rectParent.bottom -= help_fixup;
601 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
602 if (hwndStc32)
604 GetWindowRect(hwndStc32, &rectStc32);
605 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
607 /* set the size of the stc32 control according to the size of
608 * client area of the parent dialog
610 SetWindowPos(hwndStc32, 0,
611 0, 0,
612 rectParent.right, rectParent.bottom,
613 SWP_NOMOVE | SWP_NOZORDER);
615 else
616 SetRectEmpty(&rectStc32);
618 /* this part moves controls of the child dialog */
619 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
620 while (hwndChild)
622 if (hwndChild != hwndStc32)
624 GetWindowRect(hwndChild, &rectChild);
625 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
627 /* move only if stc32 exist */
628 if (hwndStc32 && rectChild.left > rectStc32.right)
630 /* move to the right of visible controls of the parent dialog */
631 rectChild.left += rectParent.right;
632 rectChild.left -= rectStc32.right;
634 /* move even if stc32 doesn't exist */
635 if (rectChild.top >= rectStc32.bottom)
637 /* move below visible controls of the parent dialog */
638 rectChild.top += rectParent.bottom;
639 rectChild.top -= rectStc32.bottom - rectStc32.top;
642 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
643 0, 0, SWP_NOSIZE | SWP_NOZORDER);
645 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
648 /* this part moves controls of the parent dialog */
649 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
650 while (hwndChild)
652 if (hwndChild != hwndChildDlg)
654 GetWindowRect(hwndChild, &rectChild);
655 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
657 /* left,top of stc32 marks the position of controls
658 * from the parent dialog
660 rectChild.left += rectStc32.left;
661 rectChild.top += rectStc32.top;
663 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
664 0, 0, SWP_NOSIZE | SWP_NOZORDER);
666 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
669 /* calculate the size of the resulting dialog */
671 /* here we have to use original parent size */
672 GetClientRect(hwndParentDlg, &rectParent);
673 GetClientRect(hwndChildDlg, &rectChild);
674 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
675 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
677 if (hwndStc32)
679 /* width */
680 if (rectParent.right > rectStc32.right - rectStc32.left)
681 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
682 else
683 chgx = rectChild.right - rectParent.right;
684 /* height */
685 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
686 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
687 else
688 /* Unconditionally set new dialog
689 * height to that of the child
691 chgy = rectChild.bottom - rectParent.bottom;
693 else
695 chgx = 0;
696 chgy = rectChild.bottom - help_fixup;
698 /* set the size of the parent dialog */
699 GetWindowRect(hwndParentDlg, &rectParent);
700 SetWindowPos(hwndParentDlg, 0,
701 0, 0,
702 rectParent.right - rectParent.left + chgx,
703 rectParent.bottom - rectParent.top + chgy,
704 SWP_NOMOVE | SWP_NOZORDER);
707 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
709 switch(uMsg) {
710 case WM_INITDIALOG:
711 return TRUE;
713 return FALSE;
716 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
718 LPCVOID template;
719 HRSRC hRes;
720 HANDLE hDlgTmpl = 0;
721 HWND hChildDlg = 0;
723 TRACE("\n");
726 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
727 * structure's hInstance parameter is not a HINSTANCE, but
728 * instead a pointer to a template resource to use.
730 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
732 HINSTANCE hinst;
733 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
735 hinst = COMDLG32_hInstance;
736 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
738 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
739 return NULL;
742 else
744 hinst = fodInfos->ofnInfos->hInstance;
745 if(fodInfos->unicode)
747 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
748 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
750 else
752 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
753 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
755 if (!hRes)
757 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
758 return NULL;
760 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
761 !(template = LockResource( hDlgTmpl )))
763 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
764 return NULL;
767 if (fodInfos->unicode)
768 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
769 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
770 (LPARAM)fodInfos->ofnInfos);
771 else
772 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
773 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
774 (LPARAM)fodInfos->ofnInfos);
775 return hChildDlg;
777 else if( IsHooked(fodInfos))
779 RECT rectHwnd;
780 struct {
781 DLGTEMPLATE tmplate;
782 WORD menu,class,title;
783 } temp;
784 GetClientRect(hwnd,&rectHwnd);
785 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
786 temp.tmplate.dwExtendedStyle = 0;
787 temp.tmplate.cdit = 0;
788 temp.tmplate.x = 0;
789 temp.tmplate.y = 0;
790 temp.tmplate.cx = 0;
791 temp.tmplate.cy = 0;
792 temp.menu = temp.class = temp.title = 0;
794 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
795 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
797 return hChildDlg;
799 return NULL;
802 /***********************************************************************
803 * SendCustomDlgNotificationMessage
805 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
808 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
810 LRESULT hook_result = 0;
811 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
813 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
815 if(!fodInfos) return 0;
817 if(fodInfos->DlgInfos.hwndCustomDlg)
819 TRACE("CALL NOTIFY for %x\n", uCode);
820 if(fodInfos->unicode)
822 OFNOTIFYW ofnNotify;
823 ofnNotify.hdr.hwndFrom=hwndParentDlg;
824 ofnNotify.hdr.idFrom=0;
825 ofnNotify.hdr.code = uCode;
826 ofnNotify.lpOFN = fodInfos->ofnInfos;
827 ofnNotify.pszFile = NULL;
828 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
830 else
832 OFNOTIFYA ofnNotify;
833 ofnNotify.hdr.hwndFrom=hwndParentDlg;
834 ofnNotify.hdr.idFrom=0;
835 ofnNotify.hdr.code = uCode;
836 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
837 ofnNotify.pszFile = NULL;
838 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
840 TRACE("RET NOTIFY\n");
842 TRACE("Retval: 0x%08lx\n", hook_result);
843 return hook_result;
846 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
848 UINT len, total;
849 WCHAR *p, *buffer;
850 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
852 TRACE("CDM_GETFILEPATH:\n");
854 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
855 return -1;
857 /* get path and filenames */
858 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
859 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
860 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
861 if (len)
863 p = buffer + strlenW(buffer);
864 *p++ = '\\';
865 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
867 if (fodInfos->unicode)
869 total = strlenW( buffer) + 1;
870 if (result) lstrcpynW( result, buffer, size );
871 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
873 else
875 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
876 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
877 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
879 HeapFree( GetProcessHeap(), 0, buffer );
880 return total;
883 /***********************************************************************
884 * FILEDLG95_HandleCustomDialogMessages
886 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
888 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
890 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
891 WCHAR lpstrPath[MAX_PATH];
892 INT_PTR retval;
894 if(!fodInfos) return FALSE;
896 switch(uMsg)
898 case CDM_GETFILEPATH:
899 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
900 break;
902 case CDM_GETFOLDERPATH:
903 TRACE("CDM_GETFOLDERPATH:\n");
904 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
905 if (lParam)
907 if (fodInfos->unicode)
908 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
909 else
910 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
911 (LPSTR)lParam, (int)wParam, NULL, NULL);
913 retval = lstrlenW(lpstrPath);
914 break;
916 case CDM_GETFOLDERIDLIST:
917 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
918 if (retval <= wParam)
919 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
920 break;
922 case CDM_GETSPEC:
923 TRACE("CDM_GETSPEC:\n");
924 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
925 if (lParam)
927 if (fodInfos->unicode)
928 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
929 else
930 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
932 break;
934 case CDM_SETCONTROLTEXT:
935 TRACE("CDM_SETCONTROLTEXT:\n");
936 if ( lParam )
938 if( fodInfos->unicode )
939 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
940 else
941 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
943 retval = TRUE;
944 break;
946 case CDM_HIDECONTROL:
947 /* MSDN states that it should fail for not OFN_EXPLORER case */
948 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
950 HWND control = GetDlgItem( hwnd, wParam );
951 if (control) ShowWindow( control, SW_HIDE );
952 retval = TRUE;
954 else retval = FALSE;
955 break;
957 default:
958 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
959 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
960 return FALSE;
962 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
963 return TRUE;
966 /***********************************************************************
967 * FILEDLG95_OnWMGetMMI
969 * WM_GETMINMAXINFO message handler for resizable dialogs
971 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
973 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
974 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
975 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
977 mmiptr->ptMinTrackSize = fodInfos->initial_size;
979 return TRUE;
982 /***********************************************************************
983 * FILEDLG95_OnWMSize
985 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
987 * FIXME: this could be made more elaborate. Now use a simple scheme
988 * where the file view is enlarged and the controls are either moved
989 * vertically or horizontally to get out of the way. Only the "grip"
990 * is moved in both directions to stay in the corner.
992 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
994 RECT rc, rcview;
995 int chgx, chgy;
996 HWND ctrl;
997 HDWP hdwp;
998 FileOpenDlgInfos *fodInfos;
1000 if( wParam != SIZE_RESTORED) return FALSE;
1001 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1002 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1003 /* get the new dialog rectangle */
1004 GetWindowRect( hwnd, &rc);
1005 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1006 rc.right -rc.left, rc.bottom -rc.top);
1007 /* not initialized yet */
1008 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1009 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1010 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1011 return FALSE;
1012 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1013 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1014 fodInfos->sizedlg.cx = rc.right - rc.left;
1015 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1016 /* change the size of the view window */
1017 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1018 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1019 hdwp = BeginDeferWindowPos( 10);
1020 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1021 rcview.right - rcview.left + chgx,
1022 rcview.bottom - rcview.top + chgy,
1023 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1024 /* change position and sizes of the controls */
1025 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1027 int ctrlid = GetDlgCtrlID( ctrl);
1028 GetWindowRect( ctrl, &rc);
1029 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1030 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1032 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1033 0, 0,
1034 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1036 else if( rc.top > rcview.bottom)
1038 /* if it was below the shell view
1039 * move to bottom */
1040 switch( ctrlid)
1042 /* file name box and file types combo change also width */
1043 case edt1:
1044 case cmb1:
1045 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1046 rc.right - rc.left + chgx, rc.bottom - rc.top,
1047 SWP_NOACTIVATE | SWP_NOZORDER);
1048 break;
1049 /* then these buttons must move out of the way */
1050 case IDOK:
1051 case IDCANCEL:
1052 case pshHelp:
1053 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1054 0, 0,
1055 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1056 break;
1057 default:
1058 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1059 0, 0,
1060 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1063 else if( rc.left > rcview.right)
1065 /* if it was to the right of the shell view
1066 * move to right */
1067 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1068 0, 0,
1069 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1071 else
1072 /* special cases */
1074 switch( ctrlid)
1076 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1077 case IDC_LOOKIN:
1078 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1079 rc.right - rc.left + chgx, rc.bottom - rc.top,
1080 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1081 break;
1082 case IDC_TOOLBARSTATIC:
1083 case IDC_TOOLBAR:
1084 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1085 0, 0,
1086 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1087 break;
1088 #endif
1089 /* not resized in windows. Since wine uses this invisible control
1090 * to size the browser view it needs to be resized */
1091 case IDC_SHELLSTATIC:
1092 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1093 rc.right - rc.left + chgx,
1094 rc.bottom - rc.top + chgy,
1095 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1096 break;
1100 if(fodInfos->DlgInfos.hwndCustomDlg &&
1101 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1103 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1104 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1106 GetWindowRect( ctrl, &rc);
1107 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1108 if( rc.top > rcview.bottom)
1110 /* if it was below the shell view
1111 * move to bottom */
1112 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1113 rc.right - rc.left, rc.bottom - rc.top,
1114 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1116 else if( rc.left > rcview.right)
1118 /* if it was to the right of the shell view
1119 * move to right */
1120 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1121 rc.right - rc.left, rc.bottom - rc.top,
1122 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1125 /* size the custom dialog at the end: some applications do some
1126 * control re-arranging at this point */
1127 GetClientRect(hwnd, &rc);
1128 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1129 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1131 EndDeferWindowPos( hdwp);
1132 /* should not be needed */
1133 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1134 return TRUE;
1137 /***********************************************************************
1138 * FileOpenDlgProc95
1140 * File open dialog procedure
1142 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1144 #if 0
1145 TRACE("%p 0x%04x\n", hwnd, uMsg);
1146 #endif
1148 switch(uMsg)
1150 case WM_INITDIALOG:
1152 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1153 RECT rc, rcstc;
1154 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1155 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1157 /* Adds the FileOpenDlgInfos in the property list of the dialog
1158 so it will be easily accessible through a GetPropA(...) */
1159 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1161 FILEDLG95_InitControls(hwnd);
1163 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1165 GetWindowRect( hwnd, &rc);
1166 fodInfos->DlgInfos.hwndGrip =
1167 CreateWindowExA( 0, "SCROLLBAR", NULL,
1168 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1169 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1170 rc.right - gripx, rc.bottom - gripy,
1171 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1174 fodInfos->DlgInfos.hwndCustomDlg =
1175 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1177 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1178 FILEDLG95_FillControls(hwnd, wParam, lParam);
1180 if( fodInfos->DlgInfos.hwndCustomDlg)
1181 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1183 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1184 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1185 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1188 /* if the app has changed the position of the invisible listbox,
1189 * change that of the listview (browser) as well */
1190 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1191 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1192 if( !EqualRect( &rc, &rcstc))
1194 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1195 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1196 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1197 SWP_NOACTIVATE | SWP_NOZORDER);
1200 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1202 GetWindowRect( hwnd, &rc);
1203 fodInfos->sizedlg.cx = rc.right - rc.left;
1204 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1205 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1206 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1207 GetClientRect( hwnd, &rc);
1208 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1209 rc.right - gripx, rc.bottom - gripy,
1210 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1211 /* resize the dialog to the previous invocation */
1212 if( MemDialogSize.cx && MemDialogSize.cy)
1213 SetWindowPos( hwnd, NULL,
1214 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1215 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1218 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1219 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1221 return 0;
1223 case WM_SIZE:
1224 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1225 case WM_GETMINMAXINFO:
1226 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1227 case WM_COMMAND:
1228 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1229 case WM_DRAWITEM:
1231 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1233 case IDC_LOOKIN:
1234 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1235 return TRUE;
1238 return FALSE;
1240 case WM_GETISHELLBROWSER:
1241 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1243 case WM_DESTROY:
1245 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1246 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1247 MemDialogSize = fodInfos->sizedlg;
1248 RemovePropA(hwnd, FileOpenDlgInfosStr);
1249 return FALSE;
1251 case WM_NOTIFY:
1253 LPNMHDR lpnmh = (LPNMHDR)lParam;
1254 UINT stringId = -1;
1256 /* set up the button tooltips strings */
1257 if(TTN_GETDISPINFOA == lpnmh->code )
1259 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1260 switch(lpnmh->idFrom )
1262 /* Up folder button */
1263 case FCIDM_TB_UPFOLDER:
1264 stringId = IDS_UPFOLDER;
1265 break;
1266 /* New folder button */
1267 case FCIDM_TB_NEWFOLDER:
1268 stringId = IDS_NEWFOLDER;
1269 break;
1270 /* List option button */
1271 case FCIDM_TB_SMALLICON:
1272 stringId = IDS_LISTVIEW;
1273 break;
1274 /* Details option button */
1275 case FCIDM_TB_REPORTVIEW:
1276 stringId = IDS_REPORTVIEW;
1277 break;
1278 /* Desktop button */
1279 case FCIDM_TB_DESKTOP:
1280 stringId = IDS_TODESKTOP;
1281 break;
1282 default:
1283 stringId = 0;
1285 lpdi->hinst = COMDLG32_hInstance;
1286 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1288 return FALSE;
1290 default :
1291 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1292 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1293 return FALSE;
1297 /***********************************************************************
1298 * FILEDLG95_InitControls
1300 * WM_INITDIALOG message handler (before hook notification)
1302 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1304 int win2000plus = 0;
1305 int win98plus = 0;
1306 int handledPath = FALSE;
1307 OSVERSIONINFOW osVi;
1308 static const WCHAR szwSlash[] = { '\\', 0 };
1309 static const WCHAR szwStar[] = { '*',0 };
1311 static const TBBUTTON tbb[] =
1313 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1314 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1315 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1316 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1317 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1318 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1319 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1320 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1321 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1323 TBADDBITMAP tba[2];
1324 RECT rectTB;
1325 RECT rectlook;
1326 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1328 tba[0].hInst = HINST_COMMCTRL;
1329 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1330 tba[1].hInst = COMDLG32_hInstance;
1331 tba[1].nID = 800;
1333 TRACE("%p\n", fodInfos);
1335 /* Get windows version emulating */
1336 osVi.dwOSVersionInfoSize = sizeof(osVi);
1337 GetVersionExW(&osVi);
1338 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1339 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1340 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1341 win2000plus = (osVi.dwMajorVersion > 4);
1342 if (win2000plus) win98plus = TRUE;
1344 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1346 /* Get the hwnd of the controls */
1347 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1348 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1349 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1351 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1352 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1354 /* construct the toolbar */
1355 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1356 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1358 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1359 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1360 rectTB.left = rectlook.right;
1361 rectTB.top = rectlook.top-1;
1363 if (fodInfos->unicode)
1364 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1365 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1366 rectTB.left, rectTB.top,
1367 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1368 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1369 else
1370 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1371 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1372 rectTB.left, rectTB.top,
1373 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1374 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1376 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1378 /* FIXME: use TB_LOADIMAGES when implemented */
1379 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1380 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1381 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1382 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1384 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1385 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1387 /* Set the window text with the text specified in the OPENFILENAME structure */
1388 if(fodInfos->title)
1390 SetWindowTextW(hwnd,fodInfos->title);
1392 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1394 WCHAR buf[16];
1395 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1396 SetWindowTextW(hwnd, buf);
1399 /* Initialise the file name edit control */
1400 handledPath = FALSE;
1401 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1403 if(fodInfos->filename)
1405 /* 1. If win2000 or higher and filename contains a path, use it
1406 in preference over the lpstrInitialDir */
1407 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1408 WCHAR tmpBuf[MAX_PATH];
1409 WCHAR *nameBit;
1410 DWORD result;
1412 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1413 if (result) {
1415 /* nameBit is always shorter than the original filename */
1416 lstrcpyW(fodInfos->filename,nameBit);
1418 *nameBit = 0x00;
1419 if (fodInfos->initdir == NULL)
1420 MemFree(fodInfos->initdir);
1421 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1422 lstrcpyW(fodInfos->initdir, tmpBuf);
1423 handledPath = TRUE;
1424 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1425 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1427 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1429 } else {
1430 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1434 /* 2. (All platforms) If initdir is not null, then use it */
1435 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1436 (*fodInfos->initdir!=0x00))
1438 /* Work out the proper path as supplied one might be relative */
1439 /* (Here because supplying '.' as dir browses to My Computer) */
1440 if (handledPath==FALSE) {
1441 WCHAR tmpBuf[MAX_PATH];
1442 WCHAR tmpBuf2[MAX_PATH];
1443 WCHAR *nameBit;
1444 DWORD result;
1446 lstrcpyW(tmpBuf, fodInfos->initdir);
1447 if( PathFileExistsW(tmpBuf) ) {
1448 /* initdir does not have to be a directory. If a file is
1449 * specified, the dir part is taken */
1450 if( PathIsDirectoryW(tmpBuf)) {
1451 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1452 lstrcatW(tmpBuf, szwSlash);
1454 lstrcatW(tmpBuf, szwStar);
1456 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1457 if (result) {
1458 *nameBit = 0x00;
1459 MemFree(fodInfos->initdir);
1460 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1461 lstrcpyW(fodInfos->initdir, tmpBuf2);
1462 handledPath = TRUE;
1463 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1466 else if (fodInfos->initdir)
1468 MemFree(fodInfos->initdir);
1469 fodInfos->initdir = NULL;
1470 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1475 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1476 (*fodInfos->initdir==0x00)))
1478 /* 3. All except w2k+: if filename contains a path use it */
1479 if (!win2000plus && fodInfos->filename &&
1480 *fodInfos->filename &&
1481 strpbrkW(fodInfos->filename, szwSlash)) {
1482 WCHAR tmpBuf[MAX_PATH];
1483 WCHAR *nameBit;
1484 DWORD result;
1486 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1487 tmpBuf, &nameBit);
1488 if (result) {
1489 int len;
1491 /* nameBit is always shorter than the original filename */
1492 lstrcpyW(fodInfos->filename, nameBit);
1493 *nameBit = 0x00;
1495 len = lstrlenW(tmpBuf);
1496 MemFree(fodInfos->initdir);
1497 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1498 lstrcpyW(fodInfos->initdir, tmpBuf);
1500 handledPath = TRUE;
1501 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1502 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1504 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1507 /* 4. win98+ and win2000+ if any files of specified filter types in
1508 current directory, use it */
1509 if ( win98plus && handledPath == FALSE &&
1510 fodInfos->filter && *fodInfos->filter) {
1512 BOOL searchMore = TRUE;
1513 LPCWSTR lpstrPos = fodInfos->filter;
1514 WIN32_FIND_DATAW FindFileData;
1515 HANDLE hFind;
1517 while (searchMore)
1519 /* filter is a list... title\0ext\0......\0\0 */
1521 /* Skip the title */
1522 if(! *lpstrPos) break; /* end */
1523 lpstrPos += lstrlenW(lpstrPos) + 1;
1525 /* See if any files exist in the current dir with this extension */
1526 if(! *lpstrPos) break; /* end */
1528 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1530 if (hFind == INVALID_HANDLE_VALUE) {
1531 /* None found - continue search */
1532 lpstrPos += lstrlenW(lpstrPos) + 1;
1534 } else {
1535 searchMore = FALSE;
1537 MemFree(fodInfos->initdir);
1538 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1539 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1541 handledPath = TRUE;
1542 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1543 debugstr_w(lpstrPos));
1544 break;
1549 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1551 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1552 if (handledPath == FALSE && (win2000plus || win98plus)) {
1553 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1555 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1557 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1559 /* last fallback */
1560 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1561 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1562 } else {
1563 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1565 } else {
1566 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1568 handledPath = TRUE;
1569 } else if (handledPath==FALSE) {
1570 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1571 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1572 handledPath = TRUE;
1573 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1576 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1577 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1579 /* Must the open as read only check box be checked ?*/
1580 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1582 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1585 /* Must the open as read only check box be hidden? */
1586 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1588 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1589 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1592 /* Must the help button be hidden? */
1593 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1595 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1596 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1599 /* change Open to Save */
1600 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1602 WCHAR buf[16];
1603 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1604 SetDlgItemTextW(hwnd, IDOK, buf);
1605 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1606 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1609 /* Initialize the filter combo box */
1610 FILEDLG95_FILETYPE_Init(hwnd);
1612 return 0;
1615 /***********************************************************************
1616 * FILEDLG95_ResizeControls
1618 * WM_INITDIALOG message handler (after hook notification)
1620 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1622 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1624 if (fodInfos->DlgInfos.hwndCustomDlg)
1626 RECT rc;
1627 UINT flags = SWP_NOACTIVATE;
1629 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1630 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1632 /* resize the custom dialog to the parent size */
1633 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1634 GetClientRect(hwnd, &rc);
1635 else
1637 /* our own fake template is zero sized and doesn't have children, so
1638 * there is no need to resize it. Picasa depends on it.
1640 flags |= SWP_NOSIZE;
1641 SetRectEmpty(&rc);
1643 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1644 0, 0, rc.right, rc.bottom, flags);
1646 else
1648 /* Resize the height, if open as read only checkbox ad help button are
1649 * hidden and we are not using a custom template nor a customDialog
1651 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1652 (!(fodInfos->ofnInfos->Flags &
1653 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1655 RECT rectDlg, rectHelp, rectCancel;
1656 GetWindowRect(hwnd, &rectDlg);
1657 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1658 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1659 /* subtract the height of the help button plus the space between the help
1660 * button and the cancel button to the height of the dialog
1662 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1663 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1664 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1667 return TRUE;
1670 /***********************************************************************
1671 * FILEDLG95_FillControls
1673 * WM_INITDIALOG message handler (after hook notification)
1675 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1677 LPITEMIDLIST pidlItemId = NULL;
1679 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1681 TRACE("dir=%s file=%s\n",
1682 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1684 /* Get the initial directory pidl */
1686 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1688 WCHAR path[MAX_PATH];
1690 GetCurrentDirectoryW(MAX_PATH,path);
1691 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1694 /* Initialise shell objects */
1695 FILEDLG95_SHELL_Init(hwnd);
1697 /* Initialize the Look In combo box */
1698 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1700 /* Browse to the initial directory */
1701 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1703 /* Free pidlItem memory */
1704 COMDLG32_SHFree(pidlItemId);
1706 return TRUE;
1708 /***********************************************************************
1709 * FILEDLG95_Clean
1711 * Regroups all the cleaning functions of the filedlg
1713 void FILEDLG95_Clean(HWND hwnd)
1715 FILEDLG95_FILETYPE_Clean(hwnd);
1716 FILEDLG95_LOOKIN_Clean(hwnd);
1717 FILEDLG95_SHELL_Clean(hwnd);
1719 /***********************************************************************
1720 * FILEDLG95_OnWMCommand
1722 * WM_COMMAND message handler
1724 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1726 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1727 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1728 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1730 switch(wID)
1732 /* OK button */
1733 case IDOK:
1734 FILEDLG95_OnOpen(hwnd);
1735 break;
1736 /* Cancel button */
1737 case IDCANCEL:
1738 FILEDLG95_Clean(hwnd);
1739 EndDialog(hwnd, FALSE);
1740 break;
1741 /* Filetype combo box */
1742 case IDC_FILETYPE:
1743 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1744 break;
1745 /* LookIn combo box */
1746 case IDC_LOOKIN:
1747 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1748 break;
1750 /* --- toolbar --- */
1751 /* Up folder button */
1752 case FCIDM_TB_UPFOLDER:
1753 FILEDLG95_SHELL_UpFolder(hwnd);
1754 break;
1755 /* New folder button */
1756 case FCIDM_TB_NEWFOLDER:
1757 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1758 break;
1759 /* List option button */
1760 case FCIDM_TB_SMALLICON:
1761 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1762 break;
1763 /* Details option button */
1764 case FCIDM_TB_REPORTVIEW:
1765 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1766 break;
1767 /* Details option button */
1768 case FCIDM_TB_DESKTOP:
1769 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1770 break;
1772 case IDC_FILENAME:
1773 break;
1776 /* Do not use the listview selection anymore */
1777 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1778 return 0;
1781 /***********************************************************************
1782 * FILEDLG95_OnWMGetIShellBrowser
1784 * WM_GETISHELLBROWSER message handler
1786 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1788 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1790 TRACE("\n");
1792 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1794 return TRUE;
1798 /***********************************************************************
1799 * FILEDLG95_SendFileOK
1801 * Sends the CDN_FILEOK notification if required
1803 * RETURNS
1804 * TRUE if the dialog should close
1805 * FALSE if the dialog should not be closed
1807 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1809 /* ask the hook if we can close */
1810 if(IsHooked(fodInfos))
1812 LRESULT retval = 0;
1814 TRACE("---\n");
1815 /* First send CDN_FILEOK as MSDN doc says */
1816 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1817 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1818 if( retval)
1820 TRACE("canceled\n");
1821 return FALSE;
1824 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1825 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1826 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1827 if( retval)
1829 TRACE("canceled\n");
1830 return FALSE;
1833 return TRUE;
1836 /***********************************************************************
1837 * FILEDLG95_OnOpenMultipleFiles
1839 * Handles the opening of multiple files.
1841 * FIXME
1842 * check destination buffer size
1844 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1846 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1847 UINT nCount, nSizePath;
1848 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1850 TRACE("\n");
1852 if(fodInfos->unicode)
1854 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1855 ofn->lpstrFile[0] = '\0';
1857 else
1859 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1860 ofn->lpstrFile[0] = '\0';
1863 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1865 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1866 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1867 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1869 LPWSTR lpstrTemp = lpstrFileList;
1871 for ( nCount = 0; nCount < nFileCount; nCount++ )
1873 LPITEMIDLIST pidl;
1875 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1876 if (!pidl)
1878 WCHAR lpstrNotFound[100];
1879 WCHAR lpstrMsg[100];
1880 WCHAR tmp[400];
1881 static const WCHAR nl[] = {'\n',0};
1883 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1884 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1886 lstrcpyW(tmp, lpstrTemp);
1887 lstrcatW(tmp, nl);
1888 lstrcatW(tmp, lpstrNotFound);
1889 lstrcatW(tmp, nl);
1890 lstrcatW(tmp, lpstrMsg);
1892 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1893 return FALSE;
1896 /* move to the next file in the list of files */
1897 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1898 COMDLG32_SHFree(pidl);
1902 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1903 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1905 /* For "oldstyle" dialog the components have to
1906 be separated by blanks (not '\0'!) and short
1907 filenames have to be used! */
1908 FIXME("Components have to be separated by blanks\n");
1910 if(fodInfos->unicode)
1912 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1913 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1914 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1916 else
1918 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1920 if (ofn->lpstrFile != NULL)
1922 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1923 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1924 if (ofn->nMaxFile > nSizePath)
1926 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1927 ofn->lpstrFile + nSizePath,
1928 ofn->nMaxFile - nSizePath, NULL, NULL);
1933 fodInfos->ofnInfos->nFileOffset = nSizePath;
1934 fodInfos->ofnInfos->nFileExtension = 0;
1936 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1937 return FALSE;
1939 /* clean and exit */
1940 FILEDLG95_Clean(hwnd);
1941 return EndDialog(hwnd,TRUE);
1944 /***********************************************************************
1945 * FILEDLG95_OnOpen
1947 * Ok button WM_COMMAND message handler
1949 * If the function succeeds, the return value is nonzero.
1951 #define ONOPEN_BROWSE 1
1952 #define ONOPEN_OPEN 2
1953 #define ONOPEN_SEARCH 3
1954 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1956 WCHAR strMsgTitle[MAX_PATH];
1957 WCHAR strMsgText [MAX_PATH];
1958 if (idCaption)
1959 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1960 else
1961 strMsgTitle[0] = '\0';
1962 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1963 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1966 BOOL FILEDLG95_OnOpen(HWND hwnd)
1968 LPWSTR lpstrFileList;
1969 UINT nFileCount = 0;
1970 UINT sizeUsed = 0;
1971 BOOL ret = TRUE;
1972 WCHAR lpstrPathAndFile[MAX_PATH];
1973 WCHAR lpstrTemp[MAX_PATH];
1974 LPSHELLFOLDER lpsf = NULL;
1975 int nOpenAction;
1976 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1978 TRACE("hwnd=%p\n", hwnd);
1980 /* get the files from the edit control */
1981 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1983 /* try if the user selected a folder in the shellview */
1984 if(nFileCount == 0)
1986 BrowseSelectedFolder(hwnd);
1987 return FALSE;
1990 if(nFileCount > 1)
1992 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1993 goto ret;
1996 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1999 Step 1: Build a complete path name from the current folder and
2000 the filename or path in the edit box.
2001 Special cases:
2002 - the path in the edit box is a root path
2003 (with or without drive letter)
2004 - the edit box contains ".." (or a path with ".." in it)
2007 /* Get the current directory name */
2008 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2010 /* last fallback */
2011 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2013 PathAddBackslashW(lpstrPathAndFile);
2015 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2017 /* if the user specified a fully qualified path use it */
2018 if(PathIsRelativeW(lpstrFileList))
2020 lstrcatW(lpstrPathAndFile, lpstrFileList);
2022 else
2024 /* does the path have a drive letter? */
2025 if (PathGetDriveNumberW(lpstrFileList) == -1)
2026 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2027 else
2028 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2031 /* resolve "." and ".." */
2032 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2033 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2034 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2036 MemFree(lpstrFileList);
2039 Step 2: here we have a cleaned up path
2041 We have to parse the path step by step to see if we have to browse
2042 to a folder if the path points to a directory or the last
2043 valid element is a directory.
2045 valid variables:
2046 lpstrPathAndFile: cleaned up path
2049 if (nFileCount &&
2050 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2051 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2052 nOpenAction = ONOPEN_OPEN;
2053 else
2054 nOpenAction = ONOPEN_BROWSE;
2056 /* don't apply any checks with OFN_NOVALIDATE */
2058 LPWSTR lpszTemp, lpszTemp1;
2059 LPITEMIDLIST pidl = NULL;
2060 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2062 /* check for invalid chars */
2063 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2065 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2066 ret = FALSE;
2067 goto ret;
2070 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2072 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2073 while (lpszTemp1)
2075 LPSHELLFOLDER lpsfChild;
2076 WCHAR lpwstrTemp[MAX_PATH];
2077 DWORD dwEaten, dwAttributes;
2078 LPWSTR p;
2080 lstrcpyW(lpwstrTemp, lpszTemp);
2081 p = PathFindNextComponentW(lpwstrTemp);
2083 if (!p) break; /* end of path */
2085 *p = 0;
2086 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2088 /* There are no wildcards when OFN_NOVALIDATE is set */
2089 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2091 static const WCHAR wszWild[] = { '*', '?', 0 };
2092 /* if the last element is a wildcard do a search */
2093 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2095 nOpenAction = ONOPEN_SEARCH;
2096 break;
2099 lpszTemp1 = lpszTemp;
2101 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2103 /* append a backslash to drive letters */
2104 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2105 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2106 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2108 PathAddBackslashW(lpwstrTemp);
2111 dwAttributes = SFGAO_FOLDER;
2112 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2114 /* the path component is valid, we have a pidl of the next path component */
2115 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2116 if(dwAttributes & SFGAO_FOLDER)
2118 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2120 ERR("bind to failed\n"); /* should not fail */
2121 break;
2123 IShellFolder_Release(lpsf);
2124 lpsf = lpsfChild;
2125 lpsfChild = NULL;
2127 else
2129 TRACE("value\n");
2131 /* end dialog, return value */
2132 nOpenAction = ONOPEN_OPEN;
2133 break;
2135 COMDLG32_SHFree(pidl);
2136 pidl = NULL;
2138 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2140 if(*lpszTemp || /* points to trailing null for last path element */
2141 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2143 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2145 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2146 break;
2149 else
2151 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2152 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2154 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2155 break;
2158 /* change to the current folder */
2159 nOpenAction = ONOPEN_OPEN;
2160 break;
2162 else
2164 nOpenAction = ONOPEN_OPEN;
2165 break;
2168 if(pidl) COMDLG32_SHFree(pidl);
2172 Step 3: here we have a cleaned up and validated path
2174 valid variables:
2175 lpsf: ShellFolder bound to the rightmost valid path component
2176 lpstrPathAndFile: cleaned up path
2177 nOpenAction: action to do
2179 TRACE("end validate sf=%p\n", lpsf);
2181 switch(nOpenAction)
2183 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2184 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2186 int iPos;
2187 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2188 DWORD len;
2190 /* replace the current filter */
2191 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2192 len = lstrlenW(lpszTemp)+1;
2193 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2194 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2196 /* set the filter cb to the extension when possible */
2197 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2198 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2200 /* fall through */
2201 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2202 TRACE("ONOPEN_BROWSE\n");
2204 IPersistFolder2 * ppf2;
2205 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2207 LPITEMIDLIST pidlCurrent;
2208 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2209 IPersistFolder2_Release(ppf2);
2210 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2212 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2213 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2215 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2218 else if( nOpenAction == ONOPEN_SEARCH )
2220 if (fodInfos->Shell.FOIShellView)
2221 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2223 COMDLG32_SHFree(pidlCurrent);
2224 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2227 ret = FALSE;
2228 break;
2229 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2230 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2232 WCHAR *ext = NULL;
2234 /* update READONLY check box flag */
2235 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2236 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2237 else
2238 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2240 /* Attach the file extension with file name*/
2241 ext = PathFindExtensionW(lpstrPathAndFile);
2242 if (! *ext)
2244 /* if no extension is specified with file name, then */
2245 /* attach the extension from file filter or default one */
2247 WCHAR *filterExt = NULL;
2248 LPWSTR lpstrFilter = NULL;
2249 static const WCHAR szwDot[] = {'.',0};
2250 int PathLength = lstrlenW(lpstrPathAndFile);
2252 /* Attach the dot*/
2253 lstrcatW(lpstrPathAndFile, szwDot);
2255 /*Get the file extension from file type filter*/
2256 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2257 fodInfos->ofnInfos->nFilterIndex-1);
2259 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2260 filterExt = PathFindExtensionW(lpstrFilter);
2262 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2263 lstrcatW(lpstrPathAndFile, filterExt + 1);
2264 else if ( fodInfos->defext ) /* attach the default file extension*/
2265 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2267 /* In Open dialog: if file does not exist try without extension */
2268 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2269 lpstrPathAndFile[PathLength] = '\0';
2272 if (fodInfos->defext) /* add default extension */
2274 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2275 if (*ext)
2276 ext++;
2277 if (!lstrcmpiW(fodInfos->defext, ext))
2278 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2279 else
2280 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2283 /* In Save dialog: check if the file already exists */
2284 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2285 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2286 && PathFileExistsW(lpstrPathAndFile))
2288 WCHAR lpstrOverwrite[100];
2289 int answer;
2291 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2292 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2293 MB_YESNO | MB_ICONEXCLAMATION);
2294 if (answer == IDNO)
2296 ret = FALSE;
2297 goto ret;
2301 /* In Open dialog: check if it should be created if it doesn't exist */
2302 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2303 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2304 && !PathFileExistsW(lpstrPathAndFile))
2306 WCHAR lpstrCreate[100];
2307 int answer;
2309 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2310 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2311 MB_YESNO | MB_ICONEXCLAMATION);
2312 if (answer == IDNO)
2314 ret = FALSE;
2315 goto ret;
2319 /* Check that the size of the file does not exceed buffer size.
2320 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2321 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2322 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2325 /* fill destination buffer */
2326 if (fodInfos->ofnInfos->lpstrFile)
2328 if(fodInfos->unicode)
2330 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2332 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2333 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2334 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2336 else
2338 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2340 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2341 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2342 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2343 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2347 if(fodInfos->unicode)
2349 LPWSTR lpszTemp;
2351 /* set filename offset */
2352 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2353 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2355 /* set extension offset */
2356 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2357 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2359 else
2361 LPSTR lpszTemp;
2362 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2364 /* set filename offset */
2365 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2366 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2368 /* set extension offset */
2369 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2370 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2373 /* set the lpstrFileTitle */
2374 if(fodInfos->ofnInfos->lpstrFileTitle)
2376 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2377 if(fodInfos->unicode)
2379 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2380 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2382 else
2384 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2385 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2386 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2390 /* copy currently selected filter to lpstrCustomFilter */
2391 if (fodInfos->ofnInfos->lpstrCustomFilter)
2393 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2394 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2395 NULL, 0, NULL, NULL);
2396 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2398 LPSTR s = ofn->lpstrCustomFilter;
2399 s += strlen(ofn->lpstrCustomFilter)+1;
2400 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2401 s, len, NULL, NULL);
2406 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2407 goto ret;
2409 TRACE("close\n");
2410 FILEDLG95_Clean(hwnd);
2411 ret = EndDialog(hwnd, TRUE);
2413 else
2415 WORD size;
2417 size = lstrlenW(lpstrPathAndFile) + 1;
2418 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2419 size += 1;
2420 /* return needed size in first two bytes of lpstrFile */
2421 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2422 FILEDLG95_Clean(hwnd);
2423 ret = EndDialog(hwnd, FALSE);
2424 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2427 break;
2430 ret:
2431 if(lpsf) IShellFolder_Release(lpsf);
2432 return ret;
2435 /***********************************************************************
2436 * FILEDLG95_SHELL_Init
2438 * Initialisation of the shell objects
2440 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2442 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2444 TRACE("\n");
2447 * Initialisation of the FileOpenDialogInfos structure
2450 /* Shell */
2452 /*ShellInfos */
2453 fodInfos->ShellInfos.hwndOwner = hwnd;
2455 /* Disable multi-select if flag not set */
2456 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2458 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2460 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2461 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2463 /* Construct the IShellBrowser interface */
2464 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2466 return NOERROR;
2469 /***********************************************************************
2470 * FILEDLG95_SHELL_ExecuteCommand
2472 * Change the folder option and refresh the view
2473 * If the function succeeds, the return value is nonzero.
2475 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2477 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2478 IContextMenu * pcm;
2480 TRACE("(%p,%p)\n", hwnd, lpVerb);
2482 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2483 SVGIO_BACKGROUND,
2484 &IID_IContextMenu,
2485 (LPVOID*)&pcm)))
2487 CMINVOKECOMMANDINFO ci;
2488 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2489 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2490 ci.lpVerb = lpVerb;
2491 ci.hwnd = hwnd;
2493 IContextMenu_InvokeCommand(pcm, &ci);
2494 IContextMenu_Release(pcm);
2497 return FALSE;
2500 /***********************************************************************
2501 * FILEDLG95_SHELL_UpFolder
2503 * Browse to the specified object
2504 * If the function succeeds, the return value is nonzero.
2506 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2508 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2510 TRACE("\n");
2512 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2513 NULL,
2514 SBSP_PARENT)))
2516 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2517 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2518 return TRUE;
2520 return FALSE;
2523 /***********************************************************************
2524 * FILEDLG95_SHELL_BrowseToDesktop
2526 * Browse to the Desktop
2527 * If the function succeeds, the return value is nonzero.
2529 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2531 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2532 LPITEMIDLIST pidl;
2533 HRESULT hres;
2535 TRACE("\n");
2537 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2538 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2539 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2540 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2541 COMDLG32_SHFree(pidl);
2542 return SUCCEEDED(hres);
2544 /***********************************************************************
2545 * FILEDLG95_SHELL_Clean
2547 * Cleans the memory used by shell objects
2549 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2551 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2553 TRACE("\n");
2555 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2557 /* clean Shell interfaces */
2558 if (fodInfos->Shell.FOIShellView)
2560 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2561 IShellView_Release(fodInfos->Shell.FOIShellView);
2563 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2564 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2565 if (fodInfos->Shell.FOIDataObject)
2566 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2569 /***********************************************************************
2570 * FILEDLG95_FILETYPE_Init
2572 * Initialisation of the file type combo box
2574 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2576 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2577 int nFilters = 0; /* number of filters */
2578 int nFilterIndexCB;
2580 TRACE("\n");
2582 if(fodInfos->customfilter)
2584 /* customfilter has one entry... title\0ext\0
2585 * Set first entry of combo box item with customfilter
2587 LPWSTR lpstrExt;
2588 LPCWSTR lpstrPos = fodInfos->customfilter;
2590 /* Get the title */
2591 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2593 /* Copy the extensions */
2594 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2595 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2596 lstrcpyW(lpstrExt,lpstrPos);
2598 /* Add the item at the end of the combo */
2599 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2600 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2601 nFilters++;
2603 if(fodInfos->filter)
2605 LPCWSTR lpstrPos = fodInfos->filter;
2607 for(;;)
2609 /* filter is a list... title\0ext\0......\0\0
2610 * Set the combo item text to the title and the item data
2611 * to the ext
2613 LPCWSTR lpstrDisplay;
2614 LPWSTR lpstrExt;
2616 /* Get the title */
2617 if(! *lpstrPos) break; /* end */
2618 lpstrDisplay = lpstrPos;
2619 lpstrPos += lstrlenW(lpstrPos) + 1;
2621 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2623 nFilters++;
2625 /* Copy the extensions */
2626 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2627 lstrcpyW(lpstrExt,lpstrPos);
2628 lpstrPos += lstrlenW(lpstrPos) + 1;
2630 /* Add the item at the end of the combo */
2631 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2633 /* malformed filters are added anyway... */
2634 if (!*lpstrExt) break;
2639 * Set the current filter to the one specified
2640 * in the initialisation structure
2642 if (fodInfos->filter || fodInfos->customfilter)
2644 LPWSTR lpstrFilter;
2646 /* Check to make sure our index isn't out of bounds. */
2647 if ( fodInfos->ofnInfos->nFilterIndex >
2648 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2649 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2651 /* set default filter index */
2652 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2653 fodInfos->ofnInfos->nFilterIndex = 1;
2655 /* calculate index of Combo Box item */
2656 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2657 if (fodInfos->customfilter == NULL)
2658 nFilterIndexCB--;
2660 /* Set the current index selection. */
2661 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2663 /* Get the corresponding text string from the combo box. */
2664 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2665 nFilterIndexCB);
2667 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2668 lpstrFilter = NULL;
2670 if(lpstrFilter)
2672 DWORD len;
2673 CharLowerW(lpstrFilter); /* lowercase */
2674 len = lstrlenW(lpstrFilter)+1;
2675 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2676 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2678 } else
2679 fodInfos->ofnInfos->nFilterIndex = 0;
2680 return S_OK;
2683 /***********************************************************************
2684 * FILEDLG95_FILETYPE_OnCommand
2686 * WM_COMMAND of the file type combo box
2687 * If the function succeeds, the return value is nonzero.
2689 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2691 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2693 switch(wNotifyCode)
2695 case CBN_SELENDOK:
2697 LPWSTR lpstrFilter;
2699 /* Get the current item of the filetype combo box */
2700 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2702 /* set the current filter index */
2703 fodInfos->ofnInfos->nFilterIndex = iItem +
2704 (fodInfos->customfilter == NULL ? 1 : 0);
2706 /* Set the current filter with the current selection */
2707 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2709 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2710 iItem);
2711 if((INT_PTR)lpstrFilter != CB_ERR)
2713 DWORD len;
2714 CharLowerW(lpstrFilter); /* lowercase */
2715 len = lstrlenW(lpstrFilter)+1;
2716 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2717 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2718 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2719 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2722 /* Refresh the actual view to display the included items*/
2723 if (fodInfos->Shell.FOIShellView)
2724 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2727 return FALSE;
2729 /***********************************************************************
2730 * FILEDLG95_FILETYPE_SearchExt
2732 * searches for an extension in the filetype box
2734 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2736 int i, iCount = CBGetCount(hwnd);
2738 TRACE("%s\n", debugstr_w(lpstrExt));
2740 if(iCount != CB_ERR)
2742 for(i=0;i<iCount;i++)
2744 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2745 return i;
2748 return -1;
2751 /***********************************************************************
2752 * FILEDLG95_FILETYPE_Clean
2754 * Clean the memory used by the filetype combo box
2756 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2758 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2759 int iPos;
2760 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2762 TRACE("\n");
2764 /* Delete each string of the combo and their associated data */
2765 if(iCount != CB_ERR)
2767 for(iPos = iCount-1;iPos>=0;iPos--)
2769 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2770 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2773 /* Current filter */
2774 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2778 /***********************************************************************
2779 * FILEDLG95_LOOKIN_Init
2781 * Initialisation of the look in combo box
2784 /* Small helper function, to determine if the unixfs shell extension is rooted
2785 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2787 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2788 HKEY hKey;
2789 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2790 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2791 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2792 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2793 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2794 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2795 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2797 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2798 return FALSE;
2800 RegCloseKey(hKey);
2801 return TRUE;
2804 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2806 IShellFolder *psfRoot, *psfDrives;
2807 IEnumIDList *lpeRoot, *lpeDrives;
2808 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2810 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2812 TRACE("\n");
2814 liInfos->iMaxIndentation = 0;
2816 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2818 /* set item height for both text field and listbox */
2819 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2820 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2822 /* Turn on the extended UI for the combo box like Windows does */
2823 CBSetExtendedUI(hwndCombo, TRUE);
2825 /* Initialise data of Desktop folder */
2826 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2827 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2828 COMDLG32_SHFree(pidlTmp);
2830 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2832 SHGetDesktopFolder(&psfRoot);
2834 if (psfRoot)
2836 /* enumerate the contents of the desktop */
2837 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2839 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2841 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2843 /* If the unixfs extension is rooted, we don't expand the drives by default */
2844 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2846 /* special handling for CSIDL_DRIVES */
2847 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2849 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2851 /* enumerate the drives */
2852 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2854 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2856 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2857 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2858 COMDLG32_SHFree(pidlAbsTmp);
2859 COMDLG32_SHFree(pidlTmp1);
2861 IEnumIDList_Release(lpeDrives);
2863 IShellFolder_Release(psfDrives);
2868 COMDLG32_SHFree(pidlTmp);
2870 IEnumIDList_Release(lpeRoot);
2872 IShellFolder_Release(psfRoot);
2875 COMDLG32_SHFree(pidlDrives);
2878 /***********************************************************************
2879 * FILEDLG95_LOOKIN_DrawItem
2881 * WM_DRAWITEM message handler
2883 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2885 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2886 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2887 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2888 RECT rectText;
2889 RECT rectIcon;
2890 SHFILEINFOW sfi;
2891 HIMAGELIST ilItemImage;
2892 int iIndentation;
2893 TEXTMETRICW tm;
2894 LPSFOLDER tmpFolder;
2895 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2897 TRACE("\n");
2899 if(pDIStruct->itemID == -1)
2900 return 0;
2902 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2903 pDIStruct->itemID)))
2904 return 0;
2907 if(pDIStruct->itemID == liInfos->uSelectedItem)
2909 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2911 &sfi,
2912 sizeof (sfi),
2913 SHGFI_PIDL | SHGFI_SMALLICON |
2914 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2915 SHGFI_DISPLAYNAME );
2917 else
2919 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2921 &sfi,
2922 sizeof (sfi),
2923 SHGFI_PIDL | SHGFI_SMALLICON |
2924 SHGFI_SYSICONINDEX |
2925 SHGFI_DISPLAYNAME);
2928 /* Is this item selected ? */
2929 if(pDIStruct->itemState & ODS_SELECTED)
2931 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2932 SetBkColor(pDIStruct->hDC,crHighLight);
2933 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2935 else
2937 SetTextColor(pDIStruct->hDC,crText);
2938 SetBkColor(pDIStruct->hDC,crWin);
2939 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2942 /* Do not indent item if drawing in the edit of the combo */
2943 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2945 iIndentation = 0;
2946 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2948 &sfi,
2949 sizeof (sfi),
2950 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2951 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2954 else
2956 iIndentation = tmpFolder->m_iIndent;
2958 /* Draw text and icon */
2960 /* Initialise the icon display area */
2961 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2962 rectIcon.top = pDIStruct->rcItem.top;
2963 rectIcon.right = rectIcon.left + ICONWIDTH;
2964 rectIcon.bottom = pDIStruct->rcItem.bottom;
2966 /* Initialise the text display area */
2967 GetTextMetricsW(pDIStruct->hDC, &tm);
2968 rectText.left = rectIcon.right;
2969 rectText.top =
2970 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2971 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2972 rectText.bottom =
2973 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2975 /* Draw the icon from the image list */
2976 ImageList_Draw(ilItemImage,
2977 sfi.iIcon,
2978 pDIStruct->hDC,
2979 rectIcon.left,
2980 rectIcon.top,
2981 ILD_TRANSPARENT );
2983 /* Draw the associated text */
2984 if(sfi.szDisplayName)
2985 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2988 return NOERROR;
2991 /***********************************************************************
2992 * FILEDLG95_LOOKIN_OnCommand
2994 * LookIn combo box WM_COMMAND message handler
2995 * If the function succeeds, the return value is nonzero.
2997 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2999 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3001 TRACE("%p\n", fodInfos);
3003 switch(wNotifyCode)
3005 case CBN_SELENDOK:
3007 LPSFOLDER tmpFolder;
3008 int iItem;
3010 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3012 if( iItem == CB_ERR) return FALSE;
3014 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3015 iItem)))
3016 return FALSE;
3019 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3020 tmpFolder->pidlItem,
3021 SBSP_ABSOLUTE)))
3023 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3024 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3025 return TRUE;
3027 break;
3031 return FALSE;
3034 /***********************************************************************
3035 * FILEDLG95_LOOKIN_AddItem
3037 * Adds an absolute pidl item to the lookin combo box
3038 * returns the index of the inserted item
3040 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3042 LPITEMIDLIST pidlNext;
3043 SHFILEINFOW sfi;
3044 SFOLDER *tmpFolder;
3045 LookInInfos *liInfos;
3047 TRACE("%08x\n", iInsertId);
3049 if(!pidl)
3050 return -1;
3052 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3053 return -1;
3055 tmpFolder = MemAlloc(sizeof(SFOLDER));
3056 tmpFolder->m_iIndent = 0;
3058 /* Calculate the indentation of the item in the lookin*/
3059 pidlNext = pidl;
3060 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3062 tmpFolder->m_iIndent++;
3065 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3067 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3068 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3070 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3071 SHGetFileInfoW((LPCWSTR)pidl,
3073 &sfi,
3074 sizeof(sfi),
3075 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3076 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3078 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3080 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3082 int iItemID;
3084 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3086 /* Add the item at the end of the list */
3087 if(iInsertId < 0)
3089 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3091 /* Insert the item at the iInsertId position*/
3092 else
3094 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3097 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3098 return iItemID;
3101 COMDLG32_SHFree( tmpFolder->pidlItem );
3102 MemFree( tmpFolder );
3103 return -1;
3107 /***********************************************************************
3108 * FILEDLG95_LOOKIN_InsertItemAfterParent
3110 * Insert an item below its parent
3112 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3115 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3116 int iParentPos;
3118 TRACE("\n");
3120 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3122 if(iParentPos < 0)
3124 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3127 /* Free pidlParent memory */
3128 COMDLG32_SHFree(pidlParent);
3130 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3133 /***********************************************************************
3134 * FILEDLG95_LOOKIN_SelectItem
3136 * Adds an absolute pidl item to the lookin combo box
3137 * returns the index of the inserted item
3139 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3141 int iItemPos;
3142 LookInInfos *liInfos;
3144 TRACE("\n");
3146 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3148 liInfos = GetPropA(hwnd,LookInInfosStr);
3150 if(iItemPos < 0)
3152 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3153 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3156 else
3158 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3159 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3161 int iRemovedItem;
3163 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3164 break;
3165 if(iRemovedItem < iItemPos)
3166 iItemPos--;
3170 CBSetCurSel(hwnd,iItemPos);
3171 liInfos->uSelectedItem = iItemPos;
3173 return 0;
3177 /***********************************************************************
3178 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3180 * Remove the item with an expansion level over iExpansionLevel
3182 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3184 int iItemPos;
3185 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3187 TRACE("\n");
3189 if(liInfos->iMaxIndentation <= 2)
3190 return -1;
3192 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3194 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3195 COMDLG32_SHFree(tmpFolder->pidlItem);
3196 MemFree(tmpFolder);
3197 CBDeleteString(hwnd,iItemPos);
3198 liInfos->iMaxIndentation--;
3200 return iItemPos;
3203 return -1;
3206 /***********************************************************************
3207 * FILEDLG95_LOOKIN_SearchItem
3209 * Search for pidl in the lookin combo box
3210 * returns the index of the found item
3212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3214 int i = 0;
3215 int iCount = CBGetCount(hwnd);
3217 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3219 if (iCount != CB_ERR)
3221 for(;i<iCount;i++)
3223 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3225 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3226 return i;
3227 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3228 return i;
3232 return -1;
3235 /***********************************************************************
3236 * FILEDLG95_LOOKIN_Clean
3238 * Clean the memory used by the lookin combo box
3240 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3242 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3243 int iPos;
3244 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3246 TRACE("\n");
3248 /* Delete each string of the combo and their associated data */
3249 if (iCount != CB_ERR)
3251 for(iPos = iCount-1;iPos>=0;iPos--)
3253 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3254 COMDLG32_SHFree(tmpFolder->pidlItem);
3255 MemFree(tmpFolder);
3256 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3260 /* LookInInfos structure */
3261 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3264 /***********************************************************************
3265 * FILEDLG95_FILENAME_FillFromSelection
3267 * fills the edit box from the cached DataObject
3269 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3271 FileOpenDlgInfos *fodInfos;
3272 LPITEMIDLIST pidl;
3273 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3274 WCHAR lpstrTemp[MAX_PATH];
3275 LPWSTR lpstrAllFile, lpstrCurrFile;
3277 TRACE("\n");
3278 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3280 /* Count how many files we have */
3281 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3283 /* calculate the string length, count files */
3284 if (nFileSelected >= 1)
3286 nLength += 3; /* first and last quotes, trailing \0 */
3287 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3289 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3291 if (pidl)
3293 /* get the total length of the selected file names */
3294 lpstrTemp[0] = '\0';
3295 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3297 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3299 nLength += lstrlenW( lpstrTemp ) + 3;
3300 nFiles++;
3302 COMDLG32_SHFree( pidl );
3307 /* allocate the buffer */
3308 if (nFiles <= 1) nLength = MAX_PATH;
3309 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3311 /* Generate the string for the edit control */
3312 if(nFiles >= 1)
3314 lpstrCurrFile = lpstrAllFile;
3315 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3317 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3319 if (pidl)
3321 /* get the file name */
3322 lpstrTemp[0] = '\0';
3323 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3325 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3327 if ( nFiles > 1)
3329 *lpstrCurrFile++ = '\"';
3330 lstrcpyW( lpstrCurrFile, lpstrTemp );
3331 lpstrCurrFile += lstrlenW( lpstrTemp );
3332 *lpstrCurrFile++ = '\"';
3333 *lpstrCurrFile++ = ' ';
3334 *lpstrCurrFile = 0;
3336 else
3338 lstrcpyW( lpstrAllFile, lpstrTemp );
3341 COMDLG32_SHFree( pidl );
3344 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3346 /* Select the file name like Windows does */
3347 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3349 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3353 /* copied from shell32 to avoid linking to it
3354 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3355 * is dependent on whether emulated OS is unicode or not.
3357 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3359 switch (src->uType)
3361 case STRRET_WSTR:
3362 lstrcpynW(dest, src->u.pOleStr, len);
3363 COMDLG32_SHFree(src->u.pOleStr);
3364 break;
3366 case STRRET_CSTR:
3367 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3368 dest[len-1] = 0;
3369 break;
3371 case STRRET_OFFSET:
3372 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3373 dest[len-1] = 0;
3374 break;
3376 default:
3377 FIXME("unknown type %x!\n", src->uType);
3378 if (len) *dest = '\0';
3379 return E_FAIL;
3381 return S_OK;
3384 /***********************************************************************
3385 * FILEDLG95_FILENAME_GetFileNames
3387 * Copies the filenames to a delimited string list.
3388 * The delimiter is specified by the parameter 'separator',
3389 * usually either a space or a nul
3391 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3393 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3394 UINT nStrCharCount = 0; /* index in src buffer */
3395 UINT nFileIndex = 0; /* index in dest buffer */
3396 UINT nFileCount = 0; /* number of files */
3397 UINT nStrLen = 0; /* length of string in edit control */
3398 LPWSTR lpstrEdit; /* buffer for string from edit control */
3400 TRACE("\n");
3402 /* get the filenames from the edit control */
3403 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3404 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3405 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3407 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3409 /* we might get single filename without any '"',
3410 * so we need nStrLen + terminating \0 + end-of-list \0 */
3411 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3412 *sizeUsed = 0;
3414 /* build delimited file list from filenames */
3415 while ( nStrCharCount <= nStrLen )
3417 if ( lpstrEdit[nStrCharCount]=='"' )
3419 nStrCharCount++;
3420 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3422 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3423 nStrCharCount++;
3425 (*lpstrFileList)[nFileIndex++] = 0;
3426 nFileCount++;
3428 nStrCharCount++;
3431 /* single, unquoted string */
3432 if ((nStrLen > 0) && (nFileIndex == 0) )
3434 lstrcpyW(*lpstrFileList, lpstrEdit);
3435 nFileIndex = lstrlenW(lpstrEdit) + 1;
3436 nFileCount = 1;
3439 /* trailing \0 */
3440 (*lpstrFileList)[nFileIndex++] = '\0';
3442 *sizeUsed = nFileIndex;
3443 MemFree(lpstrEdit);
3444 return nFileCount;
3447 #define SETDefFormatEtc(fe,cf,med) \
3449 (fe).cfFormat = cf;\
3450 (fe).dwAspect = DVASPECT_CONTENT; \
3451 (fe).ptd =NULL;\
3452 (fe).tymed = med;\
3453 (fe).lindex = -1;\
3457 * DATAOBJECT Helper functions
3460 /***********************************************************************
3461 * COMCTL32_ReleaseStgMedium
3463 * like ReleaseStgMedium from ole32
3465 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3467 if(medium.pUnkForRelease)
3469 IUnknown_Release(medium.pUnkForRelease);
3471 else
3473 GlobalUnlock(medium.u.hGlobal);
3474 GlobalFree(medium.u.hGlobal);
3478 /***********************************************************************
3479 * GetPidlFromDataObject
3481 * Return pidl(s) by number from the cached DataObject
3483 * nPidlIndex=0 gets the fully qualified root path
3485 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3488 STGMEDIUM medium;
3489 FORMATETC formatetc;
3490 LPITEMIDLIST pidl = NULL;
3492 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3494 if (!doSelected)
3495 return NULL;
3497 /* Set the FORMATETC structure*/
3498 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3500 /* Get the pidls from IDataObject */
3501 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3503 LPIDA cida = GlobalLock(medium.u.hGlobal);
3504 if(nPidlIndex <= cida->cidl)
3506 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3508 COMCTL32_ReleaseStgMedium(medium);
3510 return pidl;
3513 /***********************************************************************
3514 * GetNumSelected
3516 * Return the number of selected items in the DataObject.
3519 static UINT GetNumSelected( IDataObject *doSelected )
3521 UINT retVal = 0;
3522 STGMEDIUM medium;
3523 FORMATETC formatetc;
3525 TRACE("sv=%p\n", doSelected);
3527 if (!doSelected) return 0;
3529 /* Set the FORMATETC structure*/
3530 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3532 /* Get the pidls from IDataObject */
3533 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3535 LPIDA cida = GlobalLock(medium.u.hGlobal);
3536 retVal = cida->cidl;
3537 COMCTL32_ReleaseStgMedium(medium);
3538 return retVal;
3540 return 0;
3544 * TOOLS
3547 /***********************************************************************
3548 * GetName
3550 * Get the pidl's display name (relative to folder) and
3551 * put it in lpstrFileName.
3553 * Return NOERROR on success,
3554 * E_FAIL otherwise
3557 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3559 STRRET str;
3560 HRESULT hRes;
3562 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3564 if(!lpsf)
3566 SHGetDesktopFolder(&lpsf);
3567 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3568 IShellFolder_Release(lpsf);
3569 return hRes;
3572 /* Get the display name of the pidl relative to the folder */
3573 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3575 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3577 return E_FAIL;
3580 /***********************************************************************
3581 * GetShellFolderFromPidl
3583 * pidlRel is the item pidl relative
3584 * Return the IShellFolder of the absolute pidl
3586 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3588 IShellFolder *psf = NULL,*psfParent;
3590 TRACE("%p\n", pidlAbs);
3592 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3594 psf = psfParent;
3595 if(pidlAbs && pidlAbs->mkid.cb)
3597 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3599 IShellFolder_Release(psfParent);
3600 return psf;
3603 /* return the desktop */
3604 return psfParent;
3606 return NULL;
3609 /***********************************************************************
3610 * GetParentPidl
3612 * Return the LPITEMIDLIST to the parent of the pidl in the list
3614 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3616 LPITEMIDLIST pidlParent;
3618 TRACE("%p\n", pidl);
3620 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3621 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3623 return pidlParent;
3626 /***********************************************************************
3627 * GetPidlFromName
3629 * returns the pidl of the file name relative to folder
3630 * NULL if an error occurred
3632 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3634 LPITEMIDLIST pidl = NULL;
3635 ULONG ulEaten;
3637 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3639 if(!lpcstrFileName) return NULL;
3640 if(!*lpcstrFileName) return NULL;
3642 if(!lpsf)
3644 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3645 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3646 IShellFolder_Release(lpsf);
3649 else
3651 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3653 return pidl;
3658 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3660 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3661 HRESULT ret;
3663 TRACE("%p, %p\n", psf, pidl);
3665 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3667 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3668 /* see documentation shell 4.1*/
3669 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3672 /***********************************************************************
3673 * BrowseSelectedFolder
3675 static BOOL BrowseSelectedFolder(HWND hwnd)
3677 BOOL bBrowseSelFolder = FALSE;
3678 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3680 TRACE("\n");
3682 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3684 LPITEMIDLIST pidlSelection;
3686 /* get the file selected */
3687 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3688 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3690 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3691 pidlSelection, SBSP_RELATIVE ) ) )
3693 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3694 ' ','n','o','t',' ','e','x','i','s','t',0};
3695 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3697 bBrowseSelFolder = TRUE;
3698 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3699 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3701 COMDLG32_SHFree( pidlSelection );
3704 return bBrowseSelFolder;
3708 * Memory allocation methods */
3709 static void *MemAlloc(UINT size)
3711 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3714 static void MemFree(void *mem)
3716 HeapFree(GetProcessHeap(),0,mem);
3720 * Old-style (win3.1) dialogs */
3722 /***********************************************************************
3723 * FD32_GetTemplate [internal]
3725 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3726 * by a 32 bits application
3729 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3731 LPOPENFILENAMEW ofnW = lfs->ofnW;
3732 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3733 HANDLE hDlgTmpl;
3735 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3737 if (!(lfs->template = LockResource( ofnW->hInstance )))
3739 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3740 return FALSE;
3743 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3745 HRSRC hResInfo;
3746 if (priv->ofnA)
3747 hResInfo = FindResourceA(priv->ofnA->hInstance,
3748 priv->ofnA->lpTemplateName,
3749 (LPSTR)RT_DIALOG);
3750 else
3751 hResInfo = FindResourceW(ofnW->hInstance,
3752 ofnW->lpTemplateName,
3753 (LPWSTR)RT_DIALOG);
3754 if (!hResInfo)
3756 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3757 return FALSE;
3759 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3760 hResInfo)) ||
3761 !(lfs->template = LockResource(hDlgTmpl)))
3763 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3764 return FALSE;
3766 } else { /* get it from internal Wine resource */
3767 HRSRC hResInfo;
3768 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3769 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3771 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3772 return FALSE;
3774 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3775 !(lfs->template = LockResource( hDlgTmpl )))
3777 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3778 return FALSE;
3781 return TRUE;
3785 /************************************************************************
3786 * FD32_Init [internal]
3787 * called from the common 16/32 code to initialize 32 bit data
3789 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3791 BOOL IsUnicode = (BOOL) data;
3792 PFD32_PRIVATE priv;
3794 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3795 lfs->private1632 = priv;
3796 if (NULL == lfs->private1632) return FALSE;
3797 if (IsUnicode)
3799 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3800 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3801 if (lfs->ofnW->lpfnHook)
3802 lfs->hook = TRUE;
3804 else
3806 priv->ofnA = (LPOPENFILENAMEA) lParam;
3807 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3808 if (priv->ofnA->lpfnHook)
3809 lfs->hook = TRUE;
3810 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3811 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3814 if (! FD32_GetTemplate(lfs)) return FALSE;
3816 return TRUE;
3819 /***********************************************************************
3820 * FD32_CallWindowProc [internal]
3822 * called from the common 16/32 code to call the appropriate hook
3824 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3825 LPARAM lParam)
3827 BOOL ret;
3828 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3830 if (priv->ofnA)
3832 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3833 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3834 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3835 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3836 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3837 return ret;
3840 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3841 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3842 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3843 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3844 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3845 return ret;
3848 /***********************************************************************
3849 * FD32_UpdateResult [internal]
3850 * update the real client structures if any
3852 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3854 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3855 LPOPENFILENAMEW ofnW = lfs->ofnW;
3857 if (priv->ofnA)
3859 LPSTR lpszTemp;
3860 if (ofnW->nMaxFile &&
3861 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3862 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3863 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3865 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3866 /* set filename offset */
3867 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3868 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3870 /* set extension offset */
3871 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3872 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3876 /***********************************************************************
3877 * FD32_UpdateFileTitle [internal]
3878 * update the real client structures if any
3880 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3882 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3883 LPOPENFILENAMEW ofnW = lfs->ofnW;
3885 if (priv->ofnA)
3887 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3888 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3889 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3894 /***********************************************************************
3895 * FD32_SendLbGetCurSel [internal]
3896 * retrieve selected listbox item
3898 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3900 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3904 /************************************************************************
3905 * FD32_Destroy [internal]
3906 * called from the common 16/32 code to cleanup 32 bit data
3908 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3910 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3912 /* if ofnW has been allocated, have to free everything in it */
3913 if (NULL != priv && NULL != priv->ofnA)
3915 FD31_FreeOfnW(lfs->ofnW);
3916 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3920 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3922 callbacks->Init = FD32_Init;
3923 callbacks->CWP = FD32_CallWindowProc;
3924 callbacks->UpdateResult = FD32_UpdateResult;
3925 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3926 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3927 callbacks->Destroy = FD32_Destroy;
3930 /***********************************************************************
3931 * FD32_WMMeasureItem [internal]
3933 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3935 LPMEASUREITEMSTRUCT lpmeasure;
3937 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3938 lpmeasure->itemHeight = FD31_GetFldrHeight();
3939 return TRUE;
3943 /***********************************************************************
3944 * FileOpenDlgProc [internal]
3945 * Used for open and save, in fact.
3947 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3948 WPARAM wParam, LPARAM lParam)
3950 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3952 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3953 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3955 INT_PTR lRet;
3956 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3957 if (lRet)
3958 return lRet; /* else continue message processing */
3960 switch (wMsg)
3962 case WM_INITDIALOG:
3963 return FD31_WMInitDialog(hWnd, wParam, lParam);
3965 case WM_MEASUREITEM:
3966 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3968 case WM_DRAWITEM:
3969 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3971 case WM_COMMAND:
3972 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3973 #if 0
3974 case WM_CTLCOLOR:
3975 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3976 switch (HIWORD(lParam))
3978 case CTLCOLOR_BTN:
3979 SetTextColor((HDC16)wParam, 0x00000000);
3980 return hGRAYBrush;
3981 case CTLCOLOR_STATIC:
3982 SetTextColor((HDC16)wParam, 0x00000000);
3983 return hGRAYBrush;
3985 break;
3986 #endif
3988 return FALSE;
3992 /***********************************************************************
3993 * GetFileName31A [internal]
3995 * Creates a win31 style dialog box for the user to select a file to open/save.
3997 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3998 UINT dlgType /* type dialogue : open/save */
4001 HINSTANCE hInst;
4002 BOOL bRet = FALSE;
4003 PFD31_DATA lfs;
4004 FD31_CALLBACKS callbacks;
4006 if (!lpofn || !FD31_Init()) return FALSE;
4008 TRACE("ofn flags %08x\n", lpofn->Flags);
4009 FD32_SetupCallbacks(&callbacks);
4010 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
4011 if (lfs)
4013 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4014 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
4015 FD32_FileOpenDlgProc, (LPARAM)lfs);
4016 FD31_DestroyPrivate(lfs);
4019 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4020 return bRet;
4023 /***********************************************************************
4024 * GetFileName31W [internal]
4026 * Creates a win31 style dialog box for the user to select a file to open/save
4028 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4029 UINT dlgType /* type dialogue : open/save */
4032 HINSTANCE hInst;
4033 BOOL bRet = FALSE;
4034 PFD31_DATA lfs;
4035 FD31_CALLBACKS callbacks;
4037 if (!lpofn || !FD31_Init()) return FALSE;
4039 FD32_SetupCallbacks(&callbacks);
4040 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
4041 if (lfs)
4043 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4044 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
4045 FD32_FileOpenDlgProc, (LPARAM)lfs);
4046 FD31_DestroyPrivate(lfs);
4049 TRACE("file %s, file offset %d, ext offset %d\n",
4050 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4051 return bRet;
4054 /* ------------------ APIs ---------------------- */
4056 /***********************************************************************
4057 * GetOpenFileNameA (COMDLG32.@)
4059 * Creates a dialog box for the user to select a file to open.
4061 * RETURNS
4062 * TRUE on success: user enters a valid file
4063 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4066 BOOL WINAPI GetOpenFileNameA(
4067 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4069 BOOL win16look = FALSE;
4071 TRACE("flags %08x\n", ofn->Flags);
4073 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4074 if (ofn->Flags & OFN_FILEMUSTEXIST)
4075 ofn->Flags |= OFN_PATHMUSTEXIST;
4077 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4078 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4080 if (win16look)
4081 return GetFileName31A(ofn, OPEN_DIALOG);
4082 else
4083 return GetFileDialog95A(ofn, OPEN_DIALOG);
4086 /***********************************************************************
4087 * GetOpenFileNameW (COMDLG32.@)
4089 * Creates a dialog box for the user to select a file to open.
4091 * RETURNS
4092 * TRUE on success: user enters a valid file
4093 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4096 BOOL WINAPI GetOpenFileNameW(
4097 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4099 BOOL win16look = FALSE;
4101 TRACE("flags %08x\n", ofn->Flags);
4103 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4104 if (ofn->Flags & OFN_FILEMUSTEXIST)
4105 ofn->Flags |= OFN_PATHMUSTEXIST;
4107 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4108 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4110 if (win16look)
4111 return GetFileName31W(ofn, OPEN_DIALOG);
4112 else
4113 return GetFileDialog95W(ofn, OPEN_DIALOG);
4117 /***********************************************************************
4118 * GetSaveFileNameA (COMDLG32.@)
4120 * Creates a dialog box for the user to select a file to save.
4122 * RETURNS
4123 * TRUE on success: user enters a valid file
4124 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4127 BOOL WINAPI GetSaveFileNameA(
4128 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4130 BOOL win16look = FALSE;
4132 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4133 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4135 if (win16look)
4136 return GetFileName31A(ofn, SAVE_DIALOG);
4137 else
4138 return GetFileDialog95A(ofn, SAVE_DIALOG);
4141 /***********************************************************************
4142 * GetSaveFileNameW (COMDLG32.@)
4144 * Creates a dialog box for the user to select a file to save.
4146 * RETURNS
4147 * TRUE on success: user enters a valid file
4148 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4151 BOOL WINAPI GetSaveFileNameW(
4152 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4154 BOOL win16look = FALSE;
4156 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4157 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4159 if (win16look)
4160 return GetFileName31W(ofn, SAVE_DIALOG);
4161 else
4162 return GetFileDialog95W(ofn, SAVE_DIALOG);
4165 /***********************************************************************
4166 * GetFileTitleA (COMDLG32.@)
4168 * See GetFileTitleW.
4170 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4172 int ret;
4173 UNICODE_STRING strWFile;
4174 LPWSTR lpWTitle;
4176 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4177 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4178 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4179 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4180 RtlFreeUnicodeString( &strWFile );
4181 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4182 return ret;
4186 /***********************************************************************
4187 * GetFileTitleW (COMDLG32.@)
4189 * Get the name of a file.
4191 * PARAMS
4192 * lpFile [I] name and location of file
4193 * lpTitle [O] returned file name
4194 * cbBuf [I] buffer size of lpTitle
4196 * RETURNS
4197 * Success: zero
4198 * Failure: negative number.
4200 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4202 int i, len;
4203 static const WCHAR brkpoint[] = {'*','[',']',0};
4204 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4206 if(lpFile == NULL || lpTitle == NULL)
4207 return -1;
4209 len = lstrlenW(lpFile);
4211 if (len == 0)
4212 return -1;
4214 if(strpbrkW(lpFile, brkpoint))
4215 return -1;
4217 len--;
4219 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4220 return -1;
4222 for(i = len; i >= 0; i--)
4224 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4226 i++;
4227 break;
4231 if(i == -1)
4232 i++;
4234 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4236 len = lstrlenW(lpFile+i)+1;
4237 if(cbBuf < len)
4238 return len;
4240 lstrcpyW(lpTitle, &lpFile[i]);
4241 return 0;