comdlg32: Fixed a number of buffer overflows in the file dialog.
[wine/wine64.git] / dlls / comdlg32 / filedlg.c
blob3e662ec46199565a7160d33f2b33d7dfd0db7065
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_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winternl.h"
65 #include "winnls.h"
66 #include "wingdi.h"
67 #include "winreg.h"
68 #include "winuser.h"
69 #include "commdlg.h"
70 #include "dlgs.h"
71 #include "cdlg.h"
72 #include "filedlg31.h"
73 #include "cderr.h"
74 #include "shellapi.h"
75 #include "shlobj.h"
76 #include "filedlgbrowser.h"
77 #include "shlwapi.h"
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
124 /* AddItem flags*/
125 #define LISTEND -1
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
135 /* NOTE
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
159 #define CBGetCurSel(hwnd) \
160 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
165 #define CBGetCount(hwnd) \
166 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
175 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
176 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
178 /***********************************************************************
179 * Prototypes
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
218 /* Miscellaneous tool functions */
219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size);
226 static void MemFree(void *mem);
228 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
231 static BOOL BrowseSelectedFolder(HWND hwnd);
233 /***********************************************************************
234 * GetFileName95
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
246 LRESULT lRes;
247 LPCVOID template;
248 HRSRC hRes;
249 HANDLE hDlgTmpl = 0;
250 HRESULT hr;
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
282 /* Some shell namespace extensions depend on COM being initialized. */
283 hr = OleInitialize(NULL);
285 if (fodInfos->unicode)
286 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
287 template,
288 fodInfos->ofnInfos->hwndOwner,
289 FileOpenDlgProc95,
290 (LPARAM) fodInfos);
291 else
292 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
293 (LPCDLGTEMPLATEA) template,
294 fodInfos->ofnInfos->hwndOwner,
295 FileOpenDlgProc95,
296 (LPARAM) fodInfos);
297 if (SUCCEEDED(hr))
298 OleUninitialize();
300 /* Unable to create the dialog */
301 if( lRes == -1)
302 return FALSE;
304 return lRes;
307 /***********************************************************************
308 * GetFileDialog95A
310 * Call GetFileName95 with this structure and clean the memory.
312 * IN : The OPENFILENAMEA initialisation structure passed to
313 * GetOpenFileNameA win api function (see filedlg.c)
315 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
317 BOOL ret;
318 FileOpenDlgInfos fodInfos;
319 LPSTR lpstrSavDir = NULL;
320 LPWSTR title = NULL;
321 LPWSTR defext = NULL;
322 LPWSTR filter = NULL;
323 LPWSTR customfilter = NULL;
325 /* Initialize CommDlgExtendedError() */
326 COMDLG32_SetCommDlgExtendedError(0);
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
350 else
351 fodInfos.initdir = NULL;
353 if(ofn->lpstrFile)
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
358 else
359 fodInfos.filename = NULL;
361 if(ofn->lpstrDefExt)
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
369 if(ofn->lpstrTitle)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
379 LPCSTR s;
380 int n, len;
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
385 s++;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
396 LPCSTR s;
397 int n, len;
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
414 switch(iDlgType)
416 case OPEN_DIALOG :
417 ret = GetFileName95(&fodInfos);
418 break;
419 case SAVE_DIALOG :
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
422 break;
423 default :
424 ret = 0;
427 if (lpstrSavDir)
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
433 MemFree(title);
434 MemFree(defext);
435 MemFree(filter);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
442 return ret;
445 /***********************************************************************
446 * GetFileDialog95W
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize CommDlgExtendedError() */
459 COMDLG32_SetCommDlgExtendedError(0);
461 /* Initialize FileOpenDlgInfos structure */
462 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
464 /* Pass in the original ofn */
465 fodInfos.ofnInfos = ofn;
467 fodInfos.title = ofn->lpstrTitle;
468 fodInfos.defext = ofn->lpstrDefExt;
469 fodInfos.filter = ofn->lpstrFilter;
470 fodInfos.customfilter = ofn->lpstrCustomFilter;
472 /* convert string arguments, save others */
473 if(ofn->lpstrFile)
475 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
476 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
478 else
479 fodInfos.filename = NULL;
481 if(ofn->lpstrInitialDir)
483 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
484 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
485 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
486 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
488 else
489 fodInfos.initdir = NULL;
491 /* save current directory */
492 if (ofn->Flags & OFN_NOCHANGEDIR)
494 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
495 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
498 fodInfos.unicode = TRUE;
500 switch(iDlgType)
502 case OPEN_DIALOG :
503 ret = GetFileName95(&fodInfos);
504 break;
505 case SAVE_DIALOG :
506 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
507 ret = GetFileName95(&fodInfos);
508 break;
509 default :
510 ret = 0;
513 if (lpstrSavDir)
515 SetCurrentDirectoryW(lpstrSavDir);
516 MemFree(lpstrSavDir);
519 /* restore saved IN arguments and convert OUT arguments back */
520 MemFree(fodInfos.filename);
521 MemFree(fodInfos.initdir);
522 return ret;
525 /******************************************************************************
526 * COMDLG32_GetDisplayNameOf [internal]
528 * Helper function to get the display name for a pidl.
530 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
531 LPSHELLFOLDER psfDesktop;
532 STRRET strret;
534 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
535 return FALSE;
537 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
538 IShellFolder_Release(psfDesktop);
539 return FALSE;
542 IShellFolder_Release(psfDesktop);
543 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
546 /***********************************************************************
547 * ArrangeCtrlPositions [internal]
549 * NOTE: Do not change anything here without a lot of testing.
551 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
553 HWND hwndChild, hwndStc32;
554 RECT rectParent, rectChild, rectStc32;
555 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
557 /* Take into account if open as read only checkbox and help button
558 * are hidden
560 if (hide_help)
562 RECT rectHelp, rectCancel;
563 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
564 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
565 /* subtract the height of the help button plus the space between
566 * the help button and the cancel button to the height of the dialog
568 help_fixup = rectHelp.bottom - rectCancel.bottom;
572 There are two possibilities to add components to the default file dialog box.
574 By default, all the new components are added below the standard dialog box (the else case).
576 However, if there is a static text component with the stc32 id, a special case happens.
577 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
578 in the window and the cx and cy indicate how to size the window.
579 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
580 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
584 GetClientRect(hwndParentDlg, &rectParent);
586 /* when arranging controls we have to use fixed parent size */
587 rectParent.bottom -= help_fixup;
589 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
590 if (hwndStc32)
592 GetWindowRect(hwndStc32, &rectStc32);
593 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
595 /* set the size of the stc32 control according to the size of
596 * client area of the parent dialog
598 SetWindowPos(hwndStc32, 0,
599 0, 0,
600 rectParent.right, rectParent.bottom,
601 SWP_NOMOVE | SWP_NOZORDER);
603 else
604 SetRectEmpty(&rectStc32);
606 /* this part moves controls of the child dialog */
607 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
608 while (hwndChild)
610 if (hwndChild != hwndStc32)
612 GetWindowRect(hwndChild, &rectChild);
613 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
615 /* move only if stc32 exist */
616 if (hwndStc32 && rectChild.left > rectStc32.right)
618 LONG old_left = rectChild.left;
620 /* move to the right of visible controls of the parent dialog */
621 rectChild.left += rectParent.right;
622 rectChild.left -= rectStc32.right;
624 child_width_fixup = rectChild.left - old_left;
626 /* move even if stc32 doesn't exist */
627 if (rectChild.top >= rectStc32.bottom)
629 LONG old_top = rectChild.top;
631 /* move below visible controls of the parent dialog */
632 rectChild.top += rectParent.bottom;
633 rectChild.top -= rectStc32.bottom - rectStc32.top;
635 child_height_fixup = rectChild.top - old_top;
638 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
639 0, 0, SWP_NOSIZE | SWP_NOZORDER);
641 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
644 /* this part moves controls of the parent dialog */
645 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
646 while (hwndChild)
648 if (hwndChild != hwndChildDlg)
650 GetWindowRect(hwndChild, &rectChild);
651 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
653 /* left,top of stc32 marks the position of controls
654 * from the parent dialog
656 rectChild.left += rectStc32.left;
657 rectChild.top += rectStc32.top;
659 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
660 0, 0, SWP_NOSIZE | SWP_NOZORDER);
662 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
665 /* calculate the size of the resulting dialog */
667 /* here we have to use original parent size */
668 GetClientRect(hwndParentDlg, &rectParent);
669 GetClientRect(hwndChildDlg, &rectChild);
671 if (hwndStc32)
673 rectChild.right += child_width_fixup;
674 rectChild.bottom += child_height_fixup;
676 if (rectParent.right > rectChild.right)
678 rectParent.right += rectChild.right;
679 rectParent.right -= rectStc32.right - rectStc32.left;
681 else
683 rectParent.right = rectChild.right;
686 if (rectParent.bottom > rectChild.bottom)
688 rectParent.bottom += rectChild.bottom;
689 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
691 else
693 /* child dialog is higher, unconditionally set new dialog
694 * height to its size (help_fixup will be subtracted below)
696 rectParent.bottom = rectChild.bottom + help_fixup;
699 else
701 rectParent.bottom += rectChild.bottom;
704 /* finally use fixed parent size */
705 rectParent.bottom -= help_fixup;
707 /* set the size of the parent dialog */
708 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
709 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
710 SetWindowPos(hwndParentDlg, 0,
711 0, 0,
712 rectParent.right - rectParent.left,
713 rectParent.bottom - rectParent.top,
714 SWP_NOMOVE | SWP_NOZORDER);
717 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
719 switch(uMsg) {
720 case WM_INITDIALOG:
721 return TRUE;
723 return FALSE;
726 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
728 LPCVOID template;
729 HRSRC hRes;
730 HANDLE hDlgTmpl = 0;
731 HWND hChildDlg = 0;
733 TRACE("\n");
736 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
737 * structure's hInstance parameter is not a HINSTANCE, but
738 * instead a pointer to a template resource to use.
740 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
742 HINSTANCE hinst;
743 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
745 hinst = COMDLG32_hInstance;
746 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
749 return NULL;
752 else
754 hinst = fodInfos->ofnInfos->hInstance;
755 if(fodInfos->unicode)
757 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
758 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
760 else
762 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
763 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
765 if (!hRes)
767 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
768 return NULL;
770 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
771 !(template = LockResource( hDlgTmpl )))
773 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
774 return NULL;
777 if (fodInfos->unicode)
778 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
779 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
780 (LPARAM)fodInfos->ofnInfos);
781 else
782 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
783 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
784 (LPARAM)fodInfos->ofnInfos);
785 if(hChildDlg)
787 ShowWindow(hChildDlg,SW_SHOW);
788 return hChildDlg;
791 else if( IsHooked(fodInfos))
793 RECT rectHwnd;
794 struct {
795 DLGTEMPLATE tmplate;
796 WORD menu,class,title;
797 } temp;
798 GetClientRect(hwnd,&rectHwnd);
799 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
800 temp.tmplate.dwExtendedStyle = 0;
801 temp.tmplate.cdit = 0;
802 temp.tmplate.x = 0;
803 temp.tmplate.y = 0;
804 temp.tmplate.cx = 0;
805 temp.tmplate.cy = 0;
806 temp.menu = temp.class = temp.title = 0;
808 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
809 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
811 return hChildDlg;
813 return NULL;
816 /***********************************************************************
817 * SendCustomDlgNotificationMessage
819 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
822 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
824 LRESULT hook_result = 0;
826 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
828 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
830 if(!fodInfos) return 0;
832 if(fodInfos->DlgInfos.hwndCustomDlg)
834 TRACE("CALL NOTIFY for %x\n", uCode);
835 if(fodInfos->unicode)
837 OFNOTIFYW ofnNotify;
838 ofnNotify.hdr.hwndFrom=hwndParentDlg;
839 ofnNotify.hdr.idFrom=0;
840 ofnNotify.hdr.code = uCode;
841 ofnNotify.lpOFN = fodInfos->ofnInfos;
842 ofnNotify.pszFile = NULL;
843 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
845 else
847 OFNOTIFYA ofnNotify;
848 ofnNotify.hdr.hwndFrom=hwndParentDlg;
849 ofnNotify.hdr.idFrom=0;
850 ofnNotify.hdr.code = uCode;
851 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
852 ofnNotify.pszFile = NULL;
853 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
855 TRACE("RET NOTIFY\n");
857 TRACE("Retval: 0x%08lx\n", hook_result);
858 return hook_result;
861 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
863 UINT sizeUsed = 0, n, total;
864 LPWSTR lpstrFileList = NULL;
865 WCHAR lpstrCurrentDir[MAX_PATH];
866 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
868 TRACE("CDM_GETFILEPATH:\n");
870 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
871 return -1;
873 /* get path and filenames */
874 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
875 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
877 TRACE("path >%s< filespec >%s< %d files\n",
878 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
880 if( fodInfos->unicode )
882 LPWSTR bufW = buffer;
883 total = lstrlenW(lpstrCurrentDir) + 1 + sizeUsed;
885 /* Prepend the current path */
886 n = lstrlenW(lpstrCurrentDir) + 1;
887 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
888 if(n<size)
890 /* 'n' includes trailing \0 */
891 bufW[n-1] = '\\';
892 lstrcpynW( &bufW[n], lpstrFileList, size - n );
894 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
896 else
898 LPSTR bufA = buffer;
899 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
900 NULL, 0, NULL, NULL);
901 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
902 NULL, 0, NULL, NULL);
904 /* Prepend the current path */
905 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
906 bufA, size, NULL, NULL);
908 if(n<size)
910 /* 'n' includes trailing \0 */
911 bufA[n-1] = '\\';
912 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
913 &bufA[n], size-n, NULL, NULL);
916 TRACE("returned -> %s\n",debugstr_an(bufA, total));
918 MemFree(lpstrFileList);
920 return total;
923 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
925 UINT sizeUsed = 0;
926 LPWSTR lpstrFileList = NULL;
927 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
929 TRACE("CDM_GETSPEC:\n");
931 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
932 if( fodInfos->unicode )
934 lstrcpynW( buffer, lpstrFileList, size );
936 else
938 LPSTR bufA = buffer;
939 DWORD sizeA = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed, NULL, 0, NULL, NULL);
940 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, bufA, size, NULL, NULL);
941 if (size && size < sizeA) bufA[size - 1] = 0;
942 sizeUsed = sizeA;
944 MemFree(lpstrFileList);
946 return sizeUsed;
949 /***********************************************************************
950 * FILEDLG95_HandleCustomDialogMessages
952 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
954 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
956 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
957 WCHAR lpstrPath[MAX_PATH];
958 INT_PTR retval;
960 if(!fodInfos) return FALSE;
962 switch(uMsg)
964 case CDM_GETFILEPATH:
965 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
966 break;
968 case CDM_GETFOLDERPATH:
969 TRACE("CDM_GETFOLDERPATH:\n");
970 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
971 if (lParam)
973 if (fodInfos->unicode)
974 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
975 else
976 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
977 (LPSTR)lParam, (int)wParam, NULL, NULL);
979 retval = lstrlenW(lpstrPath);
980 break;
982 case CDM_GETSPEC:
983 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
984 break;
986 case CDM_SETCONTROLTEXT:
987 TRACE("CDM_SETCONTROLTEXT:\n");
988 if ( lParam )
990 if( fodInfos->unicode )
991 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
992 else
993 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
995 retval = TRUE;
996 break;
998 case CDM_HIDECONTROL:
999 /* MSDN states that it should fail for not OFN_EXPLORER case */
1000 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1002 HWND control = GetDlgItem( hwnd, wParam );
1003 if (control) ShowWindow( control, SW_HIDE );
1004 retval = TRUE;
1006 else retval = FALSE;
1007 break;
1009 default:
1010 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1011 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1012 return FALSE;
1014 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1015 return TRUE;
1018 /***********************************************************************
1019 * FileOpenDlgProc95
1021 * File open dialog procedure
1023 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1025 #if 0
1026 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1027 #endif
1029 switch(uMsg)
1031 case WM_INITDIALOG:
1033 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1035 /* Adds the FileOpenDlgInfos in the property list of the dialog
1036 so it will be easily accessible through a GetPropA(...) */
1037 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1039 FILEDLG95_InitControls(hwnd);
1041 fodInfos->DlgInfos.hwndCustomDlg =
1042 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1044 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1045 FILEDLG95_FillControls(hwnd, wParam, lParam);
1047 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1048 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1049 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1050 return 0;
1052 case WM_COMMAND:
1053 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1054 case WM_DRAWITEM:
1056 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1058 case IDC_LOOKIN:
1059 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1060 return TRUE;
1063 return FALSE;
1065 case WM_GETISHELLBROWSER:
1066 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1068 case WM_DESTROY:
1069 RemovePropA(hwnd, FileOpenDlgInfosStr);
1070 return FALSE;
1072 case WM_NOTIFY:
1074 LPNMHDR lpnmh = (LPNMHDR)lParam;
1075 UINT stringId = -1;
1077 /* set up the button tooltips strings */
1078 if(TTN_GETDISPINFOA == lpnmh->code )
1080 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1081 switch(lpnmh->idFrom )
1083 /* Up folder button */
1084 case FCIDM_TB_UPFOLDER:
1085 stringId = IDS_UPFOLDER;
1086 break;
1087 /* New folder button */
1088 case FCIDM_TB_NEWFOLDER:
1089 stringId = IDS_NEWFOLDER;
1090 break;
1091 /* List option button */
1092 case FCIDM_TB_SMALLICON:
1093 stringId = IDS_LISTVIEW;
1094 break;
1095 /* Details option button */
1096 case FCIDM_TB_REPORTVIEW:
1097 stringId = IDS_REPORTVIEW;
1098 break;
1099 /* Desktop button */
1100 case FCIDM_TB_DESKTOP:
1101 stringId = IDS_TODESKTOP;
1102 break;
1103 default:
1104 stringId = 0;
1106 lpdi->hinst = COMDLG32_hInstance;
1107 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1109 return FALSE;
1111 default :
1112 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1113 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1114 return FALSE;
1118 /***********************************************************************
1119 * FILEDLG95_InitControls
1121 * WM_INITDIALOG message handler (before hook notification)
1123 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1125 int win2000plus = 0;
1126 int win98plus = 0;
1127 int handledPath = FALSE;
1128 OSVERSIONINFOW osVi;
1129 static const WCHAR szwSlash[] = { '\\', 0 };
1130 static const WCHAR szwStar[] = { '*',0 };
1132 static const TBBUTTON tbb[] =
1134 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1135 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1136 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1137 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1138 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1139 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1140 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1141 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1142 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1144 TBADDBITMAP tba[2];
1145 RECT rectTB;
1146 RECT rectlook;
1147 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1149 tba[0].hInst = HINST_COMMCTRL;
1150 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1151 tba[1].hInst = COMDLG32_hInstance;
1152 tba[1].nID = 800;
1154 TRACE("%p\n", fodInfos);
1156 /* Get windows version emulating */
1157 osVi.dwOSVersionInfoSize = sizeof(osVi);
1158 GetVersionExW(&osVi);
1159 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1160 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1161 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1162 win2000plus = (osVi.dwMajorVersion > 4);
1163 if (win2000plus) win98plus = TRUE;
1165 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1167 /* Get the hwnd of the controls */
1168 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1169 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1170 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1172 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1173 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1175 /* construct the toolbar */
1176 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1177 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1179 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1180 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1181 rectTB.left = rectlook.right;
1182 rectTB.top = rectlook.top-1;
1184 if (fodInfos->unicode)
1185 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1186 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1187 rectTB.left, rectTB.top,
1188 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1189 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1190 else
1191 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1192 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1193 rectTB.left, rectTB.top,
1194 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1195 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1197 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1199 /* FIXME: use TB_LOADIMAGES when implemented */
1200 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1201 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1202 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1204 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1205 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1207 /* Set the window text with the text specified in the OPENFILENAME structure */
1208 if(fodInfos->title)
1210 SetWindowTextW(hwnd,fodInfos->title);
1212 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1214 WCHAR buf[16];
1215 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1216 SetWindowTextW(hwnd, buf);
1219 /* Initialise the file name edit control */
1220 handledPath = FALSE;
1221 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1223 if(fodInfos->filename)
1225 /* 1. If win2000 or higher and filename contains a path, use it
1226 in preference over the lpstrInitialDir */
1227 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1228 WCHAR tmpBuf[MAX_PATH];
1229 WCHAR *nameBit;
1230 DWORD result;
1232 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1233 if (result) {
1235 /* nameBit is always shorter than the original filename */
1236 lstrcpyW(fodInfos->filename,nameBit);
1238 *nameBit = 0x00;
1239 if (fodInfos->initdir == NULL)
1240 MemFree(fodInfos->initdir);
1241 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1242 lstrcpyW(fodInfos->initdir, tmpBuf);
1243 handledPath = TRUE;
1244 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1245 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1247 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1249 } else {
1250 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1254 /* 2. (All platforms) If initdir is not null, then use it */
1255 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1256 (*fodInfos->initdir!=0x00))
1258 /* Work out the proper path as supplied one might be relative */
1259 /* (Here because supplying '.' as dir browses to My Computer) */
1260 if (handledPath==FALSE) {
1261 WCHAR tmpBuf[MAX_PATH];
1262 WCHAR tmpBuf2[MAX_PATH];
1263 WCHAR *nameBit;
1264 DWORD result;
1266 lstrcpyW(tmpBuf, fodInfos->initdir);
1267 if( PathFileExistsW(tmpBuf) ) {
1268 /* initdir does not have to be a directory. If a file is
1269 * specified, the dir part is taken */
1270 if( PathIsDirectoryW(tmpBuf)) {
1271 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1272 lstrcatW(tmpBuf, szwSlash);
1274 lstrcatW(tmpBuf, szwStar);
1276 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1277 if (result) {
1278 *nameBit = 0x00;
1279 MemFree(fodInfos->initdir);
1280 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1281 lstrcpyW(fodInfos->initdir, tmpBuf2);
1282 handledPath = TRUE;
1283 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1286 else if (fodInfos->initdir)
1288 MemFree(fodInfos->initdir);
1289 fodInfos->initdir = NULL;
1290 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1295 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1296 (*fodInfos->initdir==0x00)))
1298 /* 3. All except w2k+: if filename contains a path use it */
1299 if (!win2000plus && fodInfos->filename &&
1300 *fodInfos->filename &&
1301 strpbrkW(fodInfos->filename, szwSlash)) {
1302 WCHAR tmpBuf[MAX_PATH];
1303 WCHAR *nameBit;
1304 DWORD result;
1306 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1307 tmpBuf, &nameBit);
1308 if (result) {
1309 int len;
1311 /* nameBit is always shorter than the original filename */
1312 lstrcpyW(fodInfos->filename, nameBit);
1313 *nameBit = 0x00;
1315 len = lstrlenW(tmpBuf);
1316 MemFree(fodInfos->initdir);
1317 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1318 lstrcpyW(fodInfos->initdir, tmpBuf);
1320 handledPath = TRUE;
1321 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1322 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1324 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1327 /* 4. win98+ and win2000+ if any files of specified filter types in
1328 current directory, use it */
1329 if ( win98plus && handledPath == FALSE &&
1330 fodInfos->filter && *fodInfos->filter) {
1332 BOOL searchMore = TRUE;
1333 LPCWSTR lpstrPos = fodInfos->filter;
1334 WIN32_FIND_DATAW FindFileData;
1335 HANDLE hFind;
1337 while (searchMore)
1339 /* filter is a list... title\0ext\0......\0\0 */
1341 /* Skip the title */
1342 if(! *lpstrPos) break; /* end */
1343 lpstrPos += lstrlenW(lpstrPos) + 1;
1345 /* See if any files exist in the current dir with this extension */
1346 if(! *lpstrPos) break; /* end */
1348 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1350 if (hFind == INVALID_HANDLE_VALUE) {
1351 /* None found - continue search */
1352 lpstrPos += lstrlenW(lpstrPos) + 1;
1354 } else {
1355 searchMore = FALSE;
1357 MemFree(fodInfos->initdir);
1358 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1359 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1361 handledPath = TRUE;
1362 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1363 debugstr_w(lpstrPos));
1364 break;
1369 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1371 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1372 if (handledPath == FALSE && (win2000plus || win98plus)) {
1373 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1375 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1377 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1379 /* last fallback */
1380 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1381 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1382 } else {
1383 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1385 } else {
1386 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1388 handledPath = TRUE;
1389 } else if (handledPath==FALSE) {
1390 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1391 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1392 handledPath = TRUE;
1393 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1396 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1397 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1399 /* Must the open as read only check box be checked ?*/
1400 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1402 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1405 /* Must the open as read only check box be hidden? */
1406 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1408 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1409 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1412 /* Must the help button be hidden? */
1413 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1415 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1416 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1419 /* change Open to Save */
1420 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1422 WCHAR buf[16];
1423 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1424 SetDlgItemTextW(hwnd, IDOK, buf);
1425 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1426 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1428 return 0;
1431 /***********************************************************************
1432 * FILEDLG95_ResizeControls
1434 * WM_INITDIALOG message handler (after hook notification)
1436 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1438 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1440 if (fodInfos->DlgInfos.hwndCustomDlg)
1442 RECT rc;
1443 UINT flags = SWP_NOACTIVATE;
1445 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1446 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1448 /* resize the custom dialog to the parent size */
1449 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1450 GetClientRect(hwnd, &rc);
1451 else
1453 /* our own fake template is zero sized and doesn't have children, so
1454 * there is no need to resize it. Picasa depends on it.
1456 flags |= SWP_NOSIZE;
1457 SetRectEmpty(&rc);
1459 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1460 0, 0, rc.right, rc.bottom, flags);
1462 else
1464 /* Resize the height, if open as read only checkbox ad help button are
1465 * hidden and we are not using a custom template nor a customDialog
1467 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1468 (!(fodInfos->ofnInfos->Flags &
1469 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1471 RECT rectDlg, rectHelp, rectCancel;
1472 GetWindowRect(hwnd, &rectDlg);
1473 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1474 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1475 /* subtract the height of the help button plus the space between the help
1476 * button and the cancel button to the height of the dialog
1478 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1479 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1480 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1483 return TRUE;
1486 /***********************************************************************
1487 * FILEDLG95_FillControls
1489 * WM_INITDIALOG message handler (after hook notification)
1491 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1493 LPITEMIDLIST pidlItemId = NULL;
1495 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1497 TRACE("dir=%s file=%s\n",
1498 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1500 /* Get the initial directory pidl */
1502 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1504 WCHAR path[MAX_PATH];
1506 GetCurrentDirectoryW(MAX_PATH,path);
1507 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1510 /* Initialise shell objects */
1511 FILEDLG95_SHELL_Init(hwnd);
1513 /* Initialize the Look In combo box */
1514 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1516 /* Initialize the filter combo box */
1517 FILEDLG95_FILETYPE_Init(hwnd);
1519 /* Browse to the initial directory */
1520 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1522 /* Free pidlItem memory */
1523 COMDLG32_SHFree(pidlItemId);
1525 return TRUE;
1527 /***********************************************************************
1528 * FILEDLG95_Clean
1530 * Regroups all the cleaning functions of the filedlg
1532 void FILEDLG95_Clean(HWND hwnd)
1534 FILEDLG95_FILETYPE_Clean(hwnd);
1535 FILEDLG95_LOOKIN_Clean(hwnd);
1536 FILEDLG95_SHELL_Clean(hwnd);
1538 /***********************************************************************
1539 * FILEDLG95_OnWMCommand
1541 * WM_COMMAND message handler
1543 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1545 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1546 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1547 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1549 switch(wID)
1551 /* OK button */
1552 case IDOK:
1553 FILEDLG95_OnOpen(hwnd);
1554 break;
1555 /* Cancel button */
1556 case IDCANCEL:
1557 FILEDLG95_Clean(hwnd);
1558 EndDialog(hwnd, FALSE);
1559 break;
1560 /* Filetype combo box */
1561 case IDC_FILETYPE:
1562 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1563 break;
1564 /* LookIn combo box */
1565 case IDC_LOOKIN:
1566 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1567 break;
1569 /* --- toolbar --- */
1570 /* Up folder button */
1571 case FCIDM_TB_UPFOLDER:
1572 FILEDLG95_SHELL_UpFolder(hwnd);
1573 break;
1574 /* New folder button */
1575 case FCIDM_TB_NEWFOLDER:
1576 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1577 break;
1578 /* List option button */
1579 case FCIDM_TB_SMALLICON:
1580 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1581 break;
1582 /* Details option button */
1583 case FCIDM_TB_REPORTVIEW:
1584 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1585 break;
1586 /* Details option button */
1587 case FCIDM_TB_DESKTOP:
1588 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1589 break;
1591 case IDC_FILENAME:
1592 break;
1595 /* Do not use the listview selection anymore */
1596 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1597 return 0;
1600 /***********************************************************************
1601 * FILEDLG95_OnWMGetIShellBrowser
1603 * WM_GETISHELLBROWSER message handler
1605 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1608 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1610 TRACE("\n");
1612 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1614 return TRUE;
1618 /***********************************************************************
1619 * FILEDLG95_SendFileOK
1621 * Sends the CDN_FILEOK notification if required
1623 * RETURNS
1624 * TRUE if the dialog should close
1625 * FALSE if the dialog should not be closed
1627 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1629 /* ask the hook if we can close */
1630 if(IsHooked(fodInfos))
1632 LRESULT retval;
1634 TRACE("---\n");
1635 /* First send CDN_FILEOK as MSDN doc says */
1636 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1637 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1639 TRACE("canceled\n");
1640 return (retval == 0);
1643 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1644 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1645 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1646 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1648 TRACE("canceled\n");
1649 return (retval == 0);
1652 return TRUE;
1655 /***********************************************************************
1656 * FILEDLG95_OnOpenMultipleFiles
1658 * Handles the opening of multiple files.
1660 * FIXME
1661 * check destination buffer size
1663 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1665 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1666 UINT nCount, nSizePath;
1667 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1669 TRACE("\n");
1671 if(fodInfos->unicode)
1673 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1674 ofn->lpstrFile[0] = '\0';
1676 else
1678 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1679 ofn->lpstrFile[0] = '\0';
1682 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1684 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1685 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1686 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1688 LPWSTR lpstrTemp = lpstrFileList;
1690 for ( nCount = 0; nCount < nFileCount; nCount++ )
1692 LPITEMIDLIST pidl;
1694 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1695 if (!pidl)
1697 WCHAR lpstrNotFound[100];
1698 WCHAR lpstrMsg[100];
1699 WCHAR tmp[400];
1700 static const WCHAR nl[] = {'\n',0};
1702 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1703 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1705 lstrcpyW(tmp, lpstrTemp);
1706 lstrcatW(tmp, nl);
1707 lstrcatW(tmp, lpstrNotFound);
1708 lstrcatW(tmp, nl);
1709 lstrcatW(tmp, lpstrMsg);
1711 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1712 return FALSE;
1715 /* move to the next file in the list of files */
1716 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1717 COMDLG32_SHFree(pidl);
1721 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1722 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1724 /* For "oldstyle" dialog the components have to
1725 be separated by blanks (not '\0'!) and short
1726 filenames have to be used! */
1727 FIXME("Components have to be separated by blanks\n");
1729 if(fodInfos->unicode)
1731 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1732 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1733 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1735 else
1737 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1739 if (ofn->lpstrFile != NULL)
1741 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1742 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1743 if (ofn->nMaxFile > nSizePath)
1745 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1746 ofn->lpstrFile + nSizePath,
1747 ofn->nMaxFile - nSizePath, NULL, NULL);
1752 fodInfos->ofnInfos->nFileOffset = nSizePath;
1753 fodInfos->ofnInfos->nFileExtension = 0;
1755 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1756 return FALSE;
1758 /* clean and exit */
1759 FILEDLG95_Clean(hwnd);
1760 return EndDialog(hwnd,TRUE);
1763 /***********************************************************************
1764 * FILEDLG95_OnOpen
1766 * Ok button WM_COMMAND message handler
1768 * If the function succeeds, the return value is nonzero.
1770 #define ONOPEN_BROWSE 1
1771 #define ONOPEN_OPEN 2
1772 #define ONOPEN_SEARCH 3
1773 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1775 WCHAR strMsgTitle[MAX_PATH];
1776 WCHAR strMsgText [MAX_PATH];
1777 if (idCaption)
1778 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1779 else
1780 strMsgTitle[0] = '\0';
1781 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1782 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1785 BOOL FILEDLG95_OnOpen(HWND hwnd)
1787 LPWSTR lpstrFileList;
1788 UINT nFileCount = 0;
1789 UINT sizeUsed = 0;
1790 BOOL ret = TRUE;
1791 WCHAR lpstrPathAndFile[MAX_PATH];
1792 WCHAR lpstrTemp[MAX_PATH];
1793 LPSHELLFOLDER lpsf = NULL;
1794 int nOpenAction;
1795 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1797 TRACE("hwnd=%p\n", hwnd);
1799 /* get the files from the edit control */
1800 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1802 /* try if the user selected a folder in the shellview */
1803 if(nFileCount == 0)
1805 BrowseSelectedFolder(hwnd);
1806 return FALSE;
1809 if(nFileCount > 1)
1811 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1812 goto ret;
1815 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1818 Step 1: Build a complete path name from the current folder and
1819 the filename or path in the edit box.
1820 Special cases:
1821 - the path in the edit box is a root path
1822 (with or without drive letter)
1823 - the edit box contains ".." (or a path with ".." in it)
1826 /* Get the current directory name */
1827 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1829 /* last fallback */
1830 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1832 PathAddBackslashW(lpstrPathAndFile);
1834 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1836 /* if the user specified a fully qualified path use it */
1837 if(PathIsRelativeW(lpstrFileList))
1839 lstrcatW(lpstrPathAndFile, lpstrFileList);
1841 else
1843 /* does the path have a drive letter? */
1844 if (PathGetDriveNumberW(lpstrFileList) == -1)
1845 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1846 else
1847 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1850 /* resolve "." and ".." */
1851 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1852 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1853 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1855 MemFree(lpstrFileList);
1858 Step 2: here we have a cleaned up path
1860 We have to parse the path step by step to see if we have to browse
1861 to a folder if the path points to a directory or the last
1862 valid element is a directory.
1864 valid variables:
1865 lpstrPathAndFile: cleaned up path
1868 if (nFileCount &&
1869 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1870 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1871 nOpenAction = ONOPEN_OPEN;
1872 else
1873 nOpenAction = ONOPEN_BROWSE;
1875 /* don't apply any checks with OFN_NOVALIDATE */
1877 LPWSTR lpszTemp, lpszTemp1;
1878 LPITEMIDLIST pidl = NULL;
1879 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1881 /* check for invalid chars */
1882 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1884 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1885 ret = FALSE;
1886 goto ret;
1889 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1891 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1892 while (lpszTemp1)
1894 LPSHELLFOLDER lpsfChild;
1895 WCHAR lpwstrTemp[MAX_PATH];
1896 DWORD dwEaten, dwAttributes;
1897 LPWSTR p;
1899 lstrcpyW(lpwstrTemp, lpszTemp);
1900 p = PathFindNextComponentW(lpwstrTemp);
1902 if (!p) break; /* end of path */
1904 *p = 0;
1905 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1907 /* There are no wildcards when OFN_NOVALIDATE is set */
1908 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1910 static const WCHAR wszWild[] = { '*', '?', 0 };
1911 /* if the last element is a wildcard do a search */
1912 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1914 nOpenAction = ONOPEN_SEARCH;
1915 break;
1918 lpszTemp1 = lpszTemp;
1920 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1922 /* append a backslash to drive letters */
1923 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1924 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1925 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1927 PathAddBackslashW(lpwstrTemp);
1930 dwAttributes = SFGAO_FOLDER;
1931 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1933 /* the path component is valid, we have a pidl of the next path component */
1934 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1935 if(dwAttributes & SFGAO_FOLDER)
1937 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1939 ERR("bind to failed\n"); /* should not fail */
1940 break;
1942 IShellFolder_Release(lpsf);
1943 lpsf = lpsfChild;
1944 lpsfChild = NULL;
1946 else
1948 TRACE("value\n");
1950 /* end dialog, return value */
1951 nOpenAction = ONOPEN_OPEN;
1952 break;
1954 COMDLG32_SHFree(pidl);
1955 pidl = NULL;
1957 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1959 if(*lpszTemp || /* points to trailing null for last path element */
1960 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1962 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1964 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1965 break;
1968 else
1970 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1971 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1973 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1974 break;
1977 /* change to the current folder */
1978 nOpenAction = ONOPEN_OPEN;
1979 break;
1981 else
1983 nOpenAction = ONOPEN_OPEN;
1984 break;
1987 if(pidl) COMDLG32_SHFree(pidl);
1991 Step 3: here we have a cleaned up and validated path
1993 valid variables:
1994 lpsf: ShellFolder bound to the rightmost valid path component
1995 lpstrPathAndFile: cleaned up path
1996 nOpenAction: action to do
1998 TRACE("end validate sf=%p\n", lpsf);
2000 switch(nOpenAction)
2002 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2003 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2005 int iPos;
2006 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2007 DWORD len;
2009 /* replace the current filter */
2010 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2011 len = lstrlenW(lpszTemp)+1;
2012 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2013 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2015 /* set the filter cb to the extension when possible */
2016 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2017 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2019 /* fall through */
2020 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2021 TRACE("ONOPEN_BROWSE\n");
2023 IPersistFolder2 * ppf2;
2024 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2026 LPITEMIDLIST pidlCurrent;
2027 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2028 IPersistFolder2_Release(ppf2);
2029 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2031 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2033 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2036 else if( nOpenAction == ONOPEN_SEARCH )
2038 if (fodInfos->Shell.FOIShellView)
2039 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2041 COMDLG32_SHFree(pidlCurrent);
2042 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2045 ret = FALSE;
2046 break;
2047 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2048 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2050 WCHAR *ext = NULL;
2052 /* update READONLY check box flag */
2053 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2054 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2055 else
2056 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2058 /* Attach the file extension with file name*/
2059 ext = PathFindExtensionW(lpstrPathAndFile);
2060 if (! *ext)
2062 /* if no extension is specified with file name, then */
2063 /* attach the extension from file filter or default one */
2065 WCHAR *filterExt = NULL;
2066 LPWSTR lpstrFilter = NULL;
2067 static const WCHAR szwDot[] = {'.',0};
2068 int PathLength = lstrlenW(lpstrPathAndFile);
2070 /* Attach the dot*/
2071 lstrcatW(lpstrPathAndFile, szwDot);
2073 /*Get the file extension from file type filter*/
2074 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2075 fodInfos->ofnInfos->nFilterIndex-1);
2077 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2078 filterExt = PathFindExtensionW(lpstrFilter);
2080 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2081 lstrcatW(lpstrPathAndFile, filterExt + 1);
2082 else if ( fodInfos->defext ) /* attach the default file extension*/
2083 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2085 /* In Open dialog: if file does not exist try without extension */
2086 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2087 lpstrPathAndFile[PathLength] = '\0';
2090 if (fodInfos->defext) /* add default extension */
2092 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2093 if (*ext)
2094 ext++;
2095 if (!lstrcmpiW(fodInfos->defext, ext))
2096 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2097 else
2098 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2101 /* In Save dialog: check if the file already exists */
2102 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2103 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2104 && PathFileExistsW(lpstrPathAndFile))
2106 WCHAR lpstrOverwrite[100];
2107 int answer;
2109 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2110 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2111 MB_YESNO | MB_ICONEXCLAMATION);
2112 if (answer == IDNO)
2114 ret = FALSE;
2115 goto ret;
2119 /* In Open dialog: check if it should be created if it doesn't exist */
2120 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2121 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2122 && !PathFileExistsW(lpstrPathAndFile))
2124 WCHAR lpstrCreate[100];
2125 int answer;
2127 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2128 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2129 MB_YESNO | MB_ICONEXCLAMATION);
2130 if (answer == IDNO)
2132 ret = FALSE;
2133 goto ret;
2137 /* Check that the size of the file does not exceed buffer size.
2138 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2139 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2140 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2143 /* fill destination buffer */
2144 if (fodInfos->ofnInfos->lpstrFile)
2146 if(fodInfos->unicode)
2148 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2150 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2151 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2152 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2154 else
2156 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2158 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2159 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2160 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2161 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2165 if(fodInfos->unicode)
2167 LPWSTR lpszTemp;
2169 /* set filename offset */
2170 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2171 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2173 /* set extension offset */
2174 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2175 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2177 else
2179 LPSTR lpszTemp;
2180 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2182 /* set filename offset */
2183 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2184 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2186 /* set extension offset */
2187 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2188 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2191 /* set the lpstrFileTitle */
2192 if(fodInfos->ofnInfos->lpstrFileTitle)
2194 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2195 if(fodInfos->unicode)
2197 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2198 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2200 else
2202 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2203 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2204 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2208 /* copy currently selected filter to lpstrCustomFilter */
2209 if (fodInfos->ofnInfos->lpstrCustomFilter)
2211 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2212 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2213 NULL, 0, NULL, NULL);
2214 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2216 LPSTR s = ofn->lpstrCustomFilter;
2217 s += strlen(ofn->lpstrCustomFilter)+1;
2218 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2219 s, len, NULL, NULL);
2224 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2225 goto ret;
2227 TRACE("close\n");
2228 FILEDLG95_Clean(hwnd);
2229 ret = EndDialog(hwnd, TRUE);
2231 else
2233 WORD size;
2235 size = lstrlenW(lpstrPathAndFile) + 1;
2236 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2237 size += 1;
2238 /* return needed size in first two bytes of lpstrFile */
2239 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2240 FILEDLG95_Clean(hwnd);
2241 ret = EndDialog(hwnd, FALSE);
2242 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2244 goto ret;
2246 break;
2249 ret:
2250 if(lpsf) IShellFolder_Release(lpsf);
2251 return ret;
2254 /***********************************************************************
2255 * FILEDLG95_SHELL_Init
2257 * Initialisation of the shell objects
2259 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2261 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2263 TRACE("\n");
2266 * Initialisation of the FileOpenDialogInfos structure
2269 /* Shell */
2271 /*ShellInfos */
2272 fodInfos->ShellInfos.hwndOwner = hwnd;
2274 /* Disable multi-select if flag not set */
2275 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2277 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2279 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2280 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2282 /* Construct the IShellBrowser interface */
2283 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2285 return NOERROR;
2288 /***********************************************************************
2289 * FILEDLG95_SHELL_ExecuteCommand
2291 * Change the folder option and refresh the view
2292 * If the function succeeds, the return value is nonzero.
2294 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2296 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2298 IContextMenu * pcm;
2299 TRACE("(%p,%p)\n", hwnd, lpVerb);
2301 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2302 SVGIO_BACKGROUND,
2303 &IID_IContextMenu,
2304 (LPVOID*)&pcm)))
2306 CMINVOKECOMMANDINFO ci;
2307 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2308 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2309 ci.lpVerb = lpVerb;
2310 ci.hwnd = hwnd;
2312 IContextMenu_InvokeCommand(pcm, &ci);
2313 IContextMenu_Release(pcm);
2316 return FALSE;
2319 /***********************************************************************
2320 * FILEDLG95_SHELL_UpFolder
2322 * Browse to the specified object
2323 * If the function succeeds, the return value is nonzero.
2325 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2327 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2329 TRACE("\n");
2331 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2332 NULL,
2333 SBSP_PARENT)))
2335 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2336 return TRUE;
2338 return FALSE;
2341 /***********************************************************************
2342 * FILEDLG95_SHELL_BrowseToDesktop
2344 * Browse to the Desktop
2345 * If the function succeeds, the return value is nonzero.
2347 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2349 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2350 LPITEMIDLIST pidl;
2351 HRESULT hres;
2353 TRACE("\n");
2355 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2356 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2357 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2358 COMDLG32_SHFree(pidl);
2359 return SUCCEEDED(hres);
2361 /***********************************************************************
2362 * FILEDLG95_SHELL_Clean
2364 * Cleans the memory used by shell objects
2366 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2368 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2370 TRACE("\n");
2372 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2374 /* clean Shell interfaces */
2375 if (fodInfos->Shell.FOIShellView)
2377 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2378 IShellView_Release(fodInfos->Shell.FOIShellView);
2380 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2381 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2382 if (fodInfos->Shell.FOIDataObject)
2383 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2386 /***********************************************************************
2387 * FILEDLG95_FILETYPE_Init
2389 * Initialisation of the file type combo box
2391 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2393 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2394 int nFilters = 0; /* number of filters */
2395 int nFilterIndexCB;
2397 TRACE("\n");
2399 if(fodInfos->customfilter)
2401 /* customfilter has one entry... title\0ext\0
2402 * Set first entry of combo box item with customfilter
2404 LPWSTR lpstrExt;
2405 LPCWSTR lpstrPos = fodInfos->customfilter;
2407 /* Get the title */
2408 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2410 /* Copy the extensions */
2411 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2412 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2413 lstrcpyW(lpstrExt,lpstrPos);
2415 /* Add the item at the end of the combo */
2416 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2417 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2418 nFilters++;
2420 if(fodInfos->filter)
2422 LPCWSTR lpstrPos = fodInfos->filter;
2424 for(;;)
2426 /* filter is a list... title\0ext\0......\0\0
2427 * Set the combo item text to the title and the item data
2428 * to the ext
2430 LPCWSTR lpstrDisplay;
2431 LPWSTR lpstrExt;
2433 /* Get the title */
2434 if(! *lpstrPos) break; /* end */
2435 lpstrDisplay = lpstrPos;
2436 lpstrPos += lstrlenW(lpstrPos) + 1;
2438 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2440 nFilters++;
2442 /* Copy the extensions */
2443 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2444 lstrcpyW(lpstrExt,lpstrPos);
2445 lpstrPos += lstrlenW(lpstrPos) + 1;
2447 /* Add the item at the end of the combo */
2448 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2450 /* malformed filters are added anyway... */
2451 if (!*lpstrExt) break;
2456 * Set the current filter to the one specified
2457 * in the initialisation structure
2459 if (fodInfos->filter || fodInfos->customfilter)
2461 LPWSTR lpstrFilter;
2463 /* Check to make sure our index isn't out of bounds. */
2464 if ( fodInfos->ofnInfos->nFilterIndex >
2465 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2466 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2468 /* set default filter index */
2469 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2470 fodInfos->ofnInfos->nFilterIndex = 1;
2472 /* calculate index of Combo Box item */
2473 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2474 if (fodInfos->customfilter == NULL)
2475 nFilterIndexCB--;
2477 /* Set the current index selection. */
2478 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2480 /* Get the corresponding text string from the combo box. */
2481 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2482 nFilterIndexCB);
2484 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2485 lpstrFilter = NULL;
2487 if(lpstrFilter)
2489 DWORD len;
2490 CharLowerW(lpstrFilter); /* lowercase */
2491 len = lstrlenW(lpstrFilter)+1;
2492 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2493 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2495 } else
2496 fodInfos->ofnInfos->nFilterIndex = 0;
2497 return S_OK;
2500 /***********************************************************************
2501 * FILEDLG95_FILETYPE_OnCommand
2503 * WM_COMMAND of the file type combo box
2504 * If the function succeeds, the return value is nonzero.
2506 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2508 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2510 switch(wNotifyCode)
2512 case CBN_SELENDOK:
2514 LPWSTR lpstrFilter;
2516 /* Get the current item of the filetype combo box */
2517 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2519 /* set the current filter index */
2520 fodInfos->ofnInfos->nFilterIndex = iItem +
2521 (fodInfos->customfilter == NULL ? 1 : 0);
2523 /* Set the current filter with the current selection */
2524 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2526 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2527 iItem);
2528 if((INT_PTR)lpstrFilter != CB_ERR)
2530 DWORD len;
2531 CharLowerW(lpstrFilter); /* lowercase */
2532 len = lstrlenW(lpstrFilter)+1;
2533 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2534 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2535 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2538 /* Refresh the actual view to display the included items*/
2539 if (fodInfos->Shell.FOIShellView)
2540 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2543 return FALSE;
2545 /***********************************************************************
2546 * FILEDLG95_FILETYPE_SearchExt
2548 * searches for an extension in the filetype box
2550 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2552 int i, iCount = CBGetCount(hwnd);
2554 TRACE("%s\n", debugstr_w(lpstrExt));
2556 if(iCount != CB_ERR)
2558 for(i=0;i<iCount;i++)
2560 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2561 return i;
2564 return -1;
2567 /***********************************************************************
2568 * FILEDLG95_FILETYPE_Clean
2570 * Clean the memory used by the filetype combo box
2572 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2574 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2575 int iPos;
2576 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2578 TRACE("\n");
2580 /* Delete each string of the combo and their associated data */
2581 if(iCount != CB_ERR)
2583 for(iPos = iCount-1;iPos>=0;iPos--)
2585 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2586 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2589 /* Current filter */
2590 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2594 /***********************************************************************
2595 * FILEDLG95_LOOKIN_Init
2597 * Initialisation of the look in combo box
2600 /* Small helper function, to determine if the unixfs shell extension is rooted
2601 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2603 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2604 HKEY hKey;
2605 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2606 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2607 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2608 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2609 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2610 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2611 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2613 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2614 return FALSE;
2616 RegCloseKey(hKey);
2617 return TRUE;
2620 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2622 IShellFolder *psfRoot, *psfDrives;
2623 IEnumIDList *lpeRoot, *lpeDrives;
2624 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2626 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2628 TRACE("\n");
2630 liInfos->iMaxIndentation = 0;
2632 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2634 /* set item height for both text field and listbox */
2635 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2636 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2638 /* Turn on the extended UI for the combo box like Windows does */
2639 CBSetExtendedUI(hwndCombo, TRUE);
2641 /* Initialise data of Desktop folder */
2642 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2643 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2644 COMDLG32_SHFree(pidlTmp);
2646 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2648 SHGetDesktopFolder(&psfRoot);
2650 if (psfRoot)
2652 /* enumerate the contents of the desktop */
2653 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2655 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2657 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2659 /* If the unixfs extension is rooted, we don't expand the drives by default */
2660 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2662 /* special handling for CSIDL_DRIVES */
2663 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2665 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2667 /* enumerate the drives */
2668 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2670 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2672 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2673 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2674 COMDLG32_SHFree(pidlAbsTmp);
2675 COMDLG32_SHFree(pidlTmp1);
2677 IEnumIDList_Release(lpeDrives);
2679 IShellFolder_Release(psfDrives);
2684 COMDLG32_SHFree(pidlTmp);
2686 IEnumIDList_Release(lpeRoot);
2688 IShellFolder_Release(psfRoot);
2691 COMDLG32_SHFree(pidlDrives);
2694 /***********************************************************************
2695 * FILEDLG95_LOOKIN_DrawItem
2697 * WM_DRAWITEM message handler
2699 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2701 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2702 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2703 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2704 RECT rectText;
2705 RECT rectIcon;
2706 SHFILEINFOW sfi;
2707 HIMAGELIST ilItemImage;
2708 int iIndentation;
2709 TEXTMETRICW tm;
2710 LPSFOLDER tmpFolder;
2713 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2715 TRACE("\n");
2717 if(pDIStruct->itemID == -1)
2718 return 0;
2720 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2721 pDIStruct->itemID)))
2722 return 0;
2725 if(pDIStruct->itemID == liInfos->uSelectedItem)
2727 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2729 &sfi,
2730 sizeof (sfi),
2731 SHGFI_PIDL | SHGFI_SMALLICON |
2732 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2733 SHGFI_DISPLAYNAME );
2735 else
2737 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2739 &sfi,
2740 sizeof (sfi),
2741 SHGFI_PIDL | SHGFI_SMALLICON |
2742 SHGFI_SYSICONINDEX |
2743 SHGFI_DISPLAYNAME);
2746 /* Is this item selected ? */
2747 if(pDIStruct->itemState & ODS_SELECTED)
2749 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2750 SetBkColor(pDIStruct->hDC,crHighLight);
2751 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2753 else
2755 SetTextColor(pDIStruct->hDC,crText);
2756 SetBkColor(pDIStruct->hDC,crWin);
2757 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2760 /* Do not indent item if drawing in the edit of the combo */
2761 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2763 iIndentation = 0;
2764 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2766 &sfi,
2767 sizeof (sfi),
2768 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2769 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2772 else
2774 iIndentation = tmpFolder->m_iIndent;
2776 /* Draw text and icon */
2778 /* Initialise the icon display area */
2779 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2780 rectIcon.top = pDIStruct->rcItem.top;
2781 rectIcon.right = rectIcon.left + ICONWIDTH;
2782 rectIcon.bottom = pDIStruct->rcItem.bottom;
2784 /* Initialise the text display area */
2785 GetTextMetricsW(pDIStruct->hDC, &tm);
2786 rectText.left = rectIcon.right;
2787 rectText.top =
2788 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2789 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2790 rectText.bottom =
2791 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2793 /* Draw the icon from the image list */
2794 ImageList_Draw(ilItemImage,
2795 sfi.iIcon,
2796 pDIStruct->hDC,
2797 rectIcon.left,
2798 rectIcon.top,
2799 ILD_TRANSPARENT );
2801 /* Draw the associated text */
2802 if(sfi.szDisplayName)
2803 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2806 return NOERROR;
2809 /***********************************************************************
2810 * FILEDLG95_LOOKIN_OnCommand
2812 * LookIn combo box WM_COMMAND message handler
2813 * If the function succeeds, the return value is nonzero.
2815 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2817 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2819 TRACE("%p\n", fodInfos);
2821 switch(wNotifyCode)
2823 case CBN_SELENDOK:
2825 LPSFOLDER tmpFolder;
2826 int iItem;
2828 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2830 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2831 iItem)))
2832 return FALSE;
2835 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2836 tmpFolder->pidlItem,
2837 SBSP_ABSOLUTE)))
2839 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2840 return TRUE;
2842 break;
2846 return FALSE;
2849 /***********************************************************************
2850 * FILEDLG95_LOOKIN_AddItem
2852 * Adds an absolute pidl item to the lookin combo box
2853 * returns the index of the inserted item
2855 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2857 LPITEMIDLIST pidlNext;
2858 SHFILEINFOW sfi;
2859 SFOLDER *tmpFolder;
2860 LookInInfos *liInfos;
2862 TRACE("%08x\n", iInsertId);
2864 if(!pidl)
2865 return -1;
2867 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2868 return -1;
2870 tmpFolder = MemAlloc(sizeof(SFOLDER));
2871 tmpFolder->m_iIndent = 0;
2873 /* Calculate the indentation of the item in the lookin*/
2874 pidlNext = pidl;
2875 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2877 tmpFolder->m_iIndent++;
2880 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2882 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2883 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2885 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2886 SHGetFileInfoW((LPCWSTR)pidl,
2888 &sfi,
2889 sizeof(sfi),
2890 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2891 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2893 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2895 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2897 int iItemID;
2899 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2901 /* Add the item at the end of the list */
2902 if(iInsertId < 0)
2904 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2906 /* Insert the item at the iInsertId position*/
2907 else
2909 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2912 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2913 return iItemID;
2916 COMDLG32_SHFree( tmpFolder->pidlItem );
2917 MemFree( tmpFolder );
2918 return -1;
2922 /***********************************************************************
2923 * FILEDLG95_LOOKIN_InsertItemAfterParent
2925 * Insert an item below its parent
2927 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2930 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2931 int iParentPos;
2933 TRACE("\n");
2935 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2937 if(iParentPos < 0)
2939 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2942 /* Free pidlParent memory */
2943 COMDLG32_SHFree((LPVOID)pidlParent);
2945 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2948 /***********************************************************************
2949 * FILEDLG95_LOOKIN_SelectItem
2951 * Adds an absolute pidl item to the lookin combo box
2952 * returns the index of the inserted item
2954 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2956 int iItemPos;
2957 LookInInfos *liInfos;
2959 TRACE("\n");
2961 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2963 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2965 if(iItemPos < 0)
2967 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2968 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2971 else
2973 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2974 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2976 int iRemovedItem;
2978 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2979 break;
2980 if(iRemovedItem < iItemPos)
2981 iItemPos--;
2985 CBSetCurSel(hwnd,iItemPos);
2986 liInfos->uSelectedItem = iItemPos;
2988 return 0;
2992 /***********************************************************************
2993 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2995 * Remove the item with an expansion level over iExpansionLevel
2997 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2999 int iItemPos;
3001 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
3003 TRACE("\n");
3005 if(liInfos->iMaxIndentation <= 2)
3006 return -1;
3008 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
3010 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
3011 COMDLG32_SHFree(tmpFolder->pidlItem);
3012 MemFree(tmpFolder);
3013 CBDeleteString(hwnd,iItemPos);
3014 liInfos->iMaxIndentation--;
3016 return iItemPos;
3019 return -1;
3022 /***********************************************************************
3023 * FILEDLG95_LOOKIN_SearchItem
3025 * Search for pidl in the lookin combo box
3026 * returns the index of the found item
3028 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3030 int i = 0;
3031 int iCount = CBGetCount(hwnd);
3033 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3035 if (iCount != CB_ERR)
3037 for(;i<iCount;i++)
3039 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3041 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3042 return i;
3043 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3044 return i;
3048 return -1;
3051 /***********************************************************************
3052 * FILEDLG95_LOOKIN_Clean
3054 * Clean the memory used by the lookin combo box
3056 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3058 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3059 int iPos;
3060 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3062 TRACE("\n");
3064 /* Delete each string of the combo and their associated data */
3065 if (iCount != CB_ERR)
3067 for(iPos = iCount-1;iPos>=0;iPos--)
3069 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3070 COMDLG32_SHFree(tmpFolder->pidlItem);
3071 MemFree(tmpFolder);
3072 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3076 /* LookInInfos structure */
3077 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3080 /***********************************************************************
3081 * FILEDLG95_FILENAME_FillFromSelection
3083 * fills the edit box from the cached DataObject
3085 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3087 FileOpenDlgInfos *fodInfos;
3088 LPITEMIDLIST pidl;
3089 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3090 WCHAR lpstrTemp[MAX_PATH];
3091 LPWSTR lpstrAllFile, lpstrCurrFile;
3093 TRACE("\n");
3094 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3096 /* Count how many files we have */
3097 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3099 /* calculate the string length, count files */
3100 if (nFileSelected >= 1)
3102 nLength += 3; /* first and last quotes, trailing \0 */
3103 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3105 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3107 if (pidl)
3109 /* get the total length of the selected file names */
3110 lpstrTemp[0] = '\0';
3111 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3113 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3115 nLength += lstrlenW( lpstrTemp ) + 3;
3116 nFiles++;
3118 COMDLG32_SHFree( pidl );
3123 /* allocate the buffer */
3124 if (nFiles <= 1) nLength = MAX_PATH;
3125 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3127 /* Generate the string for the edit control */
3128 if(nFiles >= 1)
3130 lpstrCurrFile = lpstrAllFile;
3131 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3133 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3135 if (pidl)
3137 /* get the file name */
3138 lpstrTemp[0] = '\0';
3139 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3141 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3143 if ( nFiles > 1)
3145 *lpstrCurrFile++ = '\"';
3146 lstrcpyW( lpstrCurrFile, lpstrTemp );
3147 lpstrCurrFile += lstrlenW( lpstrTemp );
3148 *lpstrCurrFile++ = '\"';
3149 *lpstrCurrFile++ = ' ';
3150 *lpstrCurrFile = 0;
3152 else
3154 lstrcpyW( lpstrAllFile, lpstrTemp );
3157 COMDLG32_SHFree( (LPVOID) pidl );
3160 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3162 /* Select the file name like Windows does */
3163 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3165 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3169 /* copied from shell32 to avoid linking to it
3170 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3171 * is dependent on whether emulated OS is unicode or not.
3173 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3175 switch (src->uType)
3177 case STRRET_WSTR:
3178 lstrcpynW(dest, src->u.pOleStr, len);
3179 COMDLG32_SHFree(src->u.pOleStr);
3180 break;
3182 case STRRET_CSTR:
3183 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3184 dest[len-1] = 0;
3185 break;
3187 case STRRET_OFFSET:
3188 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3189 dest[len-1] = 0;
3190 break;
3192 default:
3193 FIXME("unknown type %x!\n", src->uType);
3194 if (len) *dest = '\0';
3195 return E_FAIL;
3197 return S_OK;
3200 /***********************************************************************
3201 * FILEDLG95_FILENAME_GetFileNames
3203 * Copies the filenames to a delimited string list.
3204 * The delimiter is specified by the parameter 'separator',
3205 * usually either a space or a nul
3207 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3209 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3210 UINT nStrCharCount = 0; /* index in src buffer */
3211 UINT nFileIndex = 0; /* index in dest buffer */
3212 UINT nFileCount = 0; /* number of files */
3213 UINT nStrLen = 0; /* length of string in edit control */
3214 LPWSTR lpstrEdit; /* buffer for string from edit control */
3216 TRACE("\n");
3218 /* get the filenames from the edit control */
3219 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3220 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3221 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3223 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3225 /* we might get single filename without any '"',
3226 * so we need nStrLen + terminating \0 + end-of-list \0 */
3227 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3228 *sizeUsed = 0;
3230 /* build delimited file list from filenames */
3231 while ( nStrCharCount <= nStrLen )
3233 if ( lpstrEdit[nStrCharCount]=='"' )
3235 nStrCharCount++;
3236 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3238 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3239 nStrCharCount++;
3241 (*lpstrFileList)[nFileIndex++] = separator;
3242 nFileCount++;
3244 nStrCharCount++;
3247 /* single, unquoted string */
3248 if ((nStrLen > 0) && (nFileIndex == 0) )
3250 lstrcpyW(*lpstrFileList, lpstrEdit);
3251 nFileIndex = lstrlenW(lpstrEdit) + 1;
3252 nFileCount = 1;
3255 /* trailing \0 */
3256 if (nFileIndex && separator) nFileIndex--; /* remove trailing separator */
3257 (*lpstrFileList)[nFileIndex++] = '\0';
3259 *sizeUsed = nFileIndex;
3260 MemFree(lpstrEdit);
3261 return nFileCount;
3264 #define SETDefFormatEtc(fe,cf,med) \
3266 (fe).cfFormat = cf;\
3267 (fe).dwAspect = DVASPECT_CONTENT; \
3268 (fe).ptd =NULL;\
3269 (fe).tymed = med;\
3270 (fe).lindex = -1;\
3274 * DATAOBJECT Helper functions
3277 /***********************************************************************
3278 * COMCTL32_ReleaseStgMedium
3280 * like ReleaseStgMedium from ole32
3282 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3284 if(medium.pUnkForRelease)
3286 IUnknown_Release(medium.pUnkForRelease);
3288 else
3290 GlobalUnlock(medium.u.hGlobal);
3291 GlobalFree(medium.u.hGlobal);
3295 /***********************************************************************
3296 * GetPidlFromDataObject
3298 * Return pidl(s) by number from the cached DataObject
3300 * nPidlIndex=0 gets the fully qualified root path
3302 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3305 STGMEDIUM medium;
3306 FORMATETC formatetc;
3307 LPITEMIDLIST pidl = NULL;
3309 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3311 if (!doSelected)
3312 return NULL;
3314 /* Set the FORMATETC structure*/
3315 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3317 /* Get the pidls from IDataObject */
3318 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3320 LPIDA cida = GlobalLock(medium.u.hGlobal);
3321 if(nPidlIndex <= cida->cidl)
3323 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3325 COMCTL32_ReleaseStgMedium(medium);
3327 return pidl;
3330 /***********************************************************************
3331 * GetNumSelected
3333 * Return the number of selected items in the DataObject.
3336 UINT GetNumSelected( IDataObject *doSelected )
3338 UINT retVal = 0;
3339 STGMEDIUM medium;
3340 FORMATETC formatetc;
3342 TRACE("sv=%p\n", doSelected);
3344 if (!doSelected) return 0;
3346 /* Set the FORMATETC structure*/
3347 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3349 /* Get the pidls from IDataObject */
3350 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3352 LPIDA cida = GlobalLock(medium.u.hGlobal);
3353 retVal = cida->cidl;
3354 COMCTL32_ReleaseStgMedium(medium);
3355 return retVal;
3357 return 0;
3361 * TOOLS
3364 /***********************************************************************
3365 * GetName
3367 * Get the pidl's display name (relative to folder) and
3368 * put it in lpstrFileName.
3370 * Return NOERROR on success,
3371 * E_FAIL otherwise
3374 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3376 STRRET str;
3377 HRESULT hRes;
3379 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3381 if(!lpsf)
3383 SHGetDesktopFolder(&lpsf);
3384 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3385 IShellFolder_Release(lpsf);
3386 return hRes;
3389 /* Get the display name of the pidl relative to the folder */
3390 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3392 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3394 return E_FAIL;
3397 /***********************************************************************
3398 * GetShellFolderFromPidl
3400 * pidlRel is the item pidl relative
3401 * Return the IShellFolder of the absolute pidl
3403 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3405 IShellFolder *psf = NULL,*psfParent;
3407 TRACE("%p\n", pidlAbs);
3409 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3411 psf = psfParent;
3412 if(pidlAbs && pidlAbs->mkid.cb)
3414 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3416 IShellFolder_Release(psfParent);
3417 return psf;
3420 /* return the desktop */
3421 return psfParent;
3423 return NULL;
3426 /***********************************************************************
3427 * GetParentPidl
3429 * Return the LPITEMIDLIST to the parent of the pidl in the list
3431 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3433 LPITEMIDLIST pidlParent;
3435 TRACE("%p\n", pidl);
3437 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3438 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3440 return pidlParent;
3443 /***********************************************************************
3444 * GetPidlFromName
3446 * returns the pidl of the file name relative to folder
3447 * NULL if an error occurred
3449 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3451 LPITEMIDLIST pidl = NULL;
3452 ULONG ulEaten;
3454 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3456 if(!lpcstrFileName) return NULL;
3457 if(!*lpcstrFileName) return NULL;
3459 if(!lpsf)
3461 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3462 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3463 IShellFolder_Release(lpsf);
3466 else
3468 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3470 return pidl;
3475 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3477 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3478 HRESULT ret;
3480 TRACE("%p, %p\n", psf, pidl);
3482 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3484 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3485 /* see documentation shell 4.1*/
3486 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3489 /***********************************************************************
3490 * BrowseSelectedFolder
3492 static BOOL BrowseSelectedFolder(HWND hwnd)
3494 BOOL bBrowseSelFolder = FALSE;
3495 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3497 TRACE("\n");
3499 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3501 LPITEMIDLIST pidlSelection;
3503 /* get the file selected */
3504 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3505 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3507 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3508 pidlSelection, SBSP_RELATIVE ) ) )
3510 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3511 ' ','n','o','t',' ','e','x','i','s','t',0};
3512 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3514 bBrowseSelFolder = TRUE;
3515 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3517 COMDLG32_SHFree( pidlSelection );
3520 return bBrowseSelFolder;
3524 * Memory allocation methods */
3525 static void *MemAlloc(UINT size)
3527 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3530 static void MemFree(void *mem)
3532 HeapFree(GetProcessHeap(),0,mem);
3536 * Old-style (win3.1) dialogs */
3538 /***********************************************************************
3539 * FD32_GetTemplate [internal]
3541 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3542 * by a 32 bits application
3545 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3547 LPOPENFILENAMEW ofnW = lfs->ofnW;
3548 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3549 HANDLE hDlgTmpl;
3551 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3553 if (!(lfs->template = LockResource( ofnW->hInstance )))
3555 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3556 return FALSE;
3559 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3561 HRSRC hResInfo;
3562 if (priv->ofnA)
3563 hResInfo = FindResourceA(priv->ofnA->hInstance,
3564 priv->ofnA->lpTemplateName,
3565 (LPSTR)RT_DIALOG);
3566 else
3567 hResInfo = FindResourceW(ofnW->hInstance,
3568 ofnW->lpTemplateName,
3569 (LPWSTR)RT_DIALOG);
3570 if (!hResInfo)
3572 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3573 return FALSE;
3575 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3576 hResInfo)) ||
3577 !(lfs->template = LockResource(hDlgTmpl)))
3579 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3580 return FALSE;
3582 } else { /* get it from internal Wine resource */
3583 HRSRC hResInfo;
3584 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3585 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3587 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3588 return FALSE;
3590 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3591 !(lfs->template = LockResource( hDlgTmpl )))
3593 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3594 return FALSE;
3597 return TRUE;
3601 /************************************************************************
3602 * FD32_Init [internal]
3603 * called from the common 16/32 code to initialize 32 bit data
3605 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3607 BOOL IsUnicode = (BOOL) data;
3608 PFD32_PRIVATE priv;
3610 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3611 lfs->private1632 = priv;
3612 if (NULL == lfs->private1632) return FALSE;
3613 if (IsUnicode)
3615 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3616 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3617 if (lfs->ofnW->lpfnHook)
3618 lfs->hook = TRUE;
3620 else
3622 priv->ofnA = (LPOPENFILENAMEA) lParam;
3623 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3624 if (priv->ofnA->lpfnHook)
3625 lfs->hook = TRUE;
3626 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3627 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3630 if (! FD32_GetTemplate(lfs)) return FALSE;
3632 return TRUE;
3635 /***********************************************************************
3636 * FD32_CallWindowProc [internal]
3638 * called from the common 16/32 code to call the appropriate hook
3640 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3641 LPARAM lParam)
3643 BOOL ret;
3644 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3646 if (priv->ofnA)
3648 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3649 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3650 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3651 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3652 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3653 return ret;
3656 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3657 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3658 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3659 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3660 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3661 return ret;
3664 /***********************************************************************
3665 * FD32_UpdateResult [internal]
3666 * update the real client structures if any
3668 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3670 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3671 LPOPENFILENAMEW ofnW = lfs->ofnW;
3673 if (priv->ofnA)
3675 LPSTR lpszTemp;
3676 if (ofnW->nMaxFile &&
3677 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3678 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3679 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3681 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3682 /* set filename offset */
3683 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3684 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3686 /* set extension offset */
3687 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3688 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3692 /***********************************************************************
3693 * FD32_UpdateFileTitle [internal]
3694 * update the real client structures if any
3696 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3698 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3699 LPOPENFILENAMEW ofnW = lfs->ofnW;
3701 if (priv->ofnA)
3703 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3704 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3705 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3710 /***********************************************************************
3711 * FD32_SendLbGetCurSel [internal]
3712 * retrieve selected listbox item
3714 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3716 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3720 /************************************************************************
3721 * FD32_Destroy [internal]
3722 * called from the common 16/32 code to cleanup 32 bit data
3724 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3726 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3728 /* if ofnW has been allocated, have to free everything in it */
3729 if (NULL != priv && NULL != priv->ofnA)
3731 FD31_FreeOfnW(lfs->ofnW);
3732 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3736 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3738 callbacks->Init = FD32_Init;
3739 callbacks->CWP = FD32_CallWindowProc;
3740 callbacks->UpdateResult = FD32_UpdateResult;
3741 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3742 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3743 callbacks->Destroy = FD32_Destroy;
3746 /***********************************************************************
3747 * FD32_WMMeasureItem [internal]
3749 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3751 LPMEASUREITEMSTRUCT lpmeasure;
3753 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3754 lpmeasure->itemHeight = FD31_GetFldrHeight();
3755 return TRUE;
3759 /***********************************************************************
3760 * FileOpenDlgProc [internal]
3761 * Used for open and save, in fact.
3763 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3764 WPARAM wParam, LPARAM lParam)
3766 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3768 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3769 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3771 INT_PTR lRet;
3772 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3773 if (lRet)
3774 return lRet; /* else continue message processing */
3776 switch (wMsg)
3778 case WM_INITDIALOG:
3779 return FD31_WMInitDialog(hWnd, wParam, lParam);
3781 case WM_MEASUREITEM:
3782 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3784 case WM_DRAWITEM:
3785 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3787 case WM_COMMAND:
3788 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3789 #if 0
3790 case WM_CTLCOLOR:
3791 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3792 switch (HIWORD(lParam))
3794 case CTLCOLOR_BTN:
3795 SetTextColor((HDC16)wParam, 0x00000000);
3796 return hGRAYBrush;
3797 case CTLCOLOR_STATIC:
3798 SetTextColor((HDC16)wParam, 0x00000000);
3799 return hGRAYBrush;
3801 break;
3802 #endif
3804 return FALSE;
3808 /***********************************************************************
3809 * GetFileName31A [internal]
3811 * Creates a win31 style dialog box for the user to select a file to open/save.
3813 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3814 UINT dlgType /* type dialogue : open/save */
3817 HINSTANCE hInst;
3818 BOOL bRet = FALSE;
3819 PFD31_DATA lfs;
3820 FD31_CALLBACKS callbacks;
3822 if (!lpofn || !FD31_Init()) return FALSE;
3824 TRACE("ofn flags %08x\n", lpofn->Flags);
3825 FD32_SetupCallbacks(&callbacks);
3826 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3827 if (lfs)
3829 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3830 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3831 FD32_FileOpenDlgProc, (LPARAM)lfs);
3832 FD31_DestroyPrivate(lfs);
3835 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3836 return bRet;
3839 /***********************************************************************
3840 * GetFileName31W [internal]
3842 * Creates a win31 style dialog box for the user to select a file to open/save
3844 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3845 UINT dlgType /* type dialogue : open/save */
3848 HINSTANCE hInst;
3849 BOOL bRet = FALSE;
3850 PFD31_DATA lfs;
3851 FD31_CALLBACKS callbacks;
3853 if (!lpofn || !FD31_Init()) return FALSE;
3855 FD32_SetupCallbacks(&callbacks);
3856 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3857 if (lfs)
3859 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3860 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3861 FD32_FileOpenDlgProc, (LPARAM)lfs);
3862 FD31_DestroyPrivate(lfs);
3865 TRACE("file %s, file offset %d, ext offset %d\n",
3866 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3867 return bRet;
3870 /* ------------------ APIs ---------------------- */
3872 /***********************************************************************
3873 * GetOpenFileNameA (COMDLG32.@)
3875 * Creates a dialog box for the user to select a file to open.
3877 * RETURNS
3878 * TRUE on success: user enters a valid file
3879 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3882 BOOL WINAPI GetOpenFileNameA(
3883 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3885 BOOL win16look = FALSE;
3887 TRACE("flags %08x\n", ofn->Flags);
3889 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3890 if (ofn->Flags & OFN_FILEMUSTEXIST)
3891 ofn->Flags |= OFN_PATHMUSTEXIST;
3893 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3894 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3896 if (win16look)
3897 return GetFileName31A(ofn, OPEN_DIALOG);
3898 else
3899 return GetFileDialog95A(ofn, OPEN_DIALOG);
3902 /***********************************************************************
3903 * GetOpenFileNameW (COMDLG32.@)
3905 * Creates a dialog box for the user to select a file to open.
3907 * RETURNS
3908 * TRUE on success: user enters a valid file
3909 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3912 BOOL WINAPI GetOpenFileNameW(
3913 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3915 BOOL win16look = FALSE;
3917 TRACE("flags %08x\n", ofn->Flags);
3919 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3920 if (ofn->Flags & OFN_FILEMUSTEXIST)
3921 ofn->Flags |= OFN_PATHMUSTEXIST;
3923 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3924 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3926 if (win16look)
3927 return GetFileName31W(ofn, OPEN_DIALOG);
3928 else
3929 return GetFileDialog95W(ofn, OPEN_DIALOG);
3933 /***********************************************************************
3934 * GetSaveFileNameA (COMDLG32.@)
3936 * Creates a dialog box for the user to select a file to save.
3938 * RETURNS
3939 * TRUE on success: user enters a valid file
3940 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3943 BOOL WINAPI GetSaveFileNameA(
3944 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3946 BOOL win16look = FALSE;
3948 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3949 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3951 if (win16look)
3952 return GetFileName31A(ofn, SAVE_DIALOG);
3953 else
3954 return GetFileDialog95A(ofn, SAVE_DIALOG);
3957 /***********************************************************************
3958 * GetSaveFileNameW (COMDLG32.@)
3960 * Creates a dialog box for the user to select a file to save.
3962 * RETURNS
3963 * TRUE on success: user enters a valid file
3964 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3967 BOOL WINAPI GetSaveFileNameW(
3968 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3970 BOOL win16look = FALSE;
3972 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3973 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3975 if (win16look)
3976 return GetFileName31W(ofn, SAVE_DIALOG);
3977 else
3978 return GetFileDialog95W(ofn, SAVE_DIALOG);
3981 /***********************************************************************
3982 * GetFileTitleA (COMDLG32.@)
3984 * See GetFileTitleW.
3986 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3988 int ret;
3989 UNICODE_STRING strWFile;
3990 LPWSTR lpWTitle;
3992 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3993 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3994 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3995 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3996 RtlFreeUnicodeString( &strWFile );
3997 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3998 return ret;
4002 /***********************************************************************
4003 * GetFileTitleW (COMDLG32.@)
4005 * Get the name of a file.
4007 * PARAMS
4008 * lpFile [I] name and location of file
4009 * lpTitle [O] returned file name
4010 * cbBuf [I] buffer size of lpTitle
4012 * RETURNS
4013 * Success: zero
4014 * Failure: negative number.
4016 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
4018 int i, len;
4019 static const WCHAR brkpoint[] = {'*','[',']',0};
4020 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4022 if(lpFile == NULL || lpTitle == NULL)
4023 return -1;
4025 len = lstrlenW(lpFile);
4027 if (len == 0)
4028 return -1;
4030 if(strpbrkW(lpFile, brkpoint))
4031 return -1;
4033 len--;
4035 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4036 return -1;
4038 for(i = len; i >= 0; i--)
4040 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4042 i++;
4043 break;
4047 if(i == -1)
4048 i++;
4050 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4052 len = lstrlenW(lpFile+i)+1;
4053 if(cbBuf < len)
4054 return len;
4056 lstrcpyW(lpTitle, &lpFile[i]);
4057 return 0;