push 38a8c0aff9170390b5a3ded41e7cf5b02f3a73d8
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blobd8908fec180901c129bf01f0aca1afa6d7183aff
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 LPCWSTR lpstrPos = fodInfos->filter;
1531 WIN32_FIND_DATAW FindFileData;
1532 HANDLE hFind;
1534 while (1)
1536 /* filter is a list... title\0ext\0......\0\0 */
1538 /* Skip the title */
1539 if(! *lpstrPos) break; /* end */
1540 lpstrPos += lstrlenW(lpstrPos) + 1;
1542 /* See if any files exist in the current dir with this extension */
1543 if(! *lpstrPos) break; /* end */
1545 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1547 if (hFind == INVALID_HANDLE_VALUE) {
1548 /* None found - continue search */
1549 lpstrPos += lstrlenW(lpstrPos) + 1;
1551 } else {
1553 MemFree(fodInfos->initdir);
1554 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1555 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1557 handledPath = TRUE;
1558 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1559 debugstr_w(lpstrPos));
1560 FindClose(hFind);
1561 break;
1566 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1568 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1569 if (handledPath == FALSE && (win2000plus || win98plus)) {
1570 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1572 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1574 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1576 /* last fallback */
1577 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1578 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1579 } else {
1580 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1582 } else {
1583 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1585 handledPath = TRUE;
1586 } else if (handledPath==FALSE) {
1587 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1588 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1589 handledPath = TRUE;
1590 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1593 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1594 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1596 /* Must the open as read only check box be checked ?*/
1597 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1599 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1602 /* Must the open as read only check box be hidden? */
1603 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1605 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1606 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1609 /* Must the help button be hidden? */
1610 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1612 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1613 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1616 /* change Open to Save */
1617 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1619 WCHAR buf[16];
1620 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1621 SetDlgItemTextW(hwnd, IDOK, buf);
1622 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1623 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1626 /* Initialize the filter combo box */
1627 FILEDLG95_FILETYPE_Init(hwnd);
1629 return 0;
1632 /***********************************************************************
1633 * FILEDLG95_ResizeControls
1635 * WM_INITDIALOG message handler (after hook notification)
1637 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1639 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1641 if (fodInfos->DlgInfos.hwndCustomDlg)
1643 RECT rc;
1644 UINT flags = SWP_NOACTIVATE;
1646 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1647 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1649 /* resize the custom dialog to the parent size */
1650 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1651 GetClientRect(hwnd, &rc);
1652 else
1654 /* our own fake template is zero sized and doesn't have children, so
1655 * there is no need to resize it. Picasa depends on it.
1657 flags |= SWP_NOSIZE;
1658 SetRectEmpty(&rc);
1660 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1661 0, 0, rc.right, rc.bottom, flags);
1663 else
1665 /* Resize the height, if open as read only checkbox ad help button are
1666 * hidden and we are not using a custom template nor a customDialog
1668 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1669 (!(fodInfos->ofnInfos->Flags &
1670 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1672 RECT rectDlg, rectHelp, rectCancel;
1673 GetWindowRect(hwnd, &rectDlg);
1674 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1675 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1676 /* subtract the height of the help button plus the space between the help
1677 * button and the cancel button to the height of the dialog
1679 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1680 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1681 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1684 return TRUE;
1687 /***********************************************************************
1688 * FILEDLG95_FillControls
1690 * WM_INITDIALOG message handler (after hook notification)
1692 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1694 LPITEMIDLIST pidlItemId = NULL;
1696 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1698 TRACE("dir=%s file=%s\n",
1699 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1701 /* Get the initial directory pidl */
1703 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1705 WCHAR path[MAX_PATH];
1707 GetCurrentDirectoryW(MAX_PATH,path);
1708 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1711 /* Initialise shell objects */
1712 FILEDLG95_SHELL_Init(hwnd);
1714 /* Initialize the Look In combo box */
1715 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1717 /* Browse to the initial directory */
1718 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1720 /* Free pidlItem memory */
1721 COMDLG32_SHFree(pidlItemId);
1723 return TRUE;
1725 /***********************************************************************
1726 * FILEDLG95_Clean
1728 * Regroups all the cleaning functions of the filedlg
1730 void FILEDLG95_Clean(HWND hwnd)
1732 FILEDLG95_FILETYPE_Clean(hwnd);
1733 FILEDLG95_LOOKIN_Clean(hwnd);
1734 FILEDLG95_SHELL_Clean(hwnd);
1736 /***********************************************************************
1737 * FILEDLG95_OnWMCommand
1739 * WM_COMMAND message handler
1741 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1743 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1744 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1745 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1747 switch(wID)
1749 /* OK button */
1750 case IDOK:
1751 FILEDLG95_OnOpen(hwnd);
1752 break;
1753 /* Cancel button */
1754 case IDCANCEL:
1755 FILEDLG95_Clean(hwnd);
1756 EndDialog(hwnd, FALSE);
1757 break;
1758 /* Filetype combo box */
1759 case IDC_FILETYPE:
1760 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1761 break;
1762 /* LookIn combo box */
1763 case IDC_LOOKIN:
1764 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1765 break;
1767 /* --- toolbar --- */
1768 /* Up folder button */
1769 case FCIDM_TB_UPFOLDER:
1770 FILEDLG95_SHELL_UpFolder(hwnd);
1771 break;
1772 /* New folder button */
1773 case FCIDM_TB_NEWFOLDER:
1774 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1775 break;
1776 /* List option button */
1777 case FCIDM_TB_SMALLICON:
1778 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1779 break;
1780 /* Details option button */
1781 case FCIDM_TB_REPORTVIEW:
1782 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1783 break;
1784 /* Details option button */
1785 case FCIDM_TB_DESKTOP:
1786 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1787 break;
1789 case IDC_FILENAME:
1790 break;
1793 /* Do not use the listview selection anymore */
1794 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1795 return 0;
1798 /***********************************************************************
1799 * FILEDLG95_OnWMGetIShellBrowser
1801 * WM_GETISHELLBROWSER message handler
1803 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1805 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1807 TRACE("\n");
1809 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1811 return TRUE;
1815 /***********************************************************************
1816 * FILEDLG95_SendFileOK
1818 * Sends the CDN_FILEOK notification if required
1820 * RETURNS
1821 * TRUE if the dialog should close
1822 * FALSE if the dialog should not be closed
1824 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1826 /* ask the hook if we can close */
1827 if(IsHooked(fodInfos))
1829 LRESULT retval = 0;
1831 TRACE("---\n");
1832 /* First send CDN_FILEOK as MSDN doc says */
1833 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1834 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1835 if( retval)
1837 TRACE("canceled\n");
1838 return FALSE;
1841 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1842 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1843 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1844 if( retval)
1846 TRACE("canceled\n");
1847 return FALSE;
1850 return TRUE;
1853 /***********************************************************************
1854 * FILEDLG95_OnOpenMultipleFiles
1856 * Handles the opening of multiple files.
1858 * FIXME
1859 * check destination buffer size
1861 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1863 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1864 UINT nCount, nSizePath;
1865 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1867 TRACE("\n");
1869 if(fodInfos->unicode)
1871 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1872 ofn->lpstrFile[0] = '\0';
1874 else
1876 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1877 ofn->lpstrFile[0] = '\0';
1880 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1882 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1883 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1884 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1886 LPWSTR lpstrTemp = lpstrFileList;
1888 for ( nCount = 0; nCount < nFileCount; nCount++ )
1890 LPITEMIDLIST pidl;
1892 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1893 if (!pidl)
1895 WCHAR lpstrNotFound[100];
1896 WCHAR lpstrMsg[100];
1897 WCHAR tmp[400];
1898 static const WCHAR nl[] = {'\n',0};
1900 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1901 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1903 lstrcpyW(tmp, lpstrTemp);
1904 lstrcatW(tmp, nl);
1905 lstrcatW(tmp, lpstrNotFound);
1906 lstrcatW(tmp, nl);
1907 lstrcatW(tmp, lpstrMsg);
1909 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1910 return FALSE;
1913 /* move to the next file in the list of files */
1914 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1915 COMDLG32_SHFree(pidl);
1919 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1920 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1922 /* For "oldstyle" dialog the components have to
1923 be separated by blanks (not '\0'!) and short
1924 filenames have to be used! */
1925 FIXME("Components have to be separated by blanks\n");
1927 if(fodInfos->unicode)
1929 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1930 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1931 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1933 else
1935 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1937 if (ofn->lpstrFile != NULL)
1939 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1940 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1941 if (ofn->nMaxFile > nSizePath)
1943 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1944 ofn->lpstrFile + nSizePath,
1945 ofn->nMaxFile - nSizePath, NULL, NULL);
1950 fodInfos->ofnInfos->nFileOffset = nSizePath;
1951 fodInfos->ofnInfos->nFileExtension = 0;
1953 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1954 return FALSE;
1956 /* clean and exit */
1957 FILEDLG95_Clean(hwnd);
1958 return EndDialog(hwnd,TRUE);
1961 /***********************************************************************
1962 * FILEDLG95_OnOpen
1964 * Ok button WM_COMMAND message handler
1966 * If the function succeeds, the return value is nonzero.
1968 #define ONOPEN_BROWSE 1
1969 #define ONOPEN_OPEN 2
1970 #define ONOPEN_SEARCH 3
1971 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1973 WCHAR strMsgTitle[MAX_PATH];
1974 WCHAR strMsgText [MAX_PATH];
1975 if (idCaption)
1976 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1977 else
1978 strMsgTitle[0] = '\0';
1979 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1980 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1983 BOOL FILEDLG95_OnOpen(HWND hwnd)
1985 LPWSTR lpstrFileList;
1986 UINT nFileCount = 0;
1987 UINT sizeUsed = 0;
1988 BOOL ret = TRUE;
1989 WCHAR lpstrPathAndFile[MAX_PATH];
1990 WCHAR lpstrTemp[MAX_PATH];
1991 LPSHELLFOLDER lpsf = NULL;
1992 int nOpenAction;
1993 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
1995 TRACE("hwnd=%p\n", hwnd);
1997 /* get the files from the edit control */
1998 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
2000 /* try if the user selected a folder in the shellview */
2001 if(nFileCount == 0)
2003 BrowseSelectedFolder(hwnd);
2004 return FALSE;
2007 if(nFileCount > 1)
2009 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
2010 goto ret;
2013 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
2016 Step 1: Build a complete path name from the current folder and
2017 the filename or path in the edit box.
2018 Special cases:
2019 - the path in the edit box is a root path
2020 (with or without drive letter)
2021 - the edit box contains ".." (or a path with ".." in it)
2024 /* Get the current directory name */
2025 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
2027 /* last fallback */
2028 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
2030 PathAddBackslashW(lpstrPathAndFile);
2032 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
2034 /* if the user specified a fully qualified path use it */
2035 if(PathIsRelativeW(lpstrFileList))
2037 lstrcatW(lpstrPathAndFile, lpstrFileList);
2039 else
2041 /* does the path have a drive letter? */
2042 if (PathGetDriveNumberW(lpstrFileList) == -1)
2043 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
2044 else
2045 lstrcpyW(lpstrPathAndFile, lpstrFileList);
2048 /* resolve "." and ".." */
2049 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
2050 lstrcpyW(lpstrPathAndFile, lpstrTemp);
2051 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
2053 MemFree(lpstrFileList);
2056 Step 2: here we have a cleaned up path
2058 We have to parse the path step by step to see if we have to browse
2059 to a folder if the path points to a directory or the last
2060 valid element is a directory.
2062 valid variables:
2063 lpstrPathAndFile: cleaned up path
2066 if (nFileCount &&
2067 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
2068 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
2069 nOpenAction = ONOPEN_OPEN;
2070 else
2071 nOpenAction = ONOPEN_BROWSE;
2073 /* don't apply any checks with OFN_NOVALIDATE */
2075 LPWSTR lpszTemp, lpszTemp1;
2076 LPITEMIDLIST pidl = NULL;
2077 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
2079 /* check for invalid chars */
2080 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2082 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
2083 ret = FALSE;
2084 goto ret;
2087 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
2089 lpszTemp1 = lpszTemp = lpstrPathAndFile;
2090 while (lpszTemp1)
2092 LPSHELLFOLDER lpsfChild;
2093 WCHAR lpwstrTemp[MAX_PATH];
2094 DWORD dwEaten, dwAttributes;
2095 LPWSTR p;
2097 lstrcpyW(lpwstrTemp, lpszTemp);
2098 p = PathFindNextComponentW(lpwstrTemp);
2100 if (!p) break; /* end of path */
2102 *p = 0;
2103 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
2105 /* There are no wildcards when OFN_NOVALIDATE is set */
2106 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2108 static const WCHAR wszWild[] = { '*', '?', 0 };
2109 /* if the last element is a wildcard do a search */
2110 if(strpbrkW(lpszTemp1, wszWild) != NULL)
2112 nOpenAction = ONOPEN_SEARCH;
2113 break;
2116 lpszTemp1 = lpszTemp;
2118 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
2120 /* append a backslash to drive letters */
2121 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
2122 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
2123 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
2125 PathAddBackslashW(lpwstrTemp);
2128 dwAttributes = SFGAO_FOLDER;
2129 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
2131 /* the path component is valid, we have a pidl of the next path component */
2132 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
2133 if(dwAttributes & SFGAO_FOLDER)
2135 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
2137 ERR("bind to failed\n"); /* should not fail */
2138 break;
2140 IShellFolder_Release(lpsf);
2141 lpsf = lpsfChild;
2142 lpsfChild = NULL;
2144 else
2146 TRACE("value\n");
2148 /* end dialog, return value */
2149 nOpenAction = ONOPEN_OPEN;
2150 break;
2152 COMDLG32_SHFree(pidl);
2153 pidl = NULL;
2155 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
2157 if(*lpszTemp || /* points to trailing null for last path element */
2158 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
2160 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
2162 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
2163 break;
2166 else
2168 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
2169 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
2171 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
2172 break;
2175 /* change to the current folder */
2176 nOpenAction = ONOPEN_OPEN;
2177 break;
2179 else
2181 nOpenAction = ONOPEN_OPEN;
2182 break;
2185 if(pidl) COMDLG32_SHFree(pidl);
2189 Step 3: here we have a cleaned up and validated path
2191 valid variables:
2192 lpsf: ShellFolder bound to the rightmost valid path component
2193 lpstrPathAndFile: cleaned up path
2194 nOpenAction: action to do
2196 TRACE("end validate sf=%p\n", lpsf);
2198 switch(nOpenAction)
2200 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2201 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2203 int iPos;
2204 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2205 DWORD len;
2207 /* replace the current filter */
2208 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2209 len = lstrlenW(lpszTemp)+1;
2210 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2211 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2213 /* set the filter cb to the extension when possible */
2214 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2215 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2217 /* fall through */
2218 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2219 TRACE("ONOPEN_BROWSE\n");
2221 IPersistFolder2 * ppf2;
2222 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2224 LPITEMIDLIST pidlCurrent;
2225 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2226 IPersistFolder2_Release(ppf2);
2227 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2229 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE))
2230 && fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2232 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2235 else if( nOpenAction == ONOPEN_SEARCH )
2237 if (fodInfos->Shell.FOIShellView)
2238 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2240 COMDLG32_SHFree(pidlCurrent);
2241 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2244 ret = FALSE;
2245 break;
2246 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2247 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2249 WCHAR *ext = NULL;
2251 /* update READONLY check box flag */
2252 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2253 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2254 else
2255 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2257 /* Attach the file extension with file name*/
2258 ext = PathFindExtensionW(lpstrPathAndFile);
2259 if (! *ext)
2261 /* if no extension is specified with file name, then */
2262 /* attach the extension from file filter or default one */
2264 WCHAR *filterExt = NULL;
2265 LPWSTR lpstrFilter = NULL;
2266 static const WCHAR szwDot[] = {'.',0};
2267 int PathLength = lstrlenW(lpstrPathAndFile);
2269 /* Attach the dot*/
2270 lstrcatW(lpstrPathAndFile, szwDot);
2272 /*Get the file extension from file type filter*/
2273 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2274 fodInfos->ofnInfos->nFilterIndex-1);
2276 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2277 filterExt = PathFindExtensionW(lpstrFilter);
2279 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2280 lstrcatW(lpstrPathAndFile, filterExt + 1);
2281 else if ( fodInfos->defext ) /* attach the default file extension*/
2282 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2284 /* In Open dialog: if file does not exist try without extension */
2285 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2286 lpstrPathAndFile[PathLength] = '\0';
2289 if (fodInfos->defext) /* add default extension */
2291 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2292 if (*ext)
2293 ext++;
2294 if (!lstrcmpiW(fodInfos->defext, ext))
2295 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2296 else
2297 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2300 /* In Save dialog: check if the file already exists */
2301 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2302 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2303 && PathFileExistsW(lpstrPathAndFile))
2305 WCHAR lpstrOverwrite[100];
2306 int answer;
2308 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2309 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2310 MB_YESNO | MB_ICONEXCLAMATION);
2311 if (answer == IDNO)
2313 ret = FALSE;
2314 goto ret;
2318 /* In Open dialog: check if it should be created if it doesn't exist */
2319 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2320 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2321 && !PathFileExistsW(lpstrPathAndFile))
2323 WCHAR lpstrCreate[100];
2324 int answer;
2326 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2327 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2328 MB_YESNO | MB_ICONEXCLAMATION);
2329 if (answer == IDNO)
2331 ret = FALSE;
2332 goto ret;
2336 /* Check that the size of the file does not exceed buffer size.
2337 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2338 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2339 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2342 /* fill destination buffer */
2343 if (fodInfos->ofnInfos->lpstrFile)
2345 if(fodInfos->unicode)
2347 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2349 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2350 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2351 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2353 else
2355 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2357 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2358 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2359 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2360 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2364 if(fodInfos->unicode)
2366 LPWSTR lpszTemp;
2368 /* set filename offset */
2369 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2370 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2372 /* set extension offset */
2373 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2374 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2376 else
2378 LPSTR lpszTemp;
2379 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2381 /* set filename offset */
2382 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2383 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2385 /* set extension offset */
2386 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2387 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2390 /* set the lpstrFileTitle */
2391 if(fodInfos->ofnInfos->lpstrFileTitle)
2393 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2394 if(fodInfos->unicode)
2396 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2397 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2399 else
2401 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2402 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2403 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2407 /* copy currently selected filter to lpstrCustomFilter */
2408 if (fodInfos->ofnInfos->lpstrCustomFilter)
2410 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2411 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2412 NULL, 0, NULL, NULL);
2413 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2415 LPSTR s = ofn->lpstrCustomFilter;
2416 s += strlen(ofn->lpstrCustomFilter)+1;
2417 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2418 s, len, NULL, NULL);
2423 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2424 goto ret;
2426 TRACE("close\n");
2427 FILEDLG95_Clean(hwnd);
2428 ret = EndDialog(hwnd, TRUE);
2430 else
2432 WORD size;
2434 size = lstrlenW(lpstrPathAndFile) + 1;
2435 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2436 size += 1;
2437 /* return needed size in first two bytes of lpstrFile */
2438 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2439 FILEDLG95_Clean(hwnd);
2440 ret = EndDialog(hwnd, FALSE);
2441 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2444 break;
2447 ret:
2448 if(lpsf) IShellFolder_Release(lpsf);
2449 return ret;
2452 /***********************************************************************
2453 * FILEDLG95_SHELL_Init
2455 * Initialisation of the shell objects
2457 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2459 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2461 TRACE("\n");
2464 * Initialisation of the FileOpenDialogInfos structure
2467 /* Shell */
2469 /*ShellInfos */
2470 fodInfos->ShellInfos.hwndOwner = hwnd;
2472 /* Disable multi-select if flag not set */
2473 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2475 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2477 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2478 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2480 /* Construct the IShellBrowser interface */
2481 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2483 return NOERROR;
2486 /***********************************************************************
2487 * FILEDLG95_SHELL_ExecuteCommand
2489 * Change the folder option and refresh the view
2490 * If the function succeeds, the return value is nonzero.
2492 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2494 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2495 IContextMenu * pcm;
2497 TRACE("(%p,%p)\n", hwnd, lpVerb);
2499 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2500 SVGIO_BACKGROUND,
2501 &IID_IContextMenu,
2502 (LPVOID*)&pcm)))
2504 CMINVOKECOMMANDINFO ci;
2505 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2506 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2507 ci.lpVerb = lpVerb;
2508 ci.hwnd = hwnd;
2510 IContextMenu_InvokeCommand(pcm, &ci);
2511 IContextMenu_Release(pcm);
2514 return FALSE;
2517 /***********************************************************************
2518 * FILEDLG95_SHELL_UpFolder
2520 * Browse to the specified object
2521 * If the function succeeds, the return value is nonzero.
2523 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2525 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2527 TRACE("\n");
2529 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2530 NULL,
2531 SBSP_PARENT)))
2533 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2534 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2535 return TRUE;
2537 return FALSE;
2540 /***********************************************************************
2541 * FILEDLG95_SHELL_BrowseToDesktop
2543 * Browse to the Desktop
2544 * If the function succeeds, the return value is nonzero.
2546 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2548 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2549 LPITEMIDLIST pidl;
2550 HRESULT hres;
2552 TRACE("\n");
2554 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2555 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2556 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2557 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2558 COMDLG32_SHFree(pidl);
2559 return SUCCEEDED(hres);
2561 /***********************************************************************
2562 * FILEDLG95_SHELL_Clean
2564 * Cleans the memory used by shell objects
2566 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2568 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2570 TRACE("\n");
2572 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2574 /* clean Shell interfaces */
2575 if (fodInfos->Shell.FOIShellView)
2577 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2578 IShellView_Release(fodInfos->Shell.FOIShellView);
2580 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2581 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2582 if (fodInfos->Shell.FOIDataObject)
2583 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2586 /***********************************************************************
2587 * FILEDLG95_FILETYPE_Init
2589 * Initialisation of the file type combo box
2591 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2593 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2594 int nFilters = 0; /* number of filters */
2595 int nFilterIndexCB;
2597 TRACE("\n");
2599 if(fodInfos->customfilter)
2601 /* customfilter has one entry... title\0ext\0
2602 * Set first entry of combo box item with customfilter
2604 LPWSTR lpstrExt;
2605 LPCWSTR lpstrPos = fodInfos->customfilter;
2607 /* Get the title */
2608 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2610 /* Copy the extensions */
2611 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2612 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2613 lstrcpyW(lpstrExt,lpstrPos);
2615 /* Add the item at the end of the combo */
2616 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2617 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2618 nFilters++;
2620 if(fodInfos->filter)
2622 LPCWSTR lpstrPos = fodInfos->filter;
2624 for(;;)
2626 /* filter is a list... title\0ext\0......\0\0
2627 * Set the combo item text to the title and the item data
2628 * to the ext
2630 LPCWSTR lpstrDisplay;
2631 LPWSTR lpstrExt;
2633 /* Get the title */
2634 if(! *lpstrPos) break; /* end */
2635 lpstrDisplay = lpstrPos;
2636 lpstrPos += lstrlenW(lpstrPos) + 1;
2638 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2640 nFilters++;
2642 /* Copy the extensions */
2643 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2644 lstrcpyW(lpstrExt,lpstrPos);
2645 lpstrPos += lstrlenW(lpstrPos) + 1;
2647 /* Add the item at the end of the combo */
2648 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2650 /* malformed filters are added anyway... */
2651 if (!*lpstrExt) break;
2656 * Set the current filter to the one specified
2657 * in the initialisation structure
2659 if (fodInfos->filter || fodInfos->customfilter)
2661 LPWSTR lpstrFilter;
2663 /* Check to make sure our index isn't out of bounds. */
2664 if ( fodInfos->ofnInfos->nFilterIndex >
2665 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2666 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2668 /* set default filter index */
2669 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2670 fodInfos->ofnInfos->nFilterIndex = 1;
2672 /* calculate index of Combo Box item */
2673 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2674 if (fodInfos->customfilter == NULL)
2675 nFilterIndexCB--;
2677 /* Set the current index selection. */
2678 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2680 /* Get the corresponding text string from the combo box. */
2681 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2682 nFilterIndexCB);
2684 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2685 lpstrFilter = NULL;
2687 if(lpstrFilter)
2689 DWORD len;
2690 CharLowerW(lpstrFilter); /* lowercase */
2691 len = lstrlenW(lpstrFilter)+1;
2692 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2693 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2695 } else
2696 fodInfos->ofnInfos->nFilterIndex = 0;
2697 return S_OK;
2700 /***********************************************************************
2701 * FILEDLG95_FILETYPE_OnCommand
2703 * WM_COMMAND of the file type combo box
2704 * If the function succeeds, the return value is nonzero.
2706 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2708 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2710 switch(wNotifyCode)
2712 case CBN_SELENDOK:
2714 LPWSTR lpstrFilter;
2716 /* Get the current item of the filetype combo box */
2717 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2719 /* set the current filter index */
2720 fodInfos->ofnInfos->nFilterIndex = iItem +
2721 (fodInfos->customfilter == NULL ? 1 : 0);
2723 /* Set the current filter with the current selection */
2724 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2726 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2727 iItem);
2728 if((INT_PTR)lpstrFilter != CB_ERR)
2730 DWORD len;
2731 CharLowerW(lpstrFilter); /* lowercase */
2732 len = lstrlenW(lpstrFilter)+1;
2733 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2734 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2735 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
2736 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2739 /* Refresh the actual view to display the included items*/
2740 if (fodInfos->Shell.FOIShellView)
2741 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2744 return FALSE;
2746 /***********************************************************************
2747 * FILEDLG95_FILETYPE_SearchExt
2749 * searches for an extension in the filetype box
2751 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2753 int i, iCount = CBGetCount(hwnd);
2755 TRACE("%s\n", debugstr_w(lpstrExt));
2757 if(iCount != CB_ERR)
2759 for(i=0;i<iCount;i++)
2761 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2762 return i;
2765 return -1;
2768 /***********************************************************************
2769 * FILEDLG95_FILETYPE_Clean
2771 * Clean the memory used by the filetype combo box
2773 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2775 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
2776 int iPos;
2777 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2779 TRACE("\n");
2781 /* Delete each string of the combo and their associated data */
2782 if(iCount != CB_ERR)
2784 for(iPos = iCount-1;iPos>=0;iPos--)
2786 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2787 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2790 /* Current filter */
2791 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2795 /***********************************************************************
2796 * FILEDLG95_LOOKIN_Init
2798 * Initialisation of the look in combo box
2801 /* Small helper function, to determine if the unixfs shell extension is rooted
2802 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2804 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2805 HKEY hKey;
2806 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2807 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2808 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2809 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2810 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2811 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2812 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2814 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2815 return FALSE;
2817 RegCloseKey(hKey);
2818 return TRUE;
2821 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2823 IShellFolder *psfRoot, *psfDrives;
2824 IEnumIDList *lpeRoot, *lpeDrives;
2825 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2827 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2829 TRACE("\n");
2831 liInfos->iMaxIndentation = 0;
2833 SetPropA(hwndCombo, LookInInfosStr, liInfos);
2835 /* set item height for both text field and listbox */
2836 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2837 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2839 /* Turn on the extended UI for the combo box like Windows does */
2840 CBSetExtendedUI(hwndCombo, TRUE);
2842 /* Initialise data of Desktop folder */
2843 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2844 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2845 COMDLG32_SHFree(pidlTmp);
2847 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2849 SHGetDesktopFolder(&psfRoot);
2851 if (psfRoot)
2853 /* enumerate the contents of the desktop */
2854 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2856 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2858 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2860 /* If the unixfs extension is rooted, we don't expand the drives by default */
2861 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2863 /* special handling for CSIDL_DRIVES */
2864 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2866 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2868 /* enumerate the drives */
2869 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2871 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2873 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2874 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2875 COMDLG32_SHFree(pidlAbsTmp);
2876 COMDLG32_SHFree(pidlTmp1);
2878 IEnumIDList_Release(lpeDrives);
2880 IShellFolder_Release(psfDrives);
2885 COMDLG32_SHFree(pidlTmp);
2887 IEnumIDList_Release(lpeRoot);
2889 IShellFolder_Release(psfRoot);
2892 COMDLG32_SHFree(pidlDrives);
2895 /***********************************************************************
2896 * FILEDLG95_LOOKIN_DrawItem
2898 * WM_DRAWITEM message handler
2900 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2902 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2903 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2904 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2905 RECT rectText;
2906 RECT rectIcon;
2907 SHFILEINFOW sfi;
2908 HIMAGELIST ilItemImage;
2909 int iIndentation;
2910 TEXTMETRICW tm;
2911 LPSFOLDER tmpFolder;
2912 LookInInfos *liInfos = GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2914 TRACE("\n");
2916 if(pDIStruct->itemID == -1)
2917 return 0;
2919 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2920 pDIStruct->itemID)))
2921 return 0;
2924 if(pDIStruct->itemID == liInfos->uSelectedItem)
2926 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2928 &sfi,
2929 sizeof (sfi),
2930 SHGFI_PIDL | SHGFI_SMALLICON |
2931 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2932 SHGFI_DISPLAYNAME );
2934 else
2936 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2938 &sfi,
2939 sizeof (sfi),
2940 SHGFI_PIDL | SHGFI_SMALLICON |
2941 SHGFI_SYSICONINDEX |
2942 SHGFI_DISPLAYNAME);
2945 /* Is this item selected ? */
2946 if(pDIStruct->itemState & ODS_SELECTED)
2948 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2949 SetBkColor(pDIStruct->hDC,crHighLight);
2950 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2952 else
2954 SetTextColor(pDIStruct->hDC,crText);
2955 SetBkColor(pDIStruct->hDC,crWin);
2956 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2959 /* Do not indent item if drawing in the edit of the combo */
2960 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2962 iIndentation = 0;
2963 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2965 &sfi,
2966 sizeof (sfi),
2967 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2968 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2971 else
2973 iIndentation = tmpFolder->m_iIndent;
2975 /* Draw text and icon */
2977 /* Initialise the icon display area */
2978 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2979 rectIcon.top = pDIStruct->rcItem.top;
2980 rectIcon.right = rectIcon.left + ICONWIDTH;
2981 rectIcon.bottom = pDIStruct->rcItem.bottom;
2983 /* Initialise the text display area */
2984 GetTextMetricsW(pDIStruct->hDC, &tm);
2985 rectText.left = rectIcon.right;
2986 rectText.top =
2987 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2988 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2989 rectText.bottom =
2990 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2992 /* Draw the icon from the image list */
2993 ImageList_Draw(ilItemImage,
2994 sfi.iIcon,
2995 pDIStruct->hDC,
2996 rectIcon.left,
2997 rectIcon.top,
2998 ILD_TRANSPARENT );
3000 /* Draw the associated text */
3001 if(sfi.szDisplayName)
3002 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
3005 return NOERROR;
3008 /***********************************************************************
3009 * FILEDLG95_LOOKIN_OnCommand
3011 * LookIn combo box WM_COMMAND message handler
3012 * If the function succeeds, the return value is nonzero.
3014 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
3016 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3018 TRACE("%p\n", fodInfos);
3020 switch(wNotifyCode)
3022 case CBN_SELENDOK:
3024 LPSFOLDER tmpFolder;
3025 int iItem;
3027 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
3029 if( iItem == CB_ERR) return FALSE;
3031 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
3032 iItem)))
3033 return FALSE;
3036 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
3037 tmpFolder->pidlItem,
3038 SBSP_ABSOLUTE)))
3040 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3041 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
3042 return TRUE;
3044 break;
3048 return FALSE;
3051 /***********************************************************************
3052 * FILEDLG95_LOOKIN_AddItem
3054 * Adds an absolute pidl item to the lookin combo box
3055 * returns the index of the inserted item
3057 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
3059 LPITEMIDLIST pidlNext;
3060 SHFILEINFOW sfi;
3061 SFOLDER *tmpFolder;
3062 LookInInfos *liInfos;
3064 TRACE("%08x\n", iInsertId);
3066 if(!pidl)
3067 return -1;
3069 if(!(liInfos = GetPropA(hwnd,LookInInfosStr)))
3070 return -1;
3072 tmpFolder = MemAlloc(sizeof(SFOLDER));
3073 tmpFolder->m_iIndent = 0;
3075 /* Calculate the indentation of the item in the lookin*/
3076 pidlNext = pidl;
3077 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
3079 tmpFolder->m_iIndent++;
3082 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
3084 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
3085 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
3087 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
3088 SHGetFileInfoW((LPCWSTR)pidl,
3090 &sfi,
3091 sizeof(sfi),
3092 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
3093 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
3095 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
3097 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
3099 int iItemID;
3101 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
3103 /* Add the item at the end of the list */
3104 if(iInsertId < 0)
3106 iItemID = CBAddString(hwnd,sfi.szDisplayName);
3108 /* Insert the item at the iInsertId position*/
3109 else
3111 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
3114 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
3115 return iItemID;
3118 COMDLG32_SHFree( tmpFolder->pidlItem );
3119 MemFree( tmpFolder );
3120 return -1;
3124 /***********************************************************************
3125 * FILEDLG95_LOOKIN_InsertItemAfterParent
3127 * Insert an item below its parent
3129 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
3132 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
3133 int iParentPos;
3135 TRACE("\n");
3137 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
3139 if(iParentPos < 0)
3141 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
3144 /* Free pidlParent memory */
3145 COMDLG32_SHFree(pidlParent);
3147 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
3150 /***********************************************************************
3151 * FILEDLG95_LOOKIN_SelectItem
3153 * Adds an absolute pidl item to the lookin combo box
3154 * returns the index of the inserted item
3156 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
3158 int iItemPos;
3159 LookInInfos *liInfos;
3161 TRACE("\n");
3163 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
3165 liInfos = GetPropA(hwnd,LookInInfosStr);
3167 if(iItemPos < 0)
3169 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
3170 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
3173 else
3175 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3176 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
3178 int iRemovedItem;
3180 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
3181 break;
3182 if(iRemovedItem < iItemPos)
3183 iItemPos--;
3187 CBSetCurSel(hwnd,iItemPos);
3188 liInfos->uSelectedItem = iItemPos;
3190 return 0;
3194 /***********************************************************************
3195 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
3197 * Remove the item with an expansion level over iExpansionLevel
3199 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
3201 int iItemPos;
3202 LookInInfos *liInfos = GetPropA(hwnd,LookInInfosStr);
3204 TRACE("\n");
3206 if(liInfos->iMaxIndentation <= 2)
3207 return -1;
3209 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3211 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3212 COMDLG32_SHFree(tmpFolder->pidlItem);
3213 MemFree(tmpFolder);
3214 CBDeleteString(hwnd,iItemPos);
3215 liInfos->iMaxIndentation--;
3217 return iItemPos;
3220 return -1;
3223 /***********************************************************************
3224 * FILEDLG95_LOOKIN_SearchItem
3226 * Search for pidl in the lookin combo box
3227 * returns the index of the found item
3229 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3231 int i = 0;
3232 int iCount = CBGetCount(hwnd);
3234 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3236 if (iCount != CB_ERR)
3238 for(;i<iCount;i++)
3240 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3242 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3243 return i;
3244 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3245 return i;
3249 return -1;
3252 /***********************************************************************
3253 * FILEDLG95_LOOKIN_Clean
3255 * Clean the memory used by the lookin combo box
3257 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3259 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3260 LookInInfos *liInfos = GetPropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
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 MemFree(liInfos);
3280 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3283 /***********************************************************************
3284 * FILEDLG95_FILENAME_FillFromSelection
3286 * fills the edit box from the cached DataObject
3288 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3290 FileOpenDlgInfos *fodInfos;
3291 LPITEMIDLIST pidl;
3292 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3293 WCHAR lpstrTemp[MAX_PATH];
3294 LPWSTR lpstrAllFile, lpstrCurrFile;
3296 TRACE("\n");
3297 fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3299 /* Count how many files we have */
3300 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3302 /* calculate the string length, count files */
3303 if (nFileSelected >= 1)
3305 nLength += 3; /* first and last quotes, trailing \0 */
3306 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3308 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3310 if (pidl)
3312 /* get the total length of the selected file names */
3313 lpstrTemp[0] = '\0';
3314 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3316 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3318 nLength += lstrlenW( lpstrTemp ) + 3;
3319 nFiles++;
3321 COMDLG32_SHFree( pidl );
3326 /* allocate the buffer */
3327 if (nFiles <= 1) nLength = MAX_PATH;
3328 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3330 /* Generate the string for the edit control */
3331 if(nFiles >= 1)
3333 lpstrCurrFile = lpstrAllFile;
3334 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3336 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3338 if (pidl)
3340 /* get the file name */
3341 lpstrTemp[0] = '\0';
3342 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3344 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3346 if ( nFiles > 1)
3348 *lpstrCurrFile++ = '\"';
3349 lstrcpyW( lpstrCurrFile, lpstrTemp );
3350 lpstrCurrFile += lstrlenW( lpstrTemp );
3351 *lpstrCurrFile++ = '\"';
3352 *lpstrCurrFile++ = ' ';
3353 *lpstrCurrFile = 0;
3355 else
3357 lstrcpyW( lpstrAllFile, lpstrTemp );
3360 COMDLG32_SHFree( pidl );
3363 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3365 /* Select the file name like Windows does */
3366 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3368 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3372 /* copied from shell32 to avoid linking to it
3373 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3374 * is dependent on whether emulated OS is unicode or not.
3376 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
3378 switch (src->uType)
3380 case STRRET_WSTR:
3381 lstrcpynW(dest, src->u.pOleStr, len);
3382 COMDLG32_SHFree(src->u.pOleStr);
3383 break;
3385 case STRRET_CSTR:
3386 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3387 dest[len-1] = 0;
3388 break;
3390 case STRRET_OFFSET:
3391 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3392 dest[len-1] = 0;
3393 break;
3395 default:
3396 FIXME("unknown type %x!\n", src->uType);
3397 if (len) *dest = '\0';
3398 return E_FAIL;
3400 return S_OK;
3403 /***********************************************************************
3404 * FILEDLG95_FILENAME_GetFileNames
3406 * Copies the filenames to a delimited string list.
3407 * The delimiter is specified by the parameter 'separator',
3408 * usually either a space or a nul
3410 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3412 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3413 UINT nStrCharCount = 0; /* index in src buffer */
3414 UINT nFileIndex = 0; /* index in dest buffer */
3415 UINT nFileCount = 0; /* number of files */
3416 UINT nStrLen = 0; /* length of string in edit control */
3417 LPWSTR lpstrEdit; /* buffer for string from edit control */
3419 TRACE("\n");
3421 /* get the filenames from the edit control */
3422 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3423 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3424 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3426 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3428 /* we might get single filename without any '"',
3429 * so we need nStrLen + terminating \0 + end-of-list \0 */
3430 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3431 *sizeUsed = 0;
3433 /* build delimited file list from filenames */
3434 while ( nStrCharCount <= nStrLen )
3436 if ( lpstrEdit[nStrCharCount]=='"' )
3438 nStrCharCount++;
3439 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3441 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3442 nStrCharCount++;
3444 (*lpstrFileList)[nFileIndex++] = 0;
3445 nFileCount++;
3447 nStrCharCount++;
3450 /* single, unquoted string */
3451 if ((nStrLen > 0) && (nFileIndex == 0) )
3453 lstrcpyW(*lpstrFileList, lpstrEdit);
3454 nFileIndex = lstrlenW(lpstrEdit) + 1;
3455 nFileCount = 1;
3458 /* trailing \0 */
3459 (*lpstrFileList)[nFileIndex++] = '\0';
3461 *sizeUsed = nFileIndex;
3462 MemFree(lpstrEdit);
3463 return nFileCount;
3466 #define SETDefFormatEtc(fe,cf,med) \
3468 (fe).cfFormat = cf;\
3469 (fe).dwAspect = DVASPECT_CONTENT; \
3470 (fe).ptd =NULL;\
3471 (fe).tymed = med;\
3472 (fe).lindex = -1;\
3476 * DATAOBJECT Helper functions
3479 /***********************************************************************
3480 * COMCTL32_ReleaseStgMedium
3482 * like ReleaseStgMedium from ole32
3484 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3486 if(medium.pUnkForRelease)
3488 IUnknown_Release(medium.pUnkForRelease);
3490 else
3492 GlobalUnlock(medium.u.hGlobal);
3493 GlobalFree(medium.u.hGlobal);
3497 /***********************************************************************
3498 * GetPidlFromDataObject
3500 * Return pidl(s) by number from the cached DataObject
3502 * nPidlIndex=0 gets the fully qualified root path
3504 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3507 STGMEDIUM medium;
3508 FORMATETC formatetc;
3509 LPITEMIDLIST pidl = NULL;
3511 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3513 if (!doSelected)
3514 return NULL;
3516 /* Set the FORMATETC structure*/
3517 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3519 /* Get the pidls from IDataObject */
3520 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3522 LPIDA cida = GlobalLock(medium.u.hGlobal);
3523 if(nPidlIndex <= cida->cidl)
3525 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3527 COMCTL32_ReleaseStgMedium(medium);
3529 return pidl;
3532 /***********************************************************************
3533 * GetNumSelected
3535 * Return the number of selected items in the DataObject.
3538 static UINT GetNumSelected( IDataObject *doSelected )
3540 UINT retVal = 0;
3541 STGMEDIUM medium;
3542 FORMATETC formatetc;
3544 TRACE("sv=%p\n", doSelected);
3546 if (!doSelected) return 0;
3548 /* Set the FORMATETC structure*/
3549 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), TYMED_HGLOBAL);
3551 /* Get the pidls from IDataObject */
3552 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3554 LPIDA cida = GlobalLock(medium.u.hGlobal);
3555 retVal = cida->cidl;
3556 COMCTL32_ReleaseStgMedium(medium);
3557 return retVal;
3559 return 0;
3563 * TOOLS
3566 /***********************************************************************
3567 * GetName
3569 * Get the pidl's display name (relative to folder) and
3570 * put it in lpstrFileName.
3572 * Return NOERROR on success,
3573 * E_FAIL otherwise
3576 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3578 STRRET str;
3579 HRESULT hRes;
3581 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3583 if(!lpsf)
3585 SHGetDesktopFolder(&lpsf);
3586 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3587 IShellFolder_Release(lpsf);
3588 return hRes;
3591 /* Get the display name of the pidl relative to the folder */
3592 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3594 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3596 return E_FAIL;
3599 /***********************************************************************
3600 * GetShellFolderFromPidl
3602 * pidlRel is the item pidl relative
3603 * Return the IShellFolder of the absolute pidl
3605 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3607 IShellFolder *psf = NULL,*psfParent;
3609 TRACE("%p\n", pidlAbs);
3611 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3613 psf = psfParent;
3614 if(pidlAbs && pidlAbs->mkid.cb)
3616 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3618 IShellFolder_Release(psfParent);
3619 return psf;
3622 /* return the desktop */
3623 return psfParent;
3625 return NULL;
3628 /***********************************************************************
3629 * GetParentPidl
3631 * Return the LPITEMIDLIST to the parent of the pidl in the list
3633 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3635 LPITEMIDLIST pidlParent;
3637 TRACE("%p\n", pidl);
3639 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3640 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3642 return pidlParent;
3645 /***********************************************************************
3646 * GetPidlFromName
3648 * returns the pidl of the file name relative to folder
3649 * NULL if an error occurred
3651 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3653 LPITEMIDLIST pidl = NULL;
3654 ULONG ulEaten;
3656 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3658 if(!lpcstrFileName) return NULL;
3659 if(!*lpcstrFileName) return NULL;
3661 if(!lpsf)
3663 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3664 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3665 IShellFolder_Release(lpsf);
3668 else
3670 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3672 return pidl;
3677 static BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3679 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3680 HRESULT ret;
3682 TRACE("%p, %p\n", psf, pidl);
3684 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3686 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3687 /* see documentation shell 4.1*/
3688 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3691 /***********************************************************************
3692 * BrowseSelectedFolder
3694 static BOOL BrowseSelectedFolder(HWND hwnd)
3696 BOOL bBrowseSelFolder = FALSE;
3697 FileOpenDlgInfos *fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
3699 TRACE("\n");
3701 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3703 LPITEMIDLIST pidlSelection;
3705 /* get the file selected */
3706 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3707 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3709 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3710 pidlSelection, SBSP_RELATIVE ) ) )
3712 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3713 ' ','n','o','t',' ','e','x','i','s','t',0};
3714 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3716 bBrowseSelFolder = TRUE;
3717 if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
3718 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3720 COMDLG32_SHFree( pidlSelection );
3723 return bBrowseSelFolder;
3727 * Memory allocation methods */
3728 static void *MemAlloc(UINT size)
3730 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3733 static void MemFree(void *mem)
3735 HeapFree(GetProcessHeap(),0,mem);
3739 * Old-style (win3.1) dialogs */
3741 /***********************************************************************
3742 * FD32_GetTemplate [internal]
3744 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3745 * by a 32 bits application
3748 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3750 LPOPENFILENAMEW ofnW = lfs->ofnW;
3751 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3752 HANDLE hDlgTmpl;
3754 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3756 if (!(lfs->template = LockResource( ofnW->hInstance )))
3758 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3759 return FALSE;
3762 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3764 HRSRC hResInfo;
3765 if (priv->ofnA)
3766 hResInfo = FindResourceA(priv->ofnA->hInstance,
3767 priv->ofnA->lpTemplateName,
3768 (LPSTR)RT_DIALOG);
3769 else
3770 hResInfo = FindResourceW(ofnW->hInstance,
3771 ofnW->lpTemplateName,
3772 (LPWSTR)RT_DIALOG);
3773 if (!hResInfo)
3775 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3776 return FALSE;
3778 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3779 hResInfo)) ||
3780 !(lfs->template = LockResource(hDlgTmpl)))
3782 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3783 return FALSE;
3785 } else { /* get it from internal Wine resource */
3786 HRSRC hResInfo;
3787 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3788 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3790 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3791 return FALSE;
3793 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3794 !(lfs->template = LockResource( hDlgTmpl )))
3796 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3797 return FALSE;
3800 return TRUE;
3804 /************************************************************************
3805 * FD32_Init [internal]
3806 * called from the common 16/32 code to initialize 32 bit data
3808 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3810 BOOL IsUnicode = (BOOL) data;
3811 PFD32_PRIVATE priv;
3813 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3814 lfs->private1632 = priv;
3815 if (NULL == lfs->private1632) return FALSE;
3816 if (IsUnicode)
3818 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3819 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3820 if (lfs->ofnW->lpfnHook)
3821 lfs->hook = TRUE;
3823 else
3825 priv->ofnA = (LPOPENFILENAMEA) lParam;
3826 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3827 if (priv->ofnA->lpfnHook)
3828 lfs->hook = TRUE;
3829 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3830 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3833 if (! FD32_GetTemplate(lfs)) return FALSE;
3835 return TRUE;
3838 /***********************************************************************
3839 * FD32_CallWindowProc [internal]
3841 * called from the common 16/32 code to call the appropriate hook
3843 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3844 LPARAM lParam)
3846 BOOL ret;
3847 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3849 if (priv->ofnA)
3851 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3852 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3853 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3854 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3855 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3856 return ret;
3859 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3860 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3861 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3862 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3863 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3864 return ret;
3867 /***********************************************************************
3868 * FD32_UpdateResult [internal]
3869 * update the real client structures if any
3871 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3873 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3874 LPOPENFILENAMEW ofnW = lfs->ofnW;
3876 if (priv->ofnA)
3878 LPSTR lpszTemp;
3879 if (ofnW->nMaxFile &&
3880 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3881 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3882 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3884 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3885 /* set filename offset */
3886 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3887 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3889 /* set extension offset */
3890 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3891 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3895 /***********************************************************************
3896 * FD32_UpdateFileTitle [internal]
3897 * update the real client structures if any
3899 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3901 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3902 LPOPENFILENAMEW ofnW = lfs->ofnW;
3904 if (priv->ofnA)
3906 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3907 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3908 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3913 /***********************************************************************
3914 * FD32_SendLbGetCurSel [internal]
3915 * retrieve selected listbox item
3917 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3919 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3923 /************************************************************************
3924 * FD32_Destroy [internal]
3925 * called from the common 16/32 code to cleanup 32 bit data
3927 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3929 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3931 /* if ofnW has been allocated, have to free everything in it */
3932 if (NULL != priv && NULL != priv->ofnA)
3934 FD31_FreeOfnW(lfs->ofnW);
3935 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3939 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3941 callbacks->Init = FD32_Init;
3942 callbacks->CWP = FD32_CallWindowProc;
3943 callbacks->UpdateResult = FD32_UpdateResult;
3944 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3945 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3946 callbacks->Destroy = FD32_Destroy;
3949 /***********************************************************************
3950 * FD32_WMMeasureItem [internal]
3952 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3954 LPMEASUREITEMSTRUCT lpmeasure;
3956 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3957 lpmeasure->itemHeight = FD31_GetFldrHeight();
3958 return TRUE;
3962 /***********************************************************************
3963 * FileOpenDlgProc [internal]
3964 * Used for open and save, in fact.
3966 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3967 WPARAM wParam, LPARAM lParam)
3969 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3971 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3972 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3974 INT_PTR lRet;
3975 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3976 if (lRet)
3977 return lRet; /* else continue message processing */
3979 switch (wMsg)
3981 case WM_INITDIALOG:
3982 return FD31_WMInitDialog(hWnd, wParam, lParam);
3984 case WM_MEASUREITEM:
3985 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3987 case WM_DRAWITEM:
3988 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3990 case WM_COMMAND:
3991 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3992 #if 0
3993 case WM_CTLCOLOR:
3994 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3995 switch (HIWORD(lParam))
3997 case CTLCOLOR_BTN:
3998 SetTextColor((HDC16)wParam, 0x00000000);
3999 return hGRAYBrush;
4000 case CTLCOLOR_STATIC:
4001 SetTextColor((HDC16)wParam, 0x00000000);
4002 return hGRAYBrush;
4004 break;
4005 #endif
4007 return FALSE;
4011 /***********************************************************************
4012 * GetFileName31A [internal]
4014 * Creates a win31 style dialog box for the user to select a file to open/save.
4016 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
4017 UINT dlgType /* type dialogue : open/save */
4020 HINSTANCE hInst;
4021 BOOL bRet = FALSE;
4022 PFD31_DATA lfs;
4023 FD31_CALLBACKS callbacks;
4025 if (!lpofn || !FD31_Init()) return FALSE;
4027 TRACE("ofn flags %08x\n", lpofn->Flags);
4028 FD32_SetupCallbacks(&callbacks);
4029 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
4030 if (lfs)
4032 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4033 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
4034 FD32_FileOpenDlgProc, (LPARAM)lfs);
4035 FD31_DestroyPrivate(lfs);
4038 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
4039 return bRet;
4042 /***********************************************************************
4043 * GetFileName31W [internal]
4045 * Creates a win31 style dialog box for the user to select a file to open/save
4047 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
4048 UINT dlgType /* type dialogue : open/save */
4051 HINSTANCE hInst;
4052 BOOL bRet = FALSE;
4053 PFD31_DATA lfs;
4054 FD31_CALLBACKS callbacks;
4056 if (!lpofn || !FD31_Init()) return FALSE;
4058 FD32_SetupCallbacks(&callbacks);
4059 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
4060 if (lfs)
4062 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
4063 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
4064 FD32_FileOpenDlgProc, (LPARAM)lfs);
4065 FD31_DestroyPrivate(lfs);
4068 TRACE("file %s, file offset %d, ext offset %d\n",
4069 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
4070 return bRet;
4073 /* ------------------ APIs ---------------------- */
4075 /***********************************************************************
4076 * GetOpenFileNameA (COMDLG32.@)
4078 * Creates a dialog box for the user to select a file to open.
4080 * RETURNS
4081 * TRUE on success: user enters a valid file
4082 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4085 BOOL WINAPI GetOpenFileNameA(
4086 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4088 BOOL win16look = FALSE;
4090 TRACE("flags %08x\n", ofn->Flags);
4092 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4093 if (ofn->Flags & OFN_FILEMUSTEXIST)
4094 ofn->Flags |= OFN_PATHMUSTEXIST;
4096 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4097 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4099 if (win16look)
4100 return GetFileName31A(ofn, OPEN_DIALOG);
4101 else
4102 return GetFileDialog95A(ofn, OPEN_DIALOG);
4105 /***********************************************************************
4106 * GetOpenFileNameW (COMDLG32.@)
4108 * Creates a dialog box for the user to select a file to open.
4110 * RETURNS
4111 * TRUE on success: user enters a valid file
4112 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4115 BOOL WINAPI GetOpenFileNameW(
4116 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4118 BOOL win16look = FALSE;
4120 TRACE("flags %08x\n", ofn->Flags);
4122 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
4123 if (ofn->Flags & OFN_FILEMUSTEXIST)
4124 ofn->Flags |= OFN_PATHMUSTEXIST;
4126 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4127 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4129 if (win16look)
4130 return GetFileName31W(ofn, OPEN_DIALOG);
4131 else
4132 return GetFileDialog95W(ofn, OPEN_DIALOG);
4136 /***********************************************************************
4137 * GetSaveFileNameA (COMDLG32.@)
4139 * Creates a dialog box for the user to select a file to save.
4141 * RETURNS
4142 * TRUE on success: user enters a valid file
4143 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4146 BOOL WINAPI GetSaveFileNameA(
4147 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
4149 BOOL win16look = FALSE;
4151 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4152 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4154 if (win16look)
4155 return GetFileName31A(ofn, SAVE_DIALOG);
4156 else
4157 return GetFileDialog95A(ofn, SAVE_DIALOG);
4160 /***********************************************************************
4161 * GetSaveFileNameW (COMDLG32.@)
4163 * Creates a dialog box for the user to select a file to save.
4165 * RETURNS
4166 * TRUE on success: user enters a valid file
4167 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
4170 BOOL WINAPI GetSaveFileNameW(
4171 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
4173 BOOL win16look = FALSE;
4175 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
4176 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
4178 if (win16look)
4179 return GetFileName31W(ofn, SAVE_DIALOG);
4180 else
4181 return GetFileDialog95W(ofn, SAVE_DIALOG);
4184 /***********************************************************************
4185 * GetFileTitleA (COMDLG32.@)
4187 * See GetFileTitleW.
4189 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
4191 int ret;
4192 UNICODE_STRING strWFile;
4193 LPWSTR lpWTitle;
4195 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
4196 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
4197 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
4198 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
4199 RtlFreeUnicodeString( &strWFile );
4200 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
4201 return ret;
4205 /***********************************************************************
4206 * GetFileTitleW (COMDLG32.@)
4208 * Get the name of a file.
4210 * PARAMS
4211 * lpFile [I] name and location of file
4212 * lpTitle [O] returned file name
4213 * cbBuf [I] buffer size of lpTitle
4215 * RETURNS
4216 * Success: zero
4217 * Failure: negative number.
4219 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4221 int i, len;
4222 static const WCHAR brkpoint[] = {'*','[',']',0};
4223 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4225 if(lpFile == NULL || lpTitle == NULL)
4226 return -1;
4228 len = lstrlenW(lpFile);
4230 if (len == 0)
4231 return -1;
4233 if(strpbrkW(lpFile, brkpoint))
4234 return -1;
4236 len--;
4238 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4239 return -1;
4241 for(i = len; i >= 0; i--)
4243 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4245 i++;
4246 break;
4250 if(i == -1)
4251 i++;
4253 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4255 len = lstrlenW(lpFile+i)+1;
4256 if(cbBuf < len)
4257 return len;
4259 lstrcpyW(lpTitle, &lpFile[i]);
4260 return 0;