wininet: Fix a number of problems with InternetGetCookie.
[wine.git] / dlls / comdlg32 / filedlg.c
blobcd2ad51ac22df4f7f0a643634b0535cb73a418de
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 "winreg.h"
65 #include "winternl.h"
66 #include "winnls.h"
67 #include "wingdi.h"
68 #include "winuser.h"
69 #include "winreg.h"
70 #include "commdlg.h"
71 #include "dlgs.h"
72 #include "cdlg.h"
73 #include "filedlg31.h"
74 #include "cderr.h"
75 #include "shellapi.h"
76 #include "shlobj.h"
77 #include "filedlgbrowser.h"
78 #include "shlwapi.h"
80 #include "wine/unicode.h"
81 #include "wine/debug.h"
83 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
85 #define UNIMPLEMENTED_FLAGS \
86 (OFN_DONTADDTORECENT |\
87 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\
88 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
89 OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/)
91 #define IsHooked(fodInfos) \
92 ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
93 /***********************************************************************
94 * Data structure and global variables
96 typedef struct SFolder
98 int m_iImageIndex; /* Index of picture in image list */
99 HIMAGELIST hImgList;
100 int m_iIndent; /* Indentation index */
101 LPITEMIDLIST pidlItem; /* absolute pidl of the item */
103 } SFOLDER,*LPSFOLDER;
105 typedef struct tagLookInInfo
107 int iMaxIndentation;
108 UINT uSelectedItem;
109 } LookInInfos;
111 typedef struct tagFD32_PRIVATE
113 OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */
114 } FD32_PRIVATE, *PFD32_PRIVATE;
117 /***********************************************************************
118 * Defines and global variables
121 /* Draw item constant */
122 #define ICONWIDTH 18
123 #define XTEXTOFFSET 3
125 /* AddItem flags*/
126 #define LISTEND -1
128 /* SearchItem methods */
129 #define SEARCH_PIDL 1
130 #define SEARCH_EXP 2
131 #define ITEM_NOTFOUND -1
133 /* Undefined windows message sent by CreateViewObject*/
134 #define WM_GETISHELLBROWSER WM_USER+7
136 /* NOTE
137 * Those macros exist in windowsx.h. However, you can't really use them since
138 * they rely on the UNICODE defines and can't be used inside Wine itself.
141 /* Combo box macros */
142 #define CBAddString(hwnd,str) \
143 SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)(str));
145 #define CBInsertString(hwnd,str,pos) \
146 SendMessageW(hwnd, CB_INSERTSTRING, (WPARAM)(pos), (LPARAM)(str));
148 #define CBDeleteString(hwnd,pos) \
149 SendMessageW(hwnd, CB_DELETESTRING, (WPARAM)(pos), 0);
151 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
152 SendMessageW(hwnd, CB_SETITEMDATA, (WPARAM)(iItemId), (LPARAM)(dataPtr));
154 #define CBGetItemDataPtr(hwnd,iItemId) \
155 SendMessageW(hwnd, CB_GETITEMDATA, (WPARAM)(iItemId), 0)
157 #define CBGetLBText(hwnd,iItemId,str) \
158 SendMessageW(hwnd, CB_GETLBTEXT, (WPARAM)(iItemId), (LPARAM)(str));
160 #define CBGetCurSel(hwnd) \
161 SendMessageW(hwnd, CB_GETCURSEL, 0, 0);
163 #define CBSetCurSel(hwnd,pos) \
164 SendMessageW(hwnd, CB_SETCURSEL, (WPARAM)(pos), 0);
166 #define CBGetCount(hwnd) \
167 SendMessageW(hwnd, CB_GETCOUNT, 0, 0);
168 #define CBShowDropDown(hwnd,show) \
169 SendMessageW(hwnd, CB_SHOWDROPDOWN, (WPARAM)(show), 0);
170 #define CBSetItemHeight(hwnd,index,height) \
171 SendMessageW(hwnd, CB_SETITEMHEIGHT, (WPARAM)(index), (LPARAM)(height));
173 #define CBSetExtendedUI(hwnd,flag) \
174 SendMessageW(hwnd, CB_SETEXTENDEDUI, (WPARAM)(flag), 0)
176 const char FileOpenDlgInfosStr[] = "FileOpenDlgInfos"; /* windows property description string */
177 static const char LookInInfosStr[] = "LookInInfos"; /* LOOKIN combo box property */
179 /***********************************************************************
180 * Prototypes
183 /* Internal functions used by the dialog */
184 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
185 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
186 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
187 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
188 static BOOL FILEDLG95_OnOpen(HWND hwnd);
189 static LRESULT FILEDLG95_InitControls(HWND hwnd);
190 static void FILEDLG95_Clean(HWND hwnd);
192 /* Functions used by the shell navigation */
193 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
194 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd);
195 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
196 static void FILEDLG95_SHELL_Clean(HWND hwnd);
197 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
199 /* Functions used by the EDIT box */
200 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator);
202 /* Functions used by the filetype combo box */
203 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
204 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
205 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt);
206 static void FILEDLG95_FILETYPE_Clean(HWND hwnd);
208 /* Functions used by the Look In combo box */
209 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo);
210 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
211 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
212 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
213 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
214 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
215 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
216 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
217 static void FILEDLG95_LOOKIN_Clean(HWND hwnd);
219 /* Miscellaneous tool functions */
220 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName);
221 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
222 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl);
223 static LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName);
225 /* Shell memory allocation */
226 static void *MemAlloc(UINT size);
227 static void MemFree(void *mem);
229 static INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
230 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
231 static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
232 static BOOL BrowseSelectedFolder(HWND hwnd);
234 /***********************************************************************
235 * GetFileName95
237 * Creates an Open common dialog box that lets the user select
238 * the drive, directory, and the name of a file or set of files to open.
240 * IN : The FileOpenDlgInfos structure associated with the dialog
241 * OUT : TRUE on success
242 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
244 static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
247 LRESULT lRes;
248 LPCVOID template;
249 HRSRC hRes;
250 HANDLE hDlgTmpl = 0;
251 HRESULT hr;
253 /* test for missing functionality */
254 if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
256 FIXME("Flags 0x%08x not yet implemented\n",
257 fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
260 /* Create the dialog from a template */
262 if(!(hRes = FindResourceW(COMDLG32_hInstance,MAKEINTRESOURCEW(NEWFILEOPENORD),(LPCWSTR)RT_DIALOG)))
264 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
265 return FALSE;
267 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) ||
268 !(template = LockResource( hDlgTmpl )))
270 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
271 return FALSE;
274 /* old style hook messages */
275 if (IsHooked(fodInfos))
277 fodInfos->HookMsg.fileokstring = RegisterWindowMessageW(FILEOKSTRINGW);
278 fodInfos->HookMsg.lbselchstring = RegisterWindowMessageW(LBSELCHSTRINGW);
279 fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageW(HELPMSGSTRINGW);
280 fodInfos->HookMsg.sharevistring = RegisterWindowMessageW(SHAREVISTRINGW);
283 /* Some shell namespace extensions depend on COM being initialized. */
284 hr = OleInitialize(NULL);
286 if (fodInfos->unicode)
287 lRes = DialogBoxIndirectParamW(COMDLG32_hInstance,
288 template,
289 fodInfos->ofnInfos->hwndOwner,
290 FileOpenDlgProc95,
291 (LPARAM) fodInfos);
292 else
293 lRes = DialogBoxIndirectParamA(COMDLG32_hInstance,
294 (LPCDLGTEMPLATEA) template,
295 fodInfos->ofnInfos->hwndOwner,
296 FileOpenDlgProc95,
297 (LPARAM) fodInfos);
298 if (SUCCEEDED(hr))
299 OleUninitialize();
301 /* Unable to create the dialog */
302 if( lRes == -1)
303 return FALSE;
305 return lRes;
308 /***********************************************************************
309 * GetFileDialog95A
311 * Call GetFileName95 with this structure and clean the memory.
313 * IN : The OPENFILENAMEA initialisation structure passed to
314 * GetOpenFileNameA win api function (see filedlg.c)
316 BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
318 BOOL ret;
319 FileOpenDlgInfos fodInfos;
320 LPSTR lpstrSavDir = NULL;
321 LPWSTR title = NULL;
322 LPWSTR defext = NULL;
323 LPWSTR filter = NULL;
324 LPWSTR customfilter = NULL;
326 /* Initialize CommDlgExtendedError() */
327 COMDLG32_SetCommDlgExtendedError(0);
329 /* Initialize FileOpenDlgInfos structure */
330 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
332 /* Pass in the original ofn */
333 fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn;
335 /* save current directory */
336 if (ofn->Flags & OFN_NOCHANGEDIR)
338 lpstrSavDir = MemAlloc(MAX_PATH);
339 GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
342 fodInfos.unicode = FALSE;
344 /* convert all the input strings to unicode */
345 if(ofn->lpstrInitialDir)
347 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 );
348 fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR));
349 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len);
351 else
352 fodInfos.initdir = NULL;
354 if(ofn->lpstrFile)
356 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
357 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile);
359 else
360 fodInfos.filename = NULL;
362 if(ofn->lpstrDefExt)
364 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 );
365 defext = MemAlloc((len+1)*sizeof(WCHAR));
366 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len);
368 fodInfos.defext = defext;
370 if(ofn->lpstrTitle)
372 DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 );
373 title = MemAlloc((len+1)*sizeof(WCHAR));
374 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len);
376 fodInfos.title = title;
378 if (ofn->lpstrFilter)
380 LPCSTR s;
381 int n, len;
383 /* filter is a list... title\0ext\0......\0\0 */
384 s = ofn->lpstrFilter;
385 while (*s) s = s+strlen(s)+1;
386 s++;
387 n = s - ofn->lpstrFilter;
388 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 );
389 filter = MemAlloc(len*sizeof(WCHAR));
390 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len );
392 fodInfos.filter = filter;
394 /* convert lpstrCustomFilter */
395 if (ofn->lpstrCustomFilter)
397 LPCSTR s;
398 int n, len;
400 /* customfilter contains a pair of strings... title\0ext\0 */
401 s = ofn->lpstrCustomFilter;
402 if (*s) s = s+strlen(s)+1;
403 if (*s) s = s+strlen(s)+1;
404 n = s - ofn->lpstrCustomFilter;
405 len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 );
406 customfilter = MemAlloc(len*sizeof(WCHAR));
407 MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len );
409 fodInfos.customfilter = customfilter;
411 /* Initialize the dialog property */
412 fodInfos.DlgInfos.dwDlgProp = 0;
413 fodInfos.DlgInfos.hwndCustomDlg = NULL;
415 switch(iDlgType)
417 case OPEN_DIALOG :
418 ret = GetFileName95(&fodInfos);
419 break;
420 case SAVE_DIALOG :
421 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
422 ret = GetFileName95(&fodInfos);
423 break;
424 default :
425 ret = 0;
428 if (lpstrSavDir)
430 SetCurrentDirectoryA(lpstrSavDir);
431 MemFree(lpstrSavDir);
434 MemFree(title);
435 MemFree(defext);
436 MemFree(filter);
437 MemFree(customfilter);
438 MemFree(fodInfos.initdir);
439 MemFree(fodInfos.filename);
441 TRACE("selected file: %s\n",ofn->lpstrFile);
443 return ret;
446 /***********************************************************************
447 * GetFileDialog95W
449 * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
450 * Call GetFileName95 with this structure and clean the memory.
453 BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
455 BOOL ret;
456 FileOpenDlgInfos fodInfos;
457 LPWSTR lpstrSavDir = NULL;
459 /* Initialize CommDlgExtendedError() */
460 COMDLG32_SetCommDlgExtendedError(0);
462 /* Initialize FileOpenDlgInfos structure */
463 ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos));
465 /* Pass in the original ofn */
466 fodInfos.ofnInfos = ofn;
468 fodInfos.title = ofn->lpstrTitle;
469 fodInfos.defext = ofn->lpstrDefExt;
470 fodInfos.filter = ofn->lpstrFilter;
471 fodInfos.customfilter = ofn->lpstrCustomFilter;
473 /* convert string arguments, save others */
474 if(ofn->lpstrFile)
476 fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR));
477 lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile);
479 else
480 fodInfos.filename = NULL;
482 if(ofn->lpstrInitialDir)
484 /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */
485 DWORD len = lstrlenW(ofn->lpstrInitialDir)+1;
486 fodInfos.initdir = MemAlloc(len*sizeof(WCHAR));
487 memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR));
489 else
490 fodInfos.initdir = NULL;
492 /* save current directory */
493 if (ofn->Flags & OFN_NOCHANGEDIR)
495 lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR));
496 GetCurrentDirectoryW(MAX_PATH, lpstrSavDir);
499 fodInfos.unicode = TRUE;
501 switch(iDlgType)
503 case OPEN_DIALOG :
504 ret = GetFileName95(&fodInfos);
505 break;
506 case SAVE_DIALOG :
507 fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
508 ret = GetFileName95(&fodInfos);
509 break;
510 default :
511 ret = 0;
514 if (lpstrSavDir)
516 SetCurrentDirectoryW(lpstrSavDir);
517 MemFree(lpstrSavDir);
520 /* restore saved IN arguments and convert OUT arguments back */
521 MemFree(fodInfos.filename);
522 MemFree(fodInfos.initdir);
523 return ret;
526 /******************************************************************************
527 * COMDLG32_GetDisplayNameOf [internal]
529 * Helper function to get the display name for a pidl.
531 static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) {
532 LPSHELLFOLDER psfDesktop;
533 STRRET strret;
535 if (FAILED(SHGetDesktopFolder(&psfDesktop)))
536 return FALSE;
538 if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) {
539 IShellFolder_Release(psfDesktop);
540 return FALSE;
543 IShellFolder_Release(psfDesktop);
544 return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH));
547 /***********************************************************************
548 * ArrangeCtrlPositions [internal]
550 * NOTE: Do not change anything here without a lot of testing.
552 static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help)
554 HWND hwndChild, hwndStc32;
555 RECT rectParent, rectChild, rectStc32;
556 INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0;
558 /* Take into account if open as read only checkbox and help button
559 * are hidden
561 if (hide_help)
563 RECT rectHelp, rectCancel;
564 GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp);
565 GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel);
566 /* subtract the height of the help button plus the space between
567 * the help button and the cancel button to the height of the dialog
569 help_fixup = rectHelp.bottom - rectCancel.bottom;
573 There are two possibilities to add components to the default file dialog box.
575 By default, all the new components are added below the standard dialog box (the else case).
577 However, if there is a static text component with the stc32 id, a special case happens.
578 The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box
579 in the window and the cx and cy indicate how to size the window.
580 Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left
581 of the standard file dialog box. If they are above the stc32 component, it is placed above and so on....
585 GetClientRect(hwndParentDlg, &rectParent);
587 /* when arranging controls we have to use fixed parent size */
588 rectParent.bottom -= help_fixup;
590 hwndStc32 = GetDlgItem(hwndChildDlg, stc32);
591 if (hwndStc32)
593 GetWindowRect(hwndStc32, &rectStc32);
594 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2);
596 /* set the size of the stc32 control according to the size of
597 * client area of the parent dialog
599 SetWindowPos(hwndStc32, 0,
600 0, 0,
601 rectParent.right, rectParent.bottom,
602 SWP_NOMOVE | SWP_NOZORDER);
604 else
605 SetRectEmpty(&rectStc32);
607 /* this part moves controls of the child dialog */
608 hwndChild = GetWindow(hwndChildDlg, GW_CHILD);
609 while (hwndChild)
611 if (hwndChild != hwndStc32)
613 GetWindowRect(hwndChild, &rectChild);
614 MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2);
616 /* move only if stc32 exist */
617 if (hwndStc32 && rectChild.left > rectStc32.right)
619 LONG old_left = rectChild.left;
621 /* move to the right of visible controls of the parent dialog */
622 rectChild.left += rectParent.right;
623 rectChild.left -= rectStc32.right;
625 child_width_fixup = rectChild.left - old_left;
627 /* move even if stc32 doesn't exist */
628 if (rectChild.top >= rectStc32.bottom)
630 LONG old_top = rectChild.top;
632 /* move below visible controls of the parent dialog */
633 rectChild.top += rectParent.bottom;
634 rectChild.top -= rectStc32.bottom - rectStc32.top;
636 child_height_fixup = rectChild.top - old_top;
639 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
640 0, 0, SWP_NOSIZE | SWP_NOZORDER);
642 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
645 /* this part moves controls of the parent dialog */
646 hwndChild = GetWindow(hwndParentDlg, GW_CHILD);
647 while (hwndChild)
649 if (hwndChild != hwndChildDlg)
651 GetWindowRect(hwndChild, &rectChild);
652 MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2);
654 /* left,top of stc32 marks the position of controls
655 * from the parent dialog
657 rectChild.left += rectStc32.left;
658 rectChild.top += rectStc32.top;
660 SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top,
661 0, 0, SWP_NOSIZE | SWP_NOZORDER);
663 hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
666 /* calculate the size of the resulting dialog */
668 /* here we have to use original parent size */
669 GetClientRect(hwndParentDlg, &rectParent);
670 GetClientRect(hwndChildDlg, &rectChild);
672 if (hwndStc32)
674 rectChild.right += child_width_fixup;
675 rectChild.bottom += child_height_fixup;
677 if (rectParent.right > rectChild.right)
679 rectParent.right += rectChild.right;
680 rectParent.right -= rectStc32.right - rectStc32.left;
682 else
684 rectParent.right = rectChild.right;
687 if (rectParent.bottom > rectChild.bottom)
689 rectParent.bottom += rectChild.bottom;
690 rectParent.bottom -= rectStc32.bottom - rectStc32.top;
692 else
694 /* child dialog is higher, unconditionally set new dialog
695 * height to its size (help_fixup will be subtracted below)
697 rectParent.bottom = rectChild.bottom + help_fixup;
700 else
702 rectParent.bottom += rectChild.bottom;
705 /* finally use fixed parent size */
706 rectParent.bottom -= help_fixup;
708 /* set the size of the parent dialog */
709 AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE),
710 FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE));
711 SetWindowPos(hwndParentDlg, 0,
712 0, 0,
713 rectParent.right - rectParent.left,
714 rectParent.bottom - rectParent.top,
715 SWP_NOMOVE | SWP_NOZORDER);
718 static INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
720 switch(uMsg) {
721 case WM_INITDIALOG:
722 return TRUE;
724 return FALSE;
727 static HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
729 LPCVOID template;
730 HRSRC hRes;
731 HANDLE hDlgTmpl = 0;
732 HWND hChildDlg = 0;
734 TRACE("\n");
737 * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME
738 * structure's hInstance parameter is not a HINSTANCE, but
739 * instead a pointer to a template resource to use.
741 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
743 HINSTANCE hinst;
744 if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
746 hinst = COMDLG32_hInstance;
747 if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
749 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
750 return NULL;
753 else
755 hinst = fodInfos->ofnInfos->hInstance;
756 if(fodInfos->unicode)
758 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
759 hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG);
761 else
763 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
764 hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG);
766 if (!hRes)
768 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
769 return NULL;
771 if (!(hDlgTmpl = LoadResource( hinst, hRes )) ||
772 !(template = LockResource( hDlgTmpl )))
774 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
775 return NULL;
778 if (fodInfos->unicode)
779 hChildDlg = CreateDialogIndirectParamW(hinst, template, hwnd,
780 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
781 (LPARAM)fodInfos->ofnInfos);
782 else
783 hChildDlg = CreateDialogIndirectParamA(hinst, template, hwnd,
784 IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate,
785 (LPARAM)fodInfos->ofnInfos);
786 if(hChildDlg)
788 ShowWindow(hChildDlg,SW_SHOW);
789 return hChildDlg;
792 else if( IsHooked(fodInfos))
794 RECT rectHwnd;
795 struct {
796 DLGTEMPLATE tmplate;
797 WORD menu,class,title;
798 } temp;
799 GetClientRect(hwnd,&rectHwnd);
800 temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
801 temp.tmplate.dwExtendedStyle = 0;
802 temp.tmplate.cdit = 0;
803 temp.tmplate.x = 0;
804 temp.tmplate.y = 0;
805 temp.tmplate.cx = 0;
806 temp.tmplate.cy = 0;
807 temp.menu = temp.class = temp.title = 0;
809 hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate,
810 hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos);
812 return hChildDlg;
814 return NULL;
817 /***********************************************************************
818 * SendCustomDlgNotificationMessage
820 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
823 LRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
825 LRESULT hook_result = 0;
827 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
829 TRACE("%p 0x%04x\n",hwndParentDlg, uCode);
831 if(!fodInfos) return 0;
833 if(fodInfos->DlgInfos.hwndCustomDlg)
835 TRACE("CALL NOTIFY for %x\n", uCode);
836 if(fodInfos->unicode)
838 OFNOTIFYW ofnNotify;
839 ofnNotify.hdr.hwndFrom=hwndParentDlg;
840 ofnNotify.hdr.idFrom=0;
841 ofnNotify.hdr.code = uCode;
842 ofnNotify.lpOFN = fodInfos->ofnInfos;
843 ofnNotify.pszFile = NULL;
844 hook_result = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
846 else
848 OFNOTIFYA ofnNotify;
849 ofnNotify.hdr.hwndFrom=hwndParentDlg;
850 ofnNotify.hdr.idFrom=0;
851 ofnNotify.hdr.code = uCode;
852 ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos;
853 ofnNotify.pszFile = NULL;
854 hook_result = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
856 TRACE("RET NOTIFY\n");
858 TRACE("Retval: 0x%08lx\n", hook_result);
859 return hook_result;
862 static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer)
864 UINT sizeUsed = 0, n, total;
865 LPWSTR lpstrFileList = NULL;
866 WCHAR lpstrCurrentDir[MAX_PATH];
867 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
869 TRACE("CDM_GETFILEPATH:\n");
871 if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) )
872 return -1;
874 /* get path and filenames */
875 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir);
876 n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
878 TRACE("path >%s< filespec >%s< %d files\n",
879 debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n);
881 if( fodInfos->unicode )
883 LPWSTR bufW = buffer;
884 total = lstrlenW(lpstrCurrentDir) + 1 + sizeUsed;
886 /* Prepend the current path */
887 n = lstrlenW(lpstrCurrentDir) + 1;
888 memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR));
889 if(n<size)
891 /* 'n' includes trailing \0 */
892 bufW[n-1] = '\\';
893 memcpy( &bufW[n], lpstrFileList, (size-n)*sizeof(WCHAR) );
895 TRACE("returned -> %s\n",debugstr_wn(bufW, total));
897 else
899 LPSTR bufA = buffer;
900 total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
901 NULL, 0, NULL, NULL);
902 total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
903 NULL, 0, NULL, NULL);
905 /* Prepend the current path */
906 n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1,
907 bufA, size, NULL, NULL);
909 if(n<size)
911 /* 'n' includes trailing \0 */
912 bufA[n-1] = '\\';
913 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
914 &bufA[n], size-n, NULL, NULL);
917 TRACE("returned -> %s\n",debugstr_an(bufA, total));
919 MemFree(lpstrFileList);
921 return total;
924 static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer)
926 UINT sizeUsed = 0;
927 LPWSTR lpstrFileList = NULL;
928 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
930 TRACE("CDM_GETSPEC:\n");
932 FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' ');
933 if( fodInfos->unicode )
935 LPWSTR bufW = buffer;
936 memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed );
938 else
940 LPSTR bufA = buffer;
941 sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed,
942 NULL, 0, NULL, NULL);
943 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
944 bufA, size, NULL, NULL);
946 MemFree(lpstrFileList);
948 return sizeUsed;
951 /***********************************************************************
952 * FILEDLG95_HandleCustomDialogMessages
954 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
956 static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
958 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
959 WCHAR lpstrPath[MAX_PATH];
960 INT_PTR retval;
962 if(!fodInfos) return FALSE;
964 switch(uMsg)
966 case CDM_GETFILEPATH:
967 retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam);
968 break;
970 case CDM_GETFOLDERPATH:
971 TRACE("CDM_GETFOLDERPATH:\n");
972 COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath);
973 if (lParam)
975 if (fodInfos->unicode)
976 lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam);
977 else
978 WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1,
979 (LPSTR)lParam, (int)wParam, NULL, NULL);
981 retval = lstrlenW(lpstrPath);
982 break;
984 case CDM_GETSPEC:
985 retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam);
986 break;
988 case CDM_SETCONTROLTEXT:
989 TRACE("CDM_SETCONTROLTEXT:\n");
990 if ( lParam )
992 if( fodInfos->unicode )
993 SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam );
994 else
995 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
997 retval = TRUE;
998 break;
1000 case CDM_HIDECONTROL:
1001 /* MSDN states that it should fail for not OFN_EXPLORER case */
1002 if (fodInfos->ofnInfos->Flags & OFN_EXPLORER)
1004 HWND control = GetDlgItem( hwnd, wParam );
1005 if (control) ShowWindow( control, SW_HIDE );
1006 retval = TRUE;
1008 else retval = FALSE;
1009 break;
1011 default:
1012 if (uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1013 FIXME("message CDM_FIRST+%04x not implemented\n", uMsg - CDM_FIRST);
1014 return FALSE;
1016 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval);
1017 return TRUE;
1020 /***********************************************************************
1021 * FileOpenDlgProc95
1023 * File open dialog procedure
1025 INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1027 #if 0
1028 TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
1029 #endif
1031 switch(uMsg)
1033 case WM_INITDIALOG:
1035 FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
1037 /* Adds the FileOpenDlgInfos in the property list of the dialog
1038 so it will be easily accessible through a GetPropA(...) */
1039 SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
1041 FILEDLG95_InitControls(hwnd);
1043 fodInfos->DlgInfos.hwndCustomDlg =
1044 CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
1046 FILEDLG95_ResizeControls(hwnd, wParam, lParam);
1047 FILEDLG95_FillControls(hwnd, wParam, lParam);
1049 SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
1050 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
1051 SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
1052 return 0;
1054 case WM_COMMAND:
1055 return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
1056 case WM_DRAWITEM:
1058 switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
1060 case IDC_LOOKIN:
1061 FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
1062 return TRUE;
1065 return FALSE;
1067 case WM_GETISHELLBROWSER:
1068 return FILEDLG95_OnWMGetIShellBrowser(hwnd);
1070 case WM_DESTROY:
1071 RemovePropA(hwnd, FileOpenDlgInfosStr);
1072 return FALSE;
1074 case WM_NOTIFY:
1076 LPNMHDR lpnmh = (LPNMHDR)lParam;
1077 UINT stringId = -1;
1079 /* set up the button tooltips strings */
1080 if(TTN_GETDISPINFOA == lpnmh->code )
1082 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
1083 switch(lpnmh->idFrom )
1085 /* Up folder button */
1086 case FCIDM_TB_UPFOLDER:
1087 stringId = IDS_UPFOLDER;
1088 break;
1089 /* New folder button */
1090 case FCIDM_TB_NEWFOLDER:
1091 stringId = IDS_NEWFOLDER;
1092 break;
1093 /* List option button */
1094 case FCIDM_TB_SMALLICON:
1095 stringId = IDS_LISTVIEW;
1096 break;
1097 /* Details option button */
1098 case FCIDM_TB_REPORTVIEW:
1099 stringId = IDS_REPORTVIEW;
1100 break;
1101 /* Desktop button */
1102 case FCIDM_TB_DESKTOP:
1103 stringId = IDS_TODESKTOP;
1104 break;
1105 default:
1106 stringId = 0;
1108 lpdi->hinst = COMDLG32_hInstance;
1109 lpdi->lpszText = MAKEINTRESOURCEA(stringId);
1111 return FALSE;
1113 default :
1114 if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
1115 return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
1116 return FALSE;
1120 /***********************************************************************
1121 * FILEDLG95_InitControls
1123 * WM_INITDIALOG message handler (before hook notification)
1125 static LRESULT FILEDLG95_InitControls(HWND hwnd)
1127 int win2000plus = 0;
1128 int win98plus = 0;
1129 int handledPath = FALSE;
1130 OSVERSIONINFOW osVi;
1131 static const WCHAR szwSlash[] = { '\\', 0 };
1132 static const WCHAR szwStar[] = { '*',0 };
1134 static const TBBUTTON tbb[] =
1136 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1137 {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1138 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1139 {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1140 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1141 {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1142 {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 },
1143 {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1144 {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 },
1146 TBADDBITMAP tba[2];
1147 RECT rectTB;
1148 RECT rectlook;
1149 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1151 tba[0].hInst = HINST_COMMCTRL;
1152 tba[0].nID = IDB_VIEW_SMALL_COLOR;
1153 tba[1].hInst = COMDLG32_hInstance;
1154 tba[1].nID = 800;
1156 TRACE("%p\n", fodInfos);
1158 /* Get windows version emulating */
1159 osVi.dwOSVersionInfoSize = sizeof(osVi);
1160 GetVersionExW(&osVi);
1161 if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1162 win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0)));
1163 } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1164 win2000plus = (osVi.dwMajorVersion > 4);
1165 if (win2000plus) win98plus = TRUE;
1167 TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus);
1169 /* Get the hwnd of the controls */
1170 fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
1171 fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
1172 fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
1174 GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook);
1175 MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2);
1177 /* construct the toolbar */
1178 GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
1179 MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
1181 rectTB.right = rectlook.right + rectTB.right - rectTB.left;
1182 rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top;
1183 rectTB.left = rectlook.right;
1184 rectTB.top = rectlook.top-1;
1186 if (fodInfos->unicode)
1187 fodInfos->DlgInfos.hwndTB = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
1188 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1189 rectTB.left, rectTB.top,
1190 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1191 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1192 else
1193 fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
1194 WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
1195 rectTB.left, rectTB.top,
1196 rectTB.right - rectTB.left, rectTB.bottom - rectTB.top,
1197 hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL);
1199 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
1201 /* FIXME: use TB_LOADIMAGES when implemented */
1202 /* SendMessageW(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
1203 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 12, (LPARAM) &tba[0]);
1204 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, 1, (LPARAM) &tba[1]);
1206 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSW, 9, (LPARAM) &tbb);
1207 SendMessageW(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0);
1209 /* Set the window text with the text specified in the OPENFILENAME structure */
1210 if(fodInfos->title)
1212 SetWindowTextW(hwnd,fodInfos->title);
1214 else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1216 WCHAR buf[16];
1217 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
1218 SetWindowTextW(hwnd, buf);
1221 /* Initialise the file name edit control */
1222 handledPath = FALSE;
1223 TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1225 if(fodInfos->filename)
1227 /* 1. If win2000 or higher and filename contains a path, use it
1228 in preference over the lpstrInitialDir */
1229 if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) {
1230 WCHAR tmpBuf[MAX_PATH];
1231 WCHAR *nameBit;
1232 DWORD result;
1234 result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit);
1235 if (result) {
1237 /* nameBit is always shorter than the original filename */
1238 lstrcpyW(fodInfos->filename,nameBit);
1240 *nameBit = 0x00;
1241 if (fodInfos->initdir == NULL)
1242 MemFree(fodInfos->initdir);
1243 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf) + 1)*sizeof(WCHAR));
1244 lstrcpyW(fodInfos->initdir, tmpBuf);
1245 handledPath = TRUE;
1246 TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n",
1247 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1249 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1251 } else {
1252 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1256 /* 2. (All platforms) If initdir is not null, then use it */
1257 if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) &&
1258 (*fodInfos->initdir!=0x00))
1260 /* Work out the proper path as supplied one might be relative */
1261 /* (Here because supplying '.' as dir browses to My Computer) */
1262 if (handledPath==FALSE) {
1263 WCHAR tmpBuf[MAX_PATH];
1264 WCHAR tmpBuf2[MAX_PATH];
1265 WCHAR *nameBit;
1266 DWORD result;
1268 lstrcpyW(tmpBuf, fodInfos->initdir);
1269 if( PathFileExistsW(tmpBuf) ) {
1270 /* initdir does not have to be a directory. If a file is
1271 * specified, the dir part is taken */
1272 if( PathIsDirectoryW(tmpBuf)) {
1273 if (tmpBuf[lstrlenW(tmpBuf)-1] != '\\') {
1274 lstrcatW(tmpBuf, szwSlash);
1276 lstrcatW(tmpBuf, szwStar);
1278 result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit);
1279 if (result) {
1280 *nameBit = 0x00;
1281 MemFree(fodInfos->initdir);
1282 fodInfos->initdir = MemAlloc((lstrlenW(tmpBuf2) + 1)*sizeof(WCHAR));
1283 lstrcpyW(fodInfos->initdir, tmpBuf2);
1284 handledPath = TRUE;
1285 TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir));
1288 else if (fodInfos->initdir)
1290 MemFree(fodInfos->initdir);
1291 fodInfos->initdir = NULL;
1292 TRACE("Value in InitDir is not an existing path, changed to (nil)\n");
1297 if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) ||
1298 (*fodInfos->initdir==0x00)))
1300 /* 3. All except w2k+: if filename contains a path use it */
1301 if (!win2000plus && fodInfos->filename &&
1302 *fodInfos->filename &&
1303 strpbrkW(fodInfos->filename, szwSlash)) {
1304 WCHAR tmpBuf[MAX_PATH];
1305 WCHAR *nameBit;
1306 DWORD result;
1308 result = GetFullPathNameW(fodInfos->filename, MAX_PATH,
1309 tmpBuf, &nameBit);
1310 if (result) {
1311 int len;
1313 /* nameBit is always shorter than the original filename */
1314 lstrcpyW(fodInfos->filename, nameBit);
1315 *nameBit = 0x00;
1317 len = lstrlenW(tmpBuf);
1318 MemFree(fodInfos->initdir);
1319 fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR));
1320 lstrcpyW(fodInfos->initdir, tmpBuf);
1322 handledPath = TRUE;
1323 TRACE("Value in Filename includes path, overriding initdir: %s, %s\n",
1324 debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1326 SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename);
1329 /* 4. win98+ and win2000+ if any files of specified filter types in
1330 current directory, use it */
1331 if ( win98plus && handledPath == FALSE &&
1332 fodInfos->filter && *fodInfos->filter) {
1334 BOOL searchMore = TRUE;
1335 LPCWSTR lpstrPos = fodInfos->filter;
1336 WIN32_FIND_DATAW FindFileData;
1337 HANDLE hFind;
1339 while (searchMore)
1341 /* filter is a list... title\0ext\0......\0\0 */
1343 /* Skip the title */
1344 if(! *lpstrPos) break; /* end */
1345 lpstrPos += lstrlenW(lpstrPos) + 1;
1347 /* See if any files exist in the current dir with this extension */
1348 if(! *lpstrPos) break; /* end */
1350 hFind = FindFirstFileW(lpstrPos, &FindFileData);
1352 if (hFind == INVALID_HANDLE_VALUE) {
1353 /* None found - continue search */
1354 lpstrPos += lstrlenW(lpstrPos) + 1;
1356 } else {
1357 searchMore = FALSE;
1359 MemFree(fodInfos->initdir);
1360 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1361 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1363 handledPath = TRUE;
1364 TRACE("No initial dir specified, but files of type %s found in current, so using it\n",
1365 debugstr_w(lpstrPos));
1366 break;
1371 /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */
1373 /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */
1374 if (handledPath == FALSE && (win2000plus || win98plus)) {
1375 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1377 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir)))
1379 if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir)))
1381 /* last fallback */
1382 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1383 TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir));
1384 } else {
1385 TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir));
1387 } else {
1388 TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir));
1390 handledPath = TRUE;
1391 } else if (handledPath==FALSE) {
1392 fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR));
1393 GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir);
1394 handledPath = TRUE;
1395 TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir));
1398 SetFocus(GetDlgItem(hwnd, IDC_FILENAME));
1399 TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir));
1401 /* Must the open as read only check box be checked ?*/
1402 if(fodInfos->ofnInfos->Flags & OFN_READONLY)
1404 SendDlgItemMessageW(hwnd,IDC_OPENREADONLY,BM_SETCHECK,TRUE,0);
1407 /* Must the open as read only check box be hidden? */
1408 if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
1410 ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
1411 EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE);
1414 /* Must the help button be hidden? */
1415 if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1417 ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1418 EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE);
1421 /* change Open to Save */
1422 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1424 WCHAR buf[16];
1425 LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR));
1426 SetDlgItemTextW(hwnd, IDOK, buf);
1427 LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR));
1428 SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf);
1430 return 0;
1433 /***********************************************************************
1434 * FILEDLG95_ResizeControls
1436 * WM_INITDIALOG message handler (after hook notification)
1438 static LRESULT FILEDLG95_ResizeControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1440 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1442 if (fodInfos->DlgInfos.hwndCustomDlg)
1444 RECT rc;
1445 UINT flags = SWP_NOACTIVATE;
1447 ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd,
1448 (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY);
1450 /* resize the custom dialog to the parent size */
1451 if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))
1452 GetClientRect(hwnd, &rc);
1453 else
1455 /* our own fake template is zero sized and doesn't have children, so
1456 * there is no need to resize it. Picasa depends on it.
1458 flags |= SWP_NOSIZE;
1459 SetRectEmpty(&rc);
1461 SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
1462 0, 0, rc.right, rc.bottom, flags);
1464 else
1466 /* Resize the height, if open as read only checkbox ad help button are
1467 * hidden and we are not using a custom template nor a customDialog
1469 if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1470 (!(fodInfos->ofnInfos->Flags &
1471 (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1473 RECT rectDlg, rectHelp, rectCancel;
1474 GetWindowRect(hwnd, &rectDlg);
1475 GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1476 GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1477 /* subtract the height of the help button plus the space between the help
1478 * button and the cancel button to the height of the dialog
1480 SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left,
1481 (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom),
1482 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1485 return TRUE;
1488 /***********************************************************************
1489 * FILEDLG95_FillControls
1491 * WM_INITDIALOG message handler (after hook notification)
1493 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1495 LPITEMIDLIST pidlItemId = NULL;
1497 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1499 TRACE("dir=%s file=%s\n",
1500 debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename));
1502 /* Get the initial directory pidl */
1504 if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir)))
1506 WCHAR path[MAX_PATH];
1508 GetCurrentDirectoryW(MAX_PATH,path);
1509 pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1512 /* Initialise shell objects */
1513 FILEDLG95_SHELL_Init(hwnd);
1515 /* Initialize the Look In combo box */
1516 FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1518 /* Initialize the filter combo box */
1519 FILEDLG95_FILETYPE_Init(hwnd);
1521 /* Browse to the initial directory */
1522 IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1524 /* Free pidlItem memory */
1525 COMDLG32_SHFree(pidlItemId);
1527 return TRUE;
1529 /***********************************************************************
1530 * FILEDLG95_Clean
1532 * Regroups all the cleaning functions of the filedlg
1534 void FILEDLG95_Clean(HWND hwnd)
1536 FILEDLG95_FILETYPE_Clean(hwnd);
1537 FILEDLG95_LOOKIN_Clean(hwnd);
1538 FILEDLG95_SHELL_Clean(hwnd);
1540 /***********************************************************************
1541 * FILEDLG95_OnWMCommand
1543 * WM_COMMAND message handler
1545 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1547 WORD wNotifyCode = HIWORD(wParam); /* notification code */
1548 WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */
1549 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1551 switch(wID)
1553 /* OK button */
1554 case IDOK:
1555 FILEDLG95_OnOpen(hwnd);
1556 break;
1557 /* Cancel button */
1558 case IDCANCEL:
1559 FILEDLG95_Clean(hwnd);
1560 EndDialog(hwnd, FALSE);
1561 break;
1562 /* Filetype combo box */
1563 case IDC_FILETYPE:
1564 FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1565 break;
1566 /* LookIn combo box */
1567 case IDC_LOOKIN:
1568 FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1569 break;
1571 /* --- toolbar --- */
1572 /* Up folder button */
1573 case FCIDM_TB_UPFOLDER:
1574 FILEDLG95_SHELL_UpFolder(hwnd);
1575 break;
1576 /* New folder button */
1577 case FCIDM_TB_NEWFOLDER:
1578 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA);
1579 break;
1580 /* List option button */
1581 case FCIDM_TB_SMALLICON:
1582 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA);
1583 break;
1584 /* Details option button */
1585 case FCIDM_TB_REPORTVIEW:
1586 FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA);
1587 break;
1588 /* Details option button */
1589 case FCIDM_TB_DESKTOP:
1590 FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1591 break;
1593 case IDC_FILENAME:
1594 break;
1597 /* Do not use the listview selection anymore */
1598 fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1599 return 0;
1602 /***********************************************************************
1603 * FILEDLG95_OnWMGetIShellBrowser
1605 * WM_GETISHELLBROWSER message handler
1607 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1610 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1612 TRACE("\n");
1614 SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser);
1616 return TRUE;
1620 /***********************************************************************
1621 * FILEDLG95_SendFileOK
1623 * Sends the CDN_FILEOK notification if required
1625 * RETURNS
1626 * TRUE if the dialog should close
1627 * FALSE if the dialog should not be closed
1629 static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos )
1631 /* ask the hook if we can close */
1632 if(IsHooked(fodInfos))
1634 LRESULT retval;
1636 TRACE("---\n");
1637 /* First send CDN_FILEOK as MSDN doc says */
1638 retval = SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1639 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1641 TRACE("canceled\n");
1642 return (retval == 0);
1645 /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */
1646 retval = SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,
1647 fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1648 if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT))
1650 TRACE("canceled\n");
1651 return (retval == 0);
1654 return TRUE;
1657 /***********************************************************************
1658 * FILEDLG95_OnOpenMultipleFiles
1660 * Handles the opening of multiple files.
1662 * FIXME
1663 * check destination buffer size
1665 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1667 WCHAR lpstrPathSpec[MAX_PATH] = {0};
1668 UINT nCount, nSizePath;
1669 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1671 TRACE("\n");
1673 if(fodInfos->unicode)
1675 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1676 ofn->lpstrFile[0] = '\0';
1678 else
1680 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos;
1681 ofn->lpstrFile[0] = '\0';
1684 COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1686 if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1687 ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1688 ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1690 LPWSTR lpstrTemp = lpstrFileList;
1692 for ( nCount = 0; nCount < nFileCount; nCount++ )
1694 LPITEMIDLIST pidl;
1696 pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1697 if (!pidl)
1699 WCHAR lpstrNotFound[100];
1700 WCHAR lpstrMsg[100];
1701 WCHAR tmp[400];
1702 static const WCHAR nl[] = {'\n',0};
1704 LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100);
1705 LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100);
1707 lstrcpyW(tmp, lpstrTemp);
1708 lstrcatW(tmp, nl);
1709 lstrcatW(tmp, lpstrNotFound);
1710 lstrcatW(tmp, nl);
1711 lstrcatW(tmp, lpstrMsg);
1713 MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION);
1714 return FALSE;
1717 /* move to the next file in the list of files */
1718 lpstrTemp += lstrlenW(lpstrTemp) + 1;
1719 COMDLG32_SHFree(pidl);
1723 nSizePath = lstrlenW(lpstrPathSpec) + 1;
1724 if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) )
1726 /* For "oldstyle" dialog the components have to
1727 be separated by blanks (not '\0'!) and short
1728 filenames have to be used! */
1729 FIXME("Components have to be separated by blanks\n");
1731 if(fodInfos->unicode)
1733 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
1734 lstrcpyW( ofn->lpstrFile, lpstrPathSpec);
1735 memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) );
1737 else
1739 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
1741 if (ofn->lpstrFile != NULL)
1743 nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1,
1744 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
1745 if (ofn->nMaxFile > nSizePath)
1747 WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed,
1748 ofn->lpstrFile + nSizePath,
1749 ofn->nMaxFile - nSizePath, NULL, NULL);
1754 fodInfos->ofnInfos->nFileOffset = nSizePath;
1755 fodInfos->ofnInfos->nFileExtension = 0;
1757 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
1758 return FALSE;
1760 /* clean and exit */
1761 FILEDLG95_Clean(hwnd);
1762 return EndDialog(hwnd,TRUE);
1765 /***********************************************************************
1766 * FILEDLG95_OnOpen
1768 * Ok button WM_COMMAND message handler
1770 * If the function succeeds, the return value is nonzero.
1772 #define ONOPEN_BROWSE 1
1773 #define ONOPEN_OPEN 2
1774 #define ONOPEN_SEARCH 3
1775 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1777 WCHAR strMsgTitle[MAX_PATH];
1778 WCHAR strMsgText [MAX_PATH];
1779 if (idCaption)
1780 LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR));
1781 else
1782 strMsgTitle[0] = '\0';
1783 LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR));
1784 MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1787 BOOL FILEDLG95_OnOpen(HWND hwnd)
1789 LPWSTR lpstrFileList;
1790 UINT nFileCount = 0;
1791 UINT sizeUsed = 0;
1792 BOOL ret = TRUE;
1793 WCHAR lpstrPathAndFile[MAX_PATH];
1794 WCHAR lpstrTemp[MAX_PATH];
1795 LPSHELLFOLDER lpsf = NULL;
1796 int nOpenAction;
1797 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1799 TRACE("hwnd=%p\n", hwnd);
1801 /* get the files from the edit control */
1802 nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0');
1804 /* try if the user selected a folder in the shellview */
1805 if(nFileCount == 0)
1807 BrowseSelectedFolder(hwnd);
1808 return FALSE;
1811 if(nFileCount > 1)
1813 ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1814 goto ret;
1817 TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList));
1820 Step 1: Build a complete path name from the current folder and
1821 the filename or path in the edit box.
1822 Special cases:
1823 - the path in the edit box is a root path
1824 (with or without drive letter)
1825 - the edit box contains ".." (or a path with ".." in it)
1828 /* Get the current directory name */
1829 if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1831 /* last fallback */
1832 GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile);
1834 PathAddBackslashW(lpstrPathAndFile);
1836 TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile));
1838 /* if the user specifyed a fully qualified path use it */
1839 if(PathIsRelativeW(lpstrFileList))
1841 lstrcatW(lpstrPathAndFile, lpstrFileList);
1843 else
1845 /* does the path have a drive letter? */
1846 if (PathGetDriveNumberW(lpstrFileList) == -1)
1847 lstrcpyW(lpstrPathAndFile+2, lpstrFileList);
1848 else
1849 lstrcpyW(lpstrPathAndFile, lpstrFileList);
1852 /* resolve "." and ".." */
1853 PathCanonicalizeW(lpstrTemp, lpstrPathAndFile );
1854 lstrcpyW(lpstrPathAndFile, lpstrTemp);
1855 TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile));
1857 MemFree(lpstrFileList);
1860 Step 2: here we have a cleaned up path
1862 We have to parse the path step by step to see if we have to browse
1863 to a folder if the path points to a directory or the last
1864 valid element is a directory.
1866 valid variables:
1867 lpstrPathAndFile: cleaned up path
1870 if (nFileCount &&
1871 (fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1872 !(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1873 nOpenAction = ONOPEN_OPEN;
1874 else
1875 nOpenAction = ONOPEN_BROWSE;
1877 /* don't apply any checks with OFN_NOVALIDATE */
1879 LPWSTR lpszTemp, lpszTemp1;
1880 LPITEMIDLIST pidl = NULL;
1881 static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0};
1883 /* check for invalid chars */
1884 if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1886 FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1887 ret = FALSE;
1888 goto ret;
1891 if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1893 lpszTemp1 = lpszTemp = lpstrPathAndFile;
1894 while (lpszTemp1)
1896 LPSHELLFOLDER lpsfChild;
1897 WCHAR lpwstrTemp[MAX_PATH];
1898 DWORD dwEaten, dwAttributes;
1899 LPWSTR p;
1901 lstrcpyW(lpwstrTemp, lpszTemp);
1902 p = PathFindNextComponentW(lpwstrTemp);
1904 if (!p) break; /* end of path */
1906 *p = 0;
1907 lpszTemp = lpszTemp + lstrlenW(lpwstrTemp);
1909 /* There are no wildcards when OFN_NOVALIDATE is set */
1910 if(*lpszTemp==0 && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1912 static const WCHAR wszWild[] = { '*', '?', 0 };
1913 /* if the last element is a wildcard do a search */
1914 if(strpbrkW(lpszTemp1, wszWild) != NULL)
1916 nOpenAction = ONOPEN_SEARCH;
1917 break;
1920 lpszTemp1 = lpszTemp;
1922 TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf);
1924 /* append a backslash to drive letters */
1925 if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' &&
1926 ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') ||
1927 (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z')))
1929 PathAddBackslashW(lpwstrTemp);
1932 dwAttributes = SFGAO_FOLDER;
1933 if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1935 /* the path component is valid, we have a pidl of the next path component */
1936 TRACE("parse OK attr=0x%08x pidl=%p\n", dwAttributes, pidl);
1937 if(dwAttributes & SFGAO_FOLDER)
1939 if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1941 ERR("bind to failed\n"); /* should not fail */
1942 break;
1944 IShellFolder_Release(lpsf);
1945 lpsf = lpsfChild;
1946 lpsfChild = NULL;
1948 else
1950 TRACE("value\n");
1952 /* end dialog, return value */
1953 nOpenAction = ONOPEN_OPEN;
1954 break;
1956 COMDLG32_SHFree(pidl);
1957 pidl = NULL;
1959 else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1961 if(*lpszTemp || /* points to trailing null for last path element */
1962 (lpwstrTemp[strlenW(lpwstrTemp)-1] == '\\')) /* or if last element ends in '\' */
1964 if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1966 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1967 break;
1970 else
1972 if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) &&
1973 !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) )
1975 FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1976 break;
1979 /* change to the current folder */
1980 nOpenAction = ONOPEN_OPEN;
1981 break;
1983 else
1985 nOpenAction = ONOPEN_OPEN;
1986 break;
1989 if(pidl) COMDLG32_SHFree(pidl);
1993 Step 3: here we have a cleaned up and validated path
1995 valid variables:
1996 lpsf: ShellFolder bound to the rightmost valid path component
1997 lpstrPathAndFile: cleaned up path
1998 nOpenAction: action to do
2000 TRACE("end validate sf=%p\n", lpsf);
2002 switch(nOpenAction)
2004 case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */
2005 TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile));
2007 int iPos;
2008 LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2009 DWORD len;
2011 /* replace the current filter */
2012 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2013 len = lstrlenW(lpszTemp)+1;
2014 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
2015 lstrcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp);
2017 /* set the filter cb to the extension when possible */
2018 if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
2019 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
2021 /* fall through */
2022 case ONOPEN_BROWSE: /* browse to the highest folder we could bind to */
2023 TRACE("ONOPEN_BROWSE\n");
2025 IPersistFolder2 * ppf2;
2026 if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
2028 LPITEMIDLIST pidlCurrent;
2029 IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
2030 IPersistFolder2_Release(ppf2);
2031 if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
2033 if (SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE)))
2035 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2038 else if( nOpenAction == ONOPEN_SEARCH )
2040 if (fodInfos->Shell.FOIShellView)
2041 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2043 COMDLG32_SHFree(pidlCurrent);
2044 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
2047 ret = FALSE;
2048 break;
2049 case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
2050 TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
2052 WCHAR *ext = NULL;
2054 /* update READONLY check box flag */
2055 if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
2056 fodInfos->ofnInfos->Flags |= OFN_READONLY;
2057 else
2058 fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
2060 /* Attach the file extension with file name*/
2061 ext = PathFindExtensionW(lpstrPathAndFile);
2062 if (! *ext)
2064 /* if no extension is specified with file name, then */
2065 /* attach the extension from file filter or default one */
2067 WCHAR *filterExt = NULL;
2068 LPWSTR lpstrFilter = NULL;
2069 static const WCHAR szwDot[] = {'.',0};
2070 int PathLength = lstrlenW(lpstrPathAndFile);
2072 /* Attach the dot*/
2073 lstrcatW(lpstrPathAndFile, szwDot);
2075 /*Get the file extension from file type filter*/
2076 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2077 fodInfos->ofnInfos->nFilterIndex-1);
2079 if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
2080 filterExt = PathFindExtensionW(lpstrFilter);
2082 if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
2083 lstrcatW(lpstrPathAndFile, filterExt + 1);
2084 else if ( fodInfos->defext ) /* attach the default file extension*/
2085 lstrcatW(lpstrPathAndFile, fodInfos->defext);
2087 /* In Open dialog: if file does not exist try without extension */
2088 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
2089 lpstrPathAndFile[PathLength] = '\0';
2092 if (fodInfos->defext) /* add default extension */
2094 /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
2095 if (*ext)
2096 ext++;
2097 if (!lstrcmpiW(fodInfos->defext, ext))
2098 fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
2099 else
2100 fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
2103 /* In Save dialog: check if the file already exists */
2104 if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG
2105 && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT
2106 && PathFileExistsW(lpstrPathAndFile))
2108 WCHAR lpstrOverwrite[100];
2109 int answer;
2111 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100);
2112 answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title,
2113 MB_YESNO | MB_ICONEXCLAMATION);
2114 if (answer == IDNO)
2116 ret = FALSE;
2117 goto ret;
2121 /* In Open dialog: check if it should be created if it doesn't exist */
2122 if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
2123 && fodInfos->ofnInfos->Flags & OFN_CREATEPROMPT
2124 && !PathFileExistsW(lpstrPathAndFile))
2126 WCHAR lpstrCreate[100];
2127 int answer;
2129 LoadStringW(COMDLG32_hInstance, IDS_CREATEFILE, lpstrCreate, 100);
2130 answer = MessageBoxW(hwnd, lpstrCreate, fodInfos->title,
2131 MB_YESNO | MB_ICONEXCLAMATION);
2132 if (answer == IDNO)
2134 ret = FALSE;
2135 goto ret;
2139 /* Check that the size of the file does not exceed buffer size.
2140 (Allow for extra \0 if OFN_MULTISELECT is set.) */
2141 if(lstrlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
2142 ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
2144 LPWSTR lpszTemp;
2146 /* fill destination buffer */
2147 if (fodInfos->ofnInfos->lpstrFile)
2149 if(fodInfos->unicode)
2151 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2153 lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile);
2154 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2155 ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0';
2157 else
2159 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2161 WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1,
2162 ofn->lpstrFile, ofn->nMaxFile, NULL, NULL);
2163 if (ofn->Flags & OFN_ALLOWMULTISELECT)
2164 ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0';
2168 /* set filename offset */
2169 lpszTemp = PathFindFileNameW(lpstrPathAndFile);
2170 fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile);
2172 /* set extension offset */
2173 lpszTemp = PathFindExtensionW(lpstrPathAndFile);
2174 fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0;
2176 /* set the lpstrFileTitle */
2177 if(fodInfos->ofnInfos->lpstrFileTitle)
2179 LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile);
2180 if(fodInfos->unicode)
2182 LPOPENFILENAMEW ofn = fodInfos->ofnInfos;
2183 lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
2185 else
2187 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2188 WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1,
2189 ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL);
2193 /* copy currently selected filter to lpstrCustomFilter */
2194 if (fodInfos->ofnInfos->lpstrCustomFilter)
2196 LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos;
2197 int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2198 NULL, 0, NULL, NULL);
2199 if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter)
2201 LPSTR s = ofn->lpstrCustomFilter;
2202 s += strlen(ofn->lpstrCustomFilter)+1;
2203 WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1,
2204 s, len, NULL, NULL);
2209 if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) )
2210 goto ret;
2212 TRACE("close\n");
2213 FILEDLG95_Clean(hwnd);
2214 ret = EndDialog(hwnd, TRUE);
2216 else
2218 WORD size;
2220 size = lstrlenW(lpstrPathAndFile) + 1;
2221 if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
2222 size += 1;
2223 /* return needed size in first two bytes of lpstrFile */
2224 *(WORD *)fodInfos->ofnInfos->lpstrFile = size;
2225 FILEDLG95_Clean(hwnd);
2226 ret = EndDialog(hwnd, FALSE);
2227 COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL);
2229 goto ret;
2231 break;
2234 ret:
2235 if(lpsf) IShellFolder_Release(lpsf);
2236 return ret;
2239 /***********************************************************************
2240 * FILEDLG95_SHELL_Init
2242 * Initialisation of the shell objects
2244 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd)
2246 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2248 TRACE("\n");
2251 * Initialisation of the FileOpenDialogInfos structure
2254 /* Shell */
2256 /*ShellInfos */
2257 fodInfos->ShellInfos.hwndOwner = hwnd;
2259 /* Disable multi-select if flag not set */
2260 if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
2262 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL;
2264 fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
2265 fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
2267 /* Construct the IShellBrowser interface */
2268 fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);
2270 return NOERROR;
2273 /***********************************************************************
2274 * FILEDLG95_SHELL_ExecuteCommand
2276 * Change the folder option and refresh the view
2277 * If the function succeeds, the return value is nonzero.
2279 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
2281 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2283 IContextMenu * pcm;
2284 TRACE("(%p,%p)\n", hwnd, lpVerb);
2286 if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
2287 SVGIO_BACKGROUND,
2288 &IID_IContextMenu,
2289 (LPVOID*)&pcm)))
2291 CMINVOKECOMMANDINFO ci;
2292 ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
2293 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
2294 ci.lpVerb = lpVerb;
2295 ci.hwnd = hwnd;
2297 IContextMenu_InvokeCommand(pcm, &ci);
2298 IContextMenu_Release(pcm);
2301 return FALSE;
2304 /***********************************************************************
2305 * FILEDLG95_SHELL_UpFolder
2307 * Browse to the specified object
2308 * If the function succeeds, the return value is nonzero.
2310 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
2312 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2314 TRACE("\n");
2316 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2317 NULL,
2318 SBSP_PARENT)))
2320 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2321 return TRUE;
2323 return FALSE;
2326 /***********************************************************************
2327 * FILEDLG95_SHELL_BrowseToDesktop
2329 * Browse to the Desktop
2330 * If the function succeeds, the return value is nonzero.
2332 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
2334 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2335 LPITEMIDLIST pidl;
2336 HRESULT hres;
2338 TRACE("\n");
2340 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
2341 hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
2342 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2343 COMDLG32_SHFree(pidl);
2344 return SUCCEEDED(hres);
2346 /***********************************************************************
2347 * FILEDLG95_SHELL_Clean
2349 * Cleans the memory used by shell objects
2351 static void FILEDLG95_SHELL_Clean(HWND hwnd)
2353 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2355 TRACE("\n");
2357 COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
2359 /* clean Shell interfaces */
2360 if (fodInfos->Shell.FOIShellView)
2362 IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
2363 IShellView_Release(fodInfos->Shell.FOIShellView);
2365 IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
2366 IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
2367 if (fodInfos->Shell.FOIDataObject)
2368 IDataObject_Release(fodInfos->Shell.FOIDataObject);
2371 /***********************************************************************
2372 * FILEDLG95_FILETYPE_Init
2374 * Initialisation of the file type combo box
2376 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
2378 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2379 int nFilters = 0; /* number of filters */
2380 int nFilterIndexCB;
2382 TRACE("\n");
2384 if(fodInfos->customfilter)
2386 /* customfilter has one entry... title\0ext\0
2387 * Set first entry of combo box item with customfilter
2389 LPWSTR lpstrExt;
2390 LPCWSTR lpstrPos = fodInfos->customfilter;
2392 /* Get the title */
2393 lpstrPos += lstrlenW(fodInfos->customfilter) + 1;
2395 /* Copy the extensions */
2396 if (! *lpstrPos) return E_FAIL; /* malformed filter */
2397 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2398 lstrcpyW(lpstrExt,lpstrPos);
2400 /* Add the item at the end of the combo */
2401 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter);
2402 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
2403 nFilters++;
2405 if(fodInfos->filter)
2407 LPCWSTR lpstrPos = fodInfos->filter;
2409 for(;;)
2411 /* filter is a list... title\0ext\0......\0\0
2412 * Set the combo item text to the title and the item data
2413 * to the ext
2415 LPCWSTR lpstrDisplay;
2416 LPWSTR lpstrExt;
2418 /* Get the title */
2419 if(! *lpstrPos) break; /* end */
2420 lpstrDisplay = lpstrPos;
2421 lpstrPos += lstrlenW(lpstrPos) + 1;
2423 CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
2425 nFilters++;
2427 /* Copy the extensions */
2428 if (!(lpstrExt = MemAlloc((lstrlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL;
2429 lstrcpyW(lpstrExt,lpstrPos);
2430 lpstrPos += lstrlenW(lpstrPos) + 1;
2432 /* Add the item at the end of the combo */
2433 CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters-1, lpstrExt);
2435 /* malformed filters are added anyway... */
2436 if (!*lpstrExt) break;
2441 * Set the current filter to the one specified
2442 * in the initialisation structure
2444 if (fodInfos->filter || fodInfos->customfilter)
2446 LPWSTR lpstrFilter;
2448 /* Check to make sure our index isn't out of bounds. */
2449 if ( fodInfos->ofnInfos->nFilterIndex >
2450 nFilters - (fodInfos->customfilter == NULL ? 0 : 1) )
2451 fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0);
2453 /* set default filter index */
2454 if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL)
2455 fodInfos->ofnInfos->nFilterIndex = 1;
2457 /* calculate index of Combo Box item */
2458 nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex;
2459 if (fodInfos->customfilter == NULL)
2460 nFilterIndexCB--;
2462 /* Set the current index selection. */
2463 CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB);
2465 /* Get the corresponding text string from the combo box. */
2466 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2467 nFilterIndexCB);
2469 if ((INT_PTR)lpstrFilter == CB_ERR) /* control is empty */
2470 lpstrFilter = NULL;
2472 if(lpstrFilter)
2474 DWORD len;
2475 CharLowerW(lpstrFilter); /* lowercase */
2476 len = lstrlenW(lpstrFilter)+1;
2477 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2478 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2480 } else
2481 fodInfos->ofnInfos->nFilterIndex = 0;
2482 return S_OK;
2485 /***********************************************************************
2486 * FILEDLG95_FILETYPE_OnCommand
2488 * WM_COMMAND of the file type combo box
2489 * If the function succeeds, the return value is nonzero.
2491 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
2493 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2495 switch(wNotifyCode)
2497 case CBN_SELENDOK:
2499 LPWSTR lpstrFilter;
2501 /* Get the current item of the filetype combo box */
2502 int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
2504 /* set the current filter index */
2505 fodInfos->ofnInfos->nFilterIndex = iItem +
2506 (fodInfos->customfilter == NULL ? 1 : 0);
2508 /* Set the current filter with the current selection */
2509 MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
2511 lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
2512 iItem);
2513 if((INT_PTR)lpstrFilter != CB_ERR)
2515 DWORD len;
2516 CharLowerW(lpstrFilter); /* lowercase */
2517 len = lstrlenW(lpstrFilter)+1;
2518 fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
2519 lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
2520 SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
2523 /* Refresh the actual view to display the included items*/
2524 if (fodInfos->Shell.FOIShellView)
2525 IShellView_Refresh(fodInfos->Shell.FOIShellView);
2528 return FALSE;
2530 /***********************************************************************
2531 * FILEDLG95_FILETYPE_SearchExt
2533 * searches for an extension in the filetype box
2535 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt)
2537 int i, iCount = CBGetCount(hwnd);
2539 TRACE("%s\n", debugstr_w(lpstrExt));
2541 if(iCount != CB_ERR)
2543 for(i=0;i<iCount;i++)
2545 if(!lstrcmpiW(lpstrExt,(LPWSTR)CBGetItemDataPtr(hwnd,i)))
2546 return i;
2549 return -1;
2552 /***********************************************************************
2553 * FILEDLG95_FILETYPE_Clean
2555 * Clean the memory used by the filetype combo box
2557 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
2559 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2560 int iPos;
2561 int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
2563 TRACE("\n");
2565 /* Delete each string of the combo and their associated data */
2566 if(iCount != CB_ERR)
2568 for(iPos = iCount-1;iPos>=0;iPos--)
2570 MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
2571 CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
2574 /* Current filter */
2575 MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
2579 /***********************************************************************
2580 * FILEDLG95_LOOKIN_Init
2582 * Initialisation of the look in combo box
2585 /* Small helper function, to determine if the unixfs shell extension is rooted
2586 * at the desktop. Copied from dlls/shell32/shfldr_unixfs.c.
2588 static inline BOOL FILEDLG95_unixfs_is_rooted_at_desktop(void) {
2589 HKEY hKey;
2590 static const WCHAR wszRootedAtDesktop[] = { 'S','o','f','t','w','a','r','e','\\',
2591 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
2592 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2593 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
2594 'N','a','m','e','S','p','a','c','e','\\','{','9','D','2','0','A','A','E','8',
2595 '-','0','6','2','5','-','4','4','B','0','-','9','C','A','7','-',
2596 '7','1','8','8','9','C','2','2','5','4','D','9','}',0 };
2598 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRootedAtDesktop, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2599 return FALSE;
2601 RegCloseKey(hKey);
2602 return TRUE;
2605 static void FILEDLG95_LOOKIN_Init(HWND hwndCombo)
2607 IShellFolder *psfRoot, *psfDrives;
2608 IEnumIDList *lpeRoot, *lpeDrives;
2609 LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
2611 LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
2613 TRACE("\n");
2615 liInfos->iMaxIndentation = 0;
2617 SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
2619 /* set item height for both text field and listbox */
2620 CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
2621 CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
2623 /* Turn on the extended UI for the combo box like Windows does */
2624 CBSetExtendedUI(hwndCombo, TRUE);
2626 /* Initialise data of Desktop folder */
2627 SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
2628 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2629 COMDLG32_SHFree(pidlTmp);
2631 SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
2633 SHGetDesktopFolder(&psfRoot);
2635 if (psfRoot)
2637 /* enumerate the contents of the desktop */
2638 if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
2640 while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
2642 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
2644 /* If the unixfs extension is rooted, we don't expand the drives by default */
2645 if (!FILEDLG95_unixfs_is_rooted_at_desktop())
2647 /* special handling for CSIDL_DRIVES */
2648 if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
2650 if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
2652 /* enumerate the drives */
2653 if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
2655 while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
2657 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
2658 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
2659 COMDLG32_SHFree(pidlAbsTmp);
2660 COMDLG32_SHFree(pidlTmp1);
2662 IEnumIDList_Release(lpeDrives);
2664 IShellFolder_Release(psfDrives);
2669 COMDLG32_SHFree(pidlTmp);
2671 IEnumIDList_Release(lpeRoot);
2673 IShellFolder_Release(psfRoot);
2676 COMDLG32_SHFree(pidlDrives);
2679 /***********************************************************************
2680 * FILEDLG95_LOOKIN_DrawItem
2682 * WM_DRAWITEM message handler
2684 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
2686 COLORREF crWin = GetSysColor(COLOR_WINDOW);
2687 COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
2688 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
2689 RECT rectText;
2690 RECT rectIcon;
2691 SHFILEINFOW sfi;
2692 HIMAGELIST ilItemImage;
2693 int iIndentation;
2694 TEXTMETRICW tm;
2695 LPSFOLDER tmpFolder;
2698 LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
2700 TRACE("\n");
2702 if(pDIStruct->itemID == -1)
2703 return 0;
2705 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
2706 pDIStruct->itemID)))
2707 return 0;
2710 if(pDIStruct->itemID == liInfos->uSelectedItem)
2712 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2714 &sfi,
2715 sizeof (sfi),
2716 SHGFI_PIDL | SHGFI_SMALLICON |
2717 SHGFI_OPENICON | SHGFI_SYSICONINDEX |
2718 SHGFI_DISPLAYNAME );
2720 else
2722 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2724 &sfi,
2725 sizeof (sfi),
2726 SHGFI_PIDL | SHGFI_SMALLICON |
2727 SHGFI_SYSICONINDEX |
2728 SHGFI_DISPLAYNAME);
2731 /* Is this item selected ? */
2732 if(pDIStruct->itemState & ODS_SELECTED)
2734 SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2735 SetBkColor(pDIStruct->hDC,crHighLight);
2736 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2738 else
2740 SetTextColor(pDIStruct->hDC,crText);
2741 SetBkColor(pDIStruct->hDC,crWin);
2742 FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2745 /* Do not indent item if drawing in the edit of the combo */
2746 if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2748 iIndentation = 0;
2749 ilItemImage = (HIMAGELIST) SHGetFileInfoW ((LPCWSTR) tmpFolder->pidlItem,
2751 &sfi,
2752 sizeof (sfi),
2753 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON
2754 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME );
2757 else
2759 iIndentation = tmpFolder->m_iIndent;
2761 /* Draw text and icon */
2763 /* Initialise the icon display area */
2764 rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2765 rectIcon.top = pDIStruct->rcItem.top;
2766 rectIcon.right = rectIcon.left + ICONWIDTH;
2767 rectIcon.bottom = pDIStruct->rcItem.bottom;
2769 /* Initialise the text display area */
2770 GetTextMetricsW(pDIStruct->hDC, &tm);
2771 rectText.left = rectIcon.right;
2772 rectText.top =
2773 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2774 rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2775 rectText.bottom =
2776 (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2778 /* Draw the icon from the image list */
2779 ImageList_Draw(ilItemImage,
2780 sfi.iIcon,
2781 pDIStruct->hDC,
2782 rectIcon.left,
2783 rectIcon.top,
2784 ILD_TRANSPARENT );
2786 /* Draw the associated text */
2787 if(sfi.szDisplayName)
2788 TextOutW(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,lstrlenW(sfi.szDisplayName));
2791 return NOERROR;
2794 /***********************************************************************
2795 * FILEDLG95_LOOKIN_OnCommand
2797 * LookIn combo box WM_COMMAND message handler
2798 * If the function succeeds, the return value is nonzero.
2800 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2802 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2804 TRACE("%p\n", fodInfos);
2806 switch(wNotifyCode)
2808 case CBN_SELENDOK:
2810 LPSFOLDER tmpFolder;
2811 int iItem;
2813 iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2815 if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2816 iItem)))
2817 return FALSE;
2820 if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2821 tmpFolder->pidlItem,
2822 SBSP_ABSOLUTE)))
2824 SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE);
2825 return TRUE;
2827 break;
2831 return FALSE;
2834 /***********************************************************************
2835 * FILEDLG95_LOOKIN_AddItem
2837 * Adds an absolute pidl item to the lookin combo box
2838 * returns the index of the inserted item
2840 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2842 LPITEMIDLIST pidlNext;
2843 SHFILEINFOW sfi;
2844 SFOLDER *tmpFolder;
2845 LookInInfos *liInfos;
2847 TRACE("%08x\n", iInsertId);
2849 if(!pidl)
2850 return -1;
2852 if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2853 return -1;
2855 tmpFolder = MemAlloc(sizeof(SFOLDER));
2856 tmpFolder->m_iIndent = 0;
2858 /* Calculate the indentation of the item in the lookin*/
2859 pidlNext = pidl;
2860 while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2862 tmpFolder->m_iIndent++;
2865 tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl);
2867 if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2868 liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2870 sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2871 SHGetFileInfoW((LPCWSTR)pidl,
2873 &sfi,
2874 sizeof(sfi),
2875 SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX
2876 | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2878 TRACE("-- Add %s attr=%08x\n", debugstr_w(sfi.szDisplayName), sfi.dwAttributes);
2880 if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2882 int iItemID;
2884 TRACE("-- Add %s at %u\n", debugstr_w(sfi.szDisplayName), tmpFolder->m_iIndent);
2886 /* Add the item at the end of the list */
2887 if(iInsertId < 0)
2889 iItemID = CBAddString(hwnd,sfi.szDisplayName);
2891 /* Insert the item at the iInsertId position*/
2892 else
2894 iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2897 CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2898 return iItemID;
2901 COMDLG32_SHFree( tmpFolder->pidlItem );
2902 MemFree( tmpFolder );
2903 return -1;
2907 /***********************************************************************
2908 * FILEDLG95_LOOKIN_InsertItemAfterParent
2910 * Insert an item below its parent
2912 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2915 LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2916 int iParentPos;
2918 TRACE("\n");
2920 iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2922 if(iParentPos < 0)
2924 iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2927 /* Free pidlParent memory */
2928 COMDLG32_SHFree((LPVOID)pidlParent);
2930 return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2933 /***********************************************************************
2934 * FILEDLG95_LOOKIN_SelectItem
2936 * Adds an absolute pidl item to the lookin combo box
2937 * returns the index of the inserted item
2939 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2941 int iItemPos;
2942 LookInInfos *liInfos;
2944 TRACE("\n");
2946 iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2948 liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2950 if(iItemPos < 0)
2952 while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2953 iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2956 else
2958 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2959 while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2961 int iRemovedItem;
2963 if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2964 break;
2965 if(iRemovedItem < iItemPos)
2966 iItemPos--;
2970 CBSetCurSel(hwnd,iItemPos);
2971 liInfos->uSelectedItem = iItemPos;
2973 return 0;
2977 /***********************************************************************
2978 * FILEDLG95_LOOKIN_RemoveMostExpandedItem
2980 * Remove the item with an expansion level over iExpansionLevel
2982 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2984 int iItemPos;
2986 LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2988 TRACE("\n");
2990 if(liInfos->iMaxIndentation <= 2)
2991 return -1;
2993 if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2995 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2996 COMDLG32_SHFree(tmpFolder->pidlItem);
2997 MemFree(tmpFolder);
2998 CBDeleteString(hwnd,iItemPos);
2999 liInfos->iMaxIndentation--;
3001 return iItemPos;
3004 return -1;
3007 /***********************************************************************
3008 * FILEDLG95_LOOKIN_SearchItem
3010 * Search for pidl in the lookin combo box
3011 * returns the index of the found item
3013 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
3015 int i = 0;
3016 int iCount = CBGetCount(hwnd);
3018 TRACE("0x%08lx 0x%x\n",searchArg, iSearchMethod);
3020 if (iCount != CB_ERR)
3022 for(;i<iCount;i++)
3024 LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
3026 if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
3027 return i;
3028 if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
3029 return i;
3033 return -1;
3036 /***********************************************************************
3037 * FILEDLG95_LOOKIN_Clean
3039 * Clean the memory used by the lookin combo box
3041 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
3043 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3044 int iPos;
3045 int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
3047 TRACE("\n");
3049 /* Delete each string of the combo and their associated data */
3050 if (iCount != CB_ERR)
3052 for(iPos = iCount-1;iPos>=0;iPos--)
3054 SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
3055 COMDLG32_SHFree(tmpFolder->pidlItem);
3056 MemFree(tmpFolder);
3057 CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
3061 /* LookInInfos structure */
3062 RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
3065 /***********************************************************************
3066 * FILEDLG95_FILENAME_FillFromSelection
3068 * fills the edit box from the cached DataObject
3070 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
3072 FileOpenDlgInfos *fodInfos;
3073 LPITEMIDLIST pidl;
3074 UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
3075 WCHAR lpstrTemp[MAX_PATH];
3076 LPWSTR lpstrAllFile, lpstrCurrFile;
3078 TRACE("\n");
3079 fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3081 /* Count how many files we have */
3082 nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
3084 /* calculate the string length, count files */
3085 if (nFileSelected >= 1)
3087 nLength += 3; /* first and last quotes, trailing \0 */
3088 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3090 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3092 if (pidl)
3094 /* get the total length of the selected file names */
3095 lpstrTemp[0] = '\0';
3096 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3098 if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
3100 nLength += lstrlenW( lpstrTemp ) + 3;
3101 nFiles++;
3103 COMDLG32_SHFree( pidl );
3108 /* allocate the buffer */
3109 if (nFiles <= 1) nLength = MAX_PATH;
3110 lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
3112 /* Generate the string for the edit control */
3113 if(nFiles >= 1)
3115 lpstrCurrFile = lpstrAllFile;
3116 for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
3118 pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
3120 if (pidl)
3122 /* get the file name */
3123 lpstrTemp[0] = '\0';
3124 GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
3126 if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
3128 if ( nFiles > 1)
3130 *lpstrCurrFile++ = '\"';
3131 lstrcpyW( lpstrCurrFile, lpstrTemp );
3132 lpstrCurrFile += lstrlenW( lpstrTemp );
3133 *lpstrCurrFile++ = '\"';
3134 *lpstrCurrFile++ = ' ';
3135 *lpstrCurrFile = 0;
3137 else
3139 lstrcpyW( lpstrAllFile, lpstrTemp );
3142 COMDLG32_SHFree( (LPVOID) pidl );
3145 SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
3147 /* Select the file name like Windows does */
3148 SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, (LPARAM)-1);
3150 HeapFree(GetProcessHeap(),0, lpstrAllFile );
3154 /* copied from shell32 to avoid linking to it
3155 * Although shell32 is already linked the behaviour of exported StrRetToStrN
3156 * is dependent on whether emulated OS is unicode or not.
3158 static HRESULT COMDLG32_StrRetToStrNW (LPWSTR dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
3160 switch (src->uType)
3162 case STRRET_WSTR:
3163 lstrcpynW(dest, src->u.pOleStr, len);
3164 COMDLG32_SHFree(src->u.pOleStr);
3165 break;
3167 case STRRET_CSTR:
3168 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
3169 dest[len-1] = 0;
3170 break;
3172 case STRRET_OFFSET:
3173 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len ) && len)
3174 dest[len-1] = 0;
3175 break;
3177 default:
3178 FIXME("unknown type %x!\n", src->uType);
3179 if (len) *dest = '\0';
3180 return E_FAIL;
3182 return S_OK;
3185 /***********************************************************************
3186 * FILEDLG95_FILENAME_GetFileNames
3188 * Copies the filenames to a delimited string list.
3189 * The delimiter is specified by the parameter 'separator',
3190 * usually either a space or a nul
3192 static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator)
3194 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3195 UINT nStrCharCount = 0; /* index in src buffer */
3196 UINT nFileIndex = 0; /* index in dest buffer */
3197 UINT nFileCount = 0; /* number of files */
3198 UINT nStrLen = 0; /* length of string in edit control */
3199 LPWSTR lpstrEdit; /* buffer for string from edit control */
3201 TRACE("\n");
3203 /* get the filenames from the edit control */
3204 nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
3205 lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) );
3206 GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
3208 TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit));
3210 /* we might get single filename without any '"',
3211 * so we need nStrLen + terminating \0 + end-of-list \0 */
3212 *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) );
3213 *sizeUsed = 0;
3215 /* build delimited file list from filenames */
3216 while ( nStrCharCount <= nStrLen )
3218 if ( lpstrEdit[nStrCharCount]=='"' )
3220 nStrCharCount++;
3221 while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
3223 (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
3224 (*sizeUsed)++;
3225 nStrCharCount++;
3227 (*lpstrFileList)[nFileIndex++] = separator;
3228 (*sizeUsed)++;
3229 nFileCount++;
3231 nStrCharCount++;
3234 /* single, unquoted string */
3235 if ((nStrLen > 0) && (*sizeUsed == 0) )
3237 lstrcpyW(*lpstrFileList, lpstrEdit);
3238 nFileIndex = lstrlenW(lpstrEdit) + 1;
3239 (*sizeUsed) = nFileIndex;
3240 nFileCount = 1;
3243 /* trailing \0 */
3244 (*lpstrFileList)[nFileIndex] = '\0';
3245 (*sizeUsed)++;
3247 MemFree(lpstrEdit);
3248 return nFileCount;
3251 #define SETDefFormatEtc(fe,cf,med) \
3253 (fe).cfFormat = cf;\
3254 (fe).dwAspect = DVASPECT_CONTENT; \
3255 (fe).ptd =NULL;\
3256 (fe).tymed = med;\
3257 (fe).lindex = -1;\
3261 * DATAOBJECT Helper functions
3264 /***********************************************************************
3265 * COMCTL32_ReleaseStgMedium
3267 * like ReleaseStgMedium from ole32
3269 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
3271 if(medium.pUnkForRelease)
3273 IUnknown_Release(medium.pUnkForRelease);
3275 else
3277 GlobalUnlock(medium.u.hGlobal);
3278 GlobalFree(medium.u.hGlobal);
3282 /***********************************************************************
3283 * GetPidlFromDataObject
3285 * Return pidl(s) by number from the cached DataObject
3287 * nPidlIndex=0 gets the fully qualified root path
3289 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
3292 STGMEDIUM medium;
3293 FORMATETC formatetc;
3294 LPITEMIDLIST pidl = NULL;
3296 TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
3298 if (!doSelected)
3299 return NULL;
3301 /* Set the FORMATETC structure*/
3302 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3304 /* Get the pidls from IDataObject */
3305 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3307 LPIDA cida = GlobalLock(medium.u.hGlobal);
3308 if(nPidlIndex <= cida->cidl)
3310 pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
3312 COMCTL32_ReleaseStgMedium(medium);
3314 return pidl;
3317 /***********************************************************************
3318 * GetNumSelected
3320 * Return the number of selected items in the DataObject.
3323 UINT GetNumSelected( IDataObject *doSelected )
3325 UINT retVal = 0;
3326 STGMEDIUM medium;
3327 FORMATETC formatetc;
3329 TRACE("sv=%p\n", doSelected);
3331 if (!doSelected) return 0;
3333 /* Set the FORMATETC structure*/
3334 SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
3336 /* Get the pidls from IDataObject */
3337 if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
3339 LPIDA cida = GlobalLock(medium.u.hGlobal);
3340 retVal = cida->cidl;
3341 COMCTL32_ReleaseStgMedium(medium);
3342 return retVal;
3344 return 0;
3348 * TOOLS
3351 /***********************************************************************
3352 * GetName
3354 * Get the pidl's display name (relative to folder) and
3355 * put it in lpstrFileName.
3357 * Return NOERROR on success,
3358 * E_FAIL otherwise
3361 static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPWSTR lpstrFileName)
3363 STRRET str;
3364 HRESULT hRes;
3366 TRACE("sf=%p pidl=%p\n", lpsf, pidl);
3368 if(!lpsf)
3370 SHGetDesktopFolder(&lpsf);
3371 hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
3372 IShellFolder_Release(lpsf);
3373 return hRes;
3376 /* Get the display name of the pidl relative to the folder */
3377 if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
3379 return COMDLG32_StrRetToStrNW(lpstrFileName, MAX_PATH, &str, pidl);
3381 return E_FAIL;
3384 /***********************************************************************
3385 * GetShellFolderFromPidl
3387 * pidlRel is the item pidl relative
3388 * Return the IShellFolder of the absolute pidl
3390 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
3392 IShellFolder *psf = NULL,*psfParent;
3394 TRACE("%p\n", pidlAbs);
3396 if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
3398 psf = psfParent;
3399 if(pidlAbs && pidlAbs->mkid.cb)
3401 if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
3403 IShellFolder_Release(psfParent);
3404 return psf;
3407 /* return the desktop */
3408 return psfParent;
3410 return NULL;
3413 /***********************************************************************
3414 * GetParentPidl
3416 * Return the LPITEMIDLIST to the parent of the pidl in the list
3418 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
3420 LPITEMIDLIST pidlParent;
3422 TRACE("%p\n", pidl);
3424 pidlParent = COMDLG32_PIDL_ILClone(pidl);
3425 COMDLG32_PIDL_ILRemoveLastID(pidlParent);
3427 return pidlParent;
3430 /***********************************************************************
3431 * GetPidlFromName
3433 * returns the pidl of the file name relative to folder
3434 * NULL if an error occurred
3436 static LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName)
3438 LPITEMIDLIST pidl = NULL;
3439 ULONG ulEaten;
3441 TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName));
3443 if(!lpcstrFileName) return NULL;
3444 if(!*lpcstrFileName) return NULL;
3446 if(!lpsf)
3448 if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) {
3449 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3450 IShellFolder_Release(lpsf);
3453 else
3455 IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL);
3457 return pidl;
3462 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl)
3464 ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
3465 HRESULT ret;
3467 TRACE("%p, %p\n", psf, pidl);
3469 ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
3471 TRACE("-- 0x%08x 0x%08x\n", uAttr, ret);
3472 /* see documentation shell 4.1*/
3473 return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
3476 /***********************************************************************
3477 * BrowseSelectedFolder
3479 static BOOL BrowseSelectedFolder(HWND hwnd)
3481 BOOL bBrowseSelFolder = FALSE;
3482 FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
3484 TRACE("\n");
3486 if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
3488 LPITEMIDLIST pidlSelection;
3490 /* get the file selected */
3491 pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
3492 if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
3494 if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
3495 pidlSelection, SBSP_RELATIVE ) ) )
3497 static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s',
3498 ' ','n','o','t',' ','e','x','i','s','t',0};
3499 MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION );
3501 bBrowseSelFolder = TRUE;
3502 SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE);
3504 COMDLG32_SHFree( pidlSelection );
3507 return bBrowseSelFolder;
3511 * Memory allocation methods */
3512 static void *MemAlloc(UINT size)
3514 return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
3517 static void MemFree(void *mem)
3519 HeapFree(GetProcessHeap(),0,mem);
3523 * Old-style (win3.1) dialogs */
3525 /***********************************************************************
3526 * FD32_GetTemplate [internal]
3528 * Get a template (or FALSE if failure) when 16 bits dialogs are used
3529 * by a 32 bits application
3532 static BOOL FD32_GetTemplate(PFD31_DATA lfs)
3534 LPOPENFILENAMEW ofnW = lfs->ofnW;
3535 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3536 HANDLE hDlgTmpl;
3538 if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE)
3540 if (!(lfs->template = LockResource( ofnW->hInstance )))
3542 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3543 return FALSE;
3546 else if (ofnW->Flags & OFN_ENABLETEMPLATE)
3548 HRSRC hResInfo;
3549 if (priv->ofnA)
3550 hResInfo = FindResourceA(priv->ofnA->hInstance,
3551 priv->ofnA->lpTemplateName,
3552 (LPSTR)RT_DIALOG);
3553 else
3554 hResInfo = FindResourceW(ofnW->hInstance,
3555 ofnW->lpTemplateName,
3556 (LPWSTR)RT_DIALOG);
3557 if (!hResInfo)
3559 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3560 return FALSE;
3562 if (!(hDlgTmpl = LoadResource(ofnW->hInstance,
3563 hResInfo)) ||
3564 !(lfs->template = LockResource(hDlgTmpl)))
3566 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3567 return FALSE;
3569 } else { /* get it from internal Wine resource */
3570 HRSRC hResInfo;
3571 if (!(hResInfo = FindResourceA(COMDLG32_hInstance,
3572 lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG)))
3574 COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
3575 return FALSE;
3577 if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) ||
3578 !(lfs->template = LockResource( hDlgTmpl )))
3580 COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
3581 return FALSE;
3584 return TRUE;
3588 /************************************************************************
3589 * FD32_Init [internal]
3590 * called from the common 16/32 code to initialize 32 bit data
3592 static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data)
3594 BOOL IsUnicode = (BOOL) data;
3595 PFD32_PRIVATE priv;
3597 priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE));
3598 lfs->private1632 = priv;
3599 if (NULL == lfs->private1632) return FALSE;
3600 if (IsUnicode)
3602 lfs->ofnW = (LPOPENFILENAMEW) lParam;
3603 if (lfs->ofnW->Flags & OFN_ENABLEHOOK)
3604 if (lfs->ofnW->lpfnHook)
3605 lfs->hook = TRUE;
3607 else
3609 priv->ofnA = (LPOPENFILENAMEA) lParam;
3610 if (priv->ofnA->Flags & OFN_ENABLEHOOK)
3611 if (priv->ofnA->lpfnHook)
3612 lfs->hook = TRUE;
3613 lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW));
3614 FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open);
3617 if (! FD32_GetTemplate(lfs)) return FALSE;
3619 return TRUE;
3622 /***********************************************************************
3623 * FD32_CallWindowProc [internal]
3625 * called from the common 16/32 code to call the appropriate hook
3627 static BOOL CALLBACK FD32_CallWindowProc(const FD31_DATA *lfs, UINT wMsg, WPARAM wParam,
3628 LPARAM lParam)
3630 BOOL ret;
3631 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3633 if (priv->ofnA)
3635 TRACE("Call hookA %p (%p, %04x, %08lx, %08lx)\n",
3636 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3637 ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3638 TRACE("ret hookA %p (%p, %04x, %08lx, %08lx)\n",
3639 priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3640 return ret;
3643 TRACE("Call hookW %p (%p, %04x, %08lx, %08lx)\n",
3644 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3645 ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam);
3646 TRACE("Ret hookW %p (%p, %04x, %08lx, %08lx)\n",
3647 lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam);
3648 return ret;
3651 /***********************************************************************
3652 * FD32_UpdateResult [internal]
3653 * update the real client structures if any
3655 static void CALLBACK FD32_UpdateResult(const FD31_DATA *lfs)
3657 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3658 LPOPENFILENAMEW ofnW = lfs->ofnW;
3660 if (priv->ofnA)
3662 if (ofnW->nMaxFile &&
3663 !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1,
3664 priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL ))
3665 priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0;
3666 priv->ofnA->nFileOffset = ofnW->nFileOffset;
3667 priv->ofnA->nFileExtension = ofnW->nFileExtension;
3671 /***********************************************************************
3672 * FD32_UpdateFileTitle [internal]
3673 * update the real client structures if any
3675 static void CALLBACK FD32_UpdateFileTitle(const FD31_DATA *lfs)
3677 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3678 LPOPENFILENAMEW ofnW = lfs->ofnW;
3680 if (priv->ofnA)
3682 if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1,
3683 priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL ))
3684 priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0;
3689 /***********************************************************************
3690 * FD32_SendLbGetCurSel [internal]
3691 * retrieve selected listbox item
3693 static LRESULT CALLBACK FD32_SendLbGetCurSel(const FD31_DATA *lfs)
3695 return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0);
3699 /************************************************************************
3700 * FD32_Destroy [internal]
3701 * called from the common 16/32 code to cleanup 32 bit data
3703 static void CALLBACK FD32_Destroy(const FD31_DATA *lfs)
3705 PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632;
3707 /* if ofnW has been allocated, have to free everything in it */
3708 if (NULL != priv && NULL != priv->ofnA)
3710 FD31_FreeOfnW(lfs->ofnW);
3711 HeapFree(GetProcessHeap(), 0, lfs->ofnW);
3715 static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks)
3717 callbacks->Init = FD32_Init;
3718 callbacks->CWP = FD32_CallWindowProc;
3719 callbacks->UpdateResult = FD32_UpdateResult;
3720 callbacks->UpdateFileTitle = FD32_UpdateFileTitle;
3721 callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel;
3722 callbacks->Destroy = FD32_Destroy;
3725 /***********************************************************************
3726 * FD32_WMMeasureItem [internal]
3728 static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
3730 LPMEASUREITEMSTRUCT lpmeasure;
3732 lpmeasure = (LPMEASUREITEMSTRUCT)lParam;
3733 lpmeasure->itemHeight = FD31_GetFldrHeight();
3734 return TRUE;
3738 /***********************************************************************
3739 * FileOpenDlgProc [internal]
3740 * Used for open and save, in fact.
3742 static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg,
3743 WPARAM wParam, LPARAM lParam)
3745 PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP);
3747 TRACE("msg=%x wparam=%lx lParam=%lx\n", wMsg, wParam, lParam);
3748 if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook)
3750 INT_PTR lRet;
3751 lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam);
3752 if (lRet)
3753 return lRet; /* else continue message processing */
3755 switch (wMsg)
3757 case WM_INITDIALOG:
3758 return FD31_WMInitDialog(hWnd, wParam, lParam);
3760 case WM_MEASUREITEM:
3761 return FD32_WMMeasureItem(hWnd, wParam, lParam);
3763 case WM_DRAWITEM:
3764 return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam);
3766 case WM_COMMAND:
3767 return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs);
3768 #if 0
3769 case WM_CTLCOLOR:
3770 SetBkColor((HDC16)wParam, 0x00C0C0C0);
3771 switch (HIWORD(lParam))
3773 case CTLCOLOR_BTN:
3774 SetTextColor((HDC16)wParam, 0x00000000);
3775 return hGRAYBrush;
3776 case CTLCOLOR_STATIC:
3777 SetTextColor((HDC16)wParam, 0x00000000);
3778 return hGRAYBrush;
3780 break;
3781 #endif
3783 return FALSE;
3787 /***********************************************************************
3788 * GetFileName31A [internal]
3790 * Creates a win31 style dialog box for the user to select a file to open/save.
3792 static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/
3793 UINT dlgType /* type dialogue : open/save */
3796 HINSTANCE hInst;
3797 BOOL bRet = FALSE;
3798 PFD31_DATA lfs;
3799 FD31_CALLBACKS callbacks;
3801 if (!lpofn || !FD31_Init()) return FALSE;
3803 TRACE("ofn flags %08x\n", lpofn->Flags);
3804 FD32_SetupCallbacks(&callbacks);
3805 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE);
3806 if (lfs)
3808 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3809 bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner,
3810 FD32_FileOpenDlgProc, (LPARAM)lfs);
3811 FD31_DestroyPrivate(lfs);
3814 TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile);
3815 return bRet;
3818 /***********************************************************************
3819 * GetFileName31W [internal]
3821 * Creates a win31 style dialog box for the user to select a file to open/save
3823 static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/
3824 UINT dlgType /* type dialogue : open/save */
3827 HINSTANCE hInst;
3828 BOOL bRet = FALSE;
3829 PFD31_DATA lfs;
3830 FD31_CALLBACKS callbacks;
3832 if (!lpofn || !FD31_Init()) return FALSE;
3834 FD32_SetupCallbacks(&callbacks);
3835 lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE);
3836 if (lfs)
3838 hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE );
3839 bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner,
3840 FD32_FileOpenDlgProc, (LPARAM)lfs);
3841 FD31_DestroyPrivate(lfs);
3844 TRACE("file %s, file offset %d, ext offset %d\n",
3845 debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension);
3846 return bRet;
3849 /* ------------------ APIs ---------------------- */
3851 /***********************************************************************
3852 * GetOpenFileNameA (COMDLG32.@)
3854 * Creates a dialog box for the user to select a file to open.
3856 * RETURNS
3857 * TRUE on success: user enters a valid file
3858 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3861 BOOL WINAPI GetOpenFileNameA(
3862 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3864 BOOL win16look = FALSE;
3866 TRACE("flags %08x\n", ofn->Flags);
3868 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3869 if (ofn->Flags & OFN_FILEMUSTEXIST)
3870 ofn->Flags |= OFN_PATHMUSTEXIST;
3872 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3873 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3875 if (win16look)
3876 return GetFileName31A(ofn, OPEN_DIALOG);
3877 else
3878 return GetFileDialog95A(ofn, OPEN_DIALOG);
3881 /***********************************************************************
3882 * GetOpenFileNameW (COMDLG32.@)
3884 * Creates a dialog box for the user to select a file to open.
3886 * RETURNS
3887 * TRUE on success: user enters a valid file
3888 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3891 BOOL WINAPI GetOpenFileNameW(
3892 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3894 BOOL win16look = FALSE;
3896 TRACE("flags %08x\n", ofn->Flags);
3898 /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */
3899 if (ofn->Flags & OFN_FILEMUSTEXIST)
3900 ofn->Flags |= OFN_PATHMUSTEXIST;
3902 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3903 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3905 if (win16look)
3906 return GetFileName31W(ofn, OPEN_DIALOG);
3907 else
3908 return GetFileDialog95W(ofn, OPEN_DIALOG);
3912 /***********************************************************************
3913 * GetSaveFileNameA (COMDLG32.@)
3915 * Creates a dialog box for the user to select a file to save.
3917 * RETURNS
3918 * TRUE on success: user enters a valid file
3919 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3922 BOOL WINAPI GetSaveFileNameA(
3923 LPOPENFILENAMEA ofn) /* [in/out] address of init structure */
3925 BOOL win16look = FALSE;
3927 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3928 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3930 if (win16look)
3931 return GetFileName31A(ofn, SAVE_DIALOG);
3932 else
3933 return GetFileDialog95A(ofn, SAVE_DIALOG);
3936 /***********************************************************************
3937 * GetSaveFileNameW (COMDLG32.@)
3939 * Creates a dialog box for the user to select a file to save.
3941 * RETURNS
3942 * TRUE on success: user enters a valid file
3943 * FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
3946 BOOL WINAPI GetSaveFileNameW(
3947 LPOPENFILENAMEW ofn) /* [in/out] address of init structure */
3949 BOOL win16look = FALSE;
3951 if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE))
3952 win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE;
3954 if (win16look)
3955 return GetFileName31W(ofn, SAVE_DIALOG);
3956 else
3957 return GetFileDialog95W(ofn, SAVE_DIALOG);
3960 /***********************************************************************
3961 * GetFileTitleA (COMDLG32.@)
3963 * See GetFileTitleW.
3965 short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf)
3967 int ret;
3968 UNICODE_STRING strWFile;
3969 LPWSTR lpWTitle;
3971 RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile);
3972 lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR));
3973 ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf);
3974 if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL );
3975 RtlFreeUnicodeString( &strWFile );
3976 RtlFreeHeap( GetProcessHeap(), 0, lpWTitle );
3977 return ret;
3981 /***********************************************************************
3982 * GetFileTitleW (COMDLG32.@)
3984 * Get the name of a file.
3986 * PARAMS
3987 * lpFile [I] name and location of file
3988 * lpTitle [O] returned file name
3989 * cbBuf [I] buffer size of lpTitle
3991 * RETURNS
3992 * Success: zero
3993 * Failure: negative number.
3995 short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf)
3997 int i, len;
3998 static const WCHAR brkpoint[] = {'*','[',']',0};
3999 TRACE("(%p %p %d);\n", lpFile, lpTitle, cbBuf);
4001 if(lpFile == NULL || lpTitle == NULL)
4002 return -1;
4004 len = lstrlenW(lpFile);
4006 if (len == 0)
4007 return -1;
4009 if(strpbrkW(lpFile, brkpoint))
4010 return -1;
4012 len--;
4014 if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':')
4015 return -1;
4017 for(i = len; i >= 0; i--)
4019 if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':')
4021 i++;
4022 break;
4026 if(i == -1)
4027 i++;
4029 TRACE("---> %s\n", debugstr_w(&lpFile[i]));
4031 len = lstrlenW(lpFile+i)+1;
4032 if(cbBuf < len)
4033 return len;
4035 lstrcpyW(lpTitle, &lpFile[i]);
4036 return 0;