push 8b07bf1f08b23b9893a622b47d2be359556765b1
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blobafd02dcaa57fda19bfdb4f2e291d859214b7ef73
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 /* msdn: explorer style dialogs permit sizing by default.
275 * The OFN_ENABLESIZING flag is only needed when a hook or
276 * custom tmeplate is provided */
277 if( (fodInfos->ofnInfos->Flags & OFN_EXPLORER) &&
278 !(fodInfos->ofnInfos->Flags & ( OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
279 fodInfos->ofnInfos->Flags |= OFN_ENABLESIZING;
281 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
283 ((LPDLGTEMPLATEW)template)->style |= WS_SIZEBOX;
284 fodInfos->sizedlg.cx = fodInfos->sizedlg.cy = 0;
285 fodInfos->initial_size.x = fodInfos->initial_size.y = 0;
287 else
288 ((LPDLGTEMPLATEW)template)->style &= ~WS_SIZEBOX;
291 /* old style hook messages */
292 if (IsHooked(fodInfos))
294 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
295 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
296 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
297 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
300 /* Some shell namespace extensions depend on COM being initialized. */
301 hr = OleInitialize(NULL);
303 if (fodInfos->unicode)
304 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
305 template,
306 fodInfos->ofnInfos->hwndOwner,
307 FileOpenDlgProc95,
308 (LPARAM) fodInfos);
309 else
310 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
311 template,
312 fodInfos->ofnInfos->hwndOwner,
313 FileOpenDlgProc95,
314 (LPARAM) fodInfos);
315 if (SUCCEEDED(hr))
316 OleUninitialize();
318 /* Unable to create the dialog */
319 if( lRes == -1)
320 return FALSE;
322 return lRes;
325 /***********************************************************************
326 * GetFileDialog95A
328 * Call GetFileName95 with this structure and clean the memory.
330 * IN : The OPENFILENAMEA initialisation structure passed to
331 * GetOpenFileNameA win api function (see filedlg.c)
333 static BOOL GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
335 BOOL ret;
336 FileOpenDlgInfos fodInfos;
337 LPSTR lpstrSavDir = NULL;
338 LPWSTR title = NULL;
339 LPWSTR defext = NULL;
340 LPWSTR filter = NULL;
341 LPWSTR customfilter = NULL;
343 /* Initialize CommDlgExtendedError() */
344 COMDLG32_SetCommDlgExtendedError(0);
346 /* Initialize FileOpenDlgInfos structure */
347 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
349 /* Pass in the original ofn */
350 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
352 /* save current directory */
353 if (ofn->Flags & OFN_NOCHANGEDIR)
355 lpstrSavDir = MemAlloc(MAX_PATH);
356 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
359 fodInfos.unicode = FALSE;
361 /* convert all the input strings to unicode */
362 if(ofn->lpstrInitialDir)
364 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
365 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
366 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
368 else
369 fodInfos.initdir = NULL;
371 if(ofn->lpstrFile)
373 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
374 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
376 else
377 fodInfos.filename = NULL;
379 if(ofn->lpstrDefExt)
381 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
382 defext = MemAlloc((len+1)*sizeof(WCHAR));
383 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
385 fodInfos.defext = defext;
387 if(ofn->lpstrTitle)
389 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
390 title = MemAlloc((len+1)*sizeof(WCHAR));
391 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
393 fodInfos.title = title;
395 if (ofn->lpstrFilter)
397 LPCSTR s;
398 int n, len;
400 /* filter is a list... title\0ext\0......\0\0 */
401 s = ofn->lpstrFilter;
402 while (*s) s = s+strlen(s)+1;
403 s++;
404 n = s - ofn->lpstrFilter;
405 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
406 filter = MemAlloc(len*sizeof(WCHAR));
407 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
409 fodInfos.filter = filter;
411 /* convert lpstrCustomFilter */
412 if (ofn->lpstrCustomFilter)
414 LPCSTR s;
415 int n, len;
417 /* customfilter contains a pair of strings... title\0ext\0 */
418 s = ofn->lpstrCustomFilter;
419 if (*s) s = s+strlen(s)+1;
420 if (*s) s = s+strlen(s)+1;
421 n = s - ofn->lpstrCustomFilter;
422 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
423 customfilter = MemAlloc(len*sizeof(WCHAR));
424 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
426 fodInfos.customfilter = customfilter;
428 /* Initialize the dialog property */
429 fodInfos.DlgInfos.dwDlgProp = 0;
430 fodInfos.DlgInfos.hwndCustomDlg = NULL;
432 switch(iDlgType)
434 case OPEN_DIALOG :
435 ret = GetFileName95(&fodInfos);
436 break;
437 case SAVE_DIALOG :
438 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
439 ret = GetFileName95(&fodInfos);
440 break;
441 default :
442 ret = 0;
445 if (lpstrSavDir)
447 SetCurrentDirectoryA(lpstrSavDir);
448 MemFree(lpstrSavDir);
451 MemFree(title);
452 MemFree(defext);
453 MemFree(filter);
454 MemFree(customfilter);
455 MemFree(fodInfos.initdir);
456 MemFree(fodInfos.filename);
458 TRACE("selected file: %s\n",ofn->lpstrFile);
460 return ret;
463 /***********************************************************************
464 * GetFileDialog95W
466 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
467 * Call GetFileName95 with this structure and clean the memory.
470 static BOOL GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
472 BOOL ret;
473 FileOpenDlgInfos fodInfos;
474 LPWSTR lpstrSavDir = NULL;
476 /* Initialize CommDlgExtendedError() */
477 COMDLG32_SetCommDlgExtendedError(0);
479 /* Initialize FileOpenDlgInfos structure */
480 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
482 /* Pass in the original ofn */
483 fodInfos.ofnInfos = ofn;
485 fodInfos.title = ofn->lpstrTitle;
486 fodInfos.defext = ofn->lpstrDefExt;
487 fodInfos.filter = ofn->lpstrFilter;
488 fodInfos.customfilter = ofn->lpstrCustomFilter;
490 /* convert string arguments, save others */
491 if(ofn->lpstrFile)
493 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
494 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
496 else
497 fodInfos.filename = NULL;
499 if(ofn->lpstrInitialDir)
501 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
502 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
503 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
504 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
506 else
507 fodInfos.initdir = NULL;
509 /* save current directory */
510 if (ofn->Flags & OFN_NOCHANGEDIR)
512 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
513 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
516 fodInfos.unicode = TRUE;
518 switch(iDlgType)
520 case OPEN_DIALOG :
521 ret = GetFileName95(&fodInfos);
522 break;
523 case SAVE_DIALOG :
524 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
525 ret = GetFileName95(&fodInfos);
526 break;
527 default :
528 ret = 0;
531 if (lpstrSavDir)
533 SetCurrentDirectoryW(lpstrSavDir);
534 MemFree(lpstrSavDir);
537 /* restore saved IN arguments and convert OUT arguments back */
538 MemFree(fodInfos.filename);
539 MemFree(fodInfos.initdir);
540 return ret;
543 /******************************************************************************
544 * COMDLG32_GetDisplayNameOf [internal]
546 * Helper function to get the display name for a pidl.
548 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
549 LPSHELLFOLDER psfDesktop;
550 STRRET strret;
552 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
553 return FALSE;
555 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
556 IShellFolder_Release(psfDesktop);
557 return FALSE;
560 IShellFolder_Release(psfDesktop);
561 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
564 /***********************************************************************
565 * ArrangeCtrlPositions [internal]
567 * NOTE: Make sure to add testcases for any changes made here.
569 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
571 HWND hwndChild, hwndStc32;
572 RECT rectParent, rectChild, rectStc32;
573 INT help_fixup = 0;
574 int chgx, chgy;
576 /* Take into account if open as read only checkbox and help button
577 * are hidden
579 if (hide_help)
581 RECT rectHelp, rectCancel;
582 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
583 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
584 /* subtract the height of the help button plus the space between
585 * the help button and the cancel button to the height of the dialog
587 help_fixup = rectHelp.bottom - rectCancel.bottom;
591 There are two possibilities to add components to the default file dialog box.
593 By default, all the new components are added below the standard dialog box (the else case).
595 However, if there is a static text component with the stc32 id, a special case happens.
596 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
597 in the window and the cx and cy indicate how to size the window.
598 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
599 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
603 GetClientRect(hwndParentDlg, &rectParent);
605 /* when arranging controls we have to use fixed parent size */
606 rectParent.bottom -= help_fixup;
608 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
609 if (hwndStc32)
611 GetWindowRect(hwndStc32, &rectStc32);
612 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
614 /* set the size of the stc32 control according to the size of
615 * client area of the parent dialog
617 SetWindowPos(hwndStc32, 0,
618 0, 0,
619 rectParent.right, rectParent.bottom,
620 SWP_NOMOVE | SWP_NOZORDER);
622 else
623 SetRectEmpty(&rectStc32);
625 /* this part moves controls of the child dialog */
626 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
627 while (hwndChild)
629 if (hwndChild != hwndStc32)
631 GetWindowRect(hwndChild, &rectChild);
632 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
634 /* move only if stc32 exist */
635 if (hwndStc32 && rectChild.left > rectStc32.right)
637 /* move to the right of visible controls of the parent dialog */
638 rectChild.left += rectParent.right;
639 rectChild.left -= rectStc32.right;
641 /* move even if stc32 doesn't exist */
642 if (rectChild.top >= rectStc32.bottom)
644 /* move below visible controls of the parent dialog */
645 rectChild.top += rectParent.bottom;
646 rectChild.top -= rectStc32.bottom - rectStc32.top;
649 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
650 0, 0, SWP_NOSIZE | SWP_NOZORDER);
652 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
655 /* this part moves controls of the parent dialog */
656 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
657 while (hwndChild)
659 if (hwndChild != hwndChildDlg)
661 GetWindowRect(hwndChild, &rectChild);
662 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
664 /* left,top of stc32 marks the position of controls
665 * from the parent dialog
667 rectChild.left += rectStc32.left;
668 rectChild.top += rectStc32.top;
670 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
671 0, 0, SWP_NOSIZE | SWP_NOZORDER);
673 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
676 /* calculate the size of the resulting dialog */
678 /* here we have to use original parent size */
679 GetClientRect(hwndParentDlg, &rectParent);
680 GetClientRect(hwndChildDlg, &rectChild);
681 TRACE( "parent %s child %s stc32 %s\n", wine_dbgstr_rect( &rectParent),
682 wine_dbgstr_rect( &rectChild), wine_dbgstr_rect( &rectStc32));
684 if (hwndStc32)
686 /* width */
687 if (rectParent.right > rectStc32.right - rectStc32.left)
688 chgx = rectChild.right - ( rectStc32.right - rectStc32.left);
689 else
690 chgx = rectChild.right - rectParent.right;
691 /* height */
692 if (rectParent.bottom > rectStc32.bottom - rectStc32.top)
693 chgy = rectChild.bottom - ( rectStc32.bottom - rectStc32.top) - help_fixup;
694 else
695 /* Unconditionally set new dialog
696 * height to that of the child
698 chgy = rectChild.bottom - rectParent.bottom;
700 else
702 chgx = 0;
703 chgy = rectChild.bottom - help_fixup;
705 /* set the size of the parent dialog */
706 GetWindowRect(hwndParentDlg, &rectParent);
707 SetWindowPos(hwndParentDlg, 0,
708 0, 0,
709 rectParent.right - rectParent.left + chgx,
710 rectParent.bottom - rectParent.top + chgy,
711 SWP_NOMOVE | SWP_NOZORDER);
714 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 switch(uMsg) {
717 case WM_INITDIALOG:
718 return TRUE;
720 return FALSE;
723 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
725 LPCVOID template;
726 HRSRC hRes;
727 HANDLE hDlgTmpl = 0;
728 HWND hChildDlg = 0;
730 TRACE("\n");
733 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
734 * structure's hInstance parameter is not a HINSTANCE, but
735 * instead a pointer to a template resource to use.
737 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
739 HINSTANCE hinst;
740 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
742 hinst = COMDLG32_hInstance;
743 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
745 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
746 return NULL;
749 else
751 hinst = fodInfos->ofnInfos->hInstance;
752 if(fodInfos->unicode)
754 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
755 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
757 else
759 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
760 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
762 if (!hRes)
764 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
765 return NULL;
767 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
768 !(template = LockResource( hDlgTmpl )))
770 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
771 return NULL;
774 if (fodInfos->unicode)
775 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
776 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
777 (LPARAM)fodInfos->ofnInfos);
778 else
779 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
780 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
781 (LPARAM)fodInfos->ofnInfos);
782 return hChildDlg;
784 else if( IsHooked(fodInfos))
786 RECT rectHwnd;
787 struct {
788 DLGTEMPLATE tmplate;
789 WORD menu,class,title;
790 } temp;
791 GetClientRect(hwnd,&rectHwnd);
792 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
793 temp.tmplate.dwExtendedStyle = 0;
794 temp.tmplate.cdit = 0;
795 temp.tmplate.x = 0;
796 temp.tmplate.y = 0;
797 temp.tmplate.cx = 0;
798 temp.tmplate.cy = 0;
799 temp.menu = temp.class = temp.title = 0;
801 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
802 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
804 return hChildDlg;
806 return NULL;
809 /***********************************************************************
810 * SendCustomDlgNotificationMessage
812 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
815 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
817 LRESULT hook_result = 0;
818 FileOpenDlgInfos *fodInfos = GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
820 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
822 if(!fodInfos) return 0;
824 if(fodInfos->DlgInfos.hwndCustomDlg)
826 TRACE("CALL NOTIFY for %x\n", uCode);
827 if(fodInfos->unicode)
829 OFNOTIFYW ofnNotify;
830 ofnNotify.hdr.hwndFrom=hwndParentDlg;
831 ofnNotify.hdr.idFrom=0;
832 ofnNotify.hdr.code = uCode;
833 ofnNotify.lpOFN = fodInfos->ofnInfos;
834 ofnNotify.pszFile = NULL;
835 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
837 else
839 OFNOTIFYA ofnNotify;
840 ofnNotify.hdr.hwndFrom=hwndParentDlg;
841 ofnNotify.hdr.idFrom=0;
842 ofnNotify.hdr.code = uCode;
843 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
844 ofnNotify.pszFile = NULL;
845 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
847 TRACE("RET NOTIFY\n");
849 TRACE("Retval: 0x%08lx\n", hook_result);
850 return hook_result;
853 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID result)
855 UINT len, total;
856 WCHAR *p, *buffer;
857 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
859 TRACE("CDM_GETFILEPATH:\n");
861 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
862 return -1;
864 /* get path and filenames */
865 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
866 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
867 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
868 if (len)
870 p = buffer + strlenW(buffer);
871 *p++ = '\\';
872 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
874 if (fodInfos->unicode)
876 total = strlenW( buffer) + 1;
877 if (result) lstrcpynW( result, buffer, size );
878 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
880 else
882 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
883 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
884 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
886 HeapFree( GetProcessHeap(), 0, buffer );
887 return total;
890 /***********************************************************************
891 * FILEDLG95_HandleCustomDialogMessages
893 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
895 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
897 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
898 WCHAR lpstrPath[MAX_PATH];
899 INT_PTR retval;
901 if(!fodInfos) return FALSE;
903 switch(uMsg)
905 case CDM_GETFILEPATH:
906 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
907 break;
909 case CDM_GETFOLDERPATH:
910 TRACE("CDM_GETFOLDERPATH:\n");
911 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
912 if (lParam)
914 if (fodInfos->unicode)
915 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
916 else
917 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
918 (LPSTR)lParam, (int)wParam, NULL, NULL);
920 retval = lstrlenW(lpstrPath) + 1;
921 break;
923 case CDM_GETFOLDERIDLIST:
924 retval = COMDLG32_PIDL_ILGetSize(fodInfos->ShellInfos.pidlAbsCurrent);
925 if (retval <= wParam)
926 memcpy((void*)lParam, fodInfos->ShellInfos.pidlAbsCurrent, retval);
927 break;
929 case CDM_GETSPEC:
930 TRACE("CDM_GETSPEC:\n");
931 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
932 if (lParam)
934 if (fodInfos->unicode)
935 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
936 else
937 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
939 break;
941 case CDM_SETCONTROLTEXT:
942 TRACE("CDM_SETCONTROLTEXT:\n");
943 if ( lParam )
945 if( fodInfos->unicode )
946 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
947 else
948 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
950 retval = TRUE;
951 break;
953 case CDM_HIDECONTROL:
954 /* MSDN states that it should fail for not OFN_EXPLORER case */
955 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
957 HWND control = GetDlgItem( hwnd, wParam );
958 if (control) ShowWindow( control, SW_HIDE );
959 retval = TRUE;
961 else retval = FALSE;
962 break;
964 default:
965 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
966 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
967 return FALSE;
969 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
970 return TRUE;
973 /***********************************************************************
974 * FILEDLG95_OnWMGetMMI
976 * WM_GETMINMAXINFO message handler for resizable dialogs
978 static LRESULT FILEDLG95_OnWMGetMMI( HWND hwnd, LPMINMAXINFO mmiptr)
980 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
981 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
982 if( fodInfos->initial_size.x || fodInfos->initial_size.y)
984 mmiptr->ptMinTrackSize = fodInfos->initial_size;
986 return TRUE;
989 /***********************************************************************
990 * FILEDLG95_OnWMSize
992 * WM_SIZE message handler, resize the dialog. Re-arrange controls.
994 * FIXME: this could be made more elaborate. Now use a simple scheme
995 * where the file view is enlarged and the controls are either moved
996 * vertically or horizontally to get out of the way. Only the "grip"
997 * is moved in both directions to stay in the corner.
999 static LRESULT FILEDLG95_OnWMSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1001 RECT rc, rcview;
1002 int chgx, chgy;
1003 HWND ctrl;
1004 HDWP hdwp;
1005 FileOpenDlgInfos *fodInfos;
1007 if( wParam != SIZE_RESTORED) return FALSE;
1008 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1009 if( !(fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)) return FALSE;
1010 /* get the new dialog rectangle */
1011 GetWindowRect( hwnd, &rc);
1012 TRACE("Size from %d,%d to %d,%d\n", fodInfos->sizedlg.cx, fodInfos->sizedlg.cy,
1013 rc.right -rc.left, rc.bottom -rc.top);
1014 /* not initialized yet */
1015 if( (fodInfos->sizedlg.cx == 0 && fodInfos->sizedlg.cy == 0) ||
1016 ((fodInfos->sizedlg.cx == rc.right -rc.left) && /* no change */
1017 (fodInfos->sizedlg.cy == rc.bottom -rc.top)))
1018 return FALSE;
1019 chgx = rc.right - rc.left - fodInfos->sizedlg.cx;
1020 chgy = rc.bottom - rc.top - fodInfos->sizedlg.cy;
1021 fodInfos->sizedlg.cx = rc.right - rc.left;
1022 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1023 /* change the size of the view window */
1024 GetWindowRect( fodInfos->ShellInfos.hwndView, &rcview);
1025 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcview, 2);
1026 hdwp = BeginDeferWindowPos( 10);
1027 DeferWindowPos( hdwp, fodInfos->ShellInfos.hwndView, NULL, 0, 0,
1028 rcview.right - rcview.left + chgx,
1029 rcview.bottom - rcview.top + chgy,
1030 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1031 /* change position and sizes of the controls */
1032 for( ctrl = GetWindow( hwnd, GW_CHILD); ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1034 int ctrlid = GetDlgCtrlID( ctrl);
1035 GetWindowRect( ctrl, &rc);
1036 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1037 if( ctrl == fodInfos->DlgInfos.hwndGrip)
1039 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1040 0, 0,
1041 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1043 else if( rc.top > rcview.bottom)
1045 /* if it was below the shell view
1046 * move to bottom */
1047 switch( ctrlid)
1049 /* file name box and file types combo change also width */
1050 case edt1:
1051 case cmb1:
1052 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1053 rc.right - rc.left + chgx, rc.bottom - rc.top,
1054 SWP_NOACTIVATE | SWP_NOZORDER);
1055 break;
1056 /* then these buttons must move out of the way */
1057 case IDOK:
1058 case IDCANCEL:
1059 case pshHelp:
1060 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top + chgy,
1061 0, 0,
1062 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1063 break;
1064 default:
1065 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1066 0, 0,
1067 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1070 else if( rc.left > rcview.right)
1072 /* if it was to the right of the shell view
1073 * move to right */
1074 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1075 0, 0,
1076 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1078 else
1079 /* special cases */
1081 switch( ctrlid)
1083 #if 0 /* this is Win2k, Win XP. Vista and Higher don't move/size these controls */
1084 case IDC_LOOKIN:
1085 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1086 rc.right - rc.left + chgx, rc.bottom - rc.top,
1087 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1088 break;
1089 case IDC_TOOLBARSTATIC:
1090 case IDC_TOOLBAR:
1091 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1092 0, 0,
1093 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1094 break;
1095 #endif
1096 /* not resized in windows. Since wine uses this invisible control
1097 * to size the browser view it needs to be resized */
1098 case IDC_SHELLSTATIC:
1099 DeferWindowPos( hdwp, ctrl, NULL, 0, 0,
1100 rc.right - rc.left + chgx,
1101 rc.bottom - rc.top + chgy,
1102 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1103 break;
1107 if(fodInfos->DlgInfos.hwndCustomDlg &&
1108 (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
1110 for( ctrl = GetWindow( fodInfos->DlgInfos.hwndCustomDlg, GW_CHILD);
1111 ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT))
1113 GetWindowRect( ctrl, &rc);
1114 MapWindowPoints( NULL, hwnd, (LPPOINT) &rc, 2);
1115 if( rc.top > rcview.bottom)
1117 /* if it was below the shell view
1118 * move to bottom */
1119 DeferWindowPos( hdwp, ctrl, NULL, rc.left, rc.top + chgy,
1120 rc.right - rc.left, rc.bottom - rc.top,
1121 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1123 else if( rc.left > rcview.right)
1125 /* if it was to the right of the shell view
1126 * move to right */
1127 DeferWindowPos( hdwp, ctrl, NULL, rc.left + chgx, rc.top,
1128 rc.right - rc.left, rc.bottom - rc.top,
1129 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1132 /* size the custom dialog at the end: some applications do some
1133 * control re-arranging at this point */
1134 GetClientRect(hwnd, &rc);
1135 DeferWindowPos( hdwp,fodInfos->DlgInfos.hwndCustomDlg, NULL,
1136 0, 0, rc.right, rc.bottom, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1138 EndDeferWindowPos( hdwp);
1139 /* should not be needed */
1140 RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_INVALIDATE );
1141 return TRUE;
1144 /***********************************************************************
1145 * FileOpenDlgProc95
1147 * File open dialog procedure
1149 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1151 #if 0
1152 TRACE("%p 0x%04x\n", hwnd, uMsg);
1153 #endif
1155 switch(uMsg)
1157 case WM_INITDIALOG:
1159 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1160 RECT rc, rcstc;
1161 int gripx = GetSystemMetrics( SM_CYHSCROLL);
1162 int gripy = GetSystemMetrics( SM_CYVSCROLL);
1164 /* Adds the FileOpenDlgInfos in the property list of the dialog
1165 so it will be easily accessible through a GetPropA(...) */
1166 SetPropA(hwnd, FileOpenDlgInfosStr, fodInfos);
1168 FILEDLG95_InitControls(hwnd);
1170 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1172 GetWindowRect( hwnd, &rc);
1173 fodInfos->DlgInfos.hwndGrip =
1174 CreateWindowExA( 0, "SCROLLBAR", NULL,
1175 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
1176 SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN,
1177 rc.right - gripx, rc.bottom - gripy,
1178 gripx, gripy, hwnd, (HMENU) -1, COMDLG32_hInstance, NULL);
1181 fodInfos->DlgInfos.hwndCustomDlg =
1182 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1184 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1185 FILEDLG95_FillControls(hwnd, wParam, lParam);
1187 if( fodInfos->DlgInfos.hwndCustomDlg)
1188 ShowWindow( fodInfos->DlgInfos.hwndCustomDlg, SW_SHOW);
1190 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER) {
1191 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1192 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1195 /* if the app has changed the position of the invisible listbox,
1196 * change that of the listview (browser) as well */
1197 GetWindowRect( fodInfos->ShellInfos.hwndView, &rc);
1198 GetWindowRect( GetDlgItem( hwnd, IDC_SHELLSTATIC ), &rcstc);
1199 if( !EqualRect( &rc, &rcstc))
1201 MapWindowPoints( NULL, hwnd, (LPPOINT) &rcstc, 2);
1202 SetWindowPos( fodInfos->ShellInfos.hwndView, NULL,
1203 rcstc.left, rcstc.top, rcstc.right - rcstc.left, rcstc.bottom - rcstc.top,
1204 SWP_NOACTIVATE | SWP_NOZORDER);
1207 if (fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1209 GetWindowRect( hwnd, &rc);
1210 fodInfos->sizedlg.cx = rc.right - rc.left;
1211 fodInfos->sizedlg.cy = rc.bottom - rc.top;
1212 fodInfos->initial_size.x = fodInfos->sizedlg.cx;
1213 fodInfos->initial_size.y = fodInfos->sizedlg.cy;
1214 GetClientRect( hwnd, &rc);
1215 SetWindowPos( fodInfos->DlgInfos.hwndGrip, NULL,
1216 rc.right - gripx, rc.bottom - gripy,
1217 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
1218 /* resize the dialog to the previous invocation */
1219 if( MemDialogSize.cx && MemDialogSize.cy)
1220 SetWindowPos( hwnd, NULL,
1221 0, 0, MemDialogSize.cx, MemDialogSize.cy,
1222 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
1225 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1226 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1228 return 0;
1230 case WM_SIZE:
1231 return FILEDLG95_OnWMSize(hwnd, wParam, lParam);
1232 case WM_GETMINMAXINFO:
1233 return FILEDLG95_OnWMGetMMI( hwnd, (LPMINMAXINFO)lParam);
1234 case WM_COMMAND:
1235 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1236 case WM_DRAWITEM:
1238 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1240 case IDC_LOOKIN:
1241 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1242 return TRUE;
1245 return FALSE;
1247 case WM_GETISHELLBROWSER:
1248 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1250 case WM_DESTROY:
1252 FileOpenDlgInfos * fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1253 if (fodInfos && fodInfos->ofnInfos->Flags & OFN_ENABLESIZING)
1254 MemDialogSize = fodInfos->sizedlg;
1255 RemovePropA(hwnd, FileOpenDlgInfosStr);
1256 return FALSE;
1258 case WM_NOTIFY:
1260 LPNMHDR lpnmh = (LPNMHDR)lParam;
1261 UINT stringId = -1;
1263 /* set up the button tooltips strings */
1264 if(TTN_GETDISPINFOA == lpnmh->code )
1266 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1267 switch(lpnmh->idFrom )
1269 /* Up folder button */
1270 case FCIDM_TB_UPFOLDER:
1271 stringId = IDS_UPFOLDER;
1272 break;
1273 /* New folder button */
1274 case FCIDM_TB_NEWFOLDER:
1275 stringId = IDS_NEWFOLDER;
1276 break;
1277 /* List option button */
1278 case FCIDM_TB_SMALLICON:
1279 stringId = IDS_LISTVIEW;
1280 break;
1281 /* Details option button */
1282 case FCIDM_TB_REPORTVIEW:
1283 stringId = IDS_REPORTVIEW;
1284 break;
1285 /* Desktop button */
1286 case FCIDM_TB_DESKTOP:
1287 stringId = IDS_TODESKTOP;
1288 break;
1289 default:
1290 stringId = 0;
1292 lpdi->hinst = COMDLG32_hInstance;
1293 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1295 return FALSE;
1297 default :
1298 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1299 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1300 return FALSE;
1304 /***********************************************************************
1305 * FILEDLG95_InitControls
1307 * WM_INITDIALOG message handler (before hook notification)
1309 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1311 int win2000plus = 0;
1312 int win98plus = 0;
1313 int handledPath = FALSE;
1314 OSVERSIONINFOW osVi;
1315 static const WCHAR szwSlash[] = { '\\', 0 };
1316 static const WCHAR szwStar[] = { '*',0 };
1318 static const TBBUTTON tbb[] =
1320 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1321 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1322 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1323 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1324 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1325 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1326 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1327 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1328 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1330 static const TBADDBITMAP tba = {HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR};
1332 RECT rectTB;
1333 RECT rectlook;
1335 HIMAGELIST toolbarImageList;
1336 SHFILEINFOA shFileInfo;
1337 ITEMIDLIST *desktopPidl;
1339 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1341 TRACE("%p\n", fodInfos);
1343 /* Get windows version emulating */
1344 osVi.dwOSVersionInfoSize = sizeof(osVi);
1345 GetVersionExW(&osVi);
1346 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1347 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1348 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1349 win2000plus = (osVi.dwMajorVersion > 4);
1350 if (win2000plus) win98plus = TRUE;
1352 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1354 /* Get the hwnd of the controls */
1355 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1356 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1357 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1359 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1360 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1362 /* construct the toolbar */
1363 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1364 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1366 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1367 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1368 rectTB.left = rectlook.right;
1369 rectTB.top = rectlook.top-1;
1371 if (fodInfos->unicode)
1372 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1373 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1374 rectTB.left, rectTB.top,
1375 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1376 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1377 else
1378 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1379 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1380 rectTB.left, rectTB.top,
1381 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1382 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1384 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1386 /* FIXME: use TB_LOADIMAGES when implemented */
1387 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1388 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_SETMAXTEXTROWS, 0, 0);
1389 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba);
1391 /* Retrieve and add desktop icon to the toolbar */
1392 toolbarImageList = (HIMAGELIST)SendMessageW(fodInfos->DlgInfos.hwndTB, TB_GETIMAGELIST, 0, 0L);
1393 SHGetSpecialFolderLocation(hwnd, CSIDL_DESKTOP, &desktopPidl);
1394 SHGetFileInfoA((LPCSTR)desktopPidl, 0, &shFileInfo, sizeof(shFileInfo),
1395 SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON);
1396 ImageList_AddIcon(toolbarImageList, shFileInfo.hIcon);
1398 DestroyIcon(shFileInfo.hIcon);
1399 CoTaskMemFree(desktopPidl);
1401 /* Finish Toolbar Construction */
1402 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) tbb);
1403 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1405 /* Set the window text with the text specified in the OPENFILENAME structure */
1406 if(fodInfos->title)
1408 SetWindowTextW(hwnd,fodInfos->title);
1410 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1412 WCHAR buf[16];
1413 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1414 SetWindowTextW(hwnd, buf);
1417 /* Initialise the file name edit control */
1418 handledPath = FALSE;
1419 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1421 if(fodInfos->filename)
1423 /* 1. If win2000 or higher and filename contains a path, use it
1424 in preference over the lpstrInitialDir */
1425 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1426 WCHAR tmpBuf[MAX_PATH];
1427 WCHAR *nameBit;
1428 DWORD result;
1430 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1431 if (result) {
1433 /* nameBit is always shorter than the original filename */
1434 lstrcpyW(fodInfos->filename,nameBit);
1436 *nameBit = 0x00;
1437 if (fodInfos->initdir == NULL)
1438 MemFree(fodInfos->initdir);
1439 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1440 lstrcpyW(fodInfos->initdir, tmpBuf);
1441 handledPath = TRUE;
1442 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1443 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1445 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1447 } else {
1448 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1452 /* 2. (All platforms) If initdir is not null, then use it */
1453 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1454 (*fodInfos->initdir!=0x00))
1456 /* Work out the proper path as supplied one might be relative */
1457 /* (Here because supplying '.' as dir browses to My Computer) */
1458 if (handledPath==FALSE) {
1459 WCHAR tmpBuf[MAX_PATH];
1460 WCHAR tmpBuf2[MAX_PATH];
1461 WCHAR *nameBit;
1462 DWORD result;
1464 lstrcpyW(tmpBuf, fodInfos->initdir);
1465 if( PathFileExistsW(tmpBuf) ) {
1466 /* initdir does not have to be a directory. If a file is
1467 * specified, the dir part is taken */
1468 if( PathIsDirectoryW(tmpBuf)) {
1469 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1470 lstrcatW(tmpBuf, szwSlash);
1472 lstrcatW(tmpBuf, szwStar);
1474 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1475 if (result) {
1476 *nameBit = 0x00;
1477 MemFree(fodInfos->initdir);
1478 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1479 lstrcpyW(fodInfos->initdir, tmpBuf2);
1480 handledPath = TRUE;
1481 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1484 else if (fodInfos->initdir)
1486 MemFree(fodInfos->initdir);
1487 fodInfos->initdir = NULL;
1488 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1493 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1494 (*fodInfos->initdir==0x00)))
1496 /* 3. All except w2k+: if filename contains a path use it */
1497 if (!win2000plus && fodInfos->filename &&
1498 *fodInfos->filename &&
1499 strpbrkW(fodInfos->filename, szwSlash)) {
1500 WCHAR tmpBuf[MAX_PATH];
1501 WCHAR *nameBit;
1502 DWORD result;
1504 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1505 tmpBuf, &nameBit);
1506 if (result) {
1507 int len;
1509 /* nameBit is always shorter than the original filename */
1510 lstrcpyW(fodInfos->filename, nameBit);
1511 *nameBit = 0x00;
1513 len = lstrlenW(tmpBuf);
1514 MemFree(fodInfos->initdir);
1515 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1516 lstrcpyW(fodInfos->initdir, tmpBuf);
1518 handledPath = TRUE;
1519 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1520 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1522 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1525 /* 4. win98+ and win2000+ if any files of specified filter types in
1526 current directory, use it */
1527 if ( win98plus && handledPath == FALSE &&
1528 fodInfos->filter && *fodInfos->filter) {
1530 BOOL searchMore = TRUE;
1531 LPCWSTR lpstrPos = fodInfos->filter;
1532 WIN32_FIND_DATAW FindFileData;
1533 HANDLE hFind;
1535 while (searchMore)
1537 /* filter is a list... title\0ext\0......\0\0 */
1539 /* Skip the title */
1540 if(! *lpstrPos) break; /* end */
1541 lpstrPos += lstrlenW(lpstrPos) + 1;
1543 /* See if any files exist in the current dir with this extension */
1544 if(! *lpstrPos) break; /* end */
1546 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1548 if (hFind == INVALID_HANDLE_VALUE) {
1549 /* None found - continue search */
1550 lpstrPos += lstrlenW(lpstrPos) + 1;
1552 } else {
1553 searchMore = FALSE;
1555 MemFree(fodInfos->initdir);
1556 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1557 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1559 handledPath = TRUE;
1560 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1561 debugstr_w(lpstrPos));
1562 break;
1567 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1569 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1570 if (handledPath == FALSE && (win2000plus || win98plus)) {
1571 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1573 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1575 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1577 /* last fallback */
1578 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1579 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1580 } else {
1581 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1583 } else {
1584 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1586 handledPath = TRUE;
1587 } else if (handledPath==FALSE) {
1588 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1589 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1590 handledPath = TRUE;
1591 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1594 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1595 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1597 /* Must the open as read only check box be checked ?*/
1598 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1600 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1603 /* Must the open as read only check box be hidden? */
1604 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1606 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1607 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1610 /* Must the help button be hidden? */
1611 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1613 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1614 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1617 /* change Open to Save */
1618 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1620 WCHAR buf[16];
1621 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1622 SetDlgItemTextW(hwnd, IDOK, buf);
1623 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1624 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1627 /* Initialize the filter combo box */
1628 FILEDLG95_FILETYPE_Init(hwnd);
1630 return 0;
1633 /***********************************************************************
1634 * FILEDLG95_ResizeControls
1636 * WM_INITDIALOG message handler (after hook notification)
1638 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1640 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1642 if (fodInfos->DlgInfos.hwndCustomDlg)
1644 RECT rc;
1645 UINT flags = SWP_NOACTIVATE;
1647 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1648 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1650 /* resize the custom dialog to the parent size */
1651 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1652 GetClientRect(hwnd, &rc);
1653 else
1655 /* our own fake template is zero sized and doesn't have children, so
1656 * there is no need to resize it. Picasa depends on it.
1658 flags |= SWP_NOSIZE;
1659 SetRectEmpty(&rc);
1661 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1662 0, 0, rc.right, rc.bottom, flags);
1664 else
1666 /* Resize the height, if open as read only checkbox ad help button are
1667 * hidden and we are not using a custom template nor a customDialog
1669 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1670 (!(fodInfos->ofnInfos->Flags &
1671 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1673 RECT rectDlg, rectHelp, rectCancel;
1674 GetWindowRect(hwnd, &rectDlg);
1675 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1676 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1677 /* subtract the height of the help button plus the space between the help
1678 * button and the cancel button to the height of the dialog
1680 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1681 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1682 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1685 return TRUE;
1688 /***********************************************************************
1689 * FILEDLG95_FillControls
1691 * WM_INITDIALOG message handler (after hook notification)
1693 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1695 LPITEMIDLIST pidlItemId = NULL;
1697 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1699 TRACE("dir=%s file=%s\n",
1700 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1702 /* Get the initial directory pidl */
1704 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1706 WCHAR path[MAX_PATH];
1708 GetCurrentDirectoryW(MAX_PATH,path);
1709 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1712 /* Initialise shell objects */
1713 FILEDLG95_SHELL_Init(hwnd);
1715 /* Initialize the Look In combo box */
1716 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1718 /* Browse to the initial directory */
1719 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1721 /* Free pidlItem memory */
1722 COMDLG32_SHFree(pidlItemId);
1724 return TRUE;
1726 /***********************************************************************
1727 * FILEDLG95_Clean
1729 * Regroups all the cleaning functions of the filedlg
1731 void FILEDLG95_Clean(HWND hwnd)
1733 FILEDLG95_FILETYPE_Clean(hwnd);
1734 FILEDLG95_LOOKIN_Clean(hwnd);
1735 FILEDLG95_SHELL_Clean(hwnd);
1737 /***********************************************************************
1738 * FILEDLG95_OnWMCommand
1740 * WM_COMMAND message handler
1742 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1744 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1745 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1746 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1748 switch(wID)
1750 /* OK button */
1751 case IDOK:
1752 FILEDLG95_OnOpen(hwnd);
1753 break;
1754 /* Cancel button */
1755 case IDCANCEL:
1756 FILEDLG95_Clean(hwnd);
1757 EndDialog(hwnd, FALSE);
1758 break;
1759 /* Filetype combo box */
1760 case IDC_FILETYPE:
1761 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1762 break;
1763 /* LookIn combo box */
1764 case IDC_LOOKIN:
1765 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1766 break;
1768 /* --- toolbar --- */
1769 /* Up folder button */
1770 case FCIDM_TB_UPFOLDER:
1771 FILEDLG95_SHELL_UpFolder(hwnd);
1772 break;
1773 /* New folder button */
1774 case FCIDM_TB_NEWFOLDER:
1775 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1776 break;
1777 /* List option button */
1778 case FCIDM_TB_SMALLICON:
1779 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1780 break;
1781 /* Details option button */
1782 case FCIDM_TB_REPORTVIEW:
1783 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1784 break;
1785 /* Details option button */
1786 case FCIDM_TB_DESKTOP:
1787 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1788 break;
1790 case IDC_FILENAME:
1791 break;
1794 /* Do not use the listview selection anymore */
1795 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1796 return 0;
1799 /***********************************************************************
1800 * FILEDLG95_OnWMGetIShellBrowser
1802 * WM_GETISHELLBROWSER message handler
1804 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1806 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1808 TRACE("\n");
1810 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1812 return TRUE;
1816 /***********************************************************************
1817 * FILEDLG95_SendFileOK
1819 * Sends the CDN_FILEOK notification if required
1821 * RETURNS
1822 * TRUE if the dialog should close
1823 * FALSE if the dialog should not be closed
1825 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1827 /* ask the hook if we can close */
1828 if(IsHooked(fodInfos))
1830 LRESULT retval = 0;
1832 TRACE("---\n");
1833 /* First send CDN_FILEOK as MSDN doc says */
1834 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1835 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1836 if( retval)
1838 TRACE("canceled\n");
1839 return FALSE;
1842 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1843 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1844 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1845 if( retval)
1847 TRACE("canceled\n");
1848 return FALSE;
1851 return TRUE;
1854 /***********************************************************************
1855 * FILEDLG95_OnOpenMultipleFiles
1857 * Handles the opening of multiple files.
1859 * FIXME
1860 * check destination buffer size
1862 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1864 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1865 UINT nCount, nSizePath;
1866 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1868 TRACE("\n");
1870 if(fodInfos->unicode)
1872 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1873 ofn->lpstrFile[0] = '\0';
1875 else
1877 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1878 ofn->lpstrFile[0] = '\0';
1881 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1883 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1884 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1885 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1887 LPWSTR lpstrTemp = lpstrFileList;
1889 for ( nCount = 0; nCount < nFileCount; nCount++ )
1891 LPITEMIDLIST pidl;
1893 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1894 if (!pidl)
1896 WCHAR lpstrNotFound[100];
1897 WCHAR lpstrMsg[100];
1898 WCHAR tmp[400];
1899 static const WCHAR nl[] = {'\n',0};
1901 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1902 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1904 lstrcpyW(tmp, lpstrTemp);
1905 lstrcatW(tmp, nl);
1906 lstrcatW(tmp, lpstrNotFound);
1907 lstrcatW(tmp, nl);
1908 lstrcatW(tmp, lpstrMsg);
1910 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1911 return FALSE;
1914 /* move to the next file in the list of files */
1915 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1916 COMDLG32_SHFree(pidl);
1920 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1921 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1923 /* For "oldstyle" dialog the components have to
1924 be separated by blanks (not '\0'!) and short
1925 filenames have to be used! */
1926 FIXME("Components have to be separated by blanks\n");
1928 if(fodInfos->unicode)
1930 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1931 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1932 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1934 else
1936 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1938 if (ofn->lpstrFile != NULL)
1940 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1941 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1942 if (ofn->nMaxFile > nSizePath)
1944 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1945 ofn->lpstrFile + nSizePath,
1946 ofn->nMaxFile - nSizePath, NULL, NULL);
1951 fodInfos->ofnInfos->nFileOffset = nSizePath;
1952 fodInfos->ofnInfos->nFileExtension = 0;
1954 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1955 return FALSE;
1957 /* clean and exit */
1958 FILEDLG95_Clean(hwnd);
1959 return EndDialog(hwnd,TRUE);
1962 /***********************************************************************
1963 * FILEDLG95_OnOpen
1965 * Ok button WM_COMMAND message handler
1967 * If the function succeeds, the return value is nonzero.
1969 #define ONOPEN_BROWSE 1
1970 #define ONOPEN_OPEN 2
1971 #define ONOPEN_SEARCH 3
1972 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1974 WCHAR strMsgTitle[MAX_PATH];
1975 WCHAR strMsgText [MAX_PATH];
1976 if (idCaption)
1977 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1978 else
1979 strMsgTitle[0] = '\0';
1980 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1981 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1984 BOOL FILEDLG95_OnOpen(HWND hwnd)
1986 LPWSTR lpstrFileList;
1987 UINT nFileCount = 0;
1988 UINT sizeUsed = 0;
1989 BOOL ret = TRUE;
1990 WCHAR lpstrPathAndFile[MAX_PATH];
1991 WCHAR lpstrTemp[MAX_PATH];
1992 LPSHELLFOLDER lpsf = NULL;
1993 int nOpenAction;
1994 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1996 TRACE("hwnd=%p\n", hwnd);
1998 /* get the files from the edit control */
1999 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2001 /* try if the user selected a folder in the shellview */
2002 if(nFileCount == 0)
2004 BrowseSelectedFolder(hwnd);
2005 return FALSE;
2008 if(nFileCount > 1)
2010 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2011 goto ret;
2014 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2017 Step 1: Build a complete path name from the current folder and
2018 the filename or path in the edit box.
2019 Special cases:
2020 - the path in the edit box is a root path
2021 (with or without drive letter)
2022 - the edit box contains ".." (or a path with ".." in it)
2025 /* Get the current directory name */
2026 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2028 /* last fallback */
2029 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2031 PathAddBackslashW(lpstrPathAndFile);
2033 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2035 /* if the user specified a fully qualified path use it */
2036 if(PathIsRelativeW(lpstrFileList))
2038 lstrcatW(lpstrPathAndFile, lpstrFileList);
2040 else
2042 /* does the path have a drive letter? */
2043 if (PathGetDriveNumberW(lpstrFileList) == -1)
2044 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2045 else
2046 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2049 /* resolve "." and ".." */
2050 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2051 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2052 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2054 MemFree(lpstrFileList);
2057 Step 2: here we have a cleaned up path
2059 We have to parse the path step by step to see if we have to browse
2060 to a folder if the path points to a directory or the last
2061 valid element is a directory.
2063 valid variables:
2064 lpstrPathAndFile: cleaned up path
2067 if (nFileCount &&
2068 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2069 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2070 nOpenAction = ONOPEN_OPEN;
2071 else
2072 nOpenAction = ONOPEN_BROWSE;
2074 /* don't apply any checks with OFN_NOVALIDATE */
2076 LPWSTR lpszTemp, lpszTemp1;
2077 LPITEMIDLIST pidl = NULL;
2078 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2080 /* check for invalid chars */
2081 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2083 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2084 ret = FALSE;
2085 goto ret;
2088 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2090 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2091 while (lpszTemp1)
2093 LPSHELLFOLDER lpsfChild;
2094 WCHAR lpwstrTemp[MAX_PATH];
2095 DWORD dwEaten, dwAttributes;
2096 LPWSTR p;
2098 lstrcpyW(lpwstrTemp, lpszTemp);
2099 p = PathFindNextComponentW(lpwstrTemp);
2101 if (!p) break; /* end of path */
2103 *p = 0;
2104 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2106 /* There are no wildcards when OFN_NOVALIDATE is set */
2107 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2109 static const WCHAR wszWild[] = { '*', '?', 0 };
2110 /* if the last element is a wildcard do a search */
2111 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2113 nOpenAction = ONOPEN_SEARCH;
2114 break;
2117 lpszTemp1 = lpszTemp;
2119 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2121 /* append a backslash to drive letters */
2122 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2123 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2124 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2126 PathAddBackslashW(lpwstrTemp);
2129 dwAttributes = SFGAO_FOLDER;
2130 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2132 /* the path component is valid, we have a pidl of the next path component */
2133 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2134 if(dwAttributes & SFGAO_FOLDER)
2136 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2138 ERR("bind to failed\n"); /* should not fail */
2139 break;
2141 IShellFolder_Release(lpsf);
2142 lpsf = lpsfChild;
2143 lpsfChild = NULL;
2145 else
2147 TRACE("value\n");
2149 /* end dialog, return value */
2150 nOpenAction = ONOPEN_OPEN;
2151 break;
2153 COMDLG32_SHFree(pidl);
2154 pidl = NULL;
2156 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2158 if(*lpszTemp || /* points to trailing null for last path element */
2159 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2161 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2163 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2164 break;
2167 else
2169 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2170 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2172 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2173 break;
2176 /* change to the current folder */
2177 nOpenAction = ONOPEN_OPEN;
2178 break;
2180 else
2182 nOpenAction = ONOPEN_OPEN;
2183 break;
2186 if(pidl) COMDLG32_SHFree(pidl);
2190 Step 3: here we have a cleaned up and validated path
2192 valid variables:
2193 lpsf: ShellFolder bound to the rightmost valid path component
2194 lpstrPathAndFile: cleaned up path
2195 nOpenAction: action to do
2197 TRACE("end validate sf=%p\n", lpsf);
2199 switch(nOpenAction)
2201 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2202 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2204 int iPos;
2205 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2206 DWORD len;
2208 /* replace the current filter */
2209 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2210 len = lstrlenW(lpszTemp)+1;
2211 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2212 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2214 /* set the filter cb to the extension when possible */
2215 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2216 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2218 /* fall through */
2219 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2220 TRACE("ONOPEN_BROWSE\n");
2222 IPersistFolder2 * ppf2;
2223 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2225 LPITEMIDLIST pidlCurrent;
2226 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2227 IPersistFolder2_Release(ppf2);
2228 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2230 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2231 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2233 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2236 else if( nOpenAction == ONOPEN_SEARCH )
2238 if (fodInfos->Shell.FOIShellView)
2239 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2241 COMDLG32_SHFree(pidlCurrent);
2242 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2245 ret = FALSE;
2246 break;
2247 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2248 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2250 WCHAR *ext = NULL;
2252 /* update READONLY check box flag */
2253 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2254 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2255 else
2256 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2258 /* Attach the file extension with file name*/
2259 ext = PathFindExtensionW(lpstrPathAndFile);
2260 if (! *ext)
2262 /* if no extension is specified with file name, then */
2263 /* attach the extension from file filter or default one */
2265 WCHAR *filterExt = NULL;
2266 LPWSTR lpstrFilter = NULL;
2267 static const WCHAR szwDot[] = {'.',0};
2268 int PathLength = lstrlenW(lpstrPathAndFile);
2270 /* Attach the dot*/
2271 lstrcatW(lpstrPathAndFile, szwDot);
2273 /*Get the file extension from file type filter*/
2274 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2275 fodInfos->ofnInfos->nFilterIndex-1);
2277 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2278 filterExt = PathFindExtensionW(lpstrFilter);
2280 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2281 lstrcatW(lpstrPathAndFile, filterExt + 1);
2282 else if ( fodInfos->defext ) /* attach the default file extension*/
2283 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2285 /* In Open dialog: if file does not exist try without extension */
2286 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2287 lpstrPathAndFile[PathLength] = '\0';
2290 if (fodInfos->defext) /* add default extension */
2292 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2293 if (*ext)
2294 ext++;
2295 if (!lstrcmpiW(fodInfos->defext, ext))
2296 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2297 else
2298 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2301 /* In Save dialog: check if the file already exists */
2302 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2303 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2304 && PathFileExistsW(lpstrPathAndFile))
2306 WCHAR lpstrOverwrite[100];
2307 int answer;
2309 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2310 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2311 MB_YESNO | MB_ICONEXCLAMATION);
2312 if (answer == IDNO)
2314 ret = FALSE;
2315 goto ret;
2319 /* In Open dialog: check if it should be created if it doesn't exist */
2320 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2321 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2322 && !PathFileExistsW(lpstrPathAndFile))
2324 WCHAR lpstrCreate[100];
2325 int answer;
2327 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2328 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2329 MB_YESNO | MB_ICONEXCLAMATION);
2330 if (answer == IDNO)
2332 ret = FALSE;
2333 goto ret;
2337 /* Check that the size of the file does not exceed buffer size.
2338 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2339 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2340 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2343 /* fill destination buffer */
2344 if (fodInfos->ofnInfos->lpstrFile)
2346 if(fodInfos->unicode)
2348 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2350 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2351 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2352 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2354 else
2356 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2358 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2359 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2360 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2361 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2365 if(fodInfos->unicode)
2367 LPWSTR lpszTemp;
2369 /* set filename offset */
2370 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2371 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2373 /* set extension offset */
2374 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2375 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2377 else
2379 LPSTR lpszTemp;
2380 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2382 /* set filename offset */
2383 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2384 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2386 /* set extension offset */
2387 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2388 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2391 /* set the lpstrFileTitle */
2392 if(fodInfos->ofnInfos->lpstrFileTitle)
2394 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2395 if(fodInfos->unicode)
2397 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2398 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2400 else
2402 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2403 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2404 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2408 /* copy currently selected filter to lpstrCustomFilter */
2409 if (fodInfos->ofnInfos->lpstrCustomFilter)
2411 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2412 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2413 NULL, 0, NULL, NULL);
2414 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2416 LPSTR s = ofn->lpstrCustomFilter;
2417 s += strlen(ofn->lpstrCustomFilter)+1;
2418 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2419 s, len, NULL, NULL);
2424 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2425 goto ret;
2427 TRACE("close\n");
2428 FILEDLG95_Clean(hwnd);
2429 ret = EndDialog(hwnd, TRUE);
2431 else
2433 WORD size;
2435 size = lstrlenW(lpstrPathAndFile) + 1;
2436 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2437 size += 1;
2438 /* return needed size in first two bytes of lpstrFile */
2439 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2440 FILEDLG95_Clean(hwnd);
2441 ret = EndDialog(hwnd, FALSE);
2442 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2445 break;
2448 ret:
2449 if(lpsf) IShellFolder_Release(lpsf);
2450 return ret;
2453 /***********************************************************************
2454 * FILEDLG95_SHELL_Init
2456 * Initialisation of the shell objects
2458 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2460 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2462 TRACE("\n");
2465 * Initialisation of the FileOpenDialogInfos structure
2468 /* Shell */
2470 /*ShellInfos */
2471 fodInfos->ShellInfos.hwndOwner = hwnd;
2473 /* Disable multi-select if flag not set */
2474 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2476 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2478 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2479 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2481 /* Construct the IShellBrowser interface */
2482 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2484 return NOERROR;
2487 /***********************************************************************
2488 * FILEDLG95_SHELL_ExecuteCommand
2490 * Change the folder option and refresh the view
2491 * If the function succeeds, the return value is nonzero.
2493 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2495 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2496 IContextMenu * pcm;
2498 TRACE("(%p,%p)\n", hwnd, lpVerb);
2500 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2501 SVGIO_BACKGROUND,
2502 &IID_IContextMenu,
2503 (LPVOID*)&pcm)))
2505 CMINVOKECOMMANDINFO ci;
2506 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2507 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2508 ci.lpVerb = lpVerb;
2509 ci.hwnd = hwnd;
2511 IContextMenu_InvokeCommand(pcm, &ci);
2512 IContextMenu_Release(pcm);
2515 return FALSE;
2518 /***********************************************************************
2519 * FILEDLG95_SHELL_UpFolder
2521 * Browse to the specified object
2522 * If the function succeeds, the return value is nonzero.
2524 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2526 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2528 TRACE("\n");
2530 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2531 NULL,
2532 SBSP_PARENT)))
2534 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2535 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2536 return TRUE;
2538 return FALSE;
2541 /***********************************************************************
2542 * FILEDLG95_SHELL_BrowseToDesktop
2544 * Browse to the Desktop
2545 * If the function succeeds, the return value is nonzero.
2547 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2549 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2550 LPITEMIDLIST pidl;
2551 HRESULT hres;
2553 TRACE("\n");
2555 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2556 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2557 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2558 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2559 COMDLG32_SHFree(pidl);
2560 return SUCCEEDED(hres);
2562 /***********************************************************************
2563 * FILEDLG95_SHELL_Clean
2565 * Cleans the memory used by shell objects
2567 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2569 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2571 TRACE("\n");
2573 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2575 /* clean Shell interfaces */
2576 if (fodInfos->Shell.FOIShellView)
2578 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2579 IShellView_Release(fodInfos->Shell.FOIShellView);
2581 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2582 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2583 if (fodInfos->Shell.FOIDataObject)
2584 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2587 /***********************************************************************
2588 * FILEDLG95_FILETYPE_Init
2590 * Initialisation of the file type combo box
2592 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2594 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2595 int nFilters = 0; /* number of filters */
2596 int nFilterIndexCB;
2598 TRACE("\n");
2600 if(fodInfos->customfilter)
2602 /* customfilter has one entry... title\0ext\0
2603 * Set first entry of combo box item with customfilter
2605 LPWSTR lpstrExt;
2606 LPCWSTR lpstrPos = fodInfos->customfilter;
2608 /* Get the title */
2609 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2611 /* Copy the extensions */
2612 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2613 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2614 lstrcpyW(lpstrExt,lpstrPos);
2616 /* Add the item at the end of the combo */
2617 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2618 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2619 nFilters++;
2621 if(fodInfos->filter)
2623 LPCWSTR lpstrPos = fodInfos->filter;
2625 for(;;)
2627 /* filter is a list... title\0ext\0......\0\0
2628 * Set the combo item text to the title and the item data
2629 * to the ext
2631 LPCWSTR lpstrDisplay;
2632 LPWSTR lpstrExt;
2634 /* Get the title */
2635 if(! *lpstrPos) break; /* end */
2636 lpstrDisplay = lpstrPos;
2637 lpstrPos += lstrlenW(lpstrPos) + 1;
2639 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2641 nFilters++;
2643 /* Copy the extensions */
2644 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2645 lstrcpyW(lpstrExt,lpstrPos);
2646 lpstrPos += lstrlenW(lpstrPos) + 1;
2648 /* Add the item at the end of the combo */
2649 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2651 /* malformed filters are added anyway... */
2652 if (!*lpstrExt) break;
2657 * Set the current filter to the one specified
2658 * in the initialisation structure
2660 if (fodInfos->filter || fodInfos->customfilter)
2662 LPWSTR lpstrFilter;
2664 /* Check to make sure our index isn't out of bounds. */
2665 if ( fodInfos->ofnInfos->nFilterIndex >
2666 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2667 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2669 /* set default filter index */
2670 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2671 fodInfos->ofnInfos->nFilterIndex = 1;
2673 /* calculate index of Combo Box item */
2674 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2675 if (fodInfos->customfilter == NULL)
2676 nFilterIndexCB--;
2678 /* Set the current index selection. */
2679 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2681 /* Get the corresponding text string from the combo box. */
2682 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2683 nFilterIndexCB);
2685 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2686 lpstrFilter = NULL;
2688 if(lpstrFilter)
2690 DWORD len;
2691 CharLowerW(lpstrFilter); /* lowercase */
2692 len = lstrlenW(lpstrFilter)+1;
2693 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2694 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2696 } else
2697 fodInfos->ofnInfos->nFilterIndex = 0;
2698 return S_OK;
2701 /***********************************************************************
2702 * FILEDLG95_FILETYPE_OnCommand
2704 * WM_COMMAND of the file type combo box
2705 * If the function succeeds, the return value is nonzero.
2707 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2709 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2711 switch(wNotifyCode)
2713 case CBN_SELENDOK:
2715 LPWSTR lpstrFilter;
2717 /* Get the current item of the filetype combo box */
2718 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2720 /* set the current filter index */
2721 fodInfos->ofnInfos->nFilterIndex = iItem +
2722 (fodInfos->customfilter == NULL ? 1 : 0);
2724 /* Set the current filter with the current selection */
2725 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2727 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2728 iItem);
2729 if((INT_PTR)lpstrFilter != CB_ERR)
2731 DWORD len;
2732 CharLowerW(lpstrFilter); /* lowercase */
2733 len = lstrlenW(lpstrFilter)+1;
2734 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2735 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2736 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2737 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2740 /* Refresh the actual view to display the included items*/
2741 if (fodInfos->Shell.FOIShellView)
2742 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2745 return FALSE;
2747 /***********************************************************************
2748 * FILEDLG95_FILETYPE_SearchExt
2750 * searches for an extension in the filetype box
2752 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2754 int i, iCount = CBGetCount(hwnd);
2756 TRACE("%s\n", debugstr_w(lpstrExt));
2758 if(iCount != CB_ERR)
2760 for(i=0;i<iCount;i++)
2762 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2763 return i;
2766 return -1;
2769 /***********************************************************************
2770 * FILEDLG95_FILETYPE_Clean
2772 * Clean the memory used by the filetype combo box
2774 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2776 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2777 int iPos;
2778 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2780 TRACE("\n");
2782 /* Delete each string of the combo and their associated data */
2783 if(iCount != CB_ERR)
2785 for(iPos = iCount-1;iPos>=0;iPos--)
2787 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2788 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2791 /* Current filter */
2792 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2796 /***********************************************************************
2797 * FILEDLG95_LOOKIN_Init
2799 * Initialisation of the look in combo box
2802 /* Small helper function, to determine if the unixfs shell extension is rooted
2803 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2805 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2806 HKEY hKey;
2807 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2808 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2809 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2810 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2811 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2812 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2813 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2815 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2816 return FALSE;
2818 RegCloseKey(hKey);
2819 return TRUE;
2822 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2824 IShellFolder *psfRoot, *psfDrives;
2825 IEnumIDList *lpeRoot, *lpeDrives;
2826 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2828 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2830 TRACE("\n");
2832 liInfos->iMaxIndentation = 0;
2834 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2836 /* set item height for both text field and listbox */
2837 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2838 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2840 /* Turn on the extended UI for the combo box like Windows does */
2841 CBSetExtendedUI(hwndCombo, TRUE);
2843 /* Initialise data of Desktop folder */
2844 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2845 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2846 COMDLG32_SHFree(pidlTmp);
2848 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2850 SHGetDesktopFolder(&psfRoot);
2852 if (psfRoot)
2854 /* enumerate the contents of the desktop */
2855 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2857 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2859 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2861 /* If the unixfs extension is rooted, we don't expand the drives by default */
2862 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2864 /* special handling for CSIDL_DRIVES */
2865 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2867 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2869 /* enumerate the drives */
2870 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2872 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2874 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2875 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2876 COMDLG32_SHFree(pidlAbsTmp);
2877 COMDLG32_SHFree(pidlTmp1);
2879 IEnumIDList_Release(lpeDrives);
2881 IShellFolder_Release(psfDrives);
2886 COMDLG32_SHFree(pidlTmp);
2888 IEnumIDList_Release(lpeRoot);
2890 IShellFolder_Release(psfRoot);
2893 COMDLG32_SHFree(pidlDrives);
2896 /***********************************************************************
2897 * FILEDLG95_LOOKIN_DrawItem
2899 * WM_DRAWITEM message handler
2901 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2903 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2904 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2905 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2906 RECT rectText;
2907 RECT rectIcon;
2908 SHFILEINFOW sfi;
2909 HIMAGELIST ilItemImage;
2910 int iIndentation;
2911 TEXTMETRICW tm;
2912 LPSFOLDER tmpFolder;
2913 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2915 TRACE("\n");
2917 if(pDIStruct->itemID == -1)
2918 return 0;
2920 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2921 pDIStruct->itemID)))
2922 return 0;
2925 if(pDIStruct->itemID == liInfos->uSelectedItem)
2927 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2929 &sfi,
2930 sizeof (sfi),
2931 SHGFI_PIDL | SHGFI_SMALLICON |
2932 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2933 SHGFI_DISPLAYNAME );
2935 else
2937 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2939 &sfi,
2940 sizeof (sfi),
2941 SHGFI_PIDL | SHGFI_SMALLICON |
2942 SHGFI_SYSICONINDEX |
2943 SHGFI_DISPLAYNAME);
2946 /* Is this item selected ? */
2947 if(pDIStruct->itemState & ODS_SELECTED)
2949 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2950 SetBkColor(pDIStruct->hDC,crHighLight);
2951 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2953 else
2955 SetTextColor(pDIStruct->hDC,crText);
2956 SetBkColor(pDIStruct->hDC,crWin);
2957 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2960 /* Do not indent item if drawing in the edit of the combo */
2961 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2963 iIndentation = 0;
2964 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2966 &sfi,
2967 sizeof (sfi),
2968 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2969 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2972 else
2974 iIndentation = tmpFolder->m_iIndent;
2976 /* Draw text and icon */
2978 /* Initialise the icon display area */
2979 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2980 rectIcon.top = pDIStruct->rcItem.top;
2981 rectIcon.right = rectIcon.left + ICONWIDTH;
2982 rectIcon.bottom = pDIStruct->rcItem.bottom;
2984 /* Initialise the text display area */
2985 GetTextMetricsW(pDIStruct->hDC, &tm);
2986 rectText.left = rectIcon.right;
2987 rectText.top =
2988 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2989 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2990 rectText.bottom =
2991 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2993 /* Draw the icon from the image list */
2994 ImageList_Draw(ilItemImage,
2995 sfi.iIcon,
2996 pDIStruct->hDC,
2997 rectIcon.left,
2998 rectIcon.top,
2999 ILD_TRANSPARENT );
3001 /* Draw the associated text */
3002 if(sfi.szDisplayName)
3003 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3006 return NOERROR;
3009 /***********************************************************************
3010 * FILEDLG95_LOOKIN_OnCommand
3012 * LookIn combo box WM_COMMAND message handler
3013 * If the function succeeds, the return value is nonzero.
3015 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3017 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3019 TRACE("%p\n", fodInfos);
3021 switch(wNotifyCode)
3023 case CBN_SELENDOK:
3025 LPSFOLDER tmpFolder;
3026 int iItem;
3028 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3030 if( iItem == CB_ERR) return FALSE;
3032 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3033 iItem)))
3034 return FALSE;
3037 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3038 tmpFolder->pidlItem,
3039 SBSP_ABSOLUTE)))
3041 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3042 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3043 return TRUE;
3045 break;
3049 return FALSE;
3052 /***********************************************************************
3053 * FILEDLG95_LOOKIN_AddItem
3055 * Adds an absolute pidl item to the lookin combo box
3056 * returns the index of the inserted item
3058 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3060 LPITEMIDLIST pidlNext;
3061 SHFILEINFOW sfi;
3062 SFOLDER *tmpFolder;
3063 LookInInfos *liInfos;
3065 TRACE("%08x\n", iInsertId);
3067 if(!pidl)
3068 return -1;
3070 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3071 return -1;
3073 tmpFolder = MemAlloc(sizeof(SFOLDER));
3074 tmpFolder->m_iIndent = 0;
3076 /* Calculate the indentation of the item in the lookin*/
3077 pidlNext = pidl;
3078 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3080 tmpFolder->m_iIndent++;
3083 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3085 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3086 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3088 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3089 SHGetFileInfoW((LPCWSTR)pidl,
3091 &sfi,
3092 sizeof(sfi),
3093 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3094 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3096 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3098 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3100 int iItemID;
3102 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3104 /* Add the item at the end of the list */
3105 if(iInsertId < 0)
3107 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3109 /* Insert the item at the iInsertId position*/
3110 else
3112 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3115 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3116 return iItemID;
3119 COMDLG32_SHFree( tmpFolder->pidlItem );
3120 MemFree( tmpFolder );
3121 return -1;
3125 /***********************************************************************
3126 * FILEDLG95_LOOKIN_InsertItemAfterParent
3128 * Insert an item below its parent
3130 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3133 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3134 int iParentPos;
3136 TRACE("\n");
3138 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3140 if(iParentPos < 0)
3142 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3145 /* Free pidlParent memory */
3146 COMDLG32_SHFree(pidlParent);
3148 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3151 /***********************************************************************
3152 * FILEDLG95_LOOKIN_SelectItem
3154 * Adds an absolute pidl item to the lookin combo box
3155 * returns the index of the inserted item
3157 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3159 int iItemPos;
3160 LookInInfos *liInfos;
3162 TRACE("\n");
3164 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3166 liInfos = GetPropA(hwnd,LookInInfosStr);
3168 if(iItemPos < 0)
3170 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3171 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3174 else
3176 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3177 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3179 int iRemovedItem;
3181 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3182 break;
3183 if(iRemovedItem < iItemPos)
3184 iItemPos--;
3188 CBSetCurSel(hwnd,iItemPos);
3189 liInfos->uSelectedItem = iItemPos;
3191 return 0;
3195 /***********************************************************************
3196 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3198 * Remove the item with an expansion level over iExpansionLevel
3200 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3202 int iItemPos;
3203 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3205 TRACE("\n");
3207 if(liInfos->iMaxIndentation <= 2)
3208 return -1;
3210 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3212 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3213 COMDLG32_SHFree(tmpFolder->pidlItem);
3214 MemFree(tmpFolder);
3215 CBDeleteString(hwnd,iItemPos);
3216 liInfos->iMaxIndentation--;
3218 return iItemPos;
3221 return -1;
3224 /***********************************************************************
3225 * FILEDLG95_LOOKIN_SearchItem
3227 * Search for pidl in the lookin combo box
3228 * returns the index of the found item
3230 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3232 int i = 0;
3233 int iCount = CBGetCount(hwnd);
3235 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3237 if (iCount != CB_ERR)
3239 for(;i<iCount;i++)
3241 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3243 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3244 return i;
3245 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3246 return i;
3250 return -1;
3253 /***********************************************************************
3254 * FILEDLG95_LOOKIN_Clean
3256 * Clean the memory used by the lookin combo box
3258 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3260 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3261 int iPos;
3262 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3264 TRACE("\n");
3266 /* Delete each string of the combo and their associated data */
3267 if (iCount != CB_ERR)
3269 for(iPos = iCount-1;iPos>=0;iPos--)
3271 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3272 COMDLG32_SHFree(tmpFolder->pidlItem);
3273 MemFree(tmpFolder);
3274 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3278 /* LookInInfos structure */
3279 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3282 /***********************************************************************
3283 * FILEDLG95_FILENAME_FillFromSelection
3285 * fills the edit box from the cached DataObject
3287 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3289 FileOpenDlgInfos *fodInfos;
3290 LPITEMIDLIST pidl;
3291 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3292 WCHAR lpstrTemp[MAX_PATH];
3293 LPWSTR lpstrAllFile, lpstrCurrFile;
3295 TRACE("\n");
3296 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3298 /* Count how many files we have */
3299 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3301 /* calculate the string length, count files */
3302 if (nFileSelected >= 1)
3304 nLength += 3; /* first and last quotes, trailing \0 */
3305 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3307 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3309 if (pidl)
3311 /* get the total length of the selected file names */
3312 lpstrTemp[0] = '\0';
3313 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3315 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3317 nLength += lstrlenW( lpstrTemp ) + 3;
3318 nFiles++;
3320 COMDLG32_SHFree( pidl );
3325 /* allocate the buffer */
3326 if (nFiles <= 1) nLength = MAX_PATH;
3327 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3329 /* Generate the string for the edit control */
3330 if(nFiles >= 1)
3332 lpstrCurrFile = lpstrAllFile;
3333 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3335 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3337 if (pidl)
3339 /* get the file name */
3340 lpstrTemp[0] = '\0';
3341 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3343 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3345 if ( nFiles > 1)
3347 *lpstrCurrFile++ = '\"';
3348 lstrcpyW( lpstrCurrFile, lpstrTemp );
3349 lpstrCurrFile += lstrlenW( lpstrTemp );
3350 *lpstrCurrFile++ = '\"';
3351 *lpstrCurrFile++ = ' ';
3352 *lpstrCurrFile = 0;
3354 else
3356 lstrcpyW( lpstrAllFile, lpstrTemp );
3359 COMDLG32_SHFree( pidl );
3362 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3364 /* Select the file name like Windows does */
3365 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3367 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3371 /* copied from shell32 to avoid linking to it
3372 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3373 * is dependent on whether emulated OS is unicode or not.
3375 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3377 switch (src->uType)
3379 case STRRET_WSTR:
3380 lstrcpynW(dest, src->u.pOleStr, len);
3381 COMDLG32_SHFree(src->u.pOleStr);
3382 break;
3384 case STRRET_CSTR:
3385 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3386 dest[len-1] = 0;
3387 break;
3389 case STRRET_OFFSET:
3390 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3391 dest[len-1] = 0;
3392 break;
3394 default:
3395 FIXME("unknown type %x!\n", src->uType);
3396 if (len) *dest = '\0';
3397 return E_FAIL;
3399 return S_OK;
3402 /***********************************************************************
3403 * FILEDLG95_FILENAME_GetFileNames
3405 * Copies the filenames to a delimited string list.
3406 * The delimiter is specified by the parameter 'separator',
3407 * usually either a space or a nul
3409 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3411 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3412 UINT nStrCharCount = 0; /* index in src buffer */
3413 UINT nFileIndex = 0; /* index in dest buffer */
3414 UINT nFileCount = 0; /* number of files */
3415 UINT nStrLen = 0; /* length of string in edit control */
3416 LPWSTR lpstrEdit; /* buffer for string from edit control */
3418 TRACE("\n");
3420 /* get the filenames from the edit control */
3421 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3422 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3423 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3425 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3427 /* we might get single filename without any '"',
3428 * so we need nStrLen + terminating \0 + end-of-list \0 */
3429 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3430 *sizeUsed = 0;
3432 /* build delimited file list from filenames */
3433 while ( nStrCharCount <= nStrLen )
3435 if ( lpstrEdit[nStrCharCount]=='"' )
3437 nStrCharCount++;
3438 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3440 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3441 nStrCharCount++;
3443 (*lpstrFileList)[nFileIndex++] = 0;
3444 nFileCount++;
3446 nStrCharCount++;
3449 /* single, unquoted string */
3450 if ((nStrLen > 0) && (nFileIndex == 0) )
3452 lstrcpyW(*lpstrFileList, lpstrEdit);
3453 nFileIndex = lstrlenW(lpstrEdit) + 1;
3454 nFileCount = 1;
3457 /* trailing \0 */
3458 (*lpstrFileList)[nFileIndex++] = '\0';
3460 *sizeUsed = nFileIndex;
3461 MemFree(lpstrEdit);
3462 return nFileCount;
3465 #define SETDefFormatEtc(fe,cf,med) \
3467 (fe).cfFormat = cf;\
3468 (fe).dwAspect = DVASPECT_CONTENT; \
3469 (fe).ptd =NULL;\
3470 (fe).tymed = med;\
3471 (fe).lindex = -1;\
3475 * DATAOBJECT Helper functions
3478 /***********************************************************************
3479 * COMCTL32_ReleaseStgMedium
3481 * like ReleaseStgMedium from ole32
3483 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3485 if(medium.pUnkForRelease)
3487 IUnknown_Release(medium.pUnkForRelease);
3489 else
3491 GlobalUnlock(medium.u.hGlobal);
3492 GlobalFree(medium.u.hGlobal);
3496 /***********************************************************************
3497 * GetPidlFromDataObject
3499 * Return pidl(s) by number from the cached DataObject
3501 * nPidlIndex=0 gets the fully qualified root path
3503 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3506 STGMEDIUM medium;
3507 FORMATETC formatetc;
3508 LPITEMIDLIST pidl = NULL;
3510 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3512 if (!doSelected)
3513 return NULL;
3515 /* Set the FORMATETC structure*/
3516 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3518 /* Get the pidls from IDataObject */
3519 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3521 LPIDA cida = GlobalLock(medium.u.hGlobal);
3522 if(nPidlIndex <= cida->cidl)
3524 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3526 COMCTL32_ReleaseStgMedium(medium);
3528 return pidl;
3531 /***********************************************************************
3532 * GetNumSelected
3534 * Return the number of selected items in the DataObject.
3537 static UINT GetNumSelected( IDataObject *doSelected )
3539 UINT retVal = 0;
3540 STGMEDIUM medium;
3541 FORMATETC formatetc;
3543 TRACE("sv=%p\n", doSelected);
3545 if (!doSelected) return 0;
3547 /* Set the FORMATETC structure*/
3548 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3550 /* Get the pidls from IDataObject */
3551 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3553 LPIDA cida = GlobalLock(medium.u.hGlobal);
3554 retVal = cida->cidl;
3555 COMCTL32_ReleaseStgMedium(medium);
3556 return retVal;
3558 return 0;
3562 * TOOLS
3565 /***********************************************************************
3566 * GetName
3568 * Get the pidl's display name (relative to folder) and
3569 * put it in lpstrFileName.
3571 * Return NOERROR on success,
3572 * E_FAIL otherwise
3575 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3577 STRRET str;
3578 HRESULT hRes;
3580 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3582 if(!lpsf)
3584 SHGetDesktopFolder(&lpsf);
3585 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3586 IShellFolder_Release(lpsf);
3587 return hRes;
3590 /* Get the display name of the pidl relative to the folder */
3591 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3593 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3595 return E_FAIL;
3598 /***********************************************************************
3599 * GetShellFolderFromPidl
3601 * pidlRel is the item pidl relative
3602 * Return the IShellFolder of the absolute pidl
3604 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3606 IShellFolder *psf = NULL,*psfParent;
3608 TRACE("%p\n", pidlAbs);
3610 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3612 psf = psfParent;
3613 if(pidlAbs && pidlAbs->mkid.cb)
3615 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3617 IShellFolder_Release(psfParent);
3618 return psf;
3621 /* return the desktop */
3622 return psfParent;
3624 return NULL;
3627 /***********************************************************************
3628 * GetParentPidl
3630 * Return the LPITEMIDLIST to the parent of the pidl in the list
3632 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3634 LPITEMIDLIST pidlParent;
3636 TRACE("%p\n", pidl);
3638 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3639 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3641 return pidlParent;
3644 /***********************************************************************
3645 * GetPidlFromName
3647 * returns the pidl of the file name relative to folder
3648 * NULL if an error occurred
3650 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3652 LPITEMIDLIST pidl = NULL;
3653 ULONG ulEaten;
3655 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3657 if(!lpcstrFileName) return NULL;
3658 if(!*lpcstrFileName) return NULL;
3660 if(!lpsf)
3662 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3663 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3664 IShellFolder_Release(lpsf);
3667 else
3669 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3671 return pidl;
3676 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3678 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3679 HRESULT ret;
3681 TRACE("%p, %p\n", psf, pidl);
3683 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3685 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3686 /* see documentation shell 4.1*/
3687 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3690 /***********************************************************************
3691 * BrowseSelectedFolder
3693 static BOOL BrowseSelectedFolder(HWND hwnd)
3695 BOOL bBrowseSelFolder = FALSE;
3696 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3698 TRACE("\n");
3700 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3702 LPITEMIDLIST pidlSelection;
3704 /* get the file selected */
3705 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3706 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3708 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3709 pidlSelection, SBSP_RELATIVE ) ) )
3711 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3712 ' ','n','o','t',' ','e','x','i','s','t',0};
3713 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3715 bBrowseSelFolder = TRUE;
3716 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3717 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3719 COMDLG32_SHFree( pidlSelection );
3722 return bBrowseSelFolder;
3726 * Memory allocation methods */
3727 static void *MemAlloc(UINT size)
3729 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3732 static void MemFree(void *mem)
3734 HeapFree(GetProcessHeap(),0,mem);
3738 * Old-style (win3.1) dialogs */
3740 /***********************************************************************
3741 * FD32_GetTemplate [internal]
3743 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3744 * by a 32 bits application
3747 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3749 LPOPENFILENAMEW ofnW = lfs->ofnW;
3750 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3751 HANDLE hDlgTmpl;
3753 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3755 if (!(lfs->template = LockResource( ofnW->hInstance )))
3757 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3758 return FALSE;
3761 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3763 HRSRC hResInfo;
3764 if (priv->ofnA)
3765 hResInfo = FindResourceA(priv->ofnA->hInstance,
3766 priv->ofnA->lpTemplateName,
3767 (LPSTR)RT_DIALOG);
3768 else
3769 hResInfo = FindResourceW(ofnW->hInstance,
3770 ofnW->lpTemplateName,
3771 (LPWSTR)RT_DIALOG);
3772 if (!hResInfo)
3774 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3775 return FALSE;
3777 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3778 hResInfo)) ||
3779 !(lfs->template = LockResource(hDlgTmpl)))
3781 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3782 return FALSE;
3784 } else { /* get it from internal Wine resource */
3785 HRSRC hResInfo;
3786 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3787 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3789 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3790 return FALSE;
3792 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3793 !(lfs->template = LockResource( hDlgTmpl )))
3795 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3796 return FALSE;
3799 return TRUE;
3803 /************************************************************************
3804 * FD32_Init [internal]
3805 * called from the common 16/32 code to initialize 32 bit data
3807 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3809 BOOL IsUnicode = (BOOL) data;
3810 PFD32_PRIVATE priv;
3812 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3813 lfs->private1632 = priv;
3814 if (NULL == lfs->private1632) return FALSE;
3815 if (IsUnicode)
3817 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3818 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3819 if (lfs->ofnW->lpfnHook)
3820 lfs->hook = TRUE;
3822 else
3824 priv->ofnA = (LPOPENFILENAMEA) lParam;
3825 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3826 if (priv->ofnA->lpfnHook)
3827 lfs->hook = TRUE;
3828 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3829 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3832 if (! FD32_GetTemplate(lfs)) return FALSE;
3834 return TRUE;
3837 /***********************************************************************
3838 * FD32_CallWindowProc [internal]
3840 * called from the common 16/32 code to call the appropriate hook
3842 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3843 LPARAM lParam)
3845 BOOL ret;
3846 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3848 if (priv->ofnA)
3850 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3851 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3852 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3853 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3854 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3855 return ret;
3858 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3859 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3860 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3861 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3862 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3863 return ret;
3866 /***********************************************************************
3867 * FD32_UpdateResult [internal]
3868 * update the real client structures if any
3870 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3872 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3873 LPOPENFILENAMEW ofnW = lfs->ofnW;
3875 if (priv->ofnA)
3877 LPSTR lpszTemp;
3878 if (ofnW->nMaxFile &&
3879 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3880 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3881 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3883 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3884 /* set filename offset */
3885 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3886 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3888 /* set extension offset */
3889 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3890 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3894 /***********************************************************************
3895 * FD32_UpdateFileTitle [internal]
3896 * update the real client structures if any
3898 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3900 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3901 LPOPENFILENAMEW ofnW = lfs->ofnW;
3903 if (priv->ofnA)
3905 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3906 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3907 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3912 /***********************************************************************
3913 * FD32_SendLbGetCurSel [internal]
3914 * retrieve selected listbox item
3916 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3918 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3922 /************************************************************************
3923 * FD32_Destroy [internal]
3924 * called from the common 16/32 code to cleanup 32 bit data
3926 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3928 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3930 /* if ofnW has been allocated, have to free everything in it */
3931 if (NULL != priv && NULL != priv->ofnA)
3933 FD31_FreeOfnW(lfs->ofnW);
3934 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3938 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3940 callbacks->Init = FD32_Init;
3941 callbacks->CWP = FD32_CallWindowProc;
3942 callbacks->UpdateResult = FD32_UpdateResult;
3943 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3944 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3945 callbacks->Destroy = FD32_Destroy;
3948 /***********************************************************************
3949 * FD32_WMMeasureItem [internal]
3951 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3953 LPMEASUREITEMSTRUCT lpmeasure;
3955 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3956 lpmeasure->itemHeight = FD31_GetFldrHeight();
3957 return TRUE;
3961 /***********************************************************************
3962 * FileOpenDlgProc [internal]
3963 * Used for open and save, in fact.
3965 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3966 WPARAM wParam, LPARAM lParam)
3968 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3970 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3971 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3973 INT_PTR lRet;
3974 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3975 if (lRet)
3976 return lRet; /* else continue message processing */
3978 switch (wMsg)
3980 case WM_INITDIALOG:
3981 return FD31_WMInitDialog(hWnd, wParam, lParam);
3983 case WM_MEASUREITEM:
3984 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3986 case WM_DRAWITEM:
3987 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3989 case WM_COMMAND:
3990 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3991 #if 0
3992 case WM_CTLCOLOR:
3993 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3994 switch (HIWORD(lParam))
3996 case CTLCOLOR_BTN:
3997 SetTextColor((HDC16)wParam, 0x00000000);
3998 return hGRAYBrush;
3999 case CTLCOLOR_STATIC:
4000 SetTextColor((HDC16)wParam, 0x00000000);
4001 return hGRAYBrush;
4003 break;
4004 #endif
4006 return FALSE;
4010 /***********************************************************************
4011 * GetFileName31A [internal]
4013 * Creates a win31 style dialog box for the user to select a file to open/save.
4015 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4016 UINT dlgType /* type dialogue : open/save */
4019 HINSTANCE hInst;
4020 BOOL bRet = FALSE;
4021 PFD31_DATA lfs;
4022 FD31_CALLBACKS callbacks;
4024 if (!lpofn || !FD31_Init()) return FALSE;
4026 TRACE("ofn flags %08x\n", lpofn->Flags);
4027 FD32_SetupCallbacks(&callbacks);
4028 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
4029 if (lfs)
4031 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4032 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
4033 FD32_FileOpenDlgProc, (LPARAM)lfs);
4034 FD31_DestroyPrivate(lfs);
4037 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4038 return bRet;
4041 /***********************************************************************
4042 * GetFileName31W [internal]
4044 * Creates a win31 style dialog box for the user to select a file to open/save
4046 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4047 UINT dlgType /* type dialogue : open/save */
4050 HINSTANCE hInst;
4051 BOOL bRet = FALSE;
4052 PFD31_DATA lfs;
4053 FD31_CALLBACKS callbacks;
4055 if (!lpofn || !FD31_Init()) return FALSE;
4057 FD32_SetupCallbacks(&callbacks);
4058 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
4059 if (lfs)
4061 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4062 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
4063 FD32_FileOpenDlgProc, (LPARAM)lfs);
4064 FD31_DestroyPrivate(lfs);
4067 TRACE("file %s, file offset %d, ext offset %d\n",
4068 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4069 return bRet;
4072 /* ------------------ APIs ---------------------- */
4074 /***********************************************************************
4075 * GetOpenFileNameA (COMDLG32.@)
4077 * Creates a dialog box for the user to select a file to open.
4079 * RETURNS
4080 * TRUE on success: user enters a valid file
4081 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4084 BOOL WINAPI GetOpenFileNameA(
4085 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4087 BOOL win16look = FALSE;
4089 TRACE("flags %08x\n", ofn->Flags);
4091 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4092 if (ofn->Flags & OFN_FILEMUSTEXIST)
4093 ofn->Flags |= OFN_PATHMUSTEXIST;
4095 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4096 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4098 if (win16look)
4099 return GetFileName31A(ofn, OPEN_DIALOG);
4100 else
4101 return GetFileDialog95A(ofn, OPEN_DIALOG);
4104 /***********************************************************************
4105 * GetOpenFileNameW (COMDLG32.@)
4107 * Creates a dialog box for the user to select a file to open.
4109 * RETURNS
4110 * TRUE on success: user enters a valid file
4111 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4114 BOOL WINAPI GetOpenFileNameW(
4115 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4117 BOOL win16look = FALSE;
4119 TRACE("flags %08x\n", ofn->Flags);
4121 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4122 if (ofn->Flags & OFN_FILEMUSTEXIST)
4123 ofn->Flags |= OFN_PATHMUSTEXIST;
4125 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4126 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4128 if (win16look)
4129 return GetFileName31W(ofn, OPEN_DIALOG);
4130 else
4131 return GetFileDialog95W(ofn, OPEN_DIALOG);
4135 /***********************************************************************
4136 * GetSaveFileNameA (COMDLG32.@)
4138 * Creates a dialog box for the user to select a file to save.
4140 * RETURNS
4141 * TRUE on success: user enters a valid file
4142 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4145 BOOL WINAPI GetSaveFileNameA(
4146 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4148 BOOL win16look = FALSE;
4150 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4151 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4153 if (win16look)
4154 return GetFileName31A(ofn, SAVE_DIALOG);
4155 else
4156 return GetFileDialog95A(ofn, SAVE_DIALOG);
4159 /***********************************************************************
4160 * GetSaveFileNameW (COMDLG32.@)
4162 * Creates a dialog box for the user to select a file to save.
4164 * RETURNS
4165 * TRUE on success: user enters a valid file
4166 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4169 BOOL WINAPI GetSaveFileNameW(
4170 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4172 BOOL win16look = FALSE;
4174 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4175 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4177 if (win16look)
4178 return GetFileName31W(ofn, SAVE_DIALOG);
4179 else
4180 return GetFileDialog95W(ofn, SAVE_DIALOG);
4183 /***********************************************************************
4184 * GetFileTitleA (COMDLG32.@)
4186 * See GetFileTitleW.
4188 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4190 int ret;
4191 UNICODE_STRING strWFile;
4192 LPWSTR lpWTitle;
4194 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4195 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4196 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4197 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4198 RtlFreeUnicodeString( &strWFile );
4199 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4200 return ret;
4204 /***********************************************************************
4205 * GetFileTitleW (COMDLG32.@)
4207 * Get the name of a file.
4209 * PARAMS
4210 * lpFile [I] name and location of file
4211 * lpTitle [O] returned file name
4212 * cbBuf [I] buffer size of lpTitle
4214 * RETURNS
4215 * Success: zero
4216 * Failure: negative number.
4218 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4220 int i, len;
4221 static const WCHAR brkpoint[] = {'*','[',']',0};
4222 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4224 if(lpFile == NULL || lpTitle == NULL)
4225 return -1;
4227 len = lstrlenW(lpFile);
4229 if (len == 0)
4230 return -1;
4232 if(strpbrkW(lpFile, brkpoint))
4233 return -1;
4235 len--;
4237 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4238 return -1;
4240 for(i = len; i >= 0; i--)
4242 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4244 i++;
4245 break;
4249 if(i == -1)
4250 i++;
4252 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4254 len = lstrlenW(lpFile+i)+1;
4255 if(cbBuf < len)
4256 return len;
4258 lstrcpyW(lpTitle, &lpFile[i]);
4259 return 0;