push c4c845830c6aff14e1b16bbb8b4a57a7e0d6213f
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blob041d75c283115f150e350406d96ee5c93a296211
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;
281 /* old style hook messages */
282 if (IsHooked(fodInfos))
284 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
285 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
286 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
287 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
290 /* Some shell namespace extensions depend on COM being initialized. */
291 hr = OleInitialize(NULL);
293 if (fodInfos->unicode)
294 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
295 template,
296 fodInfos->ofnInfos->hwndOwner,
297 FileOpenDlgProc95,
298 (LPARAM) fodInfos);
299 else
300 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
301 template,
302 fodInfos->ofnInfos->hwndOwner,
303 FileOpenDlgProc95,
304 (LPARAM) fodInfos);
305 if (SUCCEEDED(hr))
306 OleUninitialize();
308 /* Unable to create the dialog */
309 if( lRes == -1)
310 return FALSE;
312 return lRes;
315 /***********************************************************************
316 * GetFileDialog95A
318 * Call GetFileName95 with this structure and clean the memory.
320 * IN : The OPENFILENAMEA initialisation structure passed to
321 * GetOpenFileNameA win api function (see filedlg.c)
323 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
325 BOOL ret;
326 FileOpenDlgInfos fodInfos;
327 LPSTR lpstrSavDir = NULL;
328 LPWSTR title = NULL;
329 LPWSTR defext = NULL;
330 LPWSTR filter = NULL;
331 LPWSTR customfilter = NULL;
333 /* Initialize CommDlgExtendedError() */
334 COMDLG32_SetCommDlgExtendedError(0);
336 /* Initialize FileOpenDlgInfos structure */
337 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
339 /* Pass in the original ofn */
340 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
342 /* save current directory */
343 if (ofn->Flags & OFN_NOCHANGEDIR)
345 lpstrSavDir = MemAlloc(MAX_PATH);
346 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
349 fodInfos.unicode = FALSE;
351 /* convert all the input strings to unicode */
352 if(ofn->lpstrInitialDir)
354 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
355 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
358 else
359 fodInfos.initdir = NULL;
361 if(ofn->lpstrFile)
363 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
364 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
366 else
367 fodInfos.filename = NULL;
369 if(ofn->lpstrDefExt)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
372 defext = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
375 fodInfos.defext = defext;
377 if(ofn->lpstrTitle)
379 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
380 title = MemAlloc((len+1)*sizeof(WCHAR));
381 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
383 fodInfos.title = title;
385 if (ofn->lpstrFilter)
387 LPCSTR s;
388 int n, len;
390 /* filter is a list... title\0ext\0......\0\0 */
391 s = ofn->lpstrFilter;
392 while (*s) s = s+strlen(s)+1;
393 s++;
394 n = s - ofn->lpstrFilter;
395 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
396 filter = MemAlloc(len*sizeof(WCHAR));
397 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
399 fodInfos.filter = filter;
401 /* convert lpstrCustomFilter */
402 if (ofn->lpstrCustomFilter)
404 LPCSTR s;
405 int n, len;
407 /* customfilter contains a pair of strings... title\0ext\0 */
408 s = ofn->lpstrCustomFilter;
409 if (*s) s = s+strlen(s)+1;
410 if (*s) s = s+strlen(s)+1;
411 n = s - ofn->lpstrCustomFilter;
412 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
413 customfilter = MemAlloc(len*sizeof(WCHAR));
414 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
416 fodInfos.customfilter = customfilter;
418 /* Initialize the dialog property */
419 fodInfos.DlgInfos.dwDlgProp = 0;
420 fodInfos.DlgInfos.hwndCustomDlg = NULL;
422 switch(iDlgType)
424 case OPEN_DIALOG :
425 ret = GetFileName95(&fodInfos);
426 break;
427 case SAVE_DIALOG :
428 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
429 ret = GetFileName95(&fodInfos);
430 break;
431 default :
432 ret = 0;
435 if (lpstrSavDir)
437 SetCurrentDirectoryA(lpstrSavDir);
438 MemFree(lpstrSavDir);
441 MemFree(title);
442 MemFree(defext);
443 MemFree(filter);
444 MemFree(customfilter);
445 MemFree(fodInfos.initdir);
446 MemFree(fodInfos.filename);
448 TRACE("selected file: %s\n",ofn->lpstrFile);
450 return ret;
453 /***********************************************************************
454 * GetFileDialog95W
456 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
457 * Call GetFileName95 with this structure and clean the memory.
460 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
462 BOOL ret;
463 FileOpenDlgInfos fodInfos;
464 LPWSTR lpstrSavDir = NULL;
466 /* Initialize CommDlgExtendedError() */
467 COMDLG32_SetCommDlgExtendedError(0);
469 /* Initialize FileOpenDlgInfos structure */
470 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
472 /* Pass in the original ofn */
473 fodInfos.ofnInfos = ofn;
475 fodInfos.title = ofn->lpstrTitle;
476 fodInfos.defext = ofn->lpstrDefExt;
477 fodInfos.filter = ofn->lpstrFilter;
478 fodInfos.customfilter = ofn->lpstrCustomFilter;
480 /* convert string arguments, save others */
481 if(ofn->lpstrFile)
483 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
484 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
486 else
487 fodInfos.filename = NULL;
489 if(ofn->lpstrInitialDir)
491 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
492 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
493 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
494 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
496 else
497 fodInfos.initdir = NULL;
499 /* save current directory */
500 if (ofn->Flags & OFN_NOCHANGEDIR)
502 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
503 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
506 fodInfos.unicode = TRUE;
508 switch(iDlgType)
510 case OPEN_DIALOG :
511 ret = GetFileName95(&fodInfos);
512 break;
513 case SAVE_DIALOG :
514 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
515 ret = GetFileName95(&fodInfos);
516 break;
517 default :
518 ret = 0;
521 if (lpstrSavDir)
523 SetCurrentDirectoryW(lpstrSavDir);
524 MemFree(lpstrSavDir);
527 /* restore saved IN arguments and convert OUT arguments back */
528 MemFree(fodInfos.filename);
529 MemFree(fodInfos.initdir);
530 return ret;
533 /******************************************************************************
534 * COMDLG32_GetDisplayNameOf [internal]
536 * Helper function to get the display name for a pidl.
538 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
539 LPSHELLFOLDER psfDesktop;
540 STRRET strret;
542 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
543 return FALSE;
545 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
546 IShellFolder_Release(psfDesktop);
547 return FALSE;
550 IShellFolder_Release(psfDesktop);
551 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
554 /***********************************************************************
555 * ArrangeCtrlPositions [internal]
557 * NOTE: Do not change anything here without a lot of testing.
559 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
561 HWND hwndChild, hwndStc32;
562 RECT rectParent, rectChild, rectStc32;
563 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
565 /* Take into account if open as read only checkbox and help button
566 * are hidden
568 if (hide_help)
570 RECT rectHelp, rectCancel;
571 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
572 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
573 /* subtract the height of the help button plus the space between
574 * the help button and the cancel button to the height of the dialog
576 help_fixup = rectHelp.bottom - rectCancel.bottom;
580 There are two possibilities to add components to the default file dialog box.
582 By default, all the new components are added below the standard dialog box (the else case).
584 However, if there is a static text component with the stc32 id, a special case happens.
585 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
586 in the window and the cx and cy indicate how to size the window.
587 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
588 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
592 GetClientRect(hwndParentDlg, &rectParent);
594 /* when arranging controls we have to use fixed parent size */
595 rectParent.bottom -= help_fixup;
597 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
598 if (hwndStc32)
600 GetWindowRect(hwndStc32, &rectStc32);
601 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
603 /* set the size of the stc32 control according to the size of
604 * client area of the parent dialog
606 SetWindowPos(hwndStc32, 0,
607 0, 0,
608 rectParent.right, rectParent.bottom,
609 SWP_NOMOVE | SWP_NOZORDER);
611 else
612 SetRectEmpty(&rectStc32);
614 /* this part moves controls of the child dialog */
615 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
616 while (hwndChild)
618 if (hwndChild != hwndStc32)
620 GetWindowRect(hwndChild, &rectChild);
621 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
623 /* move only if stc32 exist */
624 if (hwndStc32 && rectChild.left > rectStc32.right)
626 LONG old_left = rectChild.left;
628 /* move to the right of visible controls of the parent dialog */
629 rectChild.left += rectParent.right;
630 rectChild.left -= rectStc32.right;
632 child_width_fixup = rectChild.left - old_left;
634 /* move even if stc32 doesn't exist */
635 if (rectChild.top >= rectStc32.bottom)
637 LONG old_top = rectChild.top;
639 /* move below visible controls of the parent dialog */
640 rectChild.top += rectParent.bottom;
641 rectChild.top -= rectStc32.bottom - rectStc32.top;
643 child_height_fixup = rectChild.top - old_top;
646 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
647 0, 0, SWP_NOSIZE | SWP_NOZORDER);
649 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
652 /* this part moves controls of the parent dialog */
653 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
654 while (hwndChild)
656 if (hwndChild != hwndChildDlg)
658 GetWindowRect(hwndChild, &rectChild);
659 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
661 /* left,top of stc32 marks the position of controls
662 * from the parent dialog
664 rectChild.left += rectStc32.left;
665 rectChild.top += rectStc32.top;
667 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
668 0, 0, SWP_NOSIZE | SWP_NOZORDER);
670 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
673 /* calculate the size of the resulting dialog */
675 /* here we have to use original parent size */
676 GetClientRect(hwndParentDlg, &rectParent);
677 GetClientRect(hwndChildDlg, &rectChild);
679 if (hwndStc32)
681 rectChild.right += child_width_fixup;
682 rectChild.bottom += child_height_fixup;
684 if (rectParent.right > rectChild.right)
686 rectParent.right += rectChild.right;
687 rectParent.right -= rectStc32.right - rectStc32.left;
689 else
691 rectParent.right = rectChild.right;
694 if (rectParent.bottom > rectChild.bottom)
696 rectParent.bottom += rectChild.bottom;
697 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
699 else
701 /* child dialog is higher, unconditionally set new dialog
702 * height to its size (help_fixup will be subtracted below)
704 rectParent.bottom = rectChild.bottom + help_fixup;
707 else
709 rectParent.bottom += rectChild.bottom;
712 /* finally use fixed parent size */
713 rectParent.bottom -= help_fixup;
715 /* set the size of the parent dialog */
716 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
717 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
718 SetWindowPos(hwndParentDlg, 0,
719 0, 0,
720 rectParent.right - rectParent.left,
721 rectParent.bottom - rectParent.top,
722 SWP_NOMOVE | SWP_NOZORDER);
725 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
727 switch(uMsg) {
728 case WM_INITDIALOG:
729 return TRUE;
731 return FALSE;
734 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
736 LPCVOID template;
737 HRSRC hRes;
738 HANDLE hDlgTmpl = 0;
739 HWND hChildDlg = 0;
741 TRACE("\n");
744 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
745 * structure's hInstance parameter is not a HINSTANCE, but
746 * instead a pointer to a template resource to use.
748 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
750 HINSTANCE hinst;
751 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
753 hinst = COMDLG32_hInstance;
754 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
756 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
757 return NULL;
760 else
762 hinst = fodInfos->ofnInfos->hInstance;
763 if(fodInfos->unicode)
765 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
766 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
768 else
770 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
771 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
773 if (!hRes)
775 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
776 return NULL;
778 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
779 !(template = LockResource( hDlgTmpl )))
781 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
782 return NULL;
785 if (fodInfos->unicode)
786 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
787 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
788 (LPARAM)fodInfos->ofnInfos);
789 else
790 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
791 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
792 (LPARAM)fodInfos->ofnInfos);
793 return hChildDlg;
795 else if( IsHooked(fodInfos))
797 RECT rectHwnd;
798 struct {
799 DLGTEMPLATE tmplate;
800 WORD menu,class,title;
801 } temp;
802 GetClientRect(hwnd,&rectHwnd);
803 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
804 temp.tmplate.dwExtendedStyle = 0;
805 temp.tmplate.cdit = 0;
806 temp.tmplate.x = 0;
807 temp.tmplate.y = 0;
808 temp.tmplate.cx = 0;
809 temp.tmplate.cy = 0;
810 temp.menu = temp.class = temp.title = 0;
812 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
813 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
815 return hChildDlg;
817 return NULL;
820 /***********************************************************************
821 * SendCustomDlgNotificationMessage
823 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
826 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
828 LRESULT hook_result = 0;
829 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
831 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
833 if(!fodInfos) return 0;
835 if(fodInfos->DlgInfos.hwndCustomDlg)
837 TRACE("CALL NOTIFY for %x\n", uCode);
838 if(fodInfos->unicode)
840 OFNOTIFYW ofnNotify;
841 ofnNotify.hdr.hwndFrom=hwndParentDlg;
842 ofnNotify.hdr.idFrom=0;
843 ofnNotify.hdr.code = uCode;
844 ofnNotify.lpOFN = fodInfos->ofnInfos;
845 ofnNotify.pszFile = NULL;
846 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
848 else
850 OFNOTIFYA ofnNotify;
851 ofnNotify.hdr.hwndFrom=hwndParentDlg;
852 ofnNotify.hdr.idFrom=0;
853 ofnNotify.hdr.code = uCode;
854 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
855 ofnNotify.pszFile = NULL;
856 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
858 TRACE("RET NOTIFY\n");
860 TRACE("Retval: 0x%08lx\n", hook_result);
861 return hook_result;
864 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
866 UINT len, total;
867 WCHAR *p, *buffer;
868 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
870 TRACE("CDM_GETFILEPATH:\n");
872 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
873 return -1;
875 /* get path and filenames */
876 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
877 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
878 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
879 if (len)
881 p = buffer + strlenW(buffer);
882 *p++ = '\\';
883 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
885 if (fodInfos->unicode)
887 total = strlenW( buffer) + 1;
888 if (result) lstrcpynW( result, buffer, size );
889 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
891 else
893 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
894 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
895 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
897 HeapFree( GetProcessHeap(), 0, buffer );
898 return total;
901 /***********************************************************************
902 * FILEDLG95_HandleCustomDialogMessages
904 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
906 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
908 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
909 WCHAR lpstrPath[MAX_PATH];
910 INT_PTR retval;
912 if(!fodInfos) return FALSE;
914 switch(uMsg)
916 case CDM_GETFILEPATH:
917 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
918 break;
920 case CDM_GETFOLDERPATH:
921 TRACE("CDM_GETFOLDERPATH:\n");
922 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
923 if (lParam)
925 if (fodInfos->unicode)
926 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
927 else
928 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
929 (LPSTR)lParam, (int)wParam, NULL, NULL);
931 retval = lstrlenW(lpstrPath);
932 break;
934 case CDM_GETFOLDERIDLIST:
935 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
936 if (retval <= wParam)
937 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
938 break;
940 case CDM_GETSPEC:
941 TRACE("CDM_GETSPEC:\n");
942 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
943 if (lParam)
945 if (fodInfos->unicode)
946 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
947 else
948 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
950 break;
952 case CDM_SETCONTROLTEXT:
953 TRACE("CDM_SETCONTROLTEXT:\n");
954 if ( lParam )
956 if( fodInfos->unicode )
957 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
958 else
959 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
961 retval = TRUE;
962 break;
964 case CDM_HIDECONTROL:
965 /* MSDN states that it should fail for not OFN_EXPLORER case */
966 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
968 HWND control = GetDlgItem( hwnd, wParam );
969 if (control) ShowWindow( control, SW_HIDE );
970 retval = TRUE;
972 else retval = FALSE;
973 break;
975 default:
976 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
977 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
978 return FALSE;
980 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
981 return TRUE;
984 /***********************************************************************
985 * FILEDLG95_OnWMGetMMI
987 * WM_GETMINMAXINFO message handler for resizable dialogs
989 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
991 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
992 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
993 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
995 mmiptr->ptMinTrackSize = fodInfos->initial_size;
997 return TRUE;
1000 /***********************************************************************
1001 * FILEDLG95_OnWMSize
1003 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
1005 * FIXME: this could be made more elaborate. Now use a simple scheme
1006 * where the file view is enlarged and the controls are either moved
1007 * vertically or horizontally to get out of the way. Only the "grip"
1008 * is moved in both directions to stay in the corner.
1010 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1012 RECT rc, rcview;
1013 int chgx, chgy;
1014 HWND ctrl;
1015 HDWP hdwp;
1016 FileOpenDlgInfos *fodInfos;
1018 if( wParam != SIZE_RESTORED) return FALSE;
1019 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1020 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1021 /* get the new dialog rectangle */
1022 GetWindowRect( hwnd, &rc);
1023 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1024 rc.right -rc.left, rc.bottom -rc.top);
1025 /* not initialized yet */
1026 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1027 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1028 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1029 return FALSE;
1030 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1031 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1032 fodInfos->sizedlg.cx = rc.right - rc.left;
1033 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1034 /* change the size of the view window */
1035 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1036 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1037 hdwp = BeginDeferWindowPos( 10);
1038 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1039 rcview.right - rcview.left + chgx,
1040 rcview.bottom - rcview.top + chgy,
1041 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1042 /* change position and sizes of the controls */
1043 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1045 int ctrlid = GetDlgCtrlID( ctrl);
1046 GetWindowRect( ctrl, &rc);
1047 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1048 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1050 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1051 0, 0,
1052 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1054 else if( rc.top > rcview.bottom)
1056 /* if it was below the shell view
1057 * move to bottom */
1058 switch( ctrlid)
1060 /* file name box and file types combo change also width */
1061 case edt1:
1062 case cmb1:
1063 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1064 rc.right - rc.left + chgx, rc.bottom - rc.top,
1065 SWP_NOACTIVATE | SWP_NOZORDER);
1066 break;
1067 /* then these buttons must move out of the way */
1068 case IDOK:
1069 case IDCANCEL:
1070 case pshHelp:
1071 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1072 0, 0,
1073 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1074 break;
1075 default:
1076 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1077 0, 0,
1078 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1081 else if( rc.left > rcview.right)
1083 /* if it was to the right of the shell view
1084 * move to right */
1085 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1086 0, 0,
1087 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1089 else
1090 /* special cases */
1092 switch( ctrlid)
1094 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1095 case IDC_LOOKIN:
1096 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1097 rc.right - rc.left + chgx, rc.bottom - rc.top,
1098 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1099 break;
1100 case IDC_TOOLBARSTATIC:
1101 case IDC_TOOLBAR:
1102 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1103 0, 0,
1104 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1105 break;
1106 #endif
1107 /* not resized in windows. Since wine uses this invisible control
1108 * to size the browser view it needs to be resized */
1109 case IDC_SHELLSTATIC:
1110 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1111 rc.right - rc.left + chgx,
1112 rc.bottom - rc.top + chgy,
1113 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1114 break;
1118 if(fodInfos->DlgInfos.hwndCustomDlg &&
1119 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1121 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1122 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1124 GetWindowRect( ctrl, &rc);
1125 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1126 if( rc.top > rcview.bottom)
1128 /* if it was below the shell view
1129 * move to bottom */
1130 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1131 rc.right - rc.left, rc.bottom - rc.top,
1132 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1134 else if( rc.left > rcview.right)
1136 /* if it was to the right of the shell view
1137 * move to right */
1138 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1139 rc.right - rc.left, rc.bottom - rc.top,
1140 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1143 /* size the custom dialog at the end: some applications do some
1144 * control re-arranging at this point */
1145 GetClientRect(hwnd, &rc);
1146 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1147 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1149 EndDeferWindowPos( hdwp);
1150 /* should not be needed */
1151 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1152 return TRUE;
1155 /***********************************************************************
1156 * FileOpenDlgProc95
1158 * File open dialog procedure
1160 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1162 #if 0
1163 TRACE("%p 0x%04x\n", hwnd, uMsg);
1164 #endif
1166 switch(uMsg)
1168 case WM_INITDIALOG:
1170 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1171 RECT rc;
1172 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1173 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1175 /* Adds the FileOpenDlgInfos in the property list of the dialog
1176 so it will be easily accessible through a GetPropA(...) */
1177 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1179 FILEDLG95_InitControls(hwnd);
1181 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1183 GetWindowRect( hwnd, &rc);
1184 fodInfos->DlgInfos.hwndGrip =
1185 CreateWindowExA( 0, "SCROLLBAR", NULL,
1186 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1187 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1188 rc.right - gripx, rc.bottom - gripy,
1189 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1192 fodInfos->DlgInfos.hwndCustomDlg =
1193 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1195 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1196 FILEDLG95_FillControls(hwnd, wParam, lParam);
1198 if( fodInfos->DlgInfos.hwndCustomDlg)
1199 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1201 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1202 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1203 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1206 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1208 GetWindowRect( hwnd, &rc);
1209 fodInfos->sizedlg.cx = rc.right - rc.left;
1210 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1211 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1212 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1213 GetClientRect( hwnd, &rc);
1214 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1215 rc.right - gripx, rc.bottom - gripy,
1216 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1217 /* resize the dialog to the previous invocation */
1218 if( MemDialogSize.cx && MemDialogSize.cy)
1219 SetWindowPos( hwnd, NULL,
1220 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1221 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1224 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1225 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1227 return 0;
1229 case WM_SIZE:
1230 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1231 case WM_GETMINMAXINFO:
1232 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1233 case WM_COMMAND:
1234 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1235 case WM_DRAWITEM:
1237 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1239 case IDC_LOOKIN:
1240 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1241 return TRUE;
1244 return FALSE;
1246 case WM_GETISHELLBROWSER:
1247 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1249 case WM_DESTROY:
1251 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1252 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1253 MemDialogSize = fodInfos->sizedlg;
1254 RemovePropA(hwnd, FileOpenDlgInfosStr);
1255 return FALSE;
1257 case WM_NOTIFY:
1259 LPNMHDR lpnmh = (LPNMHDR)lParam;
1260 UINT stringId = -1;
1262 /* set up the button tooltips strings */
1263 if(TTN_GETDISPINFOA == lpnmh->code )
1265 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1266 switch(lpnmh->idFrom )
1268 /* Up folder button */
1269 case FCIDM_TB_UPFOLDER:
1270 stringId = IDS_UPFOLDER;
1271 break;
1272 /* New folder button */
1273 case FCIDM_TB_NEWFOLDER:
1274 stringId = IDS_NEWFOLDER;
1275 break;
1276 /* List option button */
1277 case FCIDM_TB_SMALLICON:
1278 stringId = IDS_LISTVIEW;
1279 break;
1280 /* Details option button */
1281 case FCIDM_TB_REPORTVIEW:
1282 stringId = IDS_REPORTVIEW;
1283 break;
1284 /* Desktop button */
1285 case FCIDM_TB_DESKTOP:
1286 stringId = IDS_TODESKTOP;
1287 break;
1288 default:
1289 stringId = 0;
1291 lpdi->hinst = COMDLG32_hInstance;
1292 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1294 return FALSE;
1296 default :
1297 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1298 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1299 return FALSE;
1303 /***********************************************************************
1304 * FILEDLG95_InitControls
1306 * WM_INITDIALOG message handler (before hook notification)
1308 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1310 int win2000plus = 0;
1311 int win98plus = 0;
1312 int handledPath = FALSE;
1313 OSVERSIONINFOW osVi;
1314 static const WCHAR szwSlash[] = { '\\', 0 };
1315 static const WCHAR szwStar[] = { '*',0 };
1317 static const TBBUTTON tbb[] =
1319 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1320 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1321 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1322 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1323 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1324 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1325 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1326 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1327 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1329 TBADDBITMAP tba[2];
1330 RECT rectTB;
1331 RECT rectlook;
1332 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1334 tba[0].hInst = HINST_COMMCTRL;
1335 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1336 tba[1].hInst = COMDLG32_hInstance;
1337 tba[1].nID = 800;
1339 TRACE("%p\n", fodInfos);
1341 /* Get windows version emulating */
1342 osVi.dwOSVersionInfoSize = sizeof(osVi);
1343 GetVersionExW(&osVi);
1344 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1345 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1346 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1347 win2000plus = (osVi.dwMajorVersion > 4);
1348 if (win2000plus) win98plus = TRUE;
1350 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1352 /* Get the hwnd of the controls */
1353 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1354 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1355 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1357 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1358 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1360 /* construct the toolbar */
1361 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1362 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1364 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1365 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1366 rectTB.left = rectlook.right;
1367 rectTB.top = rectlook.top-1;
1369 if (fodInfos->unicode)
1370 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, 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);
1375 else
1376 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1377 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1378 rectTB.left, rectTB.top,
1379 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1380 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1382 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1384 /* FIXME: use TB_LOADIMAGES when implemented */
1385 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1386 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1387 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1389 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1390 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1392 /* Set the window text with the text specified in the OPENFILENAME structure */
1393 if(fodInfos->title)
1395 SetWindowTextW(hwnd,fodInfos->title);
1397 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1399 WCHAR buf[16];
1400 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1401 SetWindowTextW(hwnd, buf);
1404 /* Initialise the file name edit control */
1405 handledPath = FALSE;
1406 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1408 if(fodInfos->filename)
1410 /* 1. If win2000 or higher and filename contains a path, use it
1411 in preference over the lpstrInitialDir */
1412 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1413 WCHAR tmpBuf[MAX_PATH];
1414 WCHAR *nameBit;
1415 DWORD result;
1417 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1418 if (result) {
1420 /* nameBit is always shorter than the original filename */
1421 lstrcpyW(fodInfos->filename,nameBit);
1423 *nameBit = 0x00;
1424 if (fodInfos->initdir == NULL)
1425 MemFree(fodInfos->initdir);
1426 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1427 lstrcpyW(fodInfos->initdir, tmpBuf);
1428 handledPath = TRUE;
1429 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1430 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1432 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1434 } else {
1435 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1439 /* 2. (All platforms) If initdir is not null, then use it */
1440 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1441 (*fodInfos->initdir!=0x00))
1443 /* Work out the proper path as supplied one might be relative */
1444 /* (Here because supplying '.' as dir browses to My Computer) */
1445 if (handledPath==FALSE) {
1446 WCHAR tmpBuf[MAX_PATH];
1447 WCHAR tmpBuf2[MAX_PATH];
1448 WCHAR *nameBit;
1449 DWORD result;
1451 lstrcpyW(tmpBuf, fodInfos->initdir);
1452 if( PathFileExistsW(tmpBuf) ) {
1453 /* initdir does not have to be a directory. If a file is
1454 * specified, the dir part is taken */
1455 if( PathIsDirectoryW(tmpBuf)) {
1456 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1457 lstrcatW(tmpBuf, szwSlash);
1459 lstrcatW(tmpBuf, szwStar);
1461 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1462 if (result) {
1463 *nameBit = 0x00;
1464 MemFree(fodInfos->initdir);
1465 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1466 lstrcpyW(fodInfos->initdir, tmpBuf2);
1467 handledPath = TRUE;
1468 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1471 else if (fodInfos->initdir)
1473 MemFree(fodInfos->initdir);
1474 fodInfos->initdir = NULL;
1475 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1480 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1481 (*fodInfos->initdir==0x00)))
1483 /* 3. All except w2k+: if filename contains a path use it */
1484 if (!win2000plus && fodInfos->filename &&
1485 *fodInfos->filename &&
1486 strpbrkW(fodInfos->filename, szwSlash)) {
1487 WCHAR tmpBuf[MAX_PATH];
1488 WCHAR *nameBit;
1489 DWORD result;
1491 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1492 tmpBuf, &nameBit);
1493 if (result) {
1494 int len;
1496 /* nameBit is always shorter than the original filename */
1497 lstrcpyW(fodInfos->filename, nameBit);
1498 *nameBit = 0x00;
1500 len = lstrlenW(tmpBuf);
1501 MemFree(fodInfos->initdir);
1502 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1503 lstrcpyW(fodInfos->initdir, tmpBuf);
1505 handledPath = TRUE;
1506 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1507 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1509 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1512 /* 4. win98+ and win2000+ if any files of specified filter types in
1513 current directory, use it */
1514 if ( win98plus && handledPath == FALSE &&
1515 fodInfos->filter && *fodInfos->filter) {
1517 BOOL searchMore = TRUE;
1518 LPCWSTR lpstrPos = fodInfos->filter;
1519 WIN32_FIND_DATAW FindFileData;
1520 HANDLE hFind;
1522 while (searchMore)
1524 /* filter is a list... title\0ext\0......\0\0 */
1526 /* Skip the title */
1527 if(! *lpstrPos) break; /* end */
1528 lpstrPos += lstrlenW(lpstrPos) + 1;
1530 /* See if any files exist in the current dir with this extension */
1531 if(! *lpstrPos) break; /* end */
1533 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1535 if (hFind == INVALID_HANDLE_VALUE) {
1536 /* None found - continue search */
1537 lpstrPos += lstrlenW(lpstrPos) + 1;
1539 } else {
1540 searchMore = FALSE;
1542 MemFree(fodInfos->initdir);
1543 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1544 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1546 handledPath = TRUE;
1547 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1548 debugstr_w(lpstrPos));
1549 break;
1554 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1556 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1557 if (handledPath == FALSE && (win2000plus || win98plus)) {
1558 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1560 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1562 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1564 /* last fallback */
1565 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1566 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1567 } else {
1568 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1570 } else {
1571 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1573 handledPath = TRUE;
1574 } else if (handledPath==FALSE) {
1575 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1576 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1577 handledPath = TRUE;
1578 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1581 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1582 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1584 /* Must the open as read only check box be checked ?*/
1585 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1587 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1590 /* Must the open as read only check box be hidden? */
1591 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1593 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1594 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1597 /* Must the help button be hidden? */
1598 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1600 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1601 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1604 /* change Open to Save */
1605 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1607 WCHAR buf[16];
1608 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1609 SetDlgItemTextW(hwnd, IDOK, buf);
1610 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1611 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1614 /* Initialize the filter combo box */
1615 FILEDLG95_FILETYPE_Init(hwnd);
1617 return 0;
1620 /***********************************************************************
1621 * FILEDLG95_ResizeControls
1623 * WM_INITDIALOG message handler (after hook notification)
1625 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1627 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1629 if (fodInfos->DlgInfos.hwndCustomDlg)
1631 RECT rc;
1632 UINT flags = SWP_NOACTIVATE;
1634 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1635 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1637 /* resize the custom dialog to the parent size */
1638 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1639 GetClientRect(hwnd, &rc);
1640 else
1642 /* our own fake template is zero sized and doesn't have children, so
1643 * there is no need to resize it. Picasa depends on it.
1645 flags |= SWP_NOSIZE;
1646 SetRectEmpty(&rc);
1648 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1649 0, 0, rc.right, rc.bottom, flags);
1651 else
1653 /* Resize the height, if open as read only checkbox ad help button are
1654 * hidden and we are not using a custom template nor a customDialog
1656 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1657 (!(fodInfos->ofnInfos->Flags &
1658 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1660 RECT rectDlg, rectHelp, rectCancel;
1661 GetWindowRect(hwnd, &rectDlg);
1662 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1663 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1664 /* subtract the height of the help button plus the space between the help
1665 * button and the cancel button to the height of the dialog
1667 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1668 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1669 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1672 return TRUE;
1675 /***********************************************************************
1676 * FILEDLG95_FillControls
1678 * WM_INITDIALOG message handler (after hook notification)
1680 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1682 LPITEMIDLIST pidlItemId = NULL;
1684 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1686 TRACE("dir=%s file=%s\n",
1687 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1689 /* Get the initial directory pidl */
1691 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1693 WCHAR path[MAX_PATH];
1695 GetCurrentDirectoryW(MAX_PATH,path);
1696 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1699 /* Initialise shell objects */
1700 FILEDLG95_SHELL_Init(hwnd);
1702 /* Initialize the Look In combo box */
1703 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1705 /* Browse to the initial directory */
1706 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1708 /* Free pidlItem memory */
1709 COMDLG32_SHFree(pidlItemId);
1711 return TRUE;
1713 /***********************************************************************
1714 * FILEDLG95_Clean
1716 * Regroups all the cleaning functions of the filedlg
1718 void FILEDLG95_Clean(HWND hwnd)
1720 FILEDLG95_FILETYPE_Clean(hwnd);
1721 FILEDLG95_LOOKIN_Clean(hwnd);
1722 FILEDLG95_SHELL_Clean(hwnd);
1724 /***********************************************************************
1725 * FILEDLG95_OnWMCommand
1727 * WM_COMMAND message handler
1729 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1731 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1732 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1733 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1735 switch(wID)
1737 /* OK button */
1738 case IDOK:
1739 FILEDLG95_OnOpen(hwnd);
1740 break;
1741 /* Cancel button */
1742 case IDCANCEL:
1743 FILEDLG95_Clean(hwnd);
1744 EndDialog(hwnd, FALSE);
1745 break;
1746 /* Filetype combo box */
1747 case IDC_FILETYPE:
1748 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1749 break;
1750 /* LookIn combo box */
1751 case IDC_LOOKIN:
1752 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1753 break;
1755 /* --- toolbar --- */
1756 /* Up folder button */
1757 case FCIDM_TB_UPFOLDER:
1758 FILEDLG95_SHELL_UpFolder(hwnd);
1759 break;
1760 /* New folder button */
1761 case FCIDM_TB_NEWFOLDER:
1762 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1763 break;
1764 /* List option button */
1765 case FCIDM_TB_SMALLICON:
1766 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1767 break;
1768 /* Details option button */
1769 case FCIDM_TB_REPORTVIEW:
1770 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1771 break;
1772 /* Details option button */
1773 case FCIDM_TB_DESKTOP:
1774 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1775 break;
1777 case IDC_FILENAME:
1778 break;
1781 /* Do not use the listview selection anymore */
1782 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1783 return 0;
1786 /***********************************************************************
1787 * FILEDLG95_OnWMGetIShellBrowser
1789 * WM_GETISHELLBROWSER message handler
1791 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1793 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1795 TRACE("\n");
1797 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1799 return TRUE;
1803 /***********************************************************************
1804 * FILEDLG95_SendFileOK
1806 * Sends the CDN_FILEOK notification if required
1808 * RETURNS
1809 * TRUE if the dialog should close
1810 * FALSE if the dialog should not be closed
1812 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1814 /* ask the hook if we can close */
1815 if(IsHooked(fodInfos))
1817 LRESULT retval = 0;
1819 TRACE("---\n");
1820 /* First send CDN_FILEOK as MSDN doc says */
1821 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1822 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1823 if( retval)
1825 TRACE("canceled\n");
1826 return FALSE;
1829 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1830 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1831 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1832 if( retval)
1834 TRACE("canceled\n");
1835 return FALSE;
1838 return TRUE;
1841 /***********************************************************************
1842 * FILEDLG95_OnOpenMultipleFiles
1844 * Handles the opening of multiple files.
1846 * FIXME
1847 * check destination buffer size
1849 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1851 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1852 UINT nCount, nSizePath;
1853 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1855 TRACE("\n");
1857 if(fodInfos->unicode)
1859 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1860 ofn->lpstrFile[0] = '\0';
1862 else
1864 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1865 ofn->lpstrFile[0] = '\0';
1868 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1870 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1871 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1872 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1874 LPWSTR lpstrTemp = lpstrFileList;
1876 for ( nCount = 0; nCount < nFileCount; nCount++ )
1878 LPITEMIDLIST pidl;
1880 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1881 if (!pidl)
1883 WCHAR lpstrNotFound[100];
1884 WCHAR lpstrMsg[100];
1885 WCHAR tmp[400];
1886 static const WCHAR nl[] = {'\n',0};
1888 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1889 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1891 lstrcpyW(tmp, lpstrTemp);
1892 lstrcatW(tmp, nl);
1893 lstrcatW(tmp, lpstrNotFound);
1894 lstrcatW(tmp, nl);
1895 lstrcatW(tmp, lpstrMsg);
1897 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1898 return FALSE;
1901 /* move to the next file in the list of files */
1902 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1903 COMDLG32_SHFree(pidl);
1907 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1908 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1910 /* For "oldstyle" dialog the components have to
1911 be separated by blanks (not '\0'!) and short
1912 filenames have to be used! */
1913 FIXME("Components have to be separated by blanks\n");
1915 if(fodInfos->unicode)
1917 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1918 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1919 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1921 else
1923 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1925 if (ofn->lpstrFile != NULL)
1927 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1928 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1929 if (ofn->nMaxFile > nSizePath)
1931 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1932 ofn->lpstrFile + nSizePath,
1933 ofn->nMaxFile - nSizePath, NULL, NULL);
1938 fodInfos->ofnInfos->nFileOffset = nSizePath;
1939 fodInfos->ofnInfos->nFileExtension = 0;
1941 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1942 return FALSE;
1944 /* clean and exit */
1945 FILEDLG95_Clean(hwnd);
1946 return EndDialog(hwnd,TRUE);
1949 /***********************************************************************
1950 * FILEDLG95_OnOpen
1952 * Ok button WM_COMMAND message handler
1954 * If the function succeeds, the return value is nonzero.
1956 #define ONOPEN_BROWSE 1
1957 #define ONOPEN_OPEN 2
1958 #define ONOPEN_SEARCH 3
1959 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1961 WCHAR strMsgTitle[MAX_PATH];
1962 WCHAR strMsgText [MAX_PATH];
1963 if (idCaption)
1964 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1965 else
1966 strMsgTitle[0] = '\0';
1967 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1968 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1971 BOOL FILEDLG95_OnOpen(HWND hwnd)
1973 LPWSTR lpstrFileList;
1974 UINT nFileCount = 0;
1975 UINT sizeUsed = 0;
1976 BOOL ret = TRUE;
1977 WCHAR lpstrPathAndFile[MAX_PATH];
1978 WCHAR lpstrTemp[MAX_PATH];
1979 LPSHELLFOLDER lpsf = NULL;
1980 int nOpenAction;
1981 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1983 TRACE("hwnd=%p\n", hwnd);
1985 /* get the files from the edit control */
1986 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1988 /* try if the user selected a folder in the shellview */
1989 if(nFileCount == 0)
1991 BrowseSelectedFolder(hwnd);
1992 return FALSE;
1995 if(nFileCount > 1)
1997 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1998 goto ret;
2001 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2004 Step 1: Build a complete path name from the current folder and
2005 the filename or path in the edit box.
2006 Special cases:
2007 - the path in the edit box is a root path
2008 (with or without drive letter)
2009 - the edit box contains ".." (or a path with ".." in it)
2012 /* Get the current directory name */
2013 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2015 /* last fallback */
2016 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2018 PathAddBackslashW(lpstrPathAndFile);
2020 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2022 /* if the user specified a fully qualified path use it */
2023 if(PathIsRelativeW(lpstrFileList))
2025 lstrcatW(lpstrPathAndFile, lpstrFileList);
2027 else
2029 /* does the path have a drive letter? */
2030 if (PathGetDriveNumberW(lpstrFileList) == -1)
2031 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2032 else
2033 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2036 /* resolve "." and ".." */
2037 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2038 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2039 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2041 MemFree(lpstrFileList);
2044 Step 2: here we have a cleaned up path
2046 We have to parse the path step by step to see if we have to browse
2047 to a folder if the path points to a directory or the last
2048 valid element is a directory.
2050 valid variables:
2051 lpstrPathAndFile: cleaned up path
2054 if (nFileCount &&
2055 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2056 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2057 nOpenAction = ONOPEN_OPEN;
2058 else
2059 nOpenAction = ONOPEN_BROWSE;
2061 /* don't apply any checks with OFN_NOVALIDATE */
2063 LPWSTR lpszTemp, lpszTemp1;
2064 LPITEMIDLIST pidl = NULL;
2065 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2067 /* check for invalid chars */
2068 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2070 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2071 ret = FALSE;
2072 goto ret;
2075 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2077 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2078 while (lpszTemp1)
2080 LPSHELLFOLDER lpsfChild;
2081 WCHAR lpwstrTemp[MAX_PATH];
2082 DWORD dwEaten, dwAttributes;
2083 LPWSTR p;
2085 lstrcpyW(lpwstrTemp, lpszTemp);
2086 p = PathFindNextComponentW(lpwstrTemp);
2088 if (!p) break; /* end of path */
2090 *p = 0;
2091 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2093 /* There are no wildcards when OFN_NOVALIDATE is set */
2094 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2096 static const WCHAR wszWild[] = { '*', '?', 0 };
2097 /* if the last element is a wildcard do a search */
2098 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2100 nOpenAction = ONOPEN_SEARCH;
2101 break;
2104 lpszTemp1 = lpszTemp;
2106 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2108 /* append a backslash to drive letters */
2109 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2110 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2111 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2113 PathAddBackslashW(lpwstrTemp);
2116 dwAttributes = SFGAO_FOLDER;
2117 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2119 /* the path component is valid, we have a pidl of the next path component */
2120 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2121 if(dwAttributes & SFGAO_FOLDER)
2123 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2125 ERR("bind to failed\n"); /* should not fail */
2126 break;
2128 IShellFolder_Release(lpsf);
2129 lpsf = lpsfChild;
2130 lpsfChild = NULL;
2132 else
2134 TRACE("value\n");
2136 /* end dialog, return value */
2137 nOpenAction = ONOPEN_OPEN;
2138 break;
2140 COMDLG32_SHFree(pidl);
2141 pidl = NULL;
2143 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2145 if(*lpszTemp || /* points to trailing null for last path element */
2146 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2148 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2150 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2151 break;
2154 else
2156 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2157 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2159 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2160 break;
2163 /* change to the current folder */
2164 nOpenAction = ONOPEN_OPEN;
2165 break;
2167 else
2169 nOpenAction = ONOPEN_OPEN;
2170 break;
2173 if(pidl) COMDLG32_SHFree(pidl);
2177 Step 3: here we have a cleaned up and validated path
2179 valid variables:
2180 lpsf: ShellFolder bound to the rightmost valid path component
2181 lpstrPathAndFile: cleaned up path
2182 nOpenAction: action to do
2184 TRACE("end validate sf=%p\n", lpsf);
2186 switch(nOpenAction)
2188 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2189 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2191 int iPos;
2192 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2193 DWORD len;
2195 /* replace the current filter */
2196 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2197 len = lstrlenW(lpszTemp)+1;
2198 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2199 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2201 /* set the filter cb to the extension when possible */
2202 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2203 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2205 /* fall through */
2206 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2207 TRACE("ONOPEN_BROWSE\n");
2209 IPersistFolder2 * ppf2;
2210 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2212 LPITEMIDLIST pidlCurrent;
2213 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2214 IPersistFolder2_Release(ppf2);
2215 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2217 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2218 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2220 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2223 else if( nOpenAction == ONOPEN_SEARCH )
2225 if (fodInfos->Shell.FOIShellView)
2226 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2228 COMDLG32_SHFree(pidlCurrent);
2229 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2232 ret = FALSE;
2233 break;
2234 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2235 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2237 WCHAR *ext = NULL;
2239 /* update READONLY check box flag */
2240 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2241 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2242 else
2243 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2245 /* Attach the file extension with file name*/
2246 ext = PathFindExtensionW(lpstrPathAndFile);
2247 if (! *ext)
2249 /* if no extension is specified with file name, then */
2250 /* attach the extension from file filter or default one */
2252 WCHAR *filterExt = NULL;
2253 LPWSTR lpstrFilter = NULL;
2254 static const WCHAR szwDot[] = {'.',0};
2255 int PathLength = lstrlenW(lpstrPathAndFile);
2257 /* Attach the dot*/
2258 lstrcatW(lpstrPathAndFile, szwDot);
2260 /*Get the file extension from file type filter*/
2261 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2262 fodInfos->ofnInfos->nFilterIndex-1);
2264 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2265 filterExt = PathFindExtensionW(lpstrFilter);
2267 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2268 lstrcatW(lpstrPathAndFile, filterExt + 1);
2269 else if ( fodInfos->defext ) /* attach the default file extension*/
2270 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2272 /* In Open dialog: if file does not exist try without extension */
2273 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2274 lpstrPathAndFile[PathLength] = '\0';
2277 if (fodInfos->defext) /* add default extension */
2279 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2280 if (*ext)
2281 ext++;
2282 if (!lstrcmpiW(fodInfos->defext, ext))
2283 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2284 else
2285 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2288 /* In Save dialog: check if the file already exists */
2289 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2290 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2291 && PathFileExistsW(lpstrPathAndFile))
2293 WCHAR lpstrOverwrite[100];
2294 int answer;
2296 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2297 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2298 MB_YESNO | MB_ICONEXCLAMATION);
2299 if (answer == IDNO)
2301 ret = FALSE;
2302 goto ret;
2306 /* In Open dialog: check if it should be created if it doesn't exist */
2307 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2308 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2309 && !PathFileExistsW(lpstrPathAndFile))
2311 WCHAR lpstrCreate[100];
2312 int answer;
2314 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2315 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2316 MB_YESNO | MB_ICONEXCLAMATION);
2317 if (answer == IDNO)
2319 ret = FALSE;
2320 goto ret;
2324 /* Check that the size of the file does not exceed buffer size.
2325 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2326 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2327 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2330 /* fill destination buffer */
2331 if (fodInfos->ofnInfos->lpstrFile)
2333 if(fodInfos->unicode)
2335 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2337 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2338 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2339 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2341 else
2343 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2345 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2346 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2347 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2348 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2352 if(fodInfos->unicode)
2354 LPWSTR lpszTemp;
2356 /* set filename offset */
2357 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2358 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2360 /* set extension offset */
2361 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2362 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2364 else
2366 LPSTR lpszTemp;
2367 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2369 /* set filename offset */
2370 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2371 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2373 /* set extension offset */
2374 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2375 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2378 /* set the lpstrFileTitle */
2379 if(fodInfos->ofnInfos->lpstrFileTitle)
2381 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2382 if(fodInfos->unicode)
2384 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2385 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2387 else
2389 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2390 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2391 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2395 /* copy currently selected filter to lpstrCustomFilter */
2396 if (fodInfos->ofnInfos->lpstrCustomFilter)
2398 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2399 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2400 NULL, 0, NULL, NULL);
2401 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2403 LPSTR s = ofn->lpstrCustomFilter;
2404 s += strlen(ofn->lpstrCustomFilter)+1;
2405 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2406 s, len, NULL, NULL);
2411 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2412 goto ret;
2414 TRACE("close\n");
2415 FILEDLG95_Clean(hwnd);
2416 ret = EndDialog(hwnd, TRUE);
2418 else
2420 WORD size;
2422 size = lstrlenW(lpstrPathAndFile) + 1;
2423 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2424 size += 1;
2425 /* return needed size in first two bytes of lpstrFile */
2426 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2427 FILEDLG95_Clean(hwnd);
2428 ret = EndDialog(hwnd, FALSE);
2429 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2432 break;
2435 ret:
2436 if(lpsf) IShellFolder_Release(lpsf);
2437 return ret;
2440 /***********************************************************************
2441 * FILEDLG95_SHELL_Init
2443 * Initialisation of the shell objects
2445 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2447 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2449 TRACE("\n");
2452 * Initialisation of the FileOpenDialogInfos structure
2455 /* Shell */
2457 /*ShellInfos */
2458 fodInfos->ShellInfos.hwndOwner = hwnd;
2460 /* Disable multi-select if flag not set */
2461 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2463 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2465 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2466 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2468 /* Construct the IShellBrowser interface */
2469 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2471 return NOERROR;
2474 /***********************************************************************
2475 * FILEDLG95_SHELL_ExecuteCommand
2477 * Change the folder option and refresh the view
2478 * If the function succeeds, the return value is nonzero.
2480 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2482 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2483 IContextMenu * pcm;
2485 TRACE("(%p,%p)\n", hwnd, lpVerb);
2487 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2488 SVGIO_BACKGROUND,
2489 &IID_IContextMenu,
2490 (LPVOID*)&pcm)))
2492 CMINVOKECOMMANDINFO ci;
2493 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2494 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2495 ci.lpVerb = lpVerb;
2496 ci.hwnd = hwnd;
2498 IContextMenu_InvokeCommand(pcm, &ci);
2499 IContextMenu_Release(pcm);
2502 return FALSE;
2505 /***********************************************************************
2506 * FILEDLG95_SHELL_UpFolder
2508 * Browse to the specified object
2509 * If the function succeeds, the return value is nonzero.
2511 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2513 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2515 TRACE("\n");
2517 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2518 NULL,
2519 SBSP_PARENT)))
2521 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2522 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2523 return TRUE;
2525 return FALSE;
2528 /***********************************************************************
2529 * FILEDLG95_SHELL_BrowseToDesktop
2531 * Browse to the Desktop
2532 * If the function succeeds, the return value is nonzero.
2534 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2536 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2537 LPITEMIDLIST pidl;
2538 HRESULT hres;
2540 TRACE("\n");
2542 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2543 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2544 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2545 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2546 COMDLG32_SHFree(pidl);
2547 return SUCCEEDED(hres);
2549 /***********************************************************************
2550 * FILEDLG95_SHELL_Clean
2552 * Cleans the memory used by shell objects
2554 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2556 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2558 TRACE("\n");
2560 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2562 /* clean Shell interfaces */
2563 if (fodInfos->Shell.FOIShellView)
2565 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2566 IShellView_Release(fodInfos->Shell.FOIShellView);
2568 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2569 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2570 if (fodInfos->Shell.FOIDataObject)
2571 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2574 /***********************************************************************
2575 * FILEDLG95_FILETYPE_Init
2577 * Initialisation of the file type combo box
2579 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2581 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2582 int nFilters = 0; /* number of filters */
2583 int nFilterIndexCB;
2585 TRACE("\n");
2587 if(fodInfos->customfilter)
2589 /* customfilter has one entry... title\0ext\0
2590 * Set first entry of combo box item with customfilter
2592 LPWSTR lpstrExt;
2593 LPCWSTR lpstrPos = fodInfos->customfilter;
2595 /* Get the title */
2596 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2598 /* Copy the extensions */
2599 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2600 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2601 lstrcpyW(lpstrExt,lpstrPos);
2603 /* Add the item at the end of the combo */
2604 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2605 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2606 nFilters++;
2608 if(fodInfos->filter)
2610 LPCWSTR lpstrPos = fodInfos->filter;
2612 for(;;)
2614 /* filter is a list... title\0ext\0......\0\0
2615 * Set the combo item text to the title and the item data
2616 * to the ext
2618 LPCWSTR lpstrDisplay;
2619 LPWSTR lpstrExt;
2621 /* Get the title */
2622 if(! *lpstrPos) break; /* end */
2623 lpstrDisplay = lpstrPos;
2624 lpstrPos += lstrlenW(lpstrPos) + 1;
2626 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2628 nFilters++;
2630 /* Copy the extensions */
2631 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2632 lstrcpyW(lpstrExt,lpstrPos);
2633 lpstrPos += lstrlenW(lpstrPos) + 1;
2635 /* Add the item at the end of the combo */
2636 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2638 /* malformed filters are added anyway... */
2639 if (!*lpstrExt) break;
2644 * Set the current filter to the one specified
2645 * in the initialisation structure
2647 if (fodInfos->filter || fodInfos->customfilter)
2649 LPWSTR lpstrFilter;
2651 /* Check to make sure our index isn't out of bounds. */
2652 if ( fodInfos->ofnInfos->nFilterIndex >
2653 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2654 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2656 /* set default filter index */
2657 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2658 fodInfos->ofnInfos->nFilterIndex = 1;
2660 /* calculate index of Combo Box item */
2661 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2662 if (fodInfos->customfilter == NULL)
2663 nFilterIndexCB--;
2665 /* Set the current index selection. */
2666 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2668 /* Get the corresponding text string from the combo box. */
2669 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2670 nFilterIndexCB);
2672 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2673 lpstrFilter = NULL;
2675 if(lpstrFilter)
2677 DWORD len;
2678 CharLowerW(lpstrFilter); /* lowercase */
2679 len = lstrlenW(lpstrFilter)+1;
2680 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2681 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2683 } else
2684 fodInfos->ofnInfos->nFilterIndex = 0;
2685 return S_OK;
2688 /***********************************************************************
2689 * FILEDLG95_FILETYPE_OnCommand
2691 * WM_COMMAND of the file type combo box
2692 * If the function succeeds, the return value is nonzero.
2694 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2696 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2698 switch(wNotifyCode)
2700 case CBN_SELENDOK:
2702 LPWSTR lpstrFilter;
2704 /* Get the current item of the filetype combo box */
2705 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2707 /* set the current filter index */
2708 fodInfos->ofnInfos->nFilterIndex = iItem +
2709 (fodInfos->customfilter == NULL ? 1 : 0);
2711 /* Set the current filter with the current selection */
2712 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2714 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2715 iItem);
2716 if((INT_PTR)lpstrFilter != CB_ERR)
2718 DWORD len;
2719 CharLowerW(lpstrFilter); /* lowercase */
2720 len = lstrlenW(lpstrFilter)+1;
2721 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2722 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2723 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2724 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2727 /* Refresh the actual view to display the included items*/
2728 if (fodInfos->Shell.FOIShellView)
2729 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2732 return FALSE;
2734 /***********************************************************************
2735 * FILEDLG95_FILETYPE_SearchExt
2737 * searches for an extension in the filetype box
2739 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2741 int i, iCount = CBGetCount(hwnd);
2743 TRACE("%s\n", debugstr_w(lpstrExt));
2745 if(iCount != CB_ERR)
2747 for(i=0;i<iCount;i++)
2749 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2750 return i;
2753 return -1;
2756 /***********************************************************************
2757 * FILEDLG95_FILETYPE_Clean
2759 * Clean the memory used by the filetype combo box
2761 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2763 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2764 int iPos;
2765 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2767 TRACE("\n");
2769 /* Delete each string of the combo and their associated data */
2770 if(iCount != CB_ERR)
2772 for(iPos = iCount-1;iPos>=0;iPos--)
2774 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2775 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2778 /* Current filter */
2779 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2783 /***********************************************************************
2784 * FILEDLG95_LOOKIN_Init
2786 * Initialisation of the look in combo box
2789 /* Small helper function, to determine if the unixfs shell extension is rooted
2790 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2792 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2793 HKEY hKey;
2794 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2795 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2796 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2797 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2798 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2799 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2800 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2802 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2803 return FALSE;
2805 RegCloseKey(hKey);
2806 return TRUE;
2809 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2811 IShellFolder *psfRoot, *psfDrives;
2812 IEnumIDList *lpeRoot, *lpeDrives;
2813 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2815 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2817 TRACE("\n");
2819 liInfos->iMaxIndentation = 0;
2821 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2823 /* set item height for both text field and listbox */
2824 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2825 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2827 /* Turn on the extended UI for the combo box like Windows does */
2828 CBSetExtendedUI(hwndCombo, TRUE);
2830 /* Initialise data of Desktop folder */
2831 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2832 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2833 COMDLG32_SHFree(pidlTmp);
2835 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2837 SHGetDesktopFolder(&psfRoot);
2839 if (psfRoot)
2841 /* enumerate the contents of the desktop */
2842 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2844 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2846 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2848 /* If the unixfs extension is rooted, we don't expand the drives by default */
2849 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2851 /* special handling for CSIDL_DRIVES */
2852 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2854 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2856 /* enumerate the drives */
2857 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2859 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2861 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2862 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2863 COMDLG32_SHFree(pidlAbsTmp);
2864 COMDLG32_SHFree(pidlTmp1);
2866 IEnumIDList_Release(lpeDrives);
2868 IShellFolder_Release(psfDrives);
2873 COMDLG32_SHFree(pidlTmp);
2875 IEnumIDList_Release(lpeRoot);
2877 IShellFolder_Release(psfRoot);
2880 COMDLG32_SHFree(pidlDrives);
2883 /***********************************************************************
2884 * FILEDLG95_LOOKIN_DrawItem
2886 * WM_DRAWITEM message handler
2888 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2890 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2891 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2892 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2893 RECT rectText;
2894 RECT rectIcon;
2895 SHFILEINFOW sfi;
2896 HIMAGELIST ilItemImage;
2897 int iIndentation;
2898 TEXTMETRICW tm;
2899 LPSFOLDER tmpFolder;
2900 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2902 TRACE("\n");
2904 if(pDIStruct->itemID == -1)
2905 return 0;
2907 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2908 pDIStruct->itemID)))
2909 return 0;
2912 if(pDIStruct->itemID == liInfos->uSelectedItem)
2914 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2916 &sfi,
2917 sizeof (sfi),
2918 SHGFI_PIDL | SHGFI_SMALLICON |
2919 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2920 SHGFI_DISPLAYNAME );
2922 else
2924 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2926 &sfi,
2927 sizeof (sfi),
2928 SHGFI_PIDL | SHGFI_SMALLICON |
2929 SHGFI_SYSICONINDEX |
2930 SHGFI_DISPLAYNAME);
2933 /* Is this item selected ? */
2934 if(pDIStruct->itemState & ODS_SELECTED)
2936 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2937 SetBkColor(pDIStruct->hDC,crHighLight);
2938 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2940 else
2942 SetTextColor(pDIStruct->hDC,crText);
2943 SetBkColor(pDIStruct->hDC,crWin);
2944 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2947 /* Do not indent item if drawing in the edit of the combo */
2948 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2950 iIndentation = 0;
2951 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2953 &sfi,
2954 sizeof (sfi),
2955 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2956 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2959 else
2961 iIndentation = tmpFolder->m_iIndent;
2963 /* Draw text and icon */
2965 /* Initialise the icon display area */
2966 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2967 rectIcon.top = pDIStruct->rcItem.top;
2968 rectIcon.right = rectIcon.left + ICONWIDTH;
2969 rectIcon.bottom = pDIStruct->rcItem.bottom;
2971 /* Initialise the text display area */
2972 GetTextMetricsW(pDIStruct->hDC, &tm);
2973 rectText.left = rectIcon.right;
2974 rectText.top =
2975 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2976 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2977 rectText.bottom =
2978 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2980 /* Draw the icon from the image list */
2981 ImageList_Draw(ilItemImage,
2982 sfi.iIcon,
2983 pDIStruct->hDC,
2984 rectIcon.left,
2985 rectIcon.top,
2986 ILD_TRANSPARENT );
2988 /* Draw the associated text */
2989 if(sfi.szDisplayName)
2990 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2993 return NOERROR;
2996 /***********************************************************************
2997 * FILEDLG95_LOOKIN_OnCommand
2999 * LookIn combo box WM_COMMAND message handler
3000 * If the function succeeds, the return value is nonzero.
3002 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3004 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3006 TRACE("%p\n", fodInfos);
3008 switch(wNotifyCode)
3010 case CBN_SELENDOK:
3012 LPSFOLDER tmpFolder;
3013 int iItem;
3015 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3017 if( iItem == CB_ERR) return FALSE;
3019 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3020 iItem)))
3021 return FALSE;
3024 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3025 tmpFolder->pidlItem,
3026 SBSP_ABSOLUTE)))
3028 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3029 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3030 return TRUE;
3032 break;
3036 return FALSE;
3039 /***********************************************************************
3040 * FILEDLG95_LOOKIN_AddItem
3042 * Adds an absolute pidl item to the lookin combo box
3043 * returns the index of the inserted item
3045 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3047 LPITEMIDLIST pidlNext;
3048 SHFILEINFOW sfi;
3049 SFOLDER *tmpFolder;
3050 LookInInfos *liInfos;
3052 TRACE("%08x\n", iInsertId);
3054 if(!pidl)
3055 return -1;
3057 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3058 return -1;
3060 tmpFolder = MemAlloc(sizeof(SFOLDER));
3061 tmpFolder->m_iIndent = 0;
3063 /* Calculate the indentation of the item in the lookin*/
3064 pidlNext = pidl;
3065 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3067 tmpFolder->m_iIndent++;
3070 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3072 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3073 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3075 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3076 SHGetFileInfoW((LPCWSTR)pidl,
3078 &sfi,
3079 sizeof(sfi),
3080 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3081 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3083 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3085 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3087 int iItemID;
3089 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3091 /* Add the item at the end of the list */
3092 if(iInsertId < 0)
3094 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3096 /* Insert the item at the iInsertId position*/
3097 else
3099 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3102 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3103 return iItemID;
3106 COMDLG32_SHFree( tmpFolder->pidlItem );
3107 MemFree( tmpFolder );
3108 return -1;
3112 /***********************************************************************
3113 * FILEDLG95_LOOKIN_InsertItemAfterParent
3115 * Insert an item below its parent
3117 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3120 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3121 int iParentPos;
3123 TRACE("\n");
3125 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3127 if(iParentPos < 0)
3129 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3132 /* Free pidlParent memory */
3133 COMDLG32_SHFree(pidlParent);
3135 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3138 /***********************************************************************
3139 * FILEDLG95_LOOKIN_SelectItem
3141 * Adds an absolute pidl item to the lookin combo box
3142 * returns the index of the inserted item
3144 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3146 int iItemPos;
3147 LookInInfos *liInfos;
3149 TRACE("\n");
3151 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3153 liInfos = GetPropA(hwnd,LookInInfosStr);
3155 if(iItemPos < 0)
3157 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3158 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3161 else
3163 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3164 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3166 int iRemovedItem;
3168 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3169 break;
3170 if(iRemovedItem < iItemPos)
3171 iItemPos--;
3175 CBSetCurSel(hwnd,iItemPos);
3176 liInfos->uSelectedItem = iItemPos;
3178 return 0;
3182 /***********************************************************************
3183 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3185 * Remove the item with an expansion level over iExpansionLevel
3187 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3189 int iItemPos;
3190 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3192 TRACE("\n");
3194 if(liInfos->iMaxIndentation <= 2)
3195 return -1;
3197 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3199 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3200 COMDLG32_SHFree(tmpFolder->pidlItem);
3201 MemFree(tmpFolder);
3202 CBDeleteString(hwnd,iItemPos);
3203 liInfos->iMaxIndentation--;
3205 return iItemPos;
3208 return -1;
3211 /***********************************************************************
3212 * FILEDLG95_LOOKIN_SearchItem
3214 * Search for pidl in the lookin combo box
3215 * returns the index of the found item
3217 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3219 int i = 0;
3220 int iCount = CBGetCount(hwnd);
3222 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3224 if (iCount != CB_ERR)
3226 for(;i<iCount;i++)
3228 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3230 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3231 return i;
3232 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3233 return i;
3237 return -1;
3240 /***********************************************************************
3241 * FILEDLG95_LOOKIN_Clean
3243 * Clean the memory used by the lookin combo box
3245 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3247 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3248 int iPos;
3249 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3251 TRACE("\n");
3253 /* Delete each string of the combo and their associated data */
3254 if (iCount != CB_ERR)
3256 for(iPos = iCount-1;iPos>=0;iPos--)
3258 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3259 COMDLG32_SHFree(tmpFolder->pidlItem);
3260 MemFree(tmpFolder);
3261 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3265 /* LookInInfos structure */
3266 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3269 /***********************************************************************
3270 * FILEDLG95_FILENAME_FillFromSelection
3272 * fills the edit box from the cached DataObject
3274 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3276 FileOpenDlgInfos *fodInfos;
3277 LPITEMIDLIST pidl;
3278 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3279 WCHAR lpstrTemp[MAX_PATH];
3280 LPWSTR lpstrAllFile, lpstrCurrFile;
3282 TRACE("\n");
3283 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3285 /* Count how many files we have */
3286 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3288 /* calculate the string length, count files */
3289 if (nFileSelected >= 1)
3291 nLength += 3; /* first and last quotes, trailing \0 */
3292 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3294 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3296 if (pidl)
3298 /* get the total length of the selected file names */
3299 lpstrTemp[0] = '\0';
3300 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3302 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3304 nLength += lstrlenW( lpstrTemp ) + 3;
3305 nFiles++;
3307 COMDLG32_SHFree( pidl );
3312 /* allocate the buffer */
3313 if (nFiles <= 1) nLength = MAX_PATH;
3314 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3316 /* Generate the string for the edit control */
3317 if(nFiles >= 1)
3319 lpstrCurrFile = lpstrAllFile;
3320 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3322 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3324 if (pidl)
3326 /* get the file name */
3327 lpstrTemp[0] = '\0';
3328 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3330 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3332 if ( nFiles > 1)
3334 *lpstrCurrFile++ = '\"';
3335 lstrcpyW( lpstrCurrFile, lpstrTemp );
3336 lpstrCurrFile += lstrlenW( lpstrTemp );
3337 *lpstrCurrFile++ = '\"';
3338 *lpstrCurrFile++ = ' ';
3339 *lpstrCurrFile = 0;
3341 else
3343 lstrcpyW( lpstrAllFile, lpstrTemp );
3346 COMDLG32_SHFree( pidl );
3349 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3351 /* Select the file name like Windows does */
3352 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3354 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3358 /* copied from shell32 to avoid linking to it
3359 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3360 * is dependent on whether emulated OS is unicode or not.
3362 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3364 switch (src->uType)
3366 case STRRET_WSTR:
3367 lstrcpynW(dest, src->u.pOleStr, len);
3368 COMDLG32_SHFree(src->u.pOleStr);
3369 break;
3371 case STRRET_CSTR:
3372 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3373 dest[len-1] = 0;
3374 break;
3376 case STRRET_OFFSET:
3377 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3378 dest[len-1] = 0;
3379 break;
3381 default:
3382 FIXME("unknown type %x!\n", src->uType);
3383 if (len) *dest = '\0';
3384 return E_FAIL;
3386 return S_OK;
3389 /***********************************************************************
3390 * FILEDLG95_FILENAME_GetFileNames
3392 * Copies the filenames to a delimited string list.
3393 * The delimiter is specified by the parameter 'separator',
3394 * usually either a space or a nul
3396 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3398 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3399 UINT nStrCharCount = 0; /* index in src buffer */
3400 UINT nFileIndex = 0; /* index in dest buffer */
3401 UINT nFileCount = 0; /* number of files */
3402 UINT nStrLen = 0; /* length of string in edit control */
3403 LPWSTR lpstrEdit; /* buffer for string from edit control */
3405 TRACE("\n");
3407 /* get the filenames from the edit control */
3408 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3409 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3410 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3412 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3414 /* we might get single filename without any '"',
3415 * so we need nStrLen + terminating \0 + end-of-list \0 */
3416 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3417 *sizeUsed = 0;
3419 /* build delimited file list from filenames */
3420 while ( nStrCharCount <= nStrLen )
3422 if ( lpstrEdit[nStrCharCount]=='"' )
3424 nStrCharCount++;
3425 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3427 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3428 nStrCharCount++;
3430 (*lpstrFileList)[nFileIndex++] = 0;
3431 nFileCount++;
3433 nStrCharCount++;
3436 /* single, unquoted string */
3437 if ((nStrLen > 0) && (nFileIndex == 0) )
3439 lstrcpyW(*lpstrFileList, lpstrEdit);
3440 nFileIndex = lstrlenW(lpstrEdit) + 1;
3441 nFileCount = 1;
3444 /* trailing \0 */
3445 (*lpstrFileList)[nFileIndex++] = '\0';
3447 *sizeUsed = nFileIndex;
3448 MemFree(lpstrEdit);
3449 return nFileCount;
3452 #define SETDefFormatEtc(fe,cf,med) \
3454 (fe).cfFormat = cf;\
3455 (fe).dwAspect = DVASPECT_CONTENT; \
3456 (fe).ptd =NULL;\
3457 (fe).tymed = med;\
3458 (fe).lindex = -1;\
3462 * DATAOBJECT Helper functions
3465 /***********************************************************************
3466 * COMCTL32_ReleaseStgMedium
3468 * like ReleaseStgMedium from ole32
3470 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3472 if(medium.pUnkForRelease)
3474 IUnknown_Release(medium.pUnkForRelease);
3476 else
3478 GlobalUnlock(medium.u.hGlobal);
3479 GlobalFree(medium.u.hGlobal);
3483 /***********************************************************************
3484 * GetPidlFromDataObject
3486 * Return pidl(s) by number from the cached DataObject
3488 * nPidlIndex=0 gets the fully qualified root path
3490 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3493 STGMEDIUM medium;
3494 FORMATETC formatetc;
3495 LPITEMIDLIST pidl = NULL;
3497 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3499 if (!doSelected)
3500 return NULL;
3502 /* Set the FORMATETC structure*/
3503 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3505 /* Get the pidls from IDataObject */
3506 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3508 LPIDA cida = GlobalLock(medium.u.hGlobal);
3509 if(nPidlIndex <= cida->cidl)
3511 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3513 COMCTL32_ReleaseStgMedium(medium);
3515 return pidl;
3518 /***********************************************************************
3519 * GetNumSelected
3521 * Return the number of selected items in the DataObject.
3524 static UINT GetNumSelected( IDataObject *doSelected )
3526 UINT retVal = 0;
3527 STGMEDIUM medium;
3528 FORMATETC formatetc;
3530 TRACE("sv=%p\n", doSelected);
3532 if (!doSelected) return 0;
3534 /* Set the FORMATETC structure*/
3535 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3537 /* Get the pidls from IDataObject */
3538 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3540 LPIDA cida = GlobalLock(medium.u.hGlobal);
3541 retVal = cida->cidl;
3542 COMCTL32_ReleaseStgMedium(medium);
3543 return retVal;
3545 return 0;
3549 * TOOLS
3552 /***********************************************************************
3553 * GetName
3555 * Get the pidl's display name (relative to folder) and
3556 * put it in lpstrFileName.
3558 * Return NOERROR on success,
3559 * E_FAIL otherwise
3562 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3564 STRRET str;
3565 HRESULT hRes;
3567 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3569 if(!lpsf)
3571 SHGetDesktopFolder(&lpsf);
3572 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3573 IShellFolder_Release(lpsf);
3574 return hRes;
3577 /* Get the display name of the pidl relative to the folder */
3578 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3580 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3582 return E_FAIL;
3585 /***********************************************************************
3586 * GetShellFolderFromPidl
3588 * pidlRel is the item pidl relative
3589 * Return the IShellFolder of the absolute pidl
3591 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3593 IShellFolder *psf = NULL,*psfParent;
3595 TRACE("%p\n", pidlAbs);
3597 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3599 psf = psfParent;
3600 if(pidlAbs && pidlAbs->mkid.cb)
3602 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3604 IShellFolder_Release(psfParent);
3605 return psf;
3608 /* return the desktop */
3609 return psfParent;
3611 return NULL;
3614 /***********************************************************************
3615 * GetParentPidl
3617 * Return the LPITEMIDLIST to the parent of the pidl in the list
3619 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3621 LPITEMIDLIST pidlParent;
3623 TRACE("%p\n", pidl);
3625 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3626 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3628 return pidlParent;
3631 /***********************************************************************
3632 * GetPidlFromName
3634 * returns the pidl of the file name relative to folder
3635 * NULL if an error occurred
3637 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3639 LPITEMIDLIST pidl = NULL;
3640 ULONG ulEaten;
3642 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3644 if(!lpcstrFileName) return NULL;
3645 if(!*lpcstrFileName) return NULL;
3647 if(!lpsf)
3649 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3650 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3651 IShellFolder_Release(lpsf);
3654 else
3656 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3658 return pidl;
3663 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3665 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3666 HRESULT ret;
3668 TRACE("%p, %p\n", psf, pidl);
3670 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3672 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3673 /* see documentation shell 4.1*/
3674 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3677 /***********************************************************************
3678 * BrowseSelectedFolder
3680 static BOOL BrowseSelectedFolder(HWND hwnd)
3682 BOOL bBrowseSelFolder = FALSE;
3683 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3685 TRACE("\n");
3687 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3689 LPITEMIDLIST pidlSelection;
3691 /* get the file selected */
3692 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3693 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3695 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3696 pidlSelection, SBSP_RELATIVE ) ) )
3698 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3699 ' ','n','o','t',' ','e','x','i','s','t',0};
3700 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3702 bBrowseSelFolder = TRUE;
3703 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3704 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3706 COMDLG32_SHFree( pidlSelection );
3709 return bBrowseSelFolder;
3713 * Memory allocation methods */
3714 static void *MemAlloc(UINT size)
3716 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3719 static void MemFree(void *mem)
3721 HeapFree(GetProcessHeap(),0,mem);
3725 * Old-style (win3.1) dialogs */
3727 /***********************************************************************
3728 * FD32_GetTemplate [internal]
3730 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3731 * by a 32 bits application
3734 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3736 LPOPENFILENAMEW ofnW = lfs->ofnW;
3737 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3738 HANDLE hDlgTmpl;
3740 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3742 if (!(lfs->template = LockResource( ofnW->hInstance )))
3744 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3745 return FALSE;
3748 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3750 HRSRC hResInfo;
3751 if (priv->ofnA)
3752 hResInfo = FindResourceA(priv->ofnA->hInstance,
3753 priv->ofnA->lpTemplateName,
3754 (LPSTR)RT_DIALOG);
3755 else
3756 hResInfo = FindResourceW(ofnW->hInstance,
3757 ofnW->lpTemplateName,
3758 (LPWSTR)RT_DIALOG);
3759 if (!hResInfo)
3761 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3762 return FALSE;
3764 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3765 hResInfo)) ||
3766 !(lfs->template = LockResource(hDlgTmpl)))
3768 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3769 return FALSE;
3771 } else { /* get it from internal Wine resource */
3772 HRSRC hResInfo;
3773 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3774 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3776 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3777 return FALSE;
3779 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3780 !(lfs->template = LockResource( hDlgTmpl )))
3782 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3783 return FALSE;
3786 return TRUE;
3790 /************************************************************************
3791 * FD32_Init [internal]
3792 * called from the common 16/32 code to initialize 32 bit data
3794 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3796 BOOL IsUnicode = (BOOL) data;
3797 PFD32_PRIVATE priv;
3799 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3800 lfs->private1632 = priv;
3801 if (NULL == lfs->private1632) return FALSE;
3802 if (IsUnicode)
3804 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3805 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3806 if (lfs->ofnW->lpfnHook)
3807 lfs->hook = TRUE;
3809 else
3811 priv->ofnA = (LPOPENFILENAMEA) lParam;
3812 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3813 if (priv->ofnA->lpfnHook)
3814 lfs->hook = TRUE;
3815 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3816 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3819 if (! FD32_GetTemplate(lfs)) return FALSE;
3821 return TRUE;
3824 /***********************************************************************
3825 * FD32_CallWindowProc [internal]
3827 * called from the common 16/32 code to call the appropriate hook
3829 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3830 LPARAM lParam)
3832 BOOL ret;
3833 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3835 if (priv->ofnA)
3837 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3838 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3839 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3840 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3841 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3842 return ret;
3845 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3846 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3847 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3848 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3849 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3850 return ret;
3853 /***********************************************************************
3854 * FD32_UpdateResult [internal]
3855 * update the real client structures if any
3857 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3859 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3860 LPOPENFILENAMEW ofnW = lfs->ofnW;
3862 if (priv->ofnA)
3864 LPSTR lpszTemp;
3865 if (ofnW->nMaxFile &&
3866 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3867 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3868 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3870 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3871 /* set filename offset */
3872 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3873 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3875 /* set extension offset */
3876 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3877 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3881 /***********************************************************************
3882 * FD32_UpdateFileTitle [internal]
3883 * update the real client structures if any
3885 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3887 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3888 LPOPENFILENAMEW ofnW = lfs->ofnW;
3890 if (priv->ofnA)
3892 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3893 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3894 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3899 /***********************************************************************
3900 * FD32_SendLbGetCurSel [internal]
3901 * retrieve selected listbox item
3903 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3905 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3909 /************************************************************************
3910 * FD32_Destroy [internal]
3911 * called from the common 16/32 code to cleanup 32 bit data
3913 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3915 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3917 /* if ofnW has been allocated, have to free everything in it */
3918 if (NULL != priv && NULL != priv->ofnA)
3920 FD31_FreeOfnW(lfs->ofnW);
3921 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3925 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3927 callbacks->Init = FD32_Init;
3928 callbacks->CWP = FD32_CallWindowProc;
3929 callbacks->UpdateResult = FD32_UpdateResult;
3930 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3931 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3932 callbacks->Destroy = FD32_Destroy;
3935 /***********************************************************************
3936 * FD32_WMMeasureItem [internal]
3938 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3940 LPMEASUREITEMSTRUCT lpmeasure;
3942 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3943 lpmeasure->itemHeight = FD31_GetFldrHeight();
3944 return TRUE;
3948 /***********************************************************************
3949 * FileOpenDlgProc [internal]
3950 * Used for open and save, in fact.
3952 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3953 WPARAM wParam, LPARAM lParam)
3955 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3957 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3958 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3960 INT_PTR lRet;
3961 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3962 if (lRet)
3963 return lRet; /* else continue message processing */
3965 switch (wMsg)
3967 case WM_INITDIALOG:
3968 return FD31_WMInitDialog(hWnd, wParam, lParam);
3970 case WM_MEASUREITEM:
3971 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3973 case WM_DRAWITEM:
3974 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3976 case WM_COMMAND:
3977 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3978 #if 0
3979 case WM_CTLCOLOR:
3980 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3981 switch (HIWORD(lParam))
3983 case CTLCOLOR_BTN:
3984 SetTextColor((HDC16)wParam, 0x00000000);
3985 return hGRAYBrush;
3986 case CTLCOLOR_STATIC:
3987 SetTextColor((HDC16)wParam, 0x00000000);
3988 return hGRAYBrush;
3990 break;
3991 #endif
3993 return FALSE;
3997 /***********************************************************************
3998 * GetFileName31A [internal]
4000 * Creates a win31 style dialog box for the user to select a file to open/save.
4002 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4003 UINT dlgType /* type dialogue : open/save */
4006 HINSTANCE hInst;
4007 BOOL bRet = FALSE;
4008 PFD31_DATA lfs;
4009 FD31_CALLBACKS callbacks;
4011 if (!lpofn || !FD31_Init()) return FALSE;
4013 TRACE("ofn flags %08x\n", lpofn->Flags);
4014 FD32_SetupCallbacks(&callbacks);
4015 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
4016 if (lfs)
4018 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4019 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
4020 FD32_FileOpenDlgProc, (LPARAM)lfs);
4021 FD31_DestroyPrivate(lfs);
4024 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4025 return bRet;
4028 /***********************************************************************
4029 * GetFileName31W [internal]
4031 * Creates a win31 style dialog box for the user to select a file to open/save
4033 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4034 UINT dlgType /* type dialogue : open/save */
4037 HINSTANCE hInst;
4038 BOOL bRet = FALSE;
4039 PFD31_DATA lfs;
4040 FD31_CALLBACKS callbacks;
4042 if (!lpofn || !FD31_Init()) return FALSE;
4044 FD32_SetupCallbacks(&callbacks);
4045 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
4046 if (lfs)
4048 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4049 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
4050 FD32_FileOpenDlgProc, (LPARAM)lfs);
4051 FD31_DestroyPrivate(lfs);
4054 TRACE("file %s, file offset %d, ext offset %d\n",
4055 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4056 return bRet;
4059 /* ------------------ APIs ---------------------- */
4061 /***********************************************************************
4062 * GetOpenFileNameA (COMDLG32.@)
4064 * Creates a dialog box for the user to select a file to open.
4066 * RETURNS
4067 * TRUE on success: user enters a valid file
4068 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4071 BOOL WINAPI GetOpenFileNameA(
4072 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4074 BOOL win16look = FALSE;
4076 TRACE("flags %08x\n", ofn->Flags);
4078 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4079 if (ofn->Flags & OFN_FILEMUSTEXIST)
4080 ofn->Flags |= OFN_PATHMUSTEXIST;
4082 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4083 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4085 if (win16look)
4086 return GetFileName31A(ofn, OPEN_DIALOG);
4087 else
4088 return GetFileDialog95A(ofn, OPEN_DIALOG);
4091 /***********************************************************************
4092 * GetOpenFileNameW (COMDLG32.@)
4094 * Creates a dialog box for the user to select a file to open.
4096 * RETURNS
4097 * TRUE on success: user enters a valid file
4098 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4101 BOOL WINAPI GetOpenFileNameW(
4102 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4104 BOOL win16look = FALSE;
4106 TRACE("flags %08x\n", ofn->Flags);
4108 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4109 if (ofn->Flags & OFN_FILEMUSTEXIST)
4110 ofn->Flags |= OFN_PATHMUSTEXIST;
4112 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4113 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4115 if (win16look)
4116 return GetFileName31W(ofn, OPEN_DIALOG);
4117 else
4118 return GetFileDialog95W(ofn, OPEN_DIALOG);
4122 /***********************************************************************
4123 * GetSaveFileNameA (COMDLG32.@)
4125 * Creates a dialog box for the user to select a file to save.
4127 * RETURNS
4128 * TRUE on success: user enters a valid file
4129 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4132 BOOL WINAPI GetSaveFileNameA(
4133 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4135 BOOL win16look = FALSE;
4137 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4138 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4140 if (win16look)
4141 return GetFileName31A(ofn, SAVE_DIALOG);
4142 else
4143 return GetFileDialog95A(ofn, SAVE_DIALOG);
4146 /***********************************************************************
4147 * GetSaveFileNameW (COMDLG32.@)
4149 * Creates a dialog box for the user to select a file to save.
4151 * RETURNS
4152 * TRUE on success: user enters a valid file
4153 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4156 BOOL WINAPI GetSaveFileNameW(
4157 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4159 BOOL win16look = FALSE;
4161 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4162 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4164 if (win16look)
4165 return GetFileName31W(ofn, SAVE_DIALOG);
4166 else
4167 return GetFileDialog95W(ofn, SAVE_DIALOG);
4170 /***********************************************************************
4171 * GetFileTitleA (COMDLG32.@)
4173 * See GetFileTitleW.
4175 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4177 int ret;
4178 UNICODE_STRING strWFile;
4179 LPWSTR lpWTitle;
4181 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4182 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4183 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4184 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4185 RtlFreeUnicodeString( &strWFile );
4186 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4187 return ret;
4191 /***********************************************************************
4192 * GetFileTitleW (COMDLG32.@)
4194 * Get the name of a file.
4196 * PARAMS
4197 * lpFile [I] name and location of file
4198 * lpTitle [O] returned file name
4199 * cbBuf [I] buffer size of lpTitle
4201 * RETURNS
4202 * Success: zero
4203 * Failure: negative number.
4205 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4207 int i, len;
4208 static const WCHAR brkpoint[] = {'*','[',']',0};
4209 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4211 if(lpFile == NULL || lpTitle == NULL)
4212 return -1;
4214 len = lstrlenW(lpFile);
4216 if (len == 0)
4217 return -1;
4219 if(strpbrkW(lpFile, brkpoint))
4220 return -1;
4222 len--;
4224 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4225 return -1;
4227 for(i = len; i >= 0; i--)
4229 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4231 i++;
4232 break;
4236 if(i == -1)
4237 i++;
4239 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4241 len = lstrlenW(lpFile+i)+1;
4242 if(cbBuf < len)
4243 return len;
4245 lstrcpyW(lpTitle, &lpFile[i]);
4246 return 0;