push 6fe5edf8439c19d3885814583531c2f2b1495177
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blobf64fca71c0747d6487fe843eb8ffb3e1871ff1d2
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);
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 result)
863 UINT len, total;
864 WCHAR *p, *buffer;
865 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
867 TRACE("CDM_GETFILEPATH:\n");
869 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
870 return -1;
872 /* get path and filenames */
873 len = SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0 );
874 buffer = HeapAlloc( GetProcessHeap(), 0, (len + 2 + MAX_PATH) * sizeof(WCHAR) );
875 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, buffer );
876 if (len)
878 p = buffer + strlenW(buffer);
879 *p++ = '\\';
880 SendMessageW( fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, len + 1, (LPARAM)p );
882 if (fodInfos->unicode)
884 total = strlenW( buffer) + 1;
885 if (result) lstrcpynW( result, buffer, size );
886 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_w(result));
888 else
890 total = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
891 if (total <= size) WideCharToMultiByte( CP_ACP, 0, buffer, -1, result, size, NULL, NULL );
892 TRACE( "CDM_GETFILEPATH: returning %u %s\n", total, debugstr_a(result));
894 HeapFree( GetProcessHeap(), 0, buffer );
895 return total;
898 /***********************************************************************
899 * FILEDLG95_HandleCustomDialogMessages
901 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
903 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
905 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
906 WCHAR lpstrPath[MAX_PATH];
907 INT_PTR retval;
909 if(!fodInfos) return FALSE;
911 switch(uMsg)
913 case CDM_GETFILEPATH:
914 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
915 break;
917 case CDM_GETFOLDERPATH:
918 TRACE("CDM_GETFOLDERPATH:\n");
919 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
920 if (lParam)
922 if (fodInfos->unicode)
923 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
924 else
925 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
926 (LPSTR)lParam, (int)wParam, NULL, NULL);
928 retval = lstrlenW(lpstrPath);
929 break;
931 case CDM_GETSPEC:
932 TRACE("CDM_GETSPEC:\n");
933 retval = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0) + 1;
934 if (lParam)
936 if (fodInfos->unicode)
937 SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
938 else
939 SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXT, wParam, lParam);
941 break;
943 case CDM_SETCONTROLTEXT:
944 TRACE("CDM_SETCONTROLTEXT:\n");
945 if ( lParam )
947 if( fodInfos->unicode )
948 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
949 else
950 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
952 retval = TRUE;
953 break;
955 case CDM_HIDECONTROL:
956 /* MSDN states that it should fail for not OFN_EXPLORER case */
957 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
959 HWND control = GetDlgItem( hwnd, wParam );
960 if (control) ShowWindow( control, SW_HIDE );
961 retval = TRUE;
963 else retval = FALSE;
964 break;
966 default:
967 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
968 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
969 return FALSE;
971 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
972 return TRUE;
975 /***********************************************************************
976 * FileOpenDlgProc95
978 * File open dialog procedure
980 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
982 #if 0
983 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
984 #endif
986 switch(uMsg)
988 case WM_INITDIALOG:
990 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
992 /* Adds the FileOpenDlgInfos in the property list of the dialog
993 so it will be easily accessible through a GetPropA(...) */
994 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
996 FILEDLG95_InitControls(hwnd);
998 fodInfos->DlgInfos.hwndCustomDlg =
999 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1001 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1002 FILEDLG95_FillControls(hwnd, wParam, lParam);
1004 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1005 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1006 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1007 return 0;
1009 case WM_COMMAND:
1010 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1011 case WM_DRAWITEM:
1013 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1015 case IDC_LOOKIN:
1016 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1017 return TRUE;
1020 return FALSE;
1022 case WM_GETISHELLBROWSER:
1023 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1025 case WM_DESTROY:
1026 RemovePropA(hwnd, FileOpenDlgInfosStr);
1027 return FALSE;
1029 case WM_NOTIFY:
1031 LPNMHDR lpnmh = (LPNMHDR)lParam;
1032 UINT stringId = -1;
1034 /* set up the button tooltips strings */
1035 if(TTN_GETDISPINFOA == lpnmh->code )
1037 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1038 switch(lpnmh->idFrom )
1040 /* Up folder button */
1041 case FCIDM_TB_UPFOLDER:
1042 stringId = IDS_UPFOLDER;
1043 break;
1044 /* New folder button */
1045 case FCIDM_TB_NEWFOLDER:
1046 stringId = IDS_NEWFOLDER;
1047 break;
1048 /* List option button */
1049 case FCIDM_TB_SMALLICON:
1050 stringId = IDS_LISTVIEW;
1051 break;
1052 /* Details option button */
1053 case FCIDM_TB_REPORTVIEW:
1054 stringId = IDS_REPORTVIEW;
1055 break;
1056 /* Desktop button */
1057 case FCIDM_TB_DESKTOP:
1058 stringId = IDS_TODESKTOP;
1059 break;
1060 default:
1061 stringId = 0;
1063 lpdi->hinst = COMDLG32_hInstance;
1064 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1066 return FALSE;
1068 default :
1069 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1070 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1071 return FALSE;
1075 /***********************************************************************
1076 * FILEDLG95_InitControls
1078 * WM_INITDIALOG message handler (before hook notification)
1080 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1082 int win2000plus = 0;
1083 int win98plus = 0;
1084 int handledPath = FALSE;
1085 OSVERSIONINFOW osVi;
1086 static const WCHAR szwSlash[] = { '\\', 0 };
1087 static const WCHAR szwStar[] = { '*',0 };
1089 static const TBBUTTON tbb[] =
1091 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1092 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1093 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1094 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1095 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1096 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1097 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1098 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1099 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1101 TBADDBITMAP tba[2];
1102 RECT rectTB;
1103 RECT rectlook;
1104 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1106 tba[0].hInst = HINST_COMMCTRL;
1107 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1108 tba[1].hInst = COMDLG32_hInstance;
1109 tba[1].nID = 800;
1111 TRACE("%p\n", fodInfos);
1113 /* Get windows version emulating */
1114 osVi.dwOSVersionInfoSize = sizeof(osVi);
1115 GetVersionExW(&osVi);
1116 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1117 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1118 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1119 win2000plus = (osVi.dwMajorVersion > 4);
1120 if (win2000plus) win98plus = TRUE;
1122 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1124 /* Get the hwnd of the controls */
1125 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1126 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1127 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1129 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1130 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1132 /* construct the toolbar */
1133 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1134 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1136 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1137 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1138 rectTB.left = rectlook.right;
1139 rectTB.top = rectlook.top-1;
1141 if (fodInfos->unicode)
1142 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1143 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1144 rectTB.left, rectTB.top,
1145 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1146 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1147 else
1148 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1149 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1150 rectTB.left, rectTB.top,
1151 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1152 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1154 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1156 /* FIXME: use TB_LOADIMAGES when implemented */
1157 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1158 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1159 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1161 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1162 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1164 /* Set the window text with the text specified in the OPENFILENAME structure */
1165 if(fodInfos->title)
1167 SetWindowTextW(hwnd,fodInfos->title);
1169 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1171 WCHAR buf[16];
1172 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1173 SetWindowTextW(hwnd, buf);
1176 /* Initialise the file name edit control */
1177 handledPath = FALSE;
1178 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1180 if(fodInfos->filename)
1182 /* 1. If win2000 or higher and filename contains a path, use it
1183 in preference over the lpstrInitialDir */
1184 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1185 WCHAR tmpBuf[MAX_PATH];
1186 WCHAR *nameBit;
1187 DWORD result;
1189 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1190 if (result) {
1192 /* nameBit is always shorter than the original filename */
1193 lstrcpyW(fodInfos->filename,nameBit);
1195 *nameBit = 0x00;
1196 if (fodInfos->initdir == NULL)
1197 MemFree(fodInfos->initdir);
1198 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1199 lstrcpyW(fodInfos->initdir, tmpBuf);
1200 handledPath = TRUE;
1201 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1202 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1204 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1206 } else {
1207 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1211 /* 2. (All platforms) If initdir is not null, then use it */
1212 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1213 (*fodInfos->initdir!=0x00))
1215 /* Work out the proper path as supplied one might be relative */
1216 /* (Here because supplying '.' as dir browses to My Computer) */
1217 if (handledPath==FALSE) {
1218 WCHAR tmpBuf[MAX_PATH];
1219 WCHAR tmpBuf2[MAX_PATH];
1220 WCHAR *nameBit;
1221 DWORD result;
1223 lstrcpyW(tmpBuf, fodInfos->initdir);
1224 if( PathFileExistsW(tmpBuf) ) {
1225 /* initdir does not have to be a directory. If a file is
1226 * specified, the dir part is taken */
1227 if( PathIsDirectoryW(tmpBuf)) {
1228 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1229 lstrcatW(tmpBuf, szwSlash);
1231 lstrcatW(tmpBuf, szwStar);
1233 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1234 if (result) {
1235 *nameBit = 0x00;
1236 MemFree(fodInfos->initdir);
1237 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1238 lstrcpyW(fodInfos->initdir, tmpBuf2);
1239 handledPath = TRUE;
1240 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1243 else if (fodInfos->initdir)
1245 MemFree(fodInfos->initdir);
1246 fodInfos->initdir = NULL;
1247 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1252 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1253 (*fodInfos->initdir==0x00)))
1255 /* 3. All except w2k+: if filename contains a path use it */
1256 if (!win2000plus && fodInfos->filename &&
1257 *fodInfos->filename &&
1258 strpbrkW(fodInfos->filename, szwSlash)) {
1259 WCHAR tmpBuf[MAX_PATH];
1260 WCHAR *nameBit;
1261 DWORD result;
1263 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1264 tmpBuf, &nameBit);
1265 if (result) {
1266 int len;
1268 /* nameBit is always shorter than the original filename */
1269 lstrcpyW(fodInfos->filename, nameBit);
1270 *nameBit = 0x00;
1272 len = lstrlenW(tmpBuf);
1273 MemFree(fodInfos->initdir);
1274 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1275 lstrcpyW(fodInfos->initdir, tmpBuf);
1277 handledPath = TRUE;
1278 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1279 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1281 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1284 /* 4. win98+ and win2000+ if any files of specified filter types in
1285 current directory, use it */
1286 if ( win98plus && handledPath == FALSE &&
1287 fodInfos->filter && *fodInfos->filter) {
1289 BOOL searchMore = TRUE;
1290 LPCWSTR lpstrPos = fodInfos->filter;
1291 WIN32_FIND_DATAW FindFileData;
1292 HANDLE hFind;
1294 while (searchMore)
1296 /* filter is a list... title\0ext\0......\0\0 */
1298 /* Skip the title */
1299 if(! *lpstrPos) break; /* end */
1300 lpstrPos += lstrlenW(lpstrPos) + 1;
1302 /* See if any files exist in the current dir with this extension */
1303 if(! *lpstrPos) break; /* end */
1305 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1307 if (hFind == INVALID_HANDLE_VALUE) {
1308 /* None found - continue search */
1309 lpstrPos += lstrlenW(lpstrPos) + 1;
1311 } else {
1312 searchMore = FALSE;
1314 MemFree(fodInfos->initdir);
1315 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1316 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1318 handledPath = TRUE;
1319 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1320 debugstr_w(lpstrPos));
1321 break;
1326 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1328 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1329 if (handledPath == FALSE && (win2000plus || win98plus)) {
1330 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1332 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))
1334 if(!COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))
1336 /* last fallback */
1337 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1338 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1339 } else {
1340 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1342 } else {
1343 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1345 handledPath = TRUE;
1346 } else if (handledPath==FALSE) {
1347 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1348 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1349 handledPath = TRUE;
1350 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1353 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1354 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1356 /* Must the open as read only check box be checked ?*/
1357 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1359 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1362 /* Must the open as read only check box be hidden? */
1363 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1365 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1366 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1369 /* Must the help button be hidden? */
1370 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1372 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1373 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1376 /* change Open to Save */
1377 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1379 WCHAR buf[16];
1380 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1381 SetDlgItemTextW(hwnd, IDOK, buf);
1382 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1383 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1385 return 0;
1388 /***********************************************************************
1389 * FILEDLG95_ResizeControls
1391 * WM_INITDIALOG message handler (after hook notification)
1393 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1395 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1397 if (fodInfos->DlgInfos.hwndCustomDlg)
1399 RECT rc;
1400 UINT flags = SWP_NOACTIVATE;
1402 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1403 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1405 /* resize the custom dialog to the parent size */
1406 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1407 GetClientRect(hwnd, &rc);
1408 else
1410 /* our own fake template is zero sized and doesn't have children, so
1411 * there is no need to resize it. Picasa depends on it.
1413 flags |= SWP_NOSIZE;
1414 SetRectEmpty(&rc);
1416 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1417 0, 0, rc.right, rc.bottom, flags);
1419 else
1421 /* Resize the height, if open as read only checkbox ad help button are
1422 * hidden and we are not using a custom template nor a customDialog
1424 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1425 (!(fodInfos->ofnInfos->Flags &
1426 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1428 RECT rectDlg, rectHelp, rectCancel;
1429 GetWindowRect(hwnd, &rectDlg);
1430 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1431 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1432 /* subtract the height of the help button plus the space between the help
1433 * button and the cancel button to the height of the dialog
1435 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1436 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1437 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1440 return TRUE;
1443 /***********************************************************************
1444 * FILEDLG95_FillControls
1446 * WM_INITDIALOG message handler (after hook notification)
1448 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1450 LPITEMIDLIST pidlItemId = NULL;
1452 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1454 TRACE("dir=%s file=%s\n",
1455 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1457 /* Get the initial directory pidl */
1459 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1461 WCHAR path[MAX_PATH];
1463 GetCurrentDirectoryW(MAX_PATH,path);
1464 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1467 /* Initialise shell objects */
1468 FILEDLG95_SHELL_Init(hwnd);
1470 /* Initialize the Look In combo box */
1471 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1473 /* Initialize the filter combo box */
1474 FILEDLG95_FILETYPE_Init(hwnd);
1476 /* Browse to the initial directory */
1477 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1479 /* Free pidlItem memory */
1480 COMDLG32_SHFree(pidlItemId);
1482 return TRUE;
1484 /***********************************************************************
1485 * FILEDLG95_Clean
1487 * Regroups all the cleaning functions of the filedlg
1489 void FILEDLG95_Clean(HWND hwnd)
1491 FILEDLG95_FILETYPE_Clean(hwnd);
1492 FILEDLG95_LOOKIN_Clean(hwnd);
1493 FILEDLG95_SHELL_Clean(hwnd);
1495 /***********************************************************************
1496 * FILEDLG95_OnWMCommand
1498 * WM_COMMAND message handler
1500 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1502 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1503 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1504 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1506 switch(wID)
1508 /* OK button */
1509 case IDOK:
1510 FILEDLG95_OnOpen(hwnd);
1511 break;
1512 /* Cancel button */
1513 case IDCANCEL:
1514 FILEDLG95_Clean(hwnd);
1515 EndDialog(hwnd, FALSE);
1516 break;
1517 /* Filetype combo box */
1518 case IDC_FILETYPE:
1519 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1520 break;
1521 /* LookIn combo box */
1522 case IDC_LOOKIN:
1523 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1524 break;
1526 /* --- toolbar --- */
1527 /* Up folder button */
1528 case FCIDM_TB_UPFOLDER:
1529 FILEDLG95_SHELL_UpFolder(hwnd);
1530 break;
1531 /* New folder button */
1532 case FCIDM_TB_NEWFOLDER:
1533 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1534 break;
1535 /* List option button */
1536 case FCIDM_TB_SMALLICON:
1537 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1538 break;
1539 /* Details option button */
1540 case FCIDM_TB_REPORTVIEW:
1541 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1542 break;
1543 /* Details option button */
1544 case FCIDM_TB_DESKTOP:
1545 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1546 break;
1548 case IDC_FILENAME:
1549 break;
1552 /* Do not use the listview selection anymore */
1553 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1554 return 0;
1557 /***********************************************************************
1558 * FILEDLG95_OnWMGetIShellBrowser
1560 * WM_GETISHELLBROWSER message handler
1562 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1565 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1567 TRACE("\n");
1569 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1571 return TRUE;
1575 /***********************************************************************
1576 * FILEDLG95_SendFileOK
1578 * Sends the CDN_FILEOK notification if required
1580 * RETURNS
1581 * TRUE if the dialog should close
1582 * FALSE if the dialog should not be closed
1584 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1586 /* ask the hook if we can close */
1587 if(IsHooked(fodInfos))
1589 LRESULT retval;
1591 TRACE("---\n");
1592 /* First send CDN_FILEOK as MSDN doc says */
1593 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1594 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1596 TRACE("canceled\n");
1597 return (retval == 0);
1600 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1601 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1602 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1603 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1605 TRACE("canceled\n");
1606 return (retval == 0);
1609 return TRUE;
1612 /***********************************************************************
1613 * FILEDLG95_OnOpenMultipleFiles
1615 * Handles the opening of multiple files.
1617 * FIXME
1618 * check destination buffer size
1620 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1622 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1623 UINT nCount, nSizePath;
1624 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1626 TRACE("\n");
1628 if(fodInfos->unicode)
1630 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1631 ofn->lpstrFile[0] = '\0';
1633 else
1635 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1636 ofn->lpstrFile[0] = '\0';
1639 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1641 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1642 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1643 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1645 LPWSTR lpstrTemp = lpstrFileList;
1647 for ( nCount = 0; nCount < nFileCount; nCount++ )
1649 LPITEMIDLIST pidl;
1651 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1652 if (!pidl)
1654 WCHAR lpstrNotFound[100];
1655 WCHAR lpstrMsg[100];
1656 WCHAR tmp[400];
1657 static const WCHAR nl[] = {'\n',0};
1659 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1660 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1662 lstrcpyW(tmp, lpstrTemp);
1663 lstrcatW(tmp, nl);
1664 lstrcatW(tmp, lpstrNotFound);
1665 lstrcatW(tmp, nl);
1666 lstrcatW(tmp, lpstrMsg);
1668 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1669 return FALSE;
1672 /* move to the next file in the list of files */
1673 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1674 COMDLG32_SHFree(pidl);
1678 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1679 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1681 /* For "oldstyle" dialog the components have to
1682 be separated by blanks (not '\0'!) and short
1683 filenames have to be used! */
1684 FIXME("Components have to be separated by blanks\n");
1686 if(fodInfos->unicode)
1688 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1689 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1690 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1692 else
1694 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1696 if (ofn->lpstrFile != NULL)
1698 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1699 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1700 if (ofn->nMaxFile > nSizePath)
1702 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1703 ofn->lpstrFile + nSizePath,
1704 ofn->nMaxFile - nSizePath, NULL, NULL);
1709 fodInfos->ofnInfos->nFileOffset = nSizePath;
1710 fodInfos->ofnInfos->nFileExtension = 0;
1712 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1713 return FALSE;
1715 /* clean and exit */
1716 FILEDLG95_Clean(hwnd);
1717 return EndDialog(hwnd,TRUE);
1720 /***********************************************************************
1721 * FILEDLG95_OnOpen
1723 * Ok button WM_COMMAND message handler
1725 * If the function succeeds, the return value is nonzero.
1727 #define ONOPEN_BROWSE 1
1728 #define ONOPEN_OPEN 2
1729 #define ONOPEN_SEARCH 3
1730 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1732 WCHAR strMsgTitle[MAX_PATH];
1733 WCHAR strMsgText [MAX_PATH];
1734 if (idCaption)
1735 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1736 else
1737 strMsgTitle[0] = '\0';
1738 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1739 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1742 BOOL FILEDLG95_OnOpen(HWND hwnd)
1744 LPWSTR lpstrFileList;
1745 UINT nFileCount = 0;
1746 UINT sizeUsed = 0;
1747 BOOL ret = TRUE;
1748 WCHAR lpstrPathAndFile[MAX_PATH];
1749 WCHAR lpstrTemp[MAX_PATH];
1750 LPSHELLFOLDER lpsf = NULL;
1751 int nOpenAction;
1752 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1754 TRACE("hwnd=%p\n", hwnd);
1756 /* get the files from the edit control */
1757 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1759 /* try if the user selected a folder in the shellview */
1760 if(nFileCount == 0)
1762 BrowseSelectedFolder(hwnd);
1763 return FALSE;
1766 if(nFileCount > 1)
1768 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1769 goto ret;
1772 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1775 Step 1: Build a complete path name from the current folder and
1776 the filename or path in the edit box.
1777 Special cases:
1778 - the path in the edit box is a root path
1779 (with or without drive letter)
1780 - the edit box contains ".." (or a path with ".." in it)
1783 /* Get the current directory name */
1784 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1786 /* last fallback */
1787 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1789 PathAddBackslashW(lpstrPathAndFile);
1791 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1793 /* if the user specified a fully qualified path use it */
1794 if(PathIsRelativeW(lpstrFileList))
1796 lstrcatW(lpstrPathAndFile, lpstrFileList);
1798 else
1800 /* does the path have a drive letter? */
1801 if (PathGetDriveNumberW(lpstrFileList) == -1)
1802 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1803 else
1804 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1807 /* resolve "." and ".." */
1808 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1809 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1810 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1812 MemFree(lpstrFileList);
1815 Step 2: here we have a cleaned up path
1817 We have to parse the path step by step to see if we have to browse
1818 to a folder if the path points to a directory or the last
1819 valid element is a directory.
1821 valid variables:
1822 lpstrPathAndFile: cleaned up path
1825 if (nFileCount &&
1826 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1827 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1828 nOpenAction = ONOPEN_OPEN;
1829 else
1830 nOpenAction = ONOPEN_BROWSE;
1832 /* don't apply any checks with OFN_NOVALIDATE */
1834 LPWSTR lpszTemp, lpszTemp1;
1835 LPITEMIDLIST pidl = NULL;
1836 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1838 /* check for invalid chars */
1839 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1841 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1842 ret = FALSE;
1843 goto ret;
1846 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1848 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1849 while (lpszTemp1)
1851 LPSHELLFOLDER lpsfChild;
1852 WCHAR lpwstrTemp[MAX_PATH];
1853 DWORD dwEaten, dwAttributes;
1854 LPWSTR p;
1856 lstrcpyW(lpwstrTemp, lpszTemp);
1857 p = PathFindNextComponentW(lpwstrTemp);
1859 if (!p) break; /* end of path */
1861 *p = 0;
1862 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1864 /* There are no wildcards when OFN_NOVALIDATE is set */
1865 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1867 static const WCHAR wszWild[] = { '*', '?', 0 };
1868 /* if the last element is a wildcard do a search */
1869 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1871 nOpenAction = ONOPEN_SEARCH;
1872 break;
1875 lpszTemp1 = lpszTemp;
1877 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1879 /* append a backslash to drive letters */
1880 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1881 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1882 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1884 PathAddBackslashW(lpwstrTemp);
1887 dwAttributes = SFGAO_FOLDER;
1888 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1890 /* the path component is valid, we have a pidl of the next path component */
1891 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1892 if(dwAttributes & SFGAO_FOLDER)
1894 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1896 ERR("bind to failed\n"); /* should not fail */
1897 break;
1899 IShellFolder_Release(lpsf);
1900 lpsf = lpsfChild;
1901 lpsfChild = NULL;
1903 else
1905 TRACE("value\n");
1907 /* end dialog, return value */
1908 nOpenAction = ONOPEN_OPEN;
1909 break;
1911 COMDLG32_SHFree(pidl);
1912 pidl = NULL;
1914 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1916 if(*lpszTemp || /* points to trailing null for last path element */
1917 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1919 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1921 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1922 break;
1925 else
1927 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1928 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1930 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1931 break;
1934 /* change to the current folder */
1935 nOpenAction = ONOPEN_OPEN;
1936 break;
1938 else
1940 nOpenAction = ONOPEN_OPEN;
1941 break;
1944 if(pidl) COMDLG32_SHFree(pidl);
1948 Step 3: here we have a cleaned up and validated path
1950 valid variables:
1951 lpsf: ShellFolder bound to the rightmost valid path component
1952 lpstrPathAndFile: cleaned up path
1953 nOpenAction: action to do
1955 TRACE("end validate sf=%p\n", lpsf);
1957 switch(nOpenAction)
1959 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
1960 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
1962 int iPos;
1963 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
1964 DWORD len;
1966 /* replace the current filter */
1967 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1968 len = lstrlenW(lpszTemp)+1;
1969 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1970 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
1972 /* set the filter cb to the extension when possible */
1973 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1974 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1976 /* fall through */
1977 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
1978 TRACE("ONOPEN_BROWSE\n");
1980 IPersistFolder2 * ppf2;
1981 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1983 LPITEMIDLIST pidlCurrent;
1984 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1985 IPersistFolder2_Release(ppf2);
1986 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1988 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
1990 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
1993 else if( nOpenAction == ONOPEN_SEARCH )
1995 if (fodInfos->Shell.FOIShellView)
1996 IShellView_Refresh(fodInfos->Shell.FOIShellView);
1998 COMDLG32_SHFree(pidlCurrent);
1999 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2002 ret = FALSE;
2003 break;
2004 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2005 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2007 WCHAR *ext = NULL;
2009 /* update READONLY check box flag */
2010 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2011 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2012 else
2013 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2015 /* Attach the file extension with file name*/
2016 ext = PathFindExtensionW(lpstrPathAndFile);
2017 if (! *ext)
2019 /* if no extension is specified with file name, then */
2020 /* attach the extension from file filter or default one */
2022 WCHAR *filterExt = NULL;
2023 LPWSTR lpstrFilter = NULL;
2024 static const WCHAR szwDot[] = {'.',0};
2025 int PathLength = lstrlenW(lpstrPathAndFile);
2027 /* Attach the dot*/
2028 lstrcatW(lpstrPathAndFile, szwDot);
2030 /*Get the file extension from file type filter*/
2031 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2032 fodInfos->ofnInfos->nFilterIndex-1);
2034 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2035 filterExt = PathFindExtensionW(lpstrFilter);
2037 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2038 lstrcatW(lpstrPathAndFile, filterExt + 1);
2039 else if ( fodInfos->defext ) /* attach the default file extension*/
2040 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2042 /* In Open dialog: if file does not exist try without extension */
2043 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2044 lpstrPathAndFile[PathLength] = '\0';
2047 if (fodInfos->defext) /* add default extension */
2049 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2050 if (*ext)
2051 ext++;
2052 if (!lstrcmpiW(fodInfos->defext, ext))
2053 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2054 else
2055 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2058 /* In Save dialog: check if the file already exists */
2059 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2060 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2061 && PathFileExistsW(lpstrPathAndFile))
2063 WCHAR lpstrOverwrite[100];
2064 int answer;
2066 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2067 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2068 MB_YESNO | MB_ICONEXCLAMATION);
2069 if (answer == IDNO)
2071 ret = FALSE;
2072 goto ret;
2076 /* In Open dialog: check if it should be created if it doesn't exist */
2077 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2078 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2079 && !PathFileExistsW(lpstrPathAndFile))
2081 WCHAR lpstrCreate[100];
2082 int answer;
2084 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2085 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2086 MB_YESNO | MB_ICONEXCLAMATION);
2087 if (answer == IDNO)
2089 ret = FALSE;
2090 goto ret;
2094 /* Check that the size of the file does not exceed buffer size.
2095 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2096 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2097 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2100 /* fill destination buffer */
2101 if (fodInfos->ofnInfos->lpstrFile)
2103 if(fodInfos->unicode)
2105 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2107 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2108 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2109 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2111 else
2113 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2115 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2116 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2117 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2118 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2122 if(fodInfos->unicode)
2124 LPWSTR lpszTemp;
2126 /* set filename offset */
2127 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2128 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2130 /* set extension offset */
2131 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2132 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2134 else
2136 LPSTR lpszTemp;
2137 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2139 /* set filename offset */
2140 lpszTemp = PathFindFileNameA(ofn->lpstrFile);
2141 fodInfos->ofnInfos->nFileOffset = (lpszTemp - ofn->lpstrFile);
2143 /* set extension offset */
2144 lpszTemp = PathFindExtensionA(ofn->lpstrFile);
2145 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - ofn->lpstrFile) + 1 : 0;
2148 /* set the lpstrFileTitle */
2149 if(fodInfos->ofnInfos->lpstrFileTitle)
2151 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2152 if(fodInfos->unicode)
2154 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2155 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2157 else
2159 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2160 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2161 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2165 /* copy currently selected filter to lpstrCustomFilter */
2166 if (fodInfos->ofnInfos->lpstrCustomFilter)
2168 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2169 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2170 NULL, 0, NULL, NULL);
2171 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2173 LPSTR s = ofn->lpstrCustomFilter;
2174 s += strlen(ofn->lpstrCustomFilter)+1;
2175 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2176 s, len, NULL, NULL);
2181 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2182 goto ret;
2184 TRACE("close\n");
2185 FILEDLG95_Clean(hwnd);
2186 ret = EndDialog(hwnd, TRUE);
2188 else
2190 WORD size;
2192 size = lstrlenW(lpstrPathAndFile) + 1;
2193 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2194 size += 1;
2195 /* return needed size in first two bytes of lpstrFile */
2196 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2197 FILEDLG95_Clean(hwnd);
2198 ret = EndDialog(hwnd, FALSE);
2199 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2201 goto ret;
2203 break;
2206 ret:
2207 if(lpsf) IShellFolder_Release(lpsf);
2208 return ret;
2211 /***********************************************************************
2212 * FILEDLG95_SHELL_Init
2214 * Initialisation of the shell objects
2216 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2218 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2220 TRACE("\n");
2223 * Initialisation of the FileOpenDialogInfos structure
2226 /* Shell */
2228 /*ShellInfos */
2229 fodInfos->ShellInfos.hwndOwner = hwnd;
2231 /* Disable multi-select if flag not set */
2232 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2234 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2236 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2237 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2239 /* Construct the IShellBrowser interface */
2240 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2242 return NOERROR;
2245 /***********************************************************************
2246 * FILEDLG95_SHELL_ExecuteCommand
2248 * Change the folder option and refresh the view
2249 * If the function succeeds, the return value is nonzero.
2251 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2253 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2255 IContextMenu * pcm;
2256 TRACE("(%p,%p)\n", hwnd, lpVerb);
2258 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2259 SVGIO_BACKGROUND,
2260 &IID_IContextMenu,
2261 (LPVOID*)&pcm)))
2263 CMINVOKECOMMANDINFO ci;
2264 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2265 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2266 ci.lpVerb = lpVerb;
2267 ci.hwnd = hwnd;
2269 IContextMenu_InvokeCommand(pcm, &ci);
2270 IContextMenu_Release(pcm);
2273 return FALSE;
2276 /***********************************************************************
2277 * FILEDLG95_SHELL_UpFolder
2279 * Browse to the specified object
2280 * If the function succeeds, the return value is nonzero.
2282 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2284 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2286 TRACE("\n");
2288 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2289 NULL,
2290 SBSP_PARENT)))
2292 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2293 return TRUE;
2295 return FALSE;
2298 /***********************************************************************
2299 * FILEDLG95_SHELL_BrowseToDesktop
2301 * Browse to the Desktop
2302 * If the function succeeds, the return value is nonzero.
2304 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2306 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2307 LPITEMIDLIST pidl;
2308 HRESULT hres;
2310 TRACE("\n");
2312 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2313 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2314 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2315 COMDLG32_SHFree(pidl);
2316 return SUCCEEDED(hres);
2318 /***********************************************************************
2319 * FILEDLG95_SHELL_Clean
2321 * Cleans the memory used by shell objects
2323 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2325 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2327 TRACE("\n");
2329 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2331 /* clean Shell interfaces */
2332 if (fodInfos->Shell.FOIShellView)
2334 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2335 IShellView_Release(fodInfos->Shell.FOIShellView);
2337 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2338 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2339 if (fodInfos->Shell.FOIDataObject)
2340 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2343 /***********************************************************************
2344 * FILEDLG95_FILETYPE_Init
2346 * Initialisation of the file type combo box
2348 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2350 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2351 int nFilters = 0; /* number of filters */
2352 int nFilterIndexCB;
2354 TRACE("\n");
2356 if(fodInfos->customfilter)
2358 /* customfilter has one entry... title\0ext\0
2359 * Set first entry of combo box item with customfilter
2361 LPWSTR lpstrExt;
2362 LPCWSTR lpstrPos = fodInfos->customfilter;
2364 /* Get the title */
2365 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2367 /* Copy the extensions */
2368 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2369 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2370 lstrcpyW(lpstrExt,lpstrPos);
2372 /* Add the item at the end of the combo */
2373 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2374 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2375 nFilters++;
2377 if(fodInfos->filter)
2379 LPCWSTR lpstrPos = fodInfos->filter;
2381 for(;;)
2383 /* filter is a list... title\0ext\0......\0\0
2384 * Set the combo item text to the title and the item data
2385 * to the ext
2387 LPCWSTR lpstrDisplay;
2388 LPWSTR lpstrExt;
2390 /* Get the title */
2391 if(! *lpstrPos) break; /* end */
2392 lpstrDisplay = lpstrPos;
2393 lpstrPos += lstrlenW(lpstrPos) + 1;
2395 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2397 nFilters++;
2399 /* Copy the extensions */
2400 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2401 lstrcpyW(lpstrExt,lpstrPos);
2402 lpstrPos += lstrlenW(lpstrPos) + 1;
2404 /* Add the item at the end of the combo */
2405 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2407 /* malformed filters are added anyway... */
2408 if (!*lpstrExt) break;
2413 * Set the current filter to the one specified
2414 * in the initialisation structure
2416 if (fodInfos->filter || fodInfos->customfilter)
2418 LPWSTR lpstrFilter;
2420 /* Check to make sure our index isn't out of bounds. */
2421 if ( fodInfos->ofnInfos->nFilterIndex >
2422 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2423 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2425 /* set default filter index */
2426 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2427 fodInfos->ofnInfos->nFilterIndex = 1;
2429 /* calculate index of Combo Box item */
2430 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2431 if (fodInfos->customfilter == NULL)
2432 nFilterIndexCB--;
2434 /* Set the current index selection. */
2435 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2437 /* Get the corresponding text string from the combo box. */
2438 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2439 nFilterIndexCB);
2441 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2442 lpstrFilter = NULL;
2444 if(lpstrFilter)
2446 DWORD len;
2447 CharLowerW(lpstrFilter); /* lowercase */
2448 len = lstrlenW(lpstrFilter)+1;
2449 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2450 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2452 } else
2453 fodInfos->ofnInfos->nFilterIndex = 0;
2454 return S_OK;
2457 /***********************************************************************
2458 * FILEDLG95_FILETYPE_OnCommand
2460 * WM_COMMAND of the file type combo box
2461 * If the function succeeds, the return value is nonzero.
2463 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2465 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2467 switch(wNotifyCode)
2469 case CBN_SELENDOK:
2471 LPWSTR lpstrFilter;
2473 /* Get the current item of the filetype combo box */
2474 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2476 /* set the current filter index */
2477 fodInfos->ofnInfos->nFilterIndex = iItem +
2478 (fodInfos->customfilter == NULL ? 1 : 0);
2480 /* Set the current filter with the current selection */
2481 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2483 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2484 iItem);
2485 if((INT_PTR)lpstrFilter != CB_ERR)
2487 DWORD len;
2488 CharLowerW(lpstrFilter); /* lowercase */
2489 len = lstrlenW(lpstrFilter)+1;
2490 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2491 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2492 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2495 /* Refresh the actual view to display the included items*/
2496 if (fodInfos->Shell.FOIShellView)
2497 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2500 return FALSE;
2502 /***********************************************************************
2503 * FILEDLG95_FILETYPE_SearchExt
2505 * searches for an extension in the filetype box
2507 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2509 int i, iCount = CBGetCount(hwnd);
2511 TRACE("%s\n", debugstr_w(lpstrExt));
2513 if(iCount != CB_ERR)
2515 for(i=0;i<iCount;i++)
2517 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2518 return i;
2521 return -1;
2524 /***********************************************************************
2525 * FILEDLG95_FILETYPE_Clean
2527 * Clean the memory used by the filetype combo box
2529 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2531 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2532 int iPos;
2533 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2535 TRACE("\n");
2537 /* Delete each string of the combo and their associated data */
2538 if(iCount != CB_ERR)
2540 for(iPos = iCount-1;iPos>=0;iPos--)
2542 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2543 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2546 /* Current filter */
2547 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2551 /***********************************************************************
2552 * FILEDLG95_LOOKIN_Init
2554 * Initialisation of the look in combo box
2557 /* Small helper function, to determine if the unixfs shell extension is rooted
2558 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2560 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2561 HKEY hKey;
2562 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2563 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2564 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2565 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2566 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2567 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2568 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2570 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2571 return FALSE;
2573 RegCloseKey(hKey);
2574 return TRUE;
2577 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2579 IShellFolder *psfRoot, *psfDrives;
2580 IEnumIDList *lpeRoot, *lpeDrives;
2581 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2583 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2585 TRACE("\n");
2587 liInfos->iMaxIndentation = 0;
2589 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2591 /* set item height for both text field and listbox */
2592 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2593 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2595 /* Turn on the extended UI for the combo box like Windows does */
2596 CBSetExtendedUI(hwndCombo, TRUE);
2598 /* Initialise data of Desktop folder */
2599 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2600 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2601 COMDLG32_SHFree(pidlTmp);
2603 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2605 SHGetDesktopFolder(&psfRoot);
2607 if (psfRoot)
2609 /* enumerate the contents of the desktop */
2610 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2612 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2614 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2616 /* If the unixfs extension is rooted, we don't expand the drives by default */
2617 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2619 /* special handling for CSIDL_DRIVES */
2620 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2622 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2624 /* enumerate the drives */
2625 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2627 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2629 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2630 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2631 COMDLG32_SHFree(pidlAbsTmp);
2632 COMDLG32_SHFree(pidlTmp1);
2634 IEnumIDList_Release(lpeDrives);
2636 IShellFolder_Release(psfDrives);
2641 COMDLG32_SHFree(pidlTmp);
2643 IEnumIDList_Release(lpeRoot);
2645 IShellFolder_Release(psfRoot);
2648 COMDLG32_SHFree(pidlDrives);
2651 /***********************************************************************
2652 * FILEDLG95_LOOKIN_DrawItem
2654 * WM_DRAWITEM message handler
2656 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2658 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2659 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2660 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2661 RECT rectText;
2662 RECT rectIcon;
2663 SHFILEINFOW sfi;
2664 HIMAGELIST ilItemImage;
2665 int iIndentation;
2666 TEXTMETRICW tm;
2667 LPSFOLDER tmpFolder;
2670 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2672 TRACE("\n");
2674 if(pDIStruct->itemID == -1)
2675 return 0;
2677 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2678 pDIStruct->itemID)))
2679 return 0;
2682 if(pDIStruct->itemID == liInfos->uSelectedItem)
2684 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2686 &sfi,
2687 sizeof (sfi),
2688 SHGFI_PIDL | SHGFI_SMALLICON |
2689 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2690 SHGFI_DISPLAYNAME );
2692 else
2694 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2696 &sfi,
2697 sizeof (sfi),
2698 SHGFI_PIDL | SHGFI_SMALLICON |
2699 SHGFI_SYSICONINDEX |
2700 SHGFI_DISPLAYNAME);
2703 /* Is this item selected ? */
2704 if(pDIStruct->itemState & ODS_SELECTED)
2706 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2707 SetBkColor(pDIStruct->hDC,crHighLight);
2708 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2710 else
2712 SetTextColor(pDIStruct->hDC,crText);
2713 SetBkColor(pDIStruct->hDC,crWin);
2714 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2717 /* Do not indent item if drawing in the edit of the combo */
2718 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2720 iIndentation = 0;
2721 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2723 &sfi,
2724 sizeof (sfi),
2725 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2726 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2729 else
2731 iIndentation = tmpFolder->m_iIndent;
2733 /* Draw text and icon */
2735 /* Initialise the icon display area */
2736 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2737 rectIcon.top = pDIStruct->rcItem.top;
2738 rectIcon.right = rectIcon.left + ICONWIDTH;
2739 rectIcon.bottom = pDIStruct->rcItem.bottom;
2741 /* Initialise the text display area */
2742 GetTextMetricsW(pDIStruct->hDC, &tm);
2743 rectText.left = rectIcon.right;
2744 rectText.top =
2745 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2746 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2747 rectText.bottom =
2748 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2750 /* Draw the icon from the image list */
2751 ImageList_Draw(ilItemImage,
2752 sfi.iIcon,
2753 pDIStruct->hDC,
2754 rectIcon.left,
2755 rectIcon.top,
2756 ILD_TRANSPARENT );
2758 /* Draw the associated text */
2759 if(sfi.szDisplayName)
2760 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2763 return NOERROR;
2766 /***********************************************************************
2767 * FILEDLG95_LOOKIN_OnCommand
2769 * LookIn combo box WM_COMMAND message handler
2770 * If the function succeeds, the return value is nonzero.
2772 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2774 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2776 TRACE("%p\n", fodInfos);
2778 switch(wNotifyCode)
2780 case CBN_SELENDOK:
2782 LPSFOLDER tmpFolder;
2783 int iItem;
2785 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2787 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2788 iItem)))
2789 return FALSE;
2792 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2793 tmpFolder->pidlItem,
2794 SBSP_ABSOLUTE)))
2796 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2797 return TRUE;
2799 break;
2803 return FALSE;
2806 /***********************************************************************
2807 * FILEDLG95_LOOKIN_AddItem
2809 * Adds an absolute pidl item to the lookin combo box
2810 * returns the index of the inserted item
2812 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2814 LPITEMIDLIST pidlNext;
2815 SHFILEINFOW sfi;
2816 SFOLDER *tmpFolder;
2817 LookInInfos *liInfos;
2819 TRACE("%08x\n", iInsertId);
2821 if(!pidl)
2822 return -1;
2824 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2825 return -1;
2827 tmpFolder = MemAlloc(sizeof(SFOLDER));
2828 tmpFolder->m_iIndent = 0;
2830 /* Calculate the indentation of the item in the lookin*/
2831 pidlNext = pidl;
2832 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2834 tmpFolder->m_iIndent++;
2837 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2839 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2840 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2842 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2843 SHGetFileInfoW((LPCWSTR)pidl,
2845 &sfi,
2846 sizeof(sfi),
2847 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2848 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2850 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2852 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2854 int iItemID;
2856 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2858 /* Add the item at the end of the list */
2859 if(iInsertId < 0)
2861 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2863 /* Insert the item at the iInsertId position*/
2864 else
2866 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2869 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2870 return iItemID;
2873 COMDLG32_SHFree( tmpFolder->pidlItem );
2874 MemFree( tmpFolder );
2875 return -1;
2879 /***********************************************************************
2880 * FILEDLG95_LOOKIN_InsertItemAfterParent
2882 * Insert an item below its parent
2884 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2887 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2888 int iParentPos;
2890 TRACE("\n");
2892 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2894 if(iParentPos < 0)
2896 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2899 /* Free pidlParent memory */
2900 COMDLG32_SHFree((LPVOID)pidlParent);
2902 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2905 /***********************************************************************
2906 * FILEDLG95_LOOKIN_SelectItem
2908 * Adds an absolute pidl item to the lookin combo box
2909 * returns the index of the inserted item
2911 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2913 int iItemPos;
2914 LookInInfos *liInfos;
2916 TRACE("\n");
2918 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2920 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2922 if(iItemPos < 0)
2924 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2925 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2928 else
2930 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2931 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2933 int iRemovedItem;
2935 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2936 break;
2937 if(iRemovedItem < iItemPos)
2938 iItemPos--;
2942 CBSetCurSel(hwnd,iItemPos);
2943 liInfos->uSelectedItem = iItemPos;
2945 return 0;
2949 /***********************************************************************
2950 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2952 * Remove the item with an expansion level over iExpansionLevel
2954 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2956 int iItemPos;
2958 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2960 TRACE("\n");
2962 if(liInfos->iMaxIndentation <= 2)
2963 return -1;
2965 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2967 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2968 COMDLG32_SHFree(tmpFolder->pidlItem);
2969 MemFree(tmpFolder);
2970 CBDeleteString(hwnd,iItemPos);
2971 liInfos->iMaxIndentation--;
2973 return iItemPos;
2976 return -1;
2979 /***********************************************************************
2980 * FILEDLG95_LOOKIN_SearchItem
2982 * Search for pidl in the lookin combo box
2983 * returns the index of the found item
2985 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2987 int i = 0;
2988 int iCount = CBGetCount(hwnd);
2990 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
2992 if (iCount != CB_ERR)
2994 for(;i<iCount;i++)
2996 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2998 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2999 return i;
3000 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3001 return i;
3005 return -1;
3008 /***********************************************************************
3009 * FILEDLG95_LOOKIN_Clean
3011 * Clean the memory used by the lookin combo box
3013 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3015 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3016 int iPos;
3017 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3019 TRACE("\n");
3021 /* Delete each string of the combo and their associated data */
3022 if (iCount != CB_ERR)
3024 for(iPos = iCount-1;iPos>=0;iPos--)
3026 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3027 COMDLG32_SHFree(tmpFolder->pidlItem);
3028 MemFree(tmpFolder);
3029 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3033 /* LookInInfos structure */
3034 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3037 /***********************************************************************
3038 * FILEDLG95_FILENAME_FillFromSelection
3040 * fills the edit box from the cached DataObject
3042 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3044 FileOpenDlgInfos *fodInfos;
3045 LPITEMIDLIST pidl;
3046 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3047 WCHAR lpstrTemp[MAX_PATH];
3048 LPWSTR lpstrAllFile, lpstrCurrFile;
3050 TRACE("\n");
3051 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3053 /* Count how many files we have */
3054 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3056 /* calculate the string length, count files */
3057 if (nFileSelected >= 1)
3059 nLength += 3; /* first and last quotes, trailing \0 */
3060 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3062 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3064 if (pidl)
3066 /* get the total length of the selected file names */
3067 lpstrTemp[0] = '\0';
3068 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3070 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3072 nLength += lstrlenW( lpstrTemp ) + 3;
3073 nFiles++;
3075 COMDLG32_SHFree( pidl );
3080 /* allocate the buffer */
3081 if (nFiles <= 1) nLength = MAX_PATH;
3082 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3084 /* Generate the string for the edit control */
3085 if(nFiles >= 1)
3087 lpstrCurrFile = lpstrAllFile;
3088 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3090 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3092 if (pidl)
3094 /* get the file name */
3095 lpstrTemp[0] = '\0';
3096 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3098 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3100 if ( nFiles > 1)
3102 *lpstrCurrFile++ = '\"';
3103 lstrcpyW( lpstrCurrFile, lpstrTemp );
3104 lpstrCurrFile += lstrlenW( lpstrTemp );
3105 *lpstrCurrFile++ = '\"';
3106 *lpstrCurrFile++ = ' ';
3107 *lpstrCurrFile = 0;
3109 else
3111 lstrcpyW( lpstrAllFile, lpstrTemp );
3114 COMDLG32_SHFree( (LPVOID) pidl );
3117 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3119 /* Select the file name like Windows does */
3120 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3122 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3126 /* copied from shell32 to avoid linking to it
3127 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3128 * is dependent on whether emulated OS is unicode or not.
3130 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3132 switch (src->uType)
3134 case STRRET_WSTR:
3135 lstrcpynW(dest, src->u.pOleStr, len);
3136 COMDLG32_SHFree(src->u.pOleStr);
3137 break;
3139 case STRRET_CSTR:
3140 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3141 dest[len-1] = 0;
3142 break;
3144 case STRRET_OFFSET:
3145 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3146 dest[len-1] = 0;
3147 break;
3149 default:
3150 FIXME("unknown type %x!\n", src->uType);
3151 if (len) *dest = '\0';
3152 return E_FAIL;
3154 return S_OK;
3157 /***********************************************************************
3158 * FILEDLG95_FILENAME_GetFileNames
3160 * Copies the filenames to a delimited string list.
3161 * The delimiter is specified by the parameter 'separator',
3162 * usually either a space or a nul
3164 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed)
3166 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3167 UINT nStrCharCount = 0; /* index in src buffer */
3168 UINT nFileIndex = 0; /* index in dest buffer */
3169 UINT nFileCount = 0; /* number of files */
3170 UINT nStrLen = 0; /* length of string in edit control */
3171 LPWSTR lpstrEdit; /* buffer for string from edit control */
3173 TRACE("\n");
3175 /* get the filenames from the edit control */
3176 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3177 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3178 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3180 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3182 /* we might get single filename without any '"',
3183 * so we need nStrLen + terminating \0 + end-of-list \0 */
3184 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3185 *sizeUsed = 0;
3187 /* build delimited file list from filenames */
3188 while ( nStrCharCount <= nStrLen )
3190 if ( lpstrEdit[nStrCharCount]=='"' )
3192 nStrCharCount++;
3193 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3195 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3196 nStrCharCount++;
3198 (*lpstrFileList)[nFileIndex++] = 0;
3199 nFileCount++;
3201 nStrCharCount++;
3204 /* single, unquoted string */
3205 if ((nStrLen > 0) && (nFileIndex == 0) )
3207 lstrcpyW(*lpstrFileList, lpstrEdit);
3208 nFileIndex = lstrlenW(lpstrEdit) + 1;
3209 nFileCount = 1;
3212 /* trailing \0 */
3213 (*lpstrFileList)[nFileIndex++] = '\0';
3215 *sizeUsed = nFileIndex;
3216 MemFree(lpstrEdit);
3217 return nFileCount;
3220 #define SETDefFormatEtc(fe,cf,med) \
3222 (fe).cfFormat = cf;\
3223 (fe).dwAspect = DVASPECT_CONTENT; \
3224 (fe).ptd =NULL;\
3225 (fe).tymed = med;\
3226 (fe).lindex = -1;\
3230 * DATAOBJECT Helper functions
3233 /***********************************************************************
3234 * COMCTL32_ReleaseStgMedium
3236 * like ReleaseStgMedium from ole32
3238 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3240 if(medium.pUnkForRelease)
3242 IUnknown_Release(medium.pUnkForRelease);
3244 else
3246 GlobalUnlock(medium.u.hGlobal);
3247 GlobalFree(medium.u.hGlobal);
3251 /***********************************************************************
3252 * GetPidlFromDataObject
3254 * Return pidl(s) by number from the cached DataObject
3256 * nPidlIndex=0 gets the fully qualified root path
3258 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3261 STGMEDIUM medium;
3262 FORMATETC formatetc;
3263 LPITEMIDLIST pidl = NULL;
3265 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3267 if (!doSelected)
3268 return NULL;
3270 /* Set the FORMATETC structure*/
3271 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3273 /* Get the pidls from IDataObject */
3274 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3276 LPIDA cida = GlobalLock(medium.u.hGlobal);
3277 if(nPidlIndex <= cida->cidl)
3279 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3281 COMCTL32_ReleaseStgMedium(medium);
3283 return pidl;
3286 /***********************************************************************
3287 * GetNumSelected
3289 * Return the number of selected items in the DataObject.
3292 UINT GetNumSelected( IDataObject *doSelected )
3294 UINT retVal = 0;
3295 STGMEDIUM medium;
3296 FORMATETC formatetc;
3298 TRACE("sv=%p\n", doSelected);
3300 if (!doSelected) return 0;
3302 /* Set the FORMATETC structure*/
3303 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3305 /* Get the pidls from IDataObject */
3306 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3308 LPIDA cida = GlobalLock(medium.u.hGlobal);
3309 retVal = cida->cidl;
3310 COMCTL32_ReleaseStgMedium(medium);
3311 return retVal;
3313 return 0;
3317 * TOOLS
3320 /***********************************************************************
3321 * GetName
3323 * Get the pidl's display name (relative to folder) and
3324 * put it in lpstrFileName.
3326 * Return NOERROR on success,
3327 * E_FAIL otherwise
3330 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3332 STRRET str;
3333 HRESULT hRes;
3335 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3337 if(!lpsf)
3339 SHGetDesktopFolder(&lpsf);
3340 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3341 IShellFolder_Release(lpsf);
3342 return hRes;
3345 /* Get the display name of the pidl relative to the folder */
3346 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3348 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3350 return E_FAIL;
3353 /***********************************************************************
3354 * GetShellFolderFromPidl
3356 * pidlRel is the item pidl relative
3357 * Return the IShellFolder of the absolute pidl
3359 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3361 IShellFolder *psf = NULL,*psfParent;
3363 TRACE("%p\n", pidlAbs);
3365 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3367 psf = psfParent;
3368 if(pidlAbs && pidlAbs->mkid.cb)
3370 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3372 IShellFolder_Release(psfParent);
3373 return psf;
3376 /* return the desktop */
3377 return psfParent;
3379 return NULL;
3382 /***********************************************************************
3383 * GetParentPidl
3385 * Return the LPITEMIDLIST to the parent of the pidl in the list
3387 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3389 LPITEMIDLIST pidlParent;
3391 TRACE("%p\n", pidl);
3393 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3394 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3396 return pidlParent;
3399 /***********************************************************************
3400 * GetPidlFromName
3402 * returns the pidl of the file name relative to folder
3403 * NULL if an error occurred
3405 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3407 LPITEMIDLIST pidl = NULL;
3408 ULONG ulEaten;
3410 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3412 if(!lpcstrFileName) return NULL;
3413 if(!*lpcstrFileName) return NULL;
3415 if(!lpsf)
3417 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3418 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3419 IShellFolder_Release(lpsf);
3422 else
3424 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3426 return pidl;
3431 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3433 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3434 HRESULT ret;
3436 TRACE("%p, %p\n", psf, pidl);
3438 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3440 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3441 /* see documentation shell 4.1*/
3442 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3445 /***********************************************************************
3446 * BrowseSelectedFolder
3448 static BOOL BrowseSelectedFolder(HWND hwnd)
3450 BOOL bBrowseSelFolder = FALSE;
3451 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3453 TRACE("\n");
3455 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3457 LPITEMIDLIST pidlSelection;
3459 /* get the file selected */
3460 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3461 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3463 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3464 pidlSelection, SBSP_RELATIVE ) ) )
3466 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3467 ' ','n','o','t',' ','e','x','i','s','t',0};
3468 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3470 bBrowseSelFolder = TRUE;
3471 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3473 COMDLG32_SHFree( pidlSelection );
3476 return bBrowseSelFolder;
3480 * Memory allocation methods */
3481 static void *MemAlloc(UINT size)
3483 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3486 static void MemFree(void *mem)
3488 HeapFree(GetProcessHeap(),0,mem);
3492 * Old-style (win3.1) dialogs */
3494 /***********************************************************************
3495 * FD32_GetTemplate [internal]
3497 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3498 * by a 32 bits application
3501 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3503 LPOPENFILENAMEW ofnW = lfs->ofnW;
3504 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3505 HANDLE hDlgTmpl;
3507 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3509 if (!(lfs->template = LockResource( ofnW->hInstance )))
3511 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3512 return FALSE;
3515 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3517 HRSRC hResInfo;
3518 if (priv->ofnA)
3519 hResInfo = FindResourceA(priv->ofnA->hInstance,
3520 priv->ofnA->lpTemplateName,
3521 (LPSTR)RT_DIALOG);
3522 else
3523 hResInfo = FindResourceW(ofnW->hInstance,
3524 ofnW->lpTemplateName,
3525 (LPWSTR)RT_DIALOG);
3526 if (!hResInfo)
3528 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3529 return FALSE;
3531 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3532 hResInfo)) ||
3533 !(lfs->template = LockResource(hDlgTmpl)))
3535 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3536 return FALSE;
3538 } else { /* get it from internal Wine resource */
3539 HRSRC hResInfo;
3540 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3541 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3543 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3544 return FALSE;
3546 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3547 !(lfs->template = LockResource( hDlgTmpl )))
3549 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3550 return FALSE;
3553 return TRUE;
3557 /************************************************************************
3558 * FD32_Init [internal]
3559 * called from the common 16/32 code to initialize 32 bit data
3561 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3563 BOOL IsUnicode = (BOOL) data;
3564 PFD32_PRIVATE priv;
3566 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3567 lfs->private1632 = priv;
3568 if (NULL == lfs->private1632) return FALSE;
3569 if (IsUnicode)
3571 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3572 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3573 if (lfs->ofnW->lpfnHook)
3574 lfs->hook = TRUE;
3576 else
3578 priv->ofnA = (LPOPENFILENAMEA) lParam;
3579 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3580 if (priv->ofnA->lpfnHook)
3581 lfs->hook = TRUE;
3582 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3583 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3586 if (! FD32_GetTemplate(lfs)) return FALSE;
3588 return TRUE;
3591 /***********************************************************************
3592 * FD32_CallWindowProc [internal]
3594 * called from the common 16/32 code to call the appropriate hook
3596 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3597 LPARAM lParam)
3599 BOOL ret;
3600 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3602 if (priv->ofnA)
3604 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3605 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3606 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3607 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3608 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3609 return ret;
3612 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3613 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3614 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3615 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3616 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3617 return ret;
3620 /***********************************************************************
3621 * FD32_UpdateResult [internal]
3622 * update the real client structures if any
3624 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3626 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3627 LPOPENFILENAMEW ofnW = lfs->ofnW;
3629 if (priv->ofnA)
3631 LPSTR lpszTemp;
3632 if (ofnW->nMaxFile &&
3633 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3634 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3635 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3637 /* offsets are not guaranteed to be the same in WCHAR to MULTIBYTE conversion */
3638 /* set filename offset */
3639 lpszTemp = PathFindFileNameA(priv->ofnA->lpstrFile);
3640 priv->ofnA->nFileOffset = (lpszTemp - priv->ofnA->lpstrFile);
3642 /* set extension offset */
3643 lpszTemp = PathFindExtensionA(priv->ofnA->lpstrFile);
3644 priv->ofnA->nFileExtension = (*lpszTemp) ? (lpszTemp - priv->ofnA->lpstrFile) + 1 : 0;
3648 /***********************************************************************
3649 * FD32_UpdateFileTitle [internal]
3650 * update the real client structures if any
3652 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3654 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3655 LPOPENFILENAMEW ofnW = lfs->ofnW;
3657 if (priv->ofnA)
3659 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3660 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3661 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3666 /***********************************************************************
3667 * FD32_SendLbGetCurSel [internal]
3668 * retrieve selected listbox item
3670 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3672 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3676 /************************************************************************
3677 * FD32_Destroy [internal]
3678 * called from the common 16/32 code to cleanup 32 bit data
3680 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3682 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3684 /* if ofnW has been allocated, have to free everything in it */
3685 if (NULL != priv && NULL != priv->ofnA)
3687 FD31_FreeOfnW(lfs->ofnW);
3688 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3692 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3694 callbacks->Init = FD32_Init;
3695 callbacks->CWP = FD32_CallWindowProc;
3696 callbacks->UpdateResult = FD32_UpdateResult;
3697 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3698 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3699 callbacks->Destroy = FD32_Destroy;
3702 /***********************************************************************
3703 * FD32_WMMeasureItem [internal]
3705 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3707 LPMEASUREITEMSTRUCT lpmeasure;
3709 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3710 lpmeasure->itemHeight = FD31_GetFldrHeight();
3711 return TRUE;
3715 /***********************************************************************
3716 * FileOpenDlgProc [internal]
3717 * Used for open and save, in fact.
3719 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3720 WPARAM wParam, LPARAM lParam)
3722 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3724 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3725 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3727 INT_PTR lRet;
3728 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3729 if (lRet)
3730 return lRet; /* else continue message processing */
3732 switch (wMsg)
3734 case WM_INITDIALOG:
3735 return FD31_WMInitDialog(hWnd, wParam, lParam);
3737 case WM_MEASUREITEM:
3738 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3740 case WM_DRAWITEM:
3741 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3743 case WM_COMMAND:
3744 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3745 #if 0
3746 case WM_CTLCOLOR:
3747 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3748 switch (HIWORD(lParam))
3750 case CTLCOLOR_BTN:
3751 SetTextColor((HDC16)wParam, 0x00000000);
3752 return hGRAYBrush;
3753 case CTLCOLOR_STATIC:
3754 SetTextColor((HDC16)wParam, 0x00000000);
3755 return hGRAYBrush;
3757 break;
3758 #endif
3760 return FALSE;
3764 /***********************************************************************
3765 * GetFileName31A [internal]
3767 * Creates a win31 style dialog box for the user to select a file to open/save.
3769 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* address of structure with data*/
3770 UINT dlgType /* type dialogue : open/save */
3773 HINSTANCE hInst;
3774 BOOL bRet = FALSE;
3775 PFD31_DATA lfs;
3776 FD31_CALLBACKS callbacks;
3778 if (!lpofn || !FD31_Init()) return FALSE;
3780 TRACE("ofn flags %08x\n", lpofn->Flags);
3781 FD32_SetupCallbacks(&callbacks);
3782 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3783 if (lfs)
3785 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3786 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3787 FD32_FileOpenDlgProc, (LPARAM)lfs);
3788 FD31_DestroyPrivate(lfs);
3791 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3792 return bRet;
3795 /***********************************************************************
3796 * GetFileName31W [internal]
3798 * Creates a win31 style dialog box for the user to select a file to open/save
3800 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* address of structure with data*/
3801 UINT dlgType /* type dialogue : open/save */
3804 HINSTANCE hInst;
3805 BOOL bRet = FALSE;
3806 PFD31_DATA lfs;
3807 FD31_CALLBACKS callbacks;
3809 if (!lpofn || !FD31_Init()) return FALSE;
3811 FD32_SetupCallbacks(&callbacks);
3812 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3813 if (lfs)
3815 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3816 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3817 FD32_FileOpenDlgProc, (LPARAM)lfs);
3818 FD31_DestroyPrivate(lfs);
3821 TRACE("file %s, file offset %d, ext offset %d\n",
3822 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3823 return bRet;
3826 /* ------------------ APIs ---------------------- */
3828 /***********************************************************************
3829 * GetOpenFileNameA (COMDLG32.@)
3831 * Creates a dialog box for the user to select a file to open.
3833 * RETURNS
3834 * TRUE on success: user enters a valid file
3835 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3838 BOOL WINAPI GetOpenFileNameA(
3839 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3841 BOOL win16look = FALSE;
3843 TRACE("flags %08x\n", ofn->Flags);
3845 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3846 if (ofn->Flags & OFN_FILEMUSTEXIST)
3847 ofn->Flags |= OFN_PATHMUSTEXIST;
3849 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3850 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3852 if (win16look)
3853 return GetFileName31A(ofn, OPEN_DIALOG);
3854 else
3855 return GetFileDialog95A(ofn, OPEN_DIALOG);
3858 /***********************************************************************
3859 * GetOpenFileNameW (COMDLG32.@)
3861 * Creates a dialog box for the user to select a file to open.
3863 * RETURNS
3864 * TRUE on success: user enters a valid file
3865 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3868 BOOL WINAPI GetOpenFileNameW(
3869 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3871 BOOL win16look = FALSE;
3873 TRACE("flags %08x\n", ofn->Flags);
3875 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3876 if (ofn->Flags & OFN_FILEMUSTEXIST)
3877 ofn->Flags |= OFN_PATHMUSTEXIST;
3879 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3880 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3882 if (win16look)
3883 return GetFileName31W(ofn, OPEN_DIALOG);
3884 else
3885 return GetFileDialog95W(ofn, OPEN_DIALOG);
3889 /***********************************************************************
3890 * GetSaveFileNameA (COMDLG32.@)
3892 * Creates a dialog box for the user to select a file to save.
3894 * RETURNS
3895 * TRUE on success: user enters a valid file
3896 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3899 BOOL WINAPI GetSaveFileNameA(
3900 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3902 BOOL win16look = FALSE;
3904 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3905 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3907 if (win16look)
3908 return GetFileName31A(ofn, SAVE_DIALOG);
3909 else
3910 return GetFileDialog95A(ofn, SAVE_DIALOG);
3913 /***********************************************************************
3914 * GetSaveFileNameW (COMDLG32.@)
3916 * Creates a dialog box for the user to select a file to save.
3918 * RETURNS
3919 * TRUE on success: user enters a valid file
3920 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3923 BOOL WINAPI GetSaveFileNameW(
3924 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3926 BOOL win16look = FALSE;
3928 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3929 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3931 if (win16look)
3932 return GetFileName31W(ofn, SAVE_DIALOG);
3933 else
3934 return GetFileDialog95W(ofn, SAVE_DIALOG);
3937 /***********************************************************************
3938 * GetFileTitleA (COMDLG32.@)
3940 * See GetFileTitleW.
3942 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3944 int ret;
3945 UNICODE_STRING strWFile;
3946 LPWSTR lpWTitle;
3948 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3949 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3950 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3951 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3952 RtlFreeUnicodeString( &strWFile );
3953 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3954 return ret;
3958 /***********************************************************************
3959 * GetFileTitleW (COMDLG32.@)
3961 * Get the name of a file.
3963 * PARAMS
3964 * lpFile [I] name and location of file
3965 * lpTitle [O] returned file name
3966 * cbBuf [I] buffer size of lpTitle
3968 * RETURNS
3969 * Success: zero
3970 * Failure: negative number.
3972 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3974 int i, len;
3975 static const WCHAR brkpoint[] = {'*','[',']',0};
3976 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
3978 if(lpFile == NULL || lpTitle == NULL)
3979 return -1;
3981 len = lstrlenW(lpFile);
3983 if (len == 0)
3984 return -1;
3986 if(strpbrkW(lpFile, brkpoint))
3987 return -1;
3989 len--;
3991 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
3992 return -1;
3994 for(i = len; i >= 0; i--)
3996 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
3998 i++;
3999 break;
4003 if(i == -1)
4004 i++;
4006 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4008 len = lstrlenW(lpFile+i)+1;
4009 if(cbBuf < len)
4010 return len;
4012 lstrcpyW(lpTitle, &lpFile[i]);
4013 return 0;