push 97f44e0adb27fff75ba63d8fb97c65db9edfbe82
[wine/hacks.git] / dlls / comdlg32 / filedlg.c
blob67fefd1d141bdee5eb93a6a6ecd9c5fefb1c51f5
1 /*
2 * COMMDLG - File Open Dialogs Win95 look and feel
4 * Copyright 1999 Francois Boisvert
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * FIXME: The whole concept of handling unicode is badly broken.
22 * many hook-messages expect a pointer to a
23 * OPENFILENAMEA or W structure. With the current architecture
24 * we would have to convert the beast at every call to a hook.
25 * we have to find a better solution but it would likely cause
26 * a complete rewrite after which we should handle the
27 * OPENFILENAME structure without any converting (jsch).
29 * FIXME: any hook gets a OPENFILENAMEA structure
31 * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
33 * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
35 * FIXME: algorithm for selecting the initial directory is too simple
37 * FIXME: add to recent docs
39 * FIXME: flags not implemented: OFN_DONTADDTORECENT,
40 * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING,
41 * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
42 * OFN_NOTESTFILECREATE, OFN_USEMONIKERS
44 * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
49 #include "config.h"
50 #include "wine/port.h"
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <string.h>
58 #define COBJMACROS
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
62 #include "windef.h"
63 #include "winbase.h"
64 #include "winternl.h"
65 #include "winnls.h"
66 #include "wingdi.h"
67 #include "winreg.h"
68 #include "winuser.h"
69 #include "commdlg.h"
70 #include "dlgs.h"
71 #include "cdlg.h"
72 #include "filedlg31.h"
73 #include "cderr.h"
74 #include "shellapi.h"
75 #include "shlobj.h"
76 #include "filedlgbrowser.h"
77 #include "shlwapi.h"
79 #include "wine/unicode.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
84 #define UNIMPLEMENTED_FLAGS \
85 (OFN_DONTADDTORECENT |\
86 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
87 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
88 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
90 #define IsHooked(fodInfos) \
91 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
92 /***********************************************************************
93 * Data structure and global variables
95 typedef struct SFolder
97 int m_iImageIndex; /* Index of picture in image list */
98 HIMAGELIST hImgList;
99 int m_iIndent; /* Indentation index */
100 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
102 } SFOLDER,*LPSFOLDER;
104 typedef struct tagLookInInfo
106 int iMaxIndentation;
107 UINT uSelectedItem;
108 } LookInInfos;
110 typedef struct tagFD32_PRIVATE
112 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
113 } FD32_PRIVATE, *PFD32_PRIVATE;
116 /***********************************************************************
117 * Defines and global variables
120 /* Draw item constant */
121 #define ICONWIDTH 18
122 #define XTEXTOFFSET 3
124 /* AddItem flags*/
125 #define LISTEND -1
127 /* SearchItem methods */
128 #define SEARCH_PIDL 1
129 #define SEARCH_EXP 2
130 #define ITEM_NOTFOUND -1
132 /* Undefined windows message sent by CreateViewObject*/
133 #define WM_GETISHELLBROWSER WM_USER+7
135 /* NOTE
136 * Those macros exist in windowsx.h. However, you can't really use them since
137 * they rely on the UNICODE defines and can't be used inside Wine itself.
140 /* Combo box macros */
141 #define CBAddString(hwnd,str) \
142 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
144 #define CBInsertString(hwnd,str,pos) \
145 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
147 #define CBDeleteString(hwnd,pos) \
148 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
150 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
151 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
153 #define CBGetItemDataPtr(hwnd,iItemId) \
154 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
156 #define CBGetLBText(hwnd,iItemId,str) \
157 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
159 #define CBGetCurSel(hwnd) \
160 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
162 #define CBSetCurSel(hwnd,pos) \
163 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
165 #define CBGetCount(hwnd) \
166 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
167 #define CBShowDropDown(hwnd,show) \
168 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
169 #define CBSetItemHeight(hwnd,index,height) \
170 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
172 #define CBSetExtendedUI(hwnd,flag) \
173 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
175 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
176 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
178 /***********************************************************************
179 * Prototypes
182 /* Internal functions used by the dialog */
183 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
184 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
187 static BOOL FILEDLG95_OnOpen(HWND hwnd);
188 static LRESULT FILEDLG95_InitControls(HWND hwnd);
189 static void FILEDLG95_Clean(HWND hwnd);
191 /* Functions used by the shell navigation */
192 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
193 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
195 static void FILEDLG95_SHELL_Clean(HWND hwnd);
196 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
198 /* Functions used by the EDIT box */
199 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
201 /* Functions used by the filetype combo box */
202 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
203 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
204 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
205 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
207 /* Functions used by the Look In combo box */
208 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
209 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
210 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
211 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
212 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
213 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
214 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
215 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
216 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
218 /* Miscellaneous tool functions */
219 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
220 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
221 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
222 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
224 /* Shell memory allocation */
225 static void *MemAlloc(UINT size);
226 static void MemFree(void *mem);
228 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
229 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
231 static BOOL BrowseSelectedFolder(HWND hwnd);
233 /***********************************************************************
234 * GetFileName95
236 * Creates an Open common dialog box that lets the user select
237 * the drive, directory, and the name of a file or set of files to open.
239 * IN : The FileOpenDlgInfos structure associated with the dialog
240 * OUT : TRUE on success
241 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
243 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
246 LRESULT lRes;
247 LPCVOID template;
248 HRSRC hRes;
249 HANDLE hDlgTmpl = 0;
250 HRESULT hr;
252 /* test for missing functionality */
253 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
255 FIXME("Flags 0x%08x not yet implemented\n",
256 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
259 /* Create the dialog from a template */
261 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
263 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
264 return FALSE;
266 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
267 !(template = LockResource( hDlgTmpl )))
269 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
270 return FALSE;
273 /* old style hook messages */
274 if (IsHooked(fodInfos))
276 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
277 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
278 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
279 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
282 /* Some shell namespace extensions depend on COM being initialized. */
283 hr = OleInitialize(NULL);
285 if (fodInfos->unicode)
286 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
287 template,
288 fodInfos->ofnInfos->hwndOwner,
289 FileOpenDlgProc95,
290 (LPARAM) fodInfos);
291 else
292 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
293 (LPCDLGTEMPLATEA) template,
294 fodInfos->ofnInfos->hwndOwner,
295 FileOpenDlgProc95,
296 (LPARAM) fodInfos);
297 if (SUCCEEDED(hr))
298 OleUninitialize();
300 /* Unable to create the dialog */
301 if( lRes == -1)
302 return FALSE;
304 return lRes;
307 /***********************************************************************
308 * GetFileDialog95A
310 * Call GetFileName95 with this structure and clean the memory.
312 * IN : The OPENFILENAMEA initialisation structure passed to
313 * GetOpenFileNameA win api function (see filedlg.c)
315 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
317 BOOL ret;
318 FileOpenDlgInfos fodInfos;
319 LPSTR lpstrSavDir = NULL;
320 LPWSTR title = NULL;
321 LPWSTR defext = NULL;
322 LPWSTR filter = NULL;
323 LPWSTR customfilter = NULL;
325 /* Initialize CommDlgExtendedError() */
326 COMDLG32_SetCommDlgExtendedError(0);
328 /* Initialize FileOpenDlgInfos structure */
329 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
331 /* Pass in the original ofn */
332 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
334 /* save current directory */
335 if (ofn->Flags & OFN_NOCHANGEDIR)
337 lpstrSavDir = MemAlloc(MAX_PATH);
338 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
341 fodInfos.unicode = FALSE;
343 /* convert all the input strings to unicode */
344 if(ofn->lpstrInitialDir)
346 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
347 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
348 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
350 else
351 fodInfos.initdir = NULL;
353 if(ofn->lpstrFile)
355 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
356 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
358 else
359 fodInfos.filename = NULL;
361 if(ofn->lpstrDefExt)
363 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
364 defext = MemAlloc((len+1)*sizeof(WCHAR));
365 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
367 fodInfos.defext = defext;
369 if(ofn->lpstrTitle)
371 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
372 title = MemAlloc((len+1)*sizeof(WCHAR));
373 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
375 fodInfos.title = title;
377 if (ofn->lpstrFilter)
379 LPCSTR s;
380 int n, len;
382 /* filter is a list... title\0ext\0......\0\0 */
383 s = ofn->lpstrFilter;
384 while (*s) s = s+strlen(s)+1;
385 s++;
386 n = s - ofn->lpstrFilter;
387 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
388 filter = MemAlloc(len*sizeof(WCHAR));
389 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
391 fodInfos.filter = filter;
393 /* convert lpstrCustomFilter */
394 if (ofn->lpstrCustomFilter)
396 LPCSTR s;
397 int n, len;
399 /* customfilter contains a pair of strings... title\0ext\0 */
400 s = ofn->lpstrCustomFilter;
401 if (*s) s = s+strlen(s)+1;
402 if (*s) s = s+strlen(s)+1;
403 n = s - ofn->lpstrCustomFilter;
404 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
405 customfilter = MemAlloc(len*sizeof(WCHAR));
406 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
408 fodInfos.customfilter = customfilter;
410 /* Initialize the dialog property */
411 fodInfos.DlgInfos.dwDlgProp = 0;
412 fodInfos.DlgInfos.hwndCustomDlg = NULL;
414 switch(iDlgType)
416 case OPEN_DIALOG :
417 ret = GetFileName95(&fodInfos);
418 break;
419 case SAVE_DIALOG :
420 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
421 ret = GetFileName95(&fodInfos);
422 break;
423 default :
424 ret = 0;
427 if (lpstrSavDir)
429 SetCurrentDirectoryA(lpstrSavDir);
430 MemFree(lpstrSavDir);
433 MemFree(title);
434 MemFree(defext);
435 MemFree(filter);
436 MemFree(customfilter);
437 MemFree(fodInfos.initdir);
438 MemFree(fodInfos.filename);
440 TRACE("selected file: %s\n",ofn->lpstrFile);
442 return ret;
445 /***********************************************************************
446 * GetFileDialog95W
448 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
449 * Call GetFileName95 with this structure and clean the memory.
452 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
454 BOOL ret;
455 FileOpenDlgInfos fodInfos;
456 LPWSTR lpstrSavDir = NULL;
458 /* Initialize CommDlgExtendedError() */
459 COMDLG32_SetCommDlgExtendedError(0);
461 /* Initialize FileOpenDlgInfos structure */
462 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
464 /* Pass in the original ofn */
465 fodInfos.ofnInfos = ofn;
467 fodInfos.title = ofn->lpstrTitle;
468 fodInfos.defext = ofn->lpstrDefExt;
469 fodInfos.filter = ofn->lpstrFilter;
470 fodInfos.customfilter = ofn->lpstrCustomFilter;
472 /* convert string arguments, save others */
473 if(ofn->lpstrFile)
475 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
476 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
478 else
479 fodInfos.filename = NULL;
481 if(ofn->lpstrInitialDir)
483 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
484 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
485 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
486 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
488 else
489 fodInfos.initdir = NULL;
491 /* save current directory */
492 if (ofn->Flags & OFN_NOCHANGEDIR)
494 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
495 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
498 fodInfos.unicode = TRUE;
500 switch(iDlgType)
502 case OPEN_DIALOG :
503 ret = GetFileName95(&fodInfos);
504 break;
505 case SAVE_DIALOG :
506 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
507 ret = GetFileName95(&fodInfos);
508 break;
509 default :
510 ret = 0;
513 if (lpstrSavDir)
515 SetCurrentDirectoryW(lpstrSavDir);
516 MemFree(lpstrSavDir);
519 /* restore saved IN arguments and convert OUT arguments back */
520 MemFree(fodInfos.filename);
521 MemFree(fodInfos.initdir);
522 return ret;
525 /******************************************************************************
526 * COMDLG32_GetDisplayNameOf [internal]
528 * Helper function to get the display name for a pidl.
530 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
531 LPSHELLFOLDER psfDesktop;
532 STRRET strret;
534 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
535 return FALSE;
537 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
538 IShellFolder_Release(psfDesktop);
539 return FALSE;
542 IShellFolder_Release(psfDesktop);
543 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
546 /***********************************************************************
547 * ArrangeCtrlPositions [internal]
549 * NOTE: Do not change anything here without a lot of testing.
551 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
553 HWND hwndChild, hwndStc32;
554 RECT rectParent, rectChild, rectStc32;
555 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
557 /* Take into account if open as read only checkbox and help button
558 * are hidden
560 if (hide_help)
562 RECT rectHelp, rectCancel;
563 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
564 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
565 /* subtract the height of the help button plus the space between
566 * the help button and the cancel button to the height of the dialog
568 help_fixup = rectHelp.bottom - rectCancel.bottom;
572 There are two possibilities to add components to the default file dialog box.
574 By default, all the new components are added below the standard dialog box (the else case).
576 However, if there is a static text component with the stc32 id, a special case happens.
577 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
578 in the window and the cx and cy indicate how to size the window.
579 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
580 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
584 GetClientRect(hwndParentDlg, &rectParent);
586 /* when arranging controls we have to use fixed parent size */
587 rectParent.bottom -= help_fixup;
589 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
590 if (hwndStc32)
592 GetWindowRect(hwndStc32, &rectStc32);
593 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
595 /* set the size of the stc32 control according to the size of
596 * client area of the parent dialog
598 SetWindowPos(hwndStc32, 0,
599 0, 0,
600 rectParent.right, rectParent.bottom,
601 SWP_NOMOVE | SWP_NOZORDER);
603 else
604 SetRectEmpty(&rectStc32);
606 /* this part moves controls of the child dialog */
607 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
608 while (hwndChild)
610 if (hwndChild != hwndStc32)
612 GetWindowRect(hwndChild, &rectChild);
613 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
615 /* move only if stc32 exist */
616 if (hwndStc32 && rectChild.left > rectStc32.right)
618 LONG old_left = rectChild.left;
620 /* move to the right of visible controls of the parent dialog */
621 rectChild.left += rectParent.right;
622 rectChild.left -= rectStc32.right;
624 child_width_fixup = rectChild.left - old_left;
626 /* move even if stc32 doesn't exist */
627 if (rectChild.top >= rectStc32.bottom)
629 LONG old_top = rectChild.top;
631 /* move below visible controls of the parent dialog */
632 rectChild.top += rectParent.bottom;
633 rectChild.top -= rectStc32.bottom - rectStc32.top;
635 child_height_fixup = rectChild.top - old_top;
638 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
639 0, 0, SWP_NOSIZE | SWP_NOZORDER);
641 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
644 /* this part moves controls of the parent dialog */
645 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
646 while (hwndChild)
648 if (hwndChild != hwndChildDlg)
650 GetWindowRect(hwndChild, &rectChild);
651 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
653 /* left,top of stc32 marks the position of controls
654 * from the parent dialog
656 rectChild.left += rectStc32.left;
657 rectChild.top += rectStc32.top;
659 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
660 0, 0, SWP_NOSIZE | SWP_NOZORDER);
662 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
665 /* calculate the size of the resulting dialog */
667 /* here we have to use original parent size */
668 GetClientRect(hwndParentDlg, &rectParent);
669 GetClientRect(hwndChildDlg, &rectChild);
671 if (hwndStc32)
673 rectChild.right += child_width_fixup;
674 rectChild.bottom += child_height_fixup;
676 if (rectParent.right > rectChild.right)
678 rectParent.right += rectChild.right;
679 rectParent.right -= rectStc32.right - rectStc32.left;
681 else
683 rectParent.right = rectChild.right;
686 if (rectParent.bottom > rectChild.bottom)
688 rectParent.bottom += rectChild.bottom;
689 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
691 else
693 /* child dialog is higher, unconditionally set new dialog
694 * height to its size (help_fixup will be subtracted below)
696 rectParent.bottom = rectChild.bottom + help_fixup;
699 else
701 rectParent.bottom += rectChild.bottom;
704 /* finally use fixed parent size */
705 rectParent.bottom -= help_fixup;
707 /* set the size of the parent dialog */
708 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
709 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
710 SetWindowPos(hwndParentDlg, 0,
711 0, 0,
712 rectParent.right - rectParent.left,
713 rectParent.bottom - rectParent.top,
714 SWP_NOMOVE | SWP_NOZORDER);
717 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
719 switch(uMsg) {
720 case WM_INITDIALOG:
721 return TRUE;
723 return FALSE;
726 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
728 LPCVOID template;
729 HRSRC hRes;
730 HANDLE hDlgTmpl = 0;
731 HWND hChildDlg = 0;
733 TRACE("\n");
736 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
737 * structure's hInstance parameter is not a HINSTANCE, but
738 * instead a pointer to a template resource to use.
740 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
742 HINSTANCE hinst;
743 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
745 hinst = COMDLG32_hInstance;
746 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
748 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
749 return NULL;
752 else
754 hinst = fodInfos->ofnInfos->hInstance;
755 if(fodInfos->unicode)
757 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
758 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
760 else
762 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
763 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
765 if (!hRes)
767 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
768 return NULL;
770 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
771 !(template = LockResource( hDlgTmpl )))
773 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
774 return NULL;
777 if (fodInfos->unicode)
778 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
779 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
780 (LPARAM)fodInfos->ofnInfos);
781 else
782 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
783 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
784 (LPARAM)fodInfos->ofnInfos);
785 if(hChildDlg)
787 ShowWindow(hChildDlg,SW_SHOW);
788 return hChildDlg;
791 else if( IsHooked(fodInfos))
793 RECT rectHwnd;
794 struct {
795 DLGTEMPLATE tmplate;
796 WORD menu,class,title;
797 } temp;
798 GetClientRect(hwnd,&rectHwnd);
799 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
800 temp.tmplate.dwExtendedStyle = 0;
801 temp.tmplate.cdit = 0;
802 temp.tmplate.x = 0;
803 temp.tmplate.y = 0;
804 temp.tmplate.cx = 0;
805 temp.tmplate.cy = 0;
806 temp.menu = temp.class = temp.title = 0;
808 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
809 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
811 return hChildDlg;
813 return NULL;
816 /***********************************************************************
817 * SendCustomDlgNotificationMessage
819 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
822 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
824 LRESULT hook_result = 0;
826 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
828 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
830 if(!fodInfos) return 0;
832 if(fodInfos->DlgInfos.hwndCustomDlg)
834 TRACE("CALL NOTIFY for %x\n", uCode);
835 if(fodInfos->unicode)
837 OFNOTIFYW ofnNotify;
838 ofnNotify.hdr.hwndFrom=hwndParentDlg;
839 ofnNotify.hdr.idFrom=0;
840 ofnNotify.hdr.code = uCode;
841 ofnNotify.lpOFN = fodInfos->ofnInfos;
842 ofnNotify.pszFile = NULL;
843 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
845 else
847 OFNOTIFYA ofnNotify;
848 ofnNotify.hdr.hwndFrom=hwndParentDlg;
849 ofnNotify.hdr.idFrom=0;
850 ofnNotify.hdr.code = uCode;
851 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
852 ofnNotify.pszFile = NULL;
853 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
855 TRACE("RET NOTIFY\n");
857 TRACE("Retval: 0x%08lx\n", hook_result);
858 return hook_result;
861 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
863 UINT sizeUsed = 0, n, total;
864 LPWSTR lpstrFileList = NULL;
865 WCHAR lpstrCurrentDir[MAX_PATH];
866 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
868 TRACE("CDM_GETFILEPATH:\n");
870 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
871 return -1;
873 /* get path and filenames */
874 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
875 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
877 TRACE("path >%s< filespec >%s< %d files\n",
878 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
880 if( fodInfos->unicode )
882 LPWSTR bufW = buffer;
883 total = lstrlenW(lpstrCurrentDir) + 1 + sizeUsed;
885 /* Prepend the current path */
886 n = lstrlenW(lpstrCurrentDir) + 1;
887 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
888 if(n<size)
890 /* 'n' includes trailing \0 */
891 bufW[n-1] = '\\';
892 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
894 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
896 else
898 LPSTR bufA = buffer;
899 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
900 NULL, 0, NULL, NULL);
901 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
902 NULL, 0, NULL, NULL);
904 /* Prepend the current path */
905 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
906 bufA, size, NULL, NULL);
908 if(n<size)
910 /* 'n' includes trailing \0 */
911 bufA[n-1] = '\\';
912 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
913 &bufA[n], size-n, NULL, NULL);
916 TRACE("returned -> %s\n",debugstr_an(bufA, total));
918 MemFree(lpstrFileList);
920 return total;
923 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
925 UINT sizeUsed = 0;
926 LPWSTR lpstrFileList = NULL;
927 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
929 TRACE("CDM_GETSPEC:\n");
931 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
932 if( fodInfos->unicode )
934 LPWSTR bufW = buffer;
935 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
937 else
939 LPSTR bufA = buffer;
940 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
941 NULL, 0, NULL, NULL);
942 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
943 bufA, size, NULL, NULL);
945 MemFree(lpstrFileList);
947 return sizeUsed;
950 /***********************************************************************
951 * FILEDLG95_HandleCustomDialogMessages
953 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
955 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
957 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
958 WCHAR lpstrPath[MAX_PATH];
959 INT_PTR retval;
961 if(!fodInfos) return FALSE;
963 switch(uMsg)
965 case CDM_GETFILEPATH:
966 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
967 break;
969 case CDM_GETFOLDERPATH:
970 TRACE("CDM_GETFOLDERPATH:\n");
971 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
972 if (lParam)
974 if (fodInfos->unicode)
975 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
976 else
977 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
978 (LPSTR)lParam, (int)wParam, NULL, NULL);
980 retval = lstrlenW(lpstrPath);
981 break;
983 case CDM_GETSPEC:
984 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
985 break;
987 case CDM_SETCONTROLTEXT:
988 TRACE("CDM_SETCONTROLTEXT:\n");
989 if ( lParam )
991 if( fodInfos->unicode )
992 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
993 else
994 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
996 retval = TRUE;
997 break;
999 case CDM_HIDECONTROL:
1000 /* MSDN states that it should fail for not OFN_EXPLORER case */
1001 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1003 HWND control = GetDlgItem( hwnd, wParam );
1004 if (control) ShowWindow( control, SW_HIDE );
1005 retval = TRUE;
1007 else retval = FALSE;
1008 break;
1010 default:
1011 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1012 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1013 return FALSE;
1015 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1016 return TRUE;
1019 /***********************************************************************
1020 * FileOpenDlgProc95
1022 * File open dialog procedure
1024 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1026 #if 0
1027 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1028 #endif
1030 switch(uMsg)
1032 case WM_INITDIALOG:
1034 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1036 /* Adds the FileOpenDlgInfos in the property list of the dialog
1037 so it will be easily accessible through a GetPropA(...) */
1038 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1040 FILEDLG95_InitControls(hwnd);
1042 fodInfos->DlgInfos.hwndCustomDlg =
1043 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1045 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1046 FILEDLG95_FillControls(hwnd, wParam, lParam);
1048 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1049 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1050 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1051 return 0;
1053 case WM_COMMAND:
1054 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1055 case WM_DRAWITEM:
1057 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1059 case IDC_LOOKIN:
1060 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1061 return TRUE;
1064 return FALSE;
1066 case WM_GETISHELLBROWSER:
1067 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1069 case WM_DESTROY:
1070 RemovePropA(hwnd, FileOpenDlgInfosStr);
1071 return FALSE;
1073 case WM_NOTIFY:
1075 LPNMHDR lpnmh = (LPNMHDR)lParam;
1076 UINT stringId = -1;
1078 /* set up the button tooltips strings */
1079 if(TTN_GETDISPINFOA == lpnmh->code )
1081 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1082 switch(lpnmh->idFrom )
1084 /* Up folder button */
1085 case FCIDM_TB_UPFOLDER:
1086 stringId = IDS_UPFOLDER;
1087 break;
1088 /* New folder button */
1089 case FCIDM_TB_NEWFOLDER:
1090 stringId = IDS_NEWFOLDER;
1091 break;
1092 /* List option button */
1093 case FCIDM_TB_SMALLICON:
1094 stringId = IDS_LISTVIEW;
1095 break;
1096 /* Details option button */
1097 case FCIDM_TB_REPORTVIEW:
1098 stringId = IDS_REPORTVIEW;
1099 break;
1100 /* Desktop button */
1101 case FCIDM_TB_DESKTOP:
1102 stringId = IDS_TODESKTOP;
1103 break;
1104 default:
1105 stringId = 0;
1107 lpdi->hinst = COMDLG32_hInstance;
1108 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1110 return FALSE;
1112 default :
1113 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1114 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1115 return FALSE;
1119 /***********************************************************************
1120 * FILEDLG95_InitControls
1122 * WM_INITDIALOG message handler (before hook notification)
1124 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1126 int win2000plus = 0;
1127 int win98plus = 0;
1128 int handledPath = FALSE;
1129 OSVERSIONINFOW osVi;
1130 static const WCHAR szwSlash[] = { '\\', 0 };
1131 static const WCHAR szwStar[] = { '*',0 };
1133 static const TBBUTTON tbb[] =
1135 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1136 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1137 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1138 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1139 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1140 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1141 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1142 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1143 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1145 TBADDBITMAP tba[2];
1146 RECT rectTB;
1147 RECT rectlook;
1148 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1150 tba[0].hInst = HINST_COMMCTRL;
1151 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1152 tba[1].hInst = COMDLG32_hInstance;
1153 tba[1].nID = 800;
1155 TRACE("%p\n", fodInfos);
1157 /* Get windows version emulating */
1158 osVi.dwOSVersionInfoSize = sizeof(osVi);
1159 GetVersionExW(&osVi);
1160 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1161 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1162 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1163 win2000plus = (osVi.dwMajorVersion > 4);
1164 if (win2000plus) win98plus = TRUE;
1166 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1168 /* Get the hwnd of the controls */
1169 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1170 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1171 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1173 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1174 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1176 /* construct the toolbar */
1177 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1178 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1180 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1181 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1182 rectTB.left = rectlook.right;
1183 rectTB.top = rectlook.top-1;
1185 if (fodInfos->unicode)
1186 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1187 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1188 rectTB.left, rectTB.top,
1189 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1190 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1191 else
1192 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1193 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1194 rectTB.left, rectTB.top,
1195 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1196 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1198 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1200 /* FIXME: use TB_LOADIMAGES when implemented */
1201 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1202 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1203 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1205 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1206 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1208 /* Set the window text with the text specified in the OPENFILENAME structure */
1209 if(fodInfos->title)
1211 SetWindowTextW(hwnd,fodInfos->title);
1213 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1215 WCHAR buf[16];
1216 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1217 SetWindowTextW(hwnd, buf);
1220 /* Initialise the file name edit control */
1221 handledPath = FALSE;
1222 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1224 if(fodInfos->filename)
1226 /* 1. If win2000 or higher and filename contains a path, use it
1227 in preference over the lpstrInitialDir */
1228 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1229 WCHAR tmpBuf[MAX_PATH];
1230 WCHAR *nameBit;
1231 DWORD result;
1233 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1234 if (result) {
1236 /* nameBit is always shorter than the original filename */
1237 lstrcpyW(fodInfos->filename,nameBit);
1239 *nameBit = 0x00;
1240 if (fodInfos->initdir == NULL)
1241 MemFree(fodInfos->initdir);
1242 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1243 lstrcpyW(fodInfos->initdir, tmpBuf);
1244 handledPath = TRUE;
1245 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1246 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1248 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1250 } else {
1251 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1255 /* 2. (All platforms) If initdir is not null, then use it */
1256 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1257 (*fodInfos->initdir!=0x00))
1259 /* Work out the proper path as supplied one might be relative */
1260 /* (Here because supplying '.' as dir browses to My Computer) */
1261 if (handledPath==FALSE) {
1262 WCHAR tmpBuf[MAX_PATH];
1263 WCHAR tmpBuf2[MAX_PATH];
1264 WCHAR *nameBit;
1265 DWORD result;
1267 lstrcpyW(tmpBuf, fodInfos->initdir);
1268 if( PathFileExistsW(tmpBuf) ) {
1269 /* initdir does not have to be a directory. If a file is
1270 * specified, the dir part is taken */
1271 if( PathIsDirectoryW(tmpBuf)) {
1272 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1273 lstrcatW(tmpBuf, szwSlash);
1275 lstrcatW(tmpBuf, szwStar);
1277 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1278 if (result) {
1279 *nameBit = 0x00;
1280 MemFree(fodInfos->initdir);
1281 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1282 lstrcpyW(fodInfos->initdir, tmpBuf2);
1283 handledPath = TRUE;
1284 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1287 else if (fodInfos->initdir)
1289 MemFree(fodInfos->initdir);
1290 fodInfos->initdir = NULL;
1291 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1296 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1297 (*fodInfos->initdir==0x00)))
1299 /* 3. All except w2k+: if filename contains a path use it */
1300 if (!win2000plus && fodInfos->filename &&
1301 *fodInfos->filename &&
1302 strpbrkW(fodInfos->filename, szwSlash)) {
1303 WCHAR tmpBuf[MAX_PATH];
1304 WCHAR *nameBit;
1305 DWORD result;
1307 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1308 tmpBuf, &nameBit);
1309 if (result) {
1310 int len;
1312 /* nameBit is always shorter than the original filename */
1313 lstrcpyW(fodInfos->filename, nameBit);
1314 *nameBit = 0x00;
1316 len = lstrlenW(tmpBuf);
1317 MemFree(fodInfos->initdir);
1318 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1319 lstrcpyW(fodInfos->initdir, tmpBuf);
1321 handledPath = TRUE;
1322 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1323 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1325 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1328 /* 4. win98+ and win2000+ if any files of specified filter types in
1329 current directory, use it */
1330 if ( win98plus && handledPath == FALSE &&
1331 fodInfos->filter && *fodInfos->filter) {
1333 BOOL searchMore = TRUE;
1334 LPCWSTR lpstrPos = fodInfos->filter;
1335 WIN32_FIND_DATAW FindFileData;
1336 HANDLE hFind;
1338 while (searchMore)
1340 /* filter is a list... title\0ext\0......\0\0 */
1342 /* Skip the title */
1343 if(! *lpstrPos) break; /* end */
1344 lpstrPos += lstrlenW(lpstrPos) + 1;
1346 /* See if any files exist in the current dir with this extension */
1347 if(! *lpstrPos) break; /* end */
1349 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1351 if (hFind == INVALID_HANDLE_VALUE) {
1352 /* None found - continue search */
1353 lpstrPos += lstrlenW(lpstrPos) + 1;
1355 } else {
1356 searchMore = FALSE;
1358 MemFree(fodInfos->initdir);
1359 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1360 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1362 handledPath = TRUE;
1363 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1364 debugstr_w(lpstrPos));
1365 break;
1370 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1372 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1373 if (handledPath == FALSE && (win2000plus || win98plus)) {
1374 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1376 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1378 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1380 /* last fallback */
1381 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1382 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1383 } else {
1384 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1386 } else {
1387 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1389 handledPath = TRUE;
1390 } else if (handledPath==FALSE) {
1391 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1392 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1393 handledPath = TRUE;
1394 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1397 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1398 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1400 /* Must the open as read only check box be checked ?*/
1401 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1403 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1406 /* Must the open as read only check box be hidden? */
1407 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1409 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1410 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1413 /* Must the help button be hidden? */
1414 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1416 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1417 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1420 /* change Open to Save */
1421 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1423 WCHAR buf[16];
1424 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1425 SetDlgItemTextW(hwnd, IDOK, buf);
1426 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1427 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1429 return 0;
1432 /***********************************************************************
1433 * FILEDLG95_ResizeControls
1435 * WM_INITDIALOG message handler (after hook notification)
1437 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1439 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1441 if (fodInfos->DlgInfos.hwndCustomDlg)
1443 RECT rc;
1444 UINT flags = SWP_NOACTIVATE;
1446 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1447 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1449 /* resize the custom dialog to the parent size */
1450 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1451 GetClientRect(hwnd, &rc);
1452 else
1454 /* our own fake template is zero sized and doesn't have children, so
1455 * there is no need to resize it. Picasa depends on it.
1457 flags |= SWP_NOSIZE;
1458 SetRectEmpty(&rc);
1460 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1461 0, 0, rc.right, rc.bottom, flags);
1463 else
1465 /* Resize the height, if open as read only checkbox ad help button are
1466 * hidden and we are not using a custom template nor a customDialog
1468 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1469 (!(fodInfos->ofnInfos->Flags &
1470 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1472 RECT rectDlg, rectHelp, rectCancel;
1473 GetWindowRect(hwnd, &rectDlg);
1474 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1475 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1476 /* subtract the height of the help button plus the space between the help
1477 * button and the cancel button to the height of the dialog
1479 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1480 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1481 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1484 return TRUE;
1487 /***********************************************************************
1488 * FILEDLG95_FillControls
1490 * WM_INITDIALOG message handler (after hook notification)
1492 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1494 LPITEMIDLIST pidlItemId = NULL;
1496 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1498 TRACE("dir=%s file=%s\n",
1499 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1501 /* Get the initial directory pidl */
1503 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1505 WCHAR path[MAX_PATH];
1507 GetCurrentDirectoryW(MAX_PATH,path);
1508 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1511 /* Initialise shell objects */
1512 FILEDLG95_SHELL_Init(hwnd);
1514 /* Initialize the Look In combo box */
1515 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1517 /* Initialize the filter combo box */
1518 FILEDLG95_FILETYPE_Init(hwnd);
1520 /* Browse to the initial directory */
1521 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1523 /* Free pidlItem memory */
1524 COMDLG32_SHFree(pidlItemId);
1526 return TRUE;
1528 /***********************************************************************
1529 * FILEDLG95_Clean
1531 * Regroups all the cleaning functions of the filedlg
1533 void FILEDLG95_Clean(HWND hwnd)
1535 FILEDLG95_FILETYPE_Clean(hwnd);
1536 FILEDLG95_LOOKIN_Clean(hwnd);
1537 FILEDLG95_SHELL_Clean(hwnd);
1539 /***********************************************************************
1540 * FILEDLG95_OnWMCommand
1542 * WM_COMMAND message handler
1544 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1546 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1547 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1548 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1550 switch(wID)
1552 /* OK button */
1553 case IDOK:
1554 FILEDLG95_OnOpen(hwnd);
1555 break;
1556 /* Cancel button */
1557 case IDCANCEL:
1558 FILEDLG95_Clean(hwnd);
1559 EndDialog(hwnd, FALSE);
1560 break;
1561 /* Filetype combo box */
1562 case IDC_FILETYPE:
1563 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1564 break;
1565 /* LookIn combo box */
1566 case IDC_LOOKIN:
1567 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1568 break;
1570 /* --- toolbar --- */
1571 /* Up folder button */
1572 case FCIDM_TB_UPFOLDER:
1573 FILEDLG95_SHELL_UpFolder(hwnd);
1574 break;
1575 /* New folder button */
1576 case FCIDM_TB_NEWFOLDER:
1577 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1578 break;
1579 /* List option button */
1580 case FCIDM_TB_SMALLICON:
1581 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1582 break;
1583 /* Details option button */
1584 case FCIDM_TB_REPORTVIEW:
1585 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1586 break;
1587 /* Details option button */
1588 case FCIDM_TB_DESKTOP:
1589 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1590 break;
1592 case IDC_FILENAME:
1593 break;
1596 /* Do not use the listview selection anymore */
1597 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1598 return 0;
1601 /***********************************************************************
1602 * FILEDLG95_OnWMGetIShellBrowser
1604 * WM_GETISHELLBROWSER message handler
1606 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1609 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1611 TRACE("\n");
1613 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1615 return TRUE;
1619 /***********************************************************************
1620 * FILEDLG95_SendFileOK
1622 * Sends the CDN_FILEOK notification if required
1624 * RETURNS
1625 * TRUE if the dialog should close
1626 * FALSE if the dialog should not be closed
1628 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1630 /* ask the hook if we can close */
1631 if(IsHooked(fodInfos))
1633 LRESULT retval;
1635 TRACE("---\n");
1636 /* First send CDN_FILEOK as MSDN doc says */
1637 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1638 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1640 TRACE("canceled\n");
1641 return (retval == 0);
1644 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1645 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1646 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1647 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1649 TRACE("canceled\n");
1650 return (retval == 0);
1653 return TRUE;
1656 /***********************************************************************
1657 * FILEDLG95_OnOpenMultipleFiles
1659 * Handles the opening of multiple files.
1661 * FIXME
1662 * check destination buffer size
1664 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1666 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1667 UINT nCount, nSizePath;
1668 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1670 TRACE("\n");
1672 if(fodInfos->unicode)
1674 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1675 ofn->lpstrFile[0] = '\0';
1677 else
1679 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1680 ofn->lpstrFile[0] = '\0';
1683 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1685 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1686 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1687 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1689 LPWSTR lpstrTemp = lpstrFileList;
1691 for ( nCount = 0; nCount < nFileCount; nCount++ )
1693 LPITEMIDLIST pidl;
1695 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1696 if (!pidl)
1698 WCHAR lpstrNotFound[100];
1699 WCHAR lpstrMsg[100];
1700 WCHAR tmp[400];
1701 static const WCHAR nl[] = {'\n',0};
1703 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1704 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1706 lstrcpyW(tmp, lpstrTemp);
1707 lstrcatW(tmp, nl);
1708 lstrcatW(tmp, lpstrNotFound);
1709 lstrcatW(tmp, nl);
1710 lstrcatW(tmp, lpstrMsg);
1712 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1713 return FALSE;
1716 /* move to the next file in the list of files */
1717 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1718 COMDLG32_SHFree(pidl);
1722 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1723 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1725 /* For "oldstyle" dialog the components have to
1726 be separated by blanks (not '\0'!) and short
1727 filenames have to be used! */
1728 FIXME("Components have to be separated by blanks\n");
1730 if(fodInfos->unicode)
1732 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1733 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1734 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1736 else
1738 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1740 if (ofn->lpstrFile != NULL)
1742 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1743 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1744 if (ofn->nMaxFile > nSizePath)
1746 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1747 ofn->lpstrFile + nSizePath,
1748 ofn->nMaxFile - nSizePath, NULL, NULL);
1753 fodInfos->ofnInfos->nFileOffset = nSizePath;
1754 fodInfos->ofnInfos->nFileExtension = 0;
1756 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1757 return FALSE;
1759 /* clean and exit */
1760 FILEDLG95_Clean(hwnd);
1761 return EndDialog(hwnd,TRUE);
1764 /***********************************************************************
1765 * FILEDLG95_OnOpen
1767 * Ok button WM_COMMAND message handler
1769 * If the function succeeds, the return value is nonzero.
1771 #define ONOPEN_BROWSE 1
1772 #define ONOPEN_OPEN 2
1773 #define ONOPEN_SEARCH 3
1774 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1776 WCHAR strMsgTitle[MAX_PATH];
1777 WCHAR strMsgText [MAX_PATH];
1778 if (idCaption)
1779 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1780 else
1781 strMsgTitle[0] = '\0';
1782 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1783 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1786 BOOL FILEDLG95_OnOpen(HWND hwnd)
1788 LPWSTR lpstrFileList;
1789 UINT nFileCount = 0;
1790 UINT sizeUsed = 0;
1791 BOOL ret = TRUE;
1792 WCHAR lpstrPathAndFile[MAX_PATH];
1793 WCHAR lpstrTemp[MAX_PATH];
1794 LPSHELLFOLDER lpsf = NULL;
1795 int nOpenAction;
1796 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1798 TRACE("hwnd=%p\n", hwnd);
1800 /* get the files from the edit control */
1801 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1803 /* try if the user selected a folder in the shellview */
1804 if(nFileCount == 0)
1806 BrowseSelectedFolder(hwnd);
1807 return FALSE;
1810 if(nFileCount > 1)
1812 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1813 goto ret;
1816 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1819 Step 1: Build a complete path name from the current folder and
1820 the filename or path in the edit box.
1821 Special cases:
1822 - the path in the edit box is a root path
1823 (with or without drive letter)
1824 - the edit box contains ".." (or a path with ".." in it)
1827 /* Get the current directory name */
1828 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1830 /* last fallback */
1831 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1833 PathAddBackslashW(lpstrPathAndFile);
1835 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1837 /* if the user specifyed a fully qualified path use it */
1838 if(PathIsRelativeW(lpstrFileList))
1840 lstrcatW(lpstrPathAndFile, lpstrFileList);
1842 else
1844 /* does the path have a drive letter? */
1845 if (PathGetDriveNumberW(lpstrFileList) == -1)
1846 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1847 else
1848 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1851 /* resolve "." and ".." */
1852 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1853 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1854 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1856 MemFree(lpstrFileList);
1859 Step 2: here we have a cleaned up path
1861 We have to parse the path step by step to see if we have to browse
1862 to a folder if the path points to a directory or the last
1863 valid element is a directory.
1865 valid variables:
1866 lpstrPathAndFile: cleaned up path
1869 if (nFileCount &&
1870 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1871 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1872 nOpenAction = ONOPEN_OPEN;
1873 else
1874 nOpenAction = ONOPEN_BROWSE;
1876 /* don't apply any checks with OFN_NOVALIDATE */
1878 LPWSTR lpszTemp, lpszTemp1;
1879 LPITEMIDLIST pidl = NULL;
1880 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1882 /* check for invalid chars */
1883 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1885 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1886 ret = FALSE;
1887 goto ret;
1890 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1892 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1893 while (lpszTemp1)
1895 LPSHELLFOLDER lpsfChild;
1896 WCHAR lpwstrTemp[MAX_PATH];
1897 DWORD dwEaten, dwAttributes;
1898 LPWSTR p;
1900 lstrcpyW(lpwstrTemp, lpszTemp);
1901 p = PathFindNextComponentW(lpwstrTemp);
1903 if (!p) break; /* end of path */
1905 *p = 0;
1906 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1908 /* There are no wildcards when OFN_NOVALIDATE is set */
1909 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1911 static const WCHAR wszWild[] = { '*', '?', 0 };
1912 /* if the last element is a wildcard do a search */
1913 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1915 nOpenAction = ONOPEN_SEARCH;
1916 break;
1919 lpszTemp1 = lpszTemp;
1921 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1923 /* append a backslash to drive letters */
1924 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1925 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1926 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1928 PathAddBackslashW(lpwstrTemp);
1931 dwAttributes = SFGAO_FOLDER;
1932 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1934 /* the path component is valid, we have a pidl of the next path component */
1935 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1936 if(dwAttributes & SFGAO_FOLDER)
1938 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1940 ERR("bind to failed\n"); /* should not fail */
1941 break;
1943 IShellFolder_Release(lpsf);
1944 lpsf = lpsfChild;
1945 lpsfChild = NULL;
1947 else
1949 TRACE("value\n");
1951 /* end dialog, return value */
1952 nOpenAction = ONOPEN_OPEN;
1953 break;
1955 COMDLG32_SHFree(pidl);
1956 pidl = NULL;
1958 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1960 if(*lpszTemp || /* points to trailing null for last path element */
1961 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1963 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1965 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1966 break;
1969 else
1971 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1972 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1974 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1975 break;
1978 /* change to the current folder */
1979 nOpenAction = ONOPEN_OPEN;
1980 break;
1982 else
1984 nOpenAction = ONOPEN_OPEN;
1985 break;
1988 if(pidl) COMDLG32_SHFree(pidl);
1992 Step 3: here we have a cleaned up and validated path
1994 valid variables:
1995 lpsf: ShellFolder bound to the rightmost valid path component
1996 lpstrPathAndFile: cleaned up path
1997 nOpenAction: action to do
1999 TRACE("end validate sf=%p\n", lpsf);
2001 switch(nOpenAction)
2003 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2004 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2006 int iPos;
2007 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2008 DWORD len;
2010 /* replace the current filter */
2011 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2012 len = lstrlenW(lpszTemp)+1;
2013 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2014 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2016 /* set the filter cb to the extension when possible */
2017 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2018 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2020 /* fall through */
2021 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2022 TRACE("ONOPEN_BROWSE\n");
2024 IPersistFolder2 * ppf2;
2025 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2027 LPITEMIDLIST pidlCurrent;
2028 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2029 IPersistFolder2_Release(ppf2);
2030 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2032 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2034 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2037 else if( nOpenAction == ONOPEN_SEARCH )
2039 if (fodInfos->Shell.FOIShellView)
2040 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2042 COMDLG32_SHFree(pidlCurrent);
2043 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2046 ret = FALSE;
2047 break;
2048 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2049 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2051 WCHAR *ext = NULL;
2053 /* update READONLY check box flag */
2054 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2055 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2056 else
2057 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2059 /* Attach the file extension with file name*/
2060 ext = PathFindExtensionW(lpstrPathAndFile);
2061 if (! *ext)
2063 /* if no extension is specified with file name, then */
2064 /* attach the extension from file filter or default one */
2066 WCHAR *filterExt = NULL;
2067 LPWSTR lpstrFilter = NULL;
2068 static const WCHAR szwDot[] = {'.',0};
2069 int PathLength = lstrlenW(lpstrPathAndFile);
2071 /* Attach the dot*/
2072 lstrcatW(lpstrPathAndFile, szwDot);
2074 /*Get the file extension from file type filter*/
2075 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2076 fodInfos->ofnInfos->nFilterIndex-1);
2078 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2079 filterExt = PathFindExtensionW(lpstrFilter);
2081 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2082 lstrcatW(lpstrPathAndFile, filterExt + 1);
2083 else if ( fodInfos->defext ) /* attach the default file extension*/
2084 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2086 /* In Open dialog: if file does not exist try without extension */
2087 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2088 lpstrPathAndFile[PathLength] = '\0';
2091 if (fodInfos->defext) /* add default extension */
2093 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2094 if (*ext)
2095 ext++;
2096 if (!lstrcmpiW(fodInfos->defext, ext))
2097 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2098 else
2099 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2102 /* In Save dialog: check if the file already exists */
2103 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2104 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2105 && PathFileExistsW(lpstrPathAndFile))
2107 WCHAR lpstrOverwrite[100];
2108 int answer;
2110 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2111 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2112 MB_YESNO | MB_ICONEXCLAMATION);
2113 if (answer == IDNO)
2115 ret = FALSE;
2116 goto ret;
2120 /* In Open dialog: check if it should be created if it doesn't exist */
2121 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2122 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2123 && !PathFileExistsW(lpstrPathAndFile))
2125 WCHAR lpstrCreate[100];
2126 int answer;
2128 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2129 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2130 MB_YESNO | MB_ICONEXCLAMATION);
2131 if (answer == IDNO)
2133 ret = FALSE;
2134 goto ret;
2138 /* Check that the size of the file does not exceed buffer size.
2139 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2140 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2141 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2143 LPWSTR lpszTemp;
2145 /* fill destination buffer */
2146 if (fodInfos->ofnInfos->lpstrFile)
2148 if(fodInfos->unicode)
2150 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2152 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2153 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2154 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2156 else
2158 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2160 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2161 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2162 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2163 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2167 /* set filename offset */
2168 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2169 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2171 /* set extension offset */
2172 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2173 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2175 /* set the lpstrFileTitle */
2176 if(fodInfos->ofnInfos->lpstrFileTitle)
2178 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2179 if(fodInfos->unicode)
2181 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2182 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2184 else
2186 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2187 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2188 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2192 /* copy currently selected filter to lpstrCustomFilter */
2193 if (fodInfos->ofnInfos->lpstrCustomFilter)
2195 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2196 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2197 NULL, 0, NULL, NULL);
2198 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2200 LPSTR s = ofn->lpstrCustomFilter;
2201 s += strlen(ofn->lpstrCustomFilter)+1;
2202 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2203 s, len, NULL, NULL);
2208 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2209 goto ret;
2211 TRACE("close\n");
2212 FILEDLG95_Clean(hwnd);
2213 ret = EndDialog(hwnd, TRUE);
2215 else
2217 WORD size;
2219 size = lstrlenW(lpstrPathAndFile) + 1;
2220 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2221 size += 1;
2222 /* return needed size in first two bytes of lpstrFile */
2223 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2224 FILEDLG95_Clean(hwnd);
2225 ret = EndDialog(hwnd, FALSE);
2226 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2228 goto ret;
2230 break;
2233 ret:
2234 if(lpsf) IShellFolder_Release(lpsf);
2235 return ret;
2238 /***********************************************************************
2239 * FILEDLG95_SHELL_Init
2241 * Initialisation of the shell objects
2243 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2245 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2247 TRACE("\n");
2250 * Initialisation of the FileOpenDialogInfos structure
2253 /* Shell */
2255 /*ShellInfos */
2256 fodInfos->ShellInfos.hwndOwner = hwnd;
2258 /* Disable multi-select if flag not set */
2259 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2261 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2263 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2264 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2266 /* Construct the IShellBrowser interface */
2267 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2269 return NOERROR;
2272 /***********************************************************************
2273 * FILEDLG95_SHELL_ExecuteCommand
2275 * Change the folder option and refresh the view
2276 * If the function succeeds, the return value is nonzero.
2278 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2280 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2282 IContextMenu * pcm;
2283 TRACE("(%p,%p)\n", hwnd, lpVerb);
2285 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2286 SVGIO_BACKGROUND,
2287 &IID_IContextMenu,
2288 (LPVOID*)&pcm)))
2290 CMINVOKECOMMANDINFO ci;
2291 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2292 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2293 ci.lpVerb = lpVerb;
2294 ci.hwnd = hwnd;
2296 IContextMenu_InvokeCommand(pcm, &ci);
2297 IContextMenu_Release(pcm);
2300 return FALSE;
2303 /***********************************************************************
2304 * FILEDLG95_SHELL_UpFolder
2306 * Browse to the specified object
2307 * If the function succeeds, the return value is nonzero.
2309 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2311 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2313 TRACE("\n");
2315 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2316 NULL,
2317 SBSP_PARENT)))
2319 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2320 return TRUE;
2322 return FALSE;
2325 /***********************************************************************
2326 * FILEDLG95_SHELL_BrowseToDesktop
2328 * Browse to the Desktop
2329 * If the function succeeds, the return value is nonzero.
2331 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2333 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2334 LPITEMIDLIST pidl;
2335 HRESULT hres;
2337 TRACE("\n");
2339 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2340 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2341 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2342 COMDLG32_SHFree(pidl);
2343 return SUCCEEDED(hres);
2345 /***********************************************************************
2346 * FILEDLG95_SHELL_Clean
2348 * Cleans the memory used by shell objects
2350 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2352 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2354 TRACE("\n");
2356 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2358 /* clean Shell interfaces */
2359 if (fodInfos->Shell.FOIShellView)
2361 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2362 IShellView_Release(fodInfos->Shell.FOIShellView);
2364 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2365 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2366 if (fodInfos->Shell.FOIDataObject)
2367 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2370 /***********************************************************************
2371 * FILEDLG95_FILETYPE_Init
2373 * Initialisation of the file type combo box
2375 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2377 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2378 int nFilters = 0; /* number of filters */
2379 int nFilterIndexCB;
2381 TRACE("\n");
2383 if(fodInfos->customfilter)
2385 /* customfilter has one entry... title\0ext\0
2386 * Set first entry of combo box item with customfilter
2388 LPWSTR lpstrExt;
2389 LPCWSTR lpstrPos = fodInfos->customfilter;
2391 /* Get the title */
2392 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2394 /* Copy the extensions */
2395 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2396 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2397 lstrcpyW(lpstrExt,lpstrPos);
2399 /* Add the item at the end of the combo */
2400 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2401 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2402 nFilters++;
2404 if(fodInfos->filter)
2406 LPCWSTR lpstrPos = fodInfos->filter;
2408 for(;;)
2410 /* filter is a list... title\0ext\0......\0\0
2411 * Set the combo item text to the title and the item data
2412 * to the ext
2414 LPCWSTR lpstrDisplay;
2415 LPWSTR lpstrExt;
2417 /* Get the title */
2418 if(! *lpstrPos) break; /* end */
2419 lpstrDisplay = lpstrPos;
2420 lpstrPos += lstrlenW(lpstrPos) + 1;
2422 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2424 nFilters++;
2426 /* Copy the extensions */
2427 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2428 lstrcpyW(lpstrExt,lpstrPos);
2429 lpstrPos += lstrlenW(lpstrPos) + 1;
2431 /* Add the item at the end of the combo */
2432 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2434 /* malformed filters are added anyway... */
2435 if (!*lpstrExt) break;
2440 * Set the current filter to the one specified
2441 * in the initialisation structure
2443 if (fodInfos->filter || fodInfos->customfilter)
2445 LPWSTR lpstrFilter;
2447 /* Check to make sure our index isn't out of bounds. */
2448 if ( fodInfos->ofnInfos->nFilterIndex >
2449 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2450 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2452 /* set default filter index */
2453 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2454 fodInfos->ofnInfos->nFilterIndex = 1;
2456 /* calculate index of Combo Box item */
2457 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2458 if (fodInfos->customfilter == NULL)
2459 nFilterIndexCB--;
2461 /* Set the current index selection. */
2462 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2464 /* Get the corresponding text string from the combo box. */
2465 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2466 nFilterIndexCB);
2468 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2469 lpstrFilter = NULL;
2471 if(lpstrFilter)
2473 DWORD len;
2474 CharLowerW(lpstrFilter); /* lowercase */
2475 len = lstrlenW(lpstrFilter)+1;
2476 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2477 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2479 } else
2480 fodInfos->ofnInfos->nFilterIndex = 0;
2481 return S_OK;
2484 /***********************************************************************
2485 * FILEDLG95_FILETYPE_OnCommand
2487 * WM_COMMAND of the file type combo box
2488 * If the function succeeds, the return value is nonzero.
2490 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2492 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2494 switch(wNotifyCode)
2496 case CBN_SELENDOK:
2498 LPWSTR lpstrFilter;
2500 /* Get the current item of the filetype combo box */
2501 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2503 /* set the current filter index */
2504 fodInfos->ofnInfos->nFilterIndex = iItem +
2505 (fodInfos->customfilter == NULL ? 1 : 0);
2507 /* Set the current filter with the current selection */
2508 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2510 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2511 iItem);
2512 if((INT_PTR)lpstrFilter != CB_ERR)
2514 DWORD len;
2515 CharLowerW(lpstrFilter); /* lowercase */
2516 len = lstrlenW(lpstrFilter)+1;
2517 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2518 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2519 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2522 /* Refresh the actual view to display the included items*/
2523 if (fodInfos->Shell.FOIShellView)
2524 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2527 return FALSE;
2529 /***********************************************************************
2530 * FILEDLG95_FILETYPE_SearchExt
2532 * searches for an extension in the filetype box
2534 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2536 int i, iCount = CBGetCount(hwnd);
2538 TRACE("%s\n", debugstr_w(lpstrExt));
2540 if(iCount != CB_ERR)
2542 for(i=0;i<iCount;i++)
2544 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2545 return i;
2548 return -1;
2551 /***********************************************************************
2552 * FILEDLG95_FILETYPE_Clean
2554 * Clean the memory used by the filetype combo box
2556 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2558 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2559 int iPos;
2560 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2562 TRACE("\n");
2564 /* Delete each string of the combo and their associated data */
2565 if(iCount != CB_ERR)
2567 for(iPos = iCount-1;iPos>=0;iPos--)
2569 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2570 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2573 /* Current filter */
2574 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2578 /***********************************************************************
2579 * FILEDLG95_LOOKIN_Init
2581 * Initialisation of the look in combo box
2584 /* Small helper function, to determine if the unixfs shell extension is rooted
2585 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2587 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2588 HKEY hKey;
2589 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2590 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2591 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2592 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2593 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2594 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2595 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2597 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2598 return FALSE;
2600 RegCloseKey(hKey);
2601 return TRUE;
2604 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2606 IShellFolder *psfRoot, *psfDrives;
2607 IEnumIDList *lpeRoot, *lpeDrives;
2608 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2610 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2612 TRACE("\n");
2614 liInfos->iMaxIndentation = 0;
2616 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2618 /* set item height for both text field and listbox */
2619 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2620 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2622 /* Turn on the extended UI for the combo box like Windows does */
2623 CBSetExtendedUI(hwndCombo, TRUE);
2625 /* Initialise data of Desktop folder */
2626 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2627 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2628 COMDLG32_SHFree(pidlTmp);
2630 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2632 SHGetDesktopFolder(&psfRoot);
2634 if (psfRoot)
2636 /* enumerate the contents of the desktop */
2637 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2639 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2641 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2643 /* If the unixfs extension is rooted, we don't expand the drives by default */
2644 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2646 /* special handling for CSIDL_DRIVES */
2647 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2649 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2651 /* enumerate the drives */
2652 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2654 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2656 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2657 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2658 COMDLG32_SHFree(pidlAbsTmp);
2659 COMDLG32_SHFree(pidlTmp1);
2661 IEnumIDList_Release(lpeDrives);
2663 IShellFolder_Release(psfDrives);
2668 COMDLG32_SHFree(pidlTmp);
2670 IEnumIDList_Release(lpeRoot);
2672 IShellFolder_Release(psfRoot);
2675 COMDLG32_SHFree(pidlDrives);
2678 /***********************************************************************
2679 * FILEDLG95_LOOKIN_DrawItem
2681 * WM_DRAWITEM message handler
2683 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2685 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2686 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2687 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2688 RECT rectText;
2689 RECT rectIcon;
2690 SHFILEINFOW sfi;
2691 HIMAGELIST ilItemImage;
2692 int iIndentation;
2693 TEXTMETRICW tm;
2694 LPSFOLDER tmpFolder;
2697 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2699 TRACE("\n");
2701 if(pDIStruct->itemID == -1)
2702 return 0;
2704 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2705 pDIStruct->itemID)))
2706 return 0;
2709 if(pDIStruct->itemID == liInfos->uSelectedItem)
2711 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2713 &sfi,
2714 sizeof (sfi),
2715 SHGFI_PIDL | SHGFI_SMALLICON |
2716 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2717 SHGFI_DISPLAYNAME );
2719 else
2721 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2723 &sfi,
2724 sizeof (sfi),
2725 SHGFI_PIDL | SHGFI_SMALLICON |
2726 SHGFI_SYSICONINDEX |
2727 SHGFI_DISPLAYNAME);
2730 /* Is this item selected ? */
2731 if(pDIStruct->itemState & ODS_SELECTED)
2733 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2734 SetBkColor(pDIStruct->hDC,crHighLight);
2735 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2737 else
2739 SetTextColor(pDIStruct->hDC,crText);
2740 SetBkColor(pDIStruct->hDC,crWin);
2741 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2744 /* Do not indent item if drawing in the edit of the combo */
2745 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2747 iIndentation = 0;
2748 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2750 &sfi,
2751 sizeof (sfi),
2752 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2753 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2756 else
2758 iIndentation = tmpFolder->m_iIndent;
2760 /* Draw text and icon */
2762 /* Initialise the icon display area */
2763 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2764 rectIcon.top = pDIStruct->rcItem.top;
2765 rectIcon.right = rectIcon.left + ICONWIDTH;
2766 rectIcon.bottom = pDIStruct->rcItem.bottom;
2768 /* Initialise the text display area */
2769 GetTextMetricsW(pDIStruct->hDC, &tm);
2770 rectText.left = rectIcon.right;
2771 rectText.top =
2772 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2773 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2774 rectText.bottom =
2775 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2777 /* Draw the icon from the image list */
2778 ImageList_Draw(ilItemImage,
2779 sfi.iIcon,
2780 pDIStruct->hDC,
2781 rectIcon.left,
2782 rectIcon.top,
2783 ILD_TRANSPARENT );
2785 /* Draw the associated text */
2786 if(sfi.szDisplayName)
2787 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2790 return NOERROR;
2793 /***********************************************************************
2794 * FILEDLG95_LOOKIN_OnCommand
2796 * LookIn combo box WM_COMMAND message handler
2797 * If the function succeeds, the return value is nonzero.
2799 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2801 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2803 TRACE("%p\n", fodInfos);
2805 switch(wNotifyCode)
2807 case CBN_SELENDOK:
2809 LPSFOLDER tmpFolder;
2810 int iItem;
2812 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2814 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2815 iItem)))
2816 return FALSE;
2819 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2820 tmpFolder->pidlItem,
2821 SBSP_ABSOLUTE)))
2823 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2824 return TRUE;
2826 break;
2830 return FALSE;
2833 /***********************************************************************
2834 * FILEDLG95_LOOKIN_AddItem
2836 * Adds an absolute pidl item to the lookin combo box
2837 * returns the index of the inserted item
2839 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2841 LPITEMIDLIST pidlNext;
2842 SHFILEINFOW sfi;
2843 SFOLDER *tmpFolder;
2844 LookInInfos *liInfos;
2846 TRACE("%08x\n", iInsertId);
2848 if(!pidl)
2849 return -1;
2851 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2852 return -1;
2854 tmpFolder = MemAlloc(sizeof(SFOLDER));
2855 tmpFolder->m_iIndent = 0;
2857 /* Calculate the indentation of the item in the lookin*/
2858 pidlNext = pidl;
2859 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2861 tmpFolder->m_iIndent++;
2864 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2866 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2867 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2869 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2870 SHGetFileInfoW((LPCWSTR)pidl,
2872 &sfi,
2873 sizeof(sfi),
2874 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2875 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2877 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2879 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2881 int iItemID;
2883 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2885 /* Add the item at the end of the list */
2886 if(iInsertId < 0)
2888 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2890 /* Insert the item at the iInsertId position*/
2891 else
2893 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2896 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2897 return iItemID;
2900 COMDLG32_SHFree( tmpFolder->pidlItem );
2901 MemFree( tmpFolder );
2902 return -1;
2906 /***********************************************************************
2907 * FILEDLG95_LOOKIN_InsertItemAfterParent
2909 * Insert an item below its parent
2911 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2914 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2915 int iParentPos;
2917 TRACE("\n");
2919 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2921 if(iParentPos < 0)
2923 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2926 /* Free pidlParent memory */
2927 COMDLG32_SHFree((LPVOID)pidlParent);
2929 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2932 /***********************************************************************
2933 * FILEDLG95_LOOKIN_SelectItem
2935 * Adds an absolute pidl item to the lookin combo box
2936 * returns the index of the inserted item
2938 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2940 int iItemPos;
2941 LookInInfos *liInfos;
2943 TRACE("\n");
2945 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2947 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2949 if(iItemPos < 0)
2951 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2952 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2955 else
2957 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2958 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2960 int iRemovedItem;
2962 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2963 break;
2964 if(iRemovedItem < iItemPos)
2965 iItemPos--;
2969 CBSetCurSel(hwnd,iItemPos);
2970 liInfos->uSelectedItem = iItemPos;
2972 return 0;
2976 /***********************************************************************
2977 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2979 * Remove the item with an expansion level over iExpansionLevel
2981 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2983 int iItemPos;
2985 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2987 TRACE("\n");
2989 if(liInfos->iMaxIndentation <= 2)
2990 return -1;
2992 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2994 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2995 COMDLG32_SHFree(tmpFolder->pidlItem);
2996 MemFree(tmpFolder);
2997 CBDeleteString(hwnd,iItemPos);
2998 liInfos->iMaxIndentation--;
3000 return iItemPos;
3003 return -1;
3006 /***********************************************************************
3007 * FILEDLG95_LOOKIN_SearchItem
3009 * Search for pidl in the lookin combo box
3010 * returns the index of the found item
3012 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3014 int i = 0;
3015 int iCount = CBGetCount(hwnd);
3017 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3019 if (iCount != CB_ERR)
3021 for(;i<iCount;i++)
3023 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3025 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3026 return i;
3027 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3028 return i;
3032 return -1;
3035 /***********************************************************************
3036 * FILEDLG95_LOOKIN_Clean
3038 * Clean the memory used by the lookin combo box
3040 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3042 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3043 int iPos;
3044 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3046 TRACE("\n");
3048 /* Delete each string of the combo and their associated data */
3049 if (iCount != CB_ERR)
3051 for(iPos = iCount-1;iPos>=0;iPos--)
3053 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3054 COMDLG32_SHFree(tmpFolder->pidlItem);
3055 MemFree(tmpFolder);
3056 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3060 /* LookInInfos structure */
3061 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3064 /***********************************************************************
3065 * FILEDLG95_FILENAME_FillFromSelection
3067 * fills the edit box from the cached DataObject
3069 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3071 FileOpenDlgInfos *fodInfos;
3072 LPITEMIDLIST pidl;
3073 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3074 WCHAR lpstrTemp[MAX_PATH];
3075 LPWSTR lpstrAllFile, lpstrCurrFile;
3077 TRACE("\n");
3078 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3080 /* Count how many files we have */
3081 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3083 /* calculate the string length, count files */
3084 if (nFileSelected >= 1)
3086 nLength += 3; /* first and last quotes, trailing \0 */
3087 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3089 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3091 if (pidl)
3093 /* get the total length of the selected file names */
3094 lpstrTemp[0] = '\0';
3095 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3097 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3099 nLength += lstrlenW( lpstrTemp ) + 3;
3100 nFiles++;
3102 COMDLG32_SHFree( pidl );
3107 /* allocate the buffer */
3108 if (nFiles <= 1) nLength = MAX_PATH;
3109 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3111 /* Generate the string for the edit control */
3112 if(nFiles >= 1)
3114 lpstrCurrFile = lpstrAllFile;
3115 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3117 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3119 if (pidl)
3121 /* get the file name */
3122 lpstrTemp[0] = '\0';
3123 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3125 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3127 if ( nFiles > 1)
3129 *lpstrCurrFile++ = '\"';
3130 lstrcpyW( lpstrCurrFile, lpstrTemp );
3131 lpstrCurrFile += lstrlenW( lpstrTemp );
3132 *lpstrCurrFile++ = '\"';
3133 *lpstrCurrFile++ = ' ';
3134 *lpstrCurrFile = 0;
3136 else
3138 lstrcpyW( lpstrAllFile, lpstrTemp );
3141 COMDLG32_SHFree( (LPVOID) pidl );
3144 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3146 /* Select the file name like Windows does */
3147 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3149 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3153 /* copied from shell32 to avoid linking to it
3154 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3155 * is dependent on whether emulated OS is unicode or not.
3157 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3159 switch (src->uType)
3161 case STRRET_WSTR:
3162 lstrcpynW(dest, src->u.pOleStr, len);
3163 COMDLG32_SHFree(src->u.pOleStr);
3164 break;
3166 case STRRET_CSTR:
3167 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3168 dest[len-1] = 0;
3169 break;
3171 case STRRET_OFFSET:
3172 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3173 dest[len-1] = 0;
3174 break;
3176 default:
3177 FIXME("unknown type %x!\n", src->uType);
3178 if (len) *dest = '\0';
3179 return E_FAIL;
3181 return S_OK;
3184 /***********************************************************************
3185 * FILEDLG95_FILENAME_GetFileNames
3187 * Copies the filenames to a delimited string list.
3188 * The delimiter is specified by the parameter 'separator',
3189 * usually either a space or a nul
3191 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3193 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3194 UINT nStrCharCount = 0; /* index in src buffer */
3195 UINT nFileIndex = 0; /* index in dest buffer */
3196 UINT nFileCount = 0; /* number of files */
3197 UINT nStrLen = 0; /* length of string in edit control */
3198 LPWSTR lpstrEdit; /* buffer for string from edit control */
3200 TRACE("\n");
3202 /* get the filenames from the edit control */
3203 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3204 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3205 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3207 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3209 /* we might get single filename without any '"',
3210 * so we need nStrLen + terminating \0 + end-of-list \0 */
3211 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3212 *sizeUsed = 0;
3214 /* build delimited file list from filenames */
3215 while ( nStrCharCount <= nStrLen )
3217 if ( lpstrEdit[nStrCharCount]=='"' )
3219 nStrCharCount++;
3220 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3222 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3223 (*sizeUsed)++;
3224 nStrCharCount++;
3226 (*lpstrFileList)[nFileIndex++] = separator;
3227 (*sizeUsed)++;
3228 nFileCount++;
3230 nStrCharCount++;
3233 /* single, unquoted string */
3234 if ((nStrLen > 0) && (*sizeUsed == 0) )
3236 lstrcpyW(*lpstrFileList, lpstrEdit);
3237 nFileIndex = lstrlenW(lpstrEdit) + 1;
3238 (*sizeUsed) = nFileIndex;
3239 nFileCount = 1;
3242 /* trailing \0 */
3243 (*lpstrFileList)[nFileIndex] = '\0';
3244 (*sizeUsed)++;
3246 MemFree(lpstrEdit);
3247 return nFileCount;
3250 #define SETDefFormatEtc(fe,cf,med) \
3252 (fe).cfFormat = cf;\
3253 (fe).dwAspect = DVASPECT_CONTENT; \
3254 (fe).ptd =NULL;\
3255 (fe).tymed = med;\
3256 (fe).lindex = -1;\
3260 * DATAOBJECT Helper functions
3263 /***********************************************************************
3264 * COMCTL32_ReleaseStgMedium
3266 * like ReleaseStgMedium from ole32
3268 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3270 if(medium.pUnkForRelease)
3272 IUnknown_Release(medium.pUnkForRelease);
3274 else
3276 GlobalUnlock(medium.u.hGlobal);
3277 GlobalFree(medium.u.hGlobal);
3281 /***********************************************************************
3282 * GetPidlFromDataObject
3284 * Return pidl(s) by number from the cached DataObject
3286 * nPidlIndex=0 gets the fully qualified root path
3288 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3291 STGMEDIUM medium;
3292 FORMATETC formatetc;
3293 LPITEMIDLIST pidl = NULL;
3295 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3297 if (!doSelected)
3298 return NULL;
3300 /* Set the FORMATETC structure*/
3301 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3303 /* Get the pidls from IDataObject */
3304 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3306 LPIDA cida = GlobalLock(medium.u.hGlobal);
3307 if(nPidlIndex <= cida->cidl)
3309 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3311 COMCTL32_ReleaseStgMedium(medium);
3313 return pidl;
3316 /***********************************************************************
3317 * GetNumSelected
3319 * Return the number of selected items in the DataObject.
3322 UINT GetNumSelected( IDataObject *doSelected )
3324 UINT retVal = 0;
3325 STGMEDIUM medium;
3326 FORMATETC formatetc;
3328 TRACE("sv=%p\n", doSelected);
3330 if (!doSelected) return 0;
3332 /* Set the FORMATETC structure*/
3333 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3335 /* Get the pidls from IDataObject */
3336 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3338 LPIDA cida = GlobalLock(medium.u.hGlobal);
3339 retVal = cida->cidl;
3340 COMCTL32_ReleaseStgMedium(medium);
3341 return retVal;
3343 return 0;
3347 * TOOLS
3350 /***********************************************************************
3351 * GetName
3353 * Get the pidl's display name (relative to folder) and
3354 * put it in lpstrFileName.
3356 * Return NOERROR on success,
3357 * E_FAIL otherwise
3360 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3362 STRRET str;
3363 HRESULT hRes;
3365 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3367 if(!lpsf)
3369 SHGetDesktopFolder(&lpsf);
3370 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3371 IShellFolder_Release(lpsf);
3372 return hRes;
3375 /* Get the display name of the pidl relative to the folder */
3376 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3378 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3380 return E_FAIL;
3383 /***********************************************************************
3384 * GetShellFolderFromPidl
3386 * pidlRel is the item pidl relative
3387 * Return the IShellFolder of the absolute pidl
3389 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3391 IShellFolder *psf = NULL,*psfParent;
3393 TRACE("%p\n", pidlAbs);
3395 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3397 psf = psfParent;
3398 if(pidlAbs && pidlAbs->mkid.cb)
3400 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3402 IShellFolder_Release(psfParent);
3403 return psf;
3406 /* return the desktop */
3407 return psfParent;
3409 return NULL;
3412 /***********************************************************************
3413 * GetParentPidl
3415 * Return the LPITEMIDLIST to the parent of the pidl in the list
3417 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3419 LPITEMIDLIST pidlParent;
3421 TRACE("%p\n", pidl);
3423 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3424 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3426 return pidlParent;
3429 /***********************************************************************
3430 * GetPidlFromName
3432 * returns the pidl of the file name relative to folder
3433 * NULL if an error occurred
3435 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3437 LPITEMIDLIST pidl = NULL;
3438 ULONG ulEaten;
3440 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3442 if(!lpcstrFileName) return NULL;
3443 if(!*lpcstrFileName) return NULL;
3445 if(!lpsf)
3447 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3448 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3449 IShellFolder_Release(lpsf);
3452 else
3454 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3456 return pidl;
3461 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3463 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3464 HRESULT ret;
3466 TRACE("%p, %p\n", psf, pidl);
3468 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3470 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3471 /* see documentation shell 4.1*/
3472 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3475 /***********************************************************************
3476 * BrowseSelectedFolder
3478 static BOOL BrowseSelectedFolder(HWND hwnd)
3480 BOOL bBrowseSelFolder = FALSE;
3481 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3483 TRACE("\n");
3485 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3487 LPITEMIDLIST pidlSelection;
3489 /* get the file selected */
3490 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3491 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3493 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3494 pidlSelection, SBSP_RELATIVE ) ) )
3496 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3497 ' ','n','o','t',' ','e','x','i','s','t',0};
3498 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3500 bBrowseSelFolder = TRUE;
3501 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3503 COMDLG32_SHFree( pidlSelection );
3506 return bBrowseSelFolder;
3510 * Memory allocation methods */
3511 static void *MemAlloc(UINT size)
3513 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3516 static void MemFree(void *mem)
3518 HeapFree(GetProcessHeap(),0,mem);
3522 * Old-style (win3.1) dialogs */
3524 /***********************************************************************
3525 * FD32_GetTemplate [internal]
3527 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3528 * by a 32 bits application
3531 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3533 LPOPENFILENAMEW ofnW = lfs->ofnW;
3534 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3535 HANDLE hDlgTmpl;
3537 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3539 if (!(lfs->template = LockResource( ofnW->hInstance )))
3541 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3542 return FALSE;
3545 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3547 HRSRC hResInfo;
3548 if (priv->ofnA)
3549 hResInfo = FindResourceA(priv->ofnA->hInstance,
3550 priv->ofnA->lpTemplateName,
3551 (LPSTR)RT_DIALOG);
3552 else
3553 hResInfo = FindResourceW(ofnW->hInstance,
3554 ofnW->lpTemplateName,
3555 (LPWSTR)RT_DIALOG);
3556 if (!hResInfo)
3558 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3559 return FALSE;
3561 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3562 hResInfo)) ||
3563 !(lfs->template = LockResource(hDlgTmpl)))
3565 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3566 return FALSE;
3568 } else { /* get it from internal Wine resource */
3569 HRSRC hResInfo;
3570 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3571 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3573 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3574 return FALSE;
3576 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3577 !(lfs->template = LockResource( hDlgTmpl )))
3579 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3580 return FALSE;
3583 return TRUE;
3587 /************************************************************************
3588 * FD32_Init [internal]
3589 * called from the common 16/32 code to initialize 32 bit data
3591 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3593 BOOL IsUnicode = (BOOL) data;
3594 PFD32_PRIVATE priv;
3596 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3597 lfs->private1632 = priv;
3598 if (NULL == lfs->private1632) return FALSE;
3599 if (IsUnicode)
3601 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3602 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3603 if (lfs->ofnW->lpfnHook)
3604 lfs->hook = TRUE;
3606 else
3608 priv->ofnA = (LPOPENFILENAMEA) lParam;
3609 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3610 if (priv->ofnA->lpfnHook)
3611 lfs->hook = TRUE;
3612 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3613 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3616 if (! FD32_GetTemplate(lfs)) return FALSE;
3618 return TRUE;
3621 /***********************************************************************
3622 * FD32_CallWindowProc [internal]
3624 * called from the common 16/32 code to call the appropriate hook
3626 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3627 LPARAM lParam)
3629 BOOL ret;
3630 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3632 if (priv->ofnA)
3634 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3635 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3636 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3637 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3638 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3639 return ret;
3642 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3643 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3644 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3645 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3646 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3647 return ret;
3650 /***********************************************************************
3651 * FD32_UpdateResult [internal]
3652 * update the real client structures if any
3654 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3656 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3657 LPOPENFILENAMEW ofnW = lfs->ofnW;
3659 if (priv->ofnA)
3661 if (ofnW->nMaxFile &&
3662 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3663 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3664 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3665 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3666 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3670 /***********************************************************************
3671 * FD32_UpdateFileTitle [internal]
3672 * update the real client structures if any
3674 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3676 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3677 LPOPENFILENAMEW ofnW = lfs->ofnW;
3679 if (priv->ofnA)
3681 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3682 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3683 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3688 /***********************************************************************
3689 * FD32_SendLbGetCurSel [internal]
3690 * retrieve selected listbox item
3692 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3694 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3698 /************************************************************************
3699 * FD32_Destroy [internal]
3700 * called from the common 16/32 code to cleanup 32 bit data
3702 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3704 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3706 /* if ofnW has been allocated, have to free everything in it */
3707 if (NULL != priv && NULL != priv->ofnA)
3709 FD31_FreeOfnW(lfs->ofnW);
3710 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3714 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3716 callbacks->Init = FD32_Init;
3717 callbacks->CWP = FD32_CallWindowProc;
3718 callbacks->UpdateResult = FD32_UpdateResult;
3719 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3720 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3721 callbacks->Destroy = FD32_Destroy;
3724 /***********************************************************************
3725 * FD32_WMMeasureItem [internal]
3727 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3729 LPMEASUREITEMSTRUCT lpmeasure;
3731 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3732 lpmeasure->itemHeight = FD31_GetFldrHeight();
3733 return TRUE;
3737 /***********************************************************************
3738 * FileOpenDlgProc [internal]
3739 * Used for open and save, in fact.
3741 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3742 WPARAM wParam, LPARAM lParam)
3744 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3746 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3747 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3749 INT_PTR lRet;
3750 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3751 if (lRet)
3752 return lRet; /* else continue message processing */
3754 switch (wMsg)
3756 case WM_INITDIALOG:
3757 return FD31_WMInitDialog(hWnd, wParam, lParam);
3759 case WM_MEASUREITEM:
3760 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3762 case WM_DRAWITEM:
3763 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3765 case WM_COMMAND:
3766 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3767 #if 0
3768 case WM_CTLCOLOR:
3769 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3770 switch (HIWORD(lParam))
3772 case CTLCOLOR_BTN:
3773 SetTextColor((HDC16)wParam, 0x00000000);
3774 return hGRAYBrush;
3775 case CTLCOLOR_STATIC:
3776 SetTextColor((HDC16)wParam, 0x00000000);
3777 return hGRAYBrush;
3779 break;
3780 #endif
3782 return FALSE;
3786 /***********************************************************************
3787 * GetFileName31A [internal]
3789 * Creates a win31 style dialog box for the user to select a file to open/save.
3791 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3792 UINT dlgType /* type dialogue : open/save */
3795 HINSTANCE hInst;
3796 BOOL bRet = FALSE;
3797 PFD31_DATA lfs;
3798 FD31_CALLBACKS callbacks;
3800 if (!lpofn || !FD31_Init()) return FALSE;
3802 TRACE("ofn flags %08x\n", lpofn->Flags);
3803 FD32_SetupCallbacks(&callbacks);
3804 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3805 if (lfs)
3807 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3808 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3809 FD32_FileOpenDlgProc, (LPARAM)lfs);
3810 FD31_DestroyPrivate(lfs);
3813 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3814 return bRet;
3817 /***********************************************************************
3818 * GetFileName31W [internal]
3820 * Creates a win31 style dialog box for the user to select a file to open/save
3822 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3823 UINT dlgType /* type dialogue : open/save */
3826 HINSTANCE hInst;
3827 BOOL bRet = FALSE;
3828 PFD31_DATA lfs;
3829 FD31_CALLBACKS callbacks;
3831 if (!lpofn || !FD31_Init()) return FALSE;
3833 FD32_SetupCallbacks(&callbacks);
3834 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3835 if (lfs)
3837 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3838 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3839 FD32_FileOpenDlgProc, (LPARAM)lfs);
3840 FD31_DestroyPrivate(lfs);
3843 TRACE("file %s, file offset %d, ext offset %d\n",
3844 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3845 return bRet;
3848 /* ------------------ APIs ---------------------- */
3850 /***********************************************************************
3851 * GetOpenFileNameA (COMDLG32.@)
3853 * Creates a dialog box for the user to select a file to open.
3855 * RETURNS
3856 * TRUE on success: user enters a valid file
3857 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3860 BOOL WINAPI GetOpenFileNameA(
3861 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3863 BOOL win16look = FALSE;
3865 TRACE("flags %08x\n", ofn->Flags);
3867 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3868 if (ofn->Flags & OFN_FILEMUSTEXIST)
3869 ofn->Flags |= OFN_PATHMUSTEXIST;
3871 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3872 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3874 if (win16look)
3875 return GetFileName31A(ofn, OPEN_DIALOG);
3876 else
3877 return GetFileDialog95A(ofn, OPEN_DIALOG);
3880 /***********************************************************************
3881 * GetOpenFileNameW (COMDLG32.@)
3883 * Creates a dialog box for the user to select a file to open.
3885 * RETURNS
3886 * TRUE on success: user enters a valid file
3887 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3890 BOOL WINAPI GetOpenFileNameW(
3891 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3893 BOOL win16look = FALSE;
3895 TRACE("flags %08x\n", ofn->Flags);
3897 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3898 if (ofn->Flags & OFN_FILEMUSTEXIST)
3899 ofn->Flags |= OFN_PATHMUSTEXIST;
3901 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3902 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3904 if (win16look)
3905 return GetFileName31W(ofn, OPEN_DIALOG);
3906 else
3907 return GetFileDialog95W(ofn, OPEN_DIALOG);
3911 /***********************************************************************
3912 * GetSaveFileNameA (COMDLG32.@)
3914 * Creates a dialog box for the user to select a file to save.
3916 * RETURNS
3917 * TRUE on success: user enters a valid file
3918 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3921 BOOL WINAPI GetSaveFileNameA(
3922 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3924 BOOL win16look = FALSE;
3926 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3927 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3929 if (win16look)
3930 return GetFileName31A(ofn, SAVE_DIALOG);
3931 else
3932 return GetFileDialog95A(ofn, SAVE_DIALOG);
3935 /***********************************************************************
3936 * GetSaveFileNameW (COMDLG32.@)
3938 * Creates a dialog box for the user to select a file to save.
3940 * RETURNS
3941 * TRUE on success: user enters a valid file
3942 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3945 BOOL WINAPI GetSaveFileNameW(
3946 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3948 BOOL win16look = FALSE;
3950 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3951 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3953 if (win16look)
3954 return GetFileName31W(ofn, SAVE_DIALOG);
3955 else
3956 return GetFileDialog95W(ofn, SAVE_DIALOG);
3959 /***********************************************************************
3960 * GetFileTitleA (COMDLG32.@)
3962 * See GetFileTitleW.
3964 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3966 int ret;
3967 UNICODE_STRING strWFile;
3968 LPWSTR lpWTitle;
3970 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3971 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3972 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3973 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3974 RtlFreeUnicodeString( &strWFile );
3975 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3976 return ret;
3980 /***********************************************************************
3981 * GetFileTitleW (COMDLG32.@)
3983 * Get the name of a file.
3985 * PARAMS
3986 * lpFile [I] name and location of file
3987 * lpTitle [O] returned file name
3988 * cbBuf [I] buffer size of lpTitle
3990 * RETURNS
3991 * Success: zero
3992 * Failure: negative number.
3994 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3996 int i, len;
3997 static const WCHAR brkpoint[] = {'*','[',']',0};
3998 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4000 if(lpFile == NULL || lpTitle == NULL)
4001 return -1;
4003 len = lstrlenW(lpFile);
4005 if (len == 0)
4006 return -1;
4008 if(strpbrkW(lpFile, brkpoint))
4009 return -1;
4011 len--;
4013 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4014 return -1;
4016 for(i = len; i >= 0; i--)
4018 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4020 i++;
4021 break;
4025 if(i == -1)
4026 i++;
4028 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4030 len = lstrlenW(lpFile+i)+1;
4031 if(cbBuf < len)
4032 return len;
4034 lstrcpyW(lpTitle, &lpFile[i]);
4035 return 0;